summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/AUTHORS16
-rw-r--r--host/CMakeLists.txt31
-rw-r--r--host/README1
-rw-r--r--host/config/CPack.cmake42
-rw-r--r--host/config/Python.cmake49
-rw-r--r--host/config/Version.cmake71
-rw-r--r--host/config/cmake_uninstall.cmake.in (renamed from host/cmake_uninstall.cmake.in)0
-rw-r--r--host/docs/build.rst6
-rw-r--r--host/docs/dboards.rst58
-rw-r--r--host/docs/usrp2.rst4
-rw-r--r--host/examples/CMakeLists.txt5
-rw-r--r--host/examples/benchmark_rx_rate.cpp2
-rw-r--r--host/examples/rx_timed_samples.cpp7
-rw-r--r--host/examples/tx_continuous_samples.cpp110
-rw-r--r--host/include/uhd/CMakeLists.txt1
-rw-r--r--host/include/uhd/device.hpp28
-rw-r--r--host/include/uhd/device.ipp5
-rw-r--r--host/include/uhd/transport/alignment_buffer.ipp13
-rw-r--r--host/include/uhd/transport/udp_simple.hpp3
-rw-r--r--host/include/uhd/types/dict.hpp8
-rw-r--r--host/include/uhd/types/metadata.hpp48
-rw-r--r--host/include/uhd/types/tune_result.hpp10
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt2
-rw-r--r--host/include/uhd/usrp/codec_props.hpp42
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp2
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp7
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp10
-rw-r--r--host/include/uhd/usrp/device_props.hpp16
-rw-r--r--host/include/uhd/usrp/mboard_props.hpp2
-rw-r--r--host/include/uhd/usrp/mimo_usrp.hpp9
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp9
-rw-r--r--host/include/uhd/usrp/subdev_props.hpp20
-rw-r--r--host/include/uhd/usrp/subdev_spec.hpp95
-rw-r--r--host/include/uhd/usrp/tune_helper.hpp112
-rw-r--r--host/include/uhd/utils/CMakeLists.txt3
-rw-r--r--host/include/uhd/utils/algorithm.hpp36
-rw-r--r--host/include/uhd/utils/gain_group.hpp85
-rw-r--r--host/include/uhd/utils/gain_handler.hpp90
-rw-r--r--host/include/uhd/utils/pimpl.hpp3
-rw-r--r--host/include/uhd/utils/warning.hpp34
-rw-r--r--host/include/uhd/version.hpp28
-rw-r--r--host/lib/CMakeLists.txt105
-rw-r--r--host/lib/constants.hpp.in28
-rw-r--r--host/lib/device.cpp2
-rw-r--r--host/lib/gain_handler.cpp177
-rw-r--r--host/lib/ic_reg_maps/CMakeLists.txt5
-rw-r--r--host/lib/ic_reg_maps/common.py4
-rw-r--r--host/lib/ic_reg_maps/gen_max2118_regs.py126
-rw-r--r--host/lib/transport/udp_simple.cpp21
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp26
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp52
-rw-r--r--host/lib/transport/zero_copy.cpp6
-rw-r--r--host/lib/types.cpp40
-rw-r--r--host/lib/usrp/CMakeLists.txt7
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt1
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp32
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp610
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp57
-rw-r--r--host/lib/usrp/dboard/db_unknown.cpp24
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp27
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp24
-rw-r--r--host/lib/usrp/dboard_base.cpp6
-rw-r--r--host/lib/usrp/dboard_ctor_args.hpp20
-rw-r--r--host/lib/usrp/dboard_manager.cpp25
-rw-r--r--host/lib/usrp/dsp_utils.hpp42
-rw-r--r--host/lib/usrp/mimo_usrp.cpp195
-rw-r--r--host/lib/usrp/misc_utils.cpp114
-rw-r--r--host/lib/usrp/misc_utils.hpp35
-rw-r--r--host/lib/usrp/simple_usrp.cpp160
-rw-r--r--host/lib/usrp/subdev_spec.cpp77
-rw-r--r--host/lib/usrp/tune_helper.cpp83
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt1
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp96
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp63
-rw-r--r--host/lib/usrp/usrp2/fw_common.h22
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp71
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp72
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp38
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp16
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp22
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp15
-rw-r--r--host/lib/usrp/usrp_e/CMakeLists.txt23
-rw-r--r--host/lib/utils/CMakeLists.txt87
-rw-r--r--host/lib/utils/assert.cpp24
-rw-r--r--host/lib/utils/gain_group.cpp149
-rw-r--r--host/lib/utils/load_modules.cpp (renamed from host/lib/load_modules.cpp)55
-rw-r--r--host/lib/utils/paths.cpp103
-rw-r--r--host/lib/utils/props.cpp (renamed from host/lib/utils.cpp)24
-rw-r--r--host/lib/utils/thread_priority.cpp (renamed from host/lib/thread_priority.cpp)0
-rw-r--r--host/lib/utils/warning.cpp36
-rw-r--r--host/lib/version.cpp23
-rw-r--r--host/test/CMakeLists.txt5
-rw-r--r--host/test/addr_test.cpp2
-rw-r--r--host/test/gain_group_test.cpp122
-rw-r--r--host/test/gain_handler_test.cpp121
-rw-r--r--host/test/subdev_spec_test.cpp45
-rw-r--r--host/test/tune_helper_test.cpp174
-rw-r--r--host/test/warning_test.cpp29
-rw-r--r--host/uhd.pc.in4
-rw-r--r--host/utils/uhd_usrp_probe.cpp19
-rwxr-xr-xhost/utils/usrp2_card_burner.py40
-rwxr-xr-xhost/utils/usrp2_card_burner_gui.py4
105 files changed, 3545 insertions, 1227 deletions
diff --git a/host/AUTHORS b/host/AUTHORS
index d0fe52768..137eba0e6 100644
--- a/host/AUTHORS
+++ b/host/AUTHORS
@@ -1 +1,17 @@
+Matt Ettus - matt@ettus.com
+ USRP1/USRP2 FPGA code
+
Josh Blum - josh@ettus.com
+ driver framework
+ USRP2 firmware
+ USRP2 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
+
+Eric Blossom - eb@comsec.com
+ USRP2 firmware
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index e26ec03d2..ceea5d024 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -20,14 +20,11 @@ PROJECT(UHD CXX)
ENABLE_TESTING()
########################################################################
-# Setup CPack
+# Config Files (include order is important)
########################################################################
-SET(CPACK_PACKAGE_VERSION_MAJOR 0)
-SET(CPACK_PACKAGE_VERSION_MINOR 0)
-SET(CPACK_PACKAGE_VERSION_PATCH 0)
-SET(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README)
-SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE)
-INCLUDE(CPack) #include after setting vars
+INCLUDE(${CMAKE_SOURCE_DIR}/config/Python.cmake)
+INCLUDE(${CMAKE_SOURCE_DIR}/config/Version.cmake)
+INCLUDE(${CMAKE_SOURCE_DIR}/config/CPack.cmake)
########################################################################
# Install Dirs
@@ -42,7 +39,7 @@ MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
########################################################################
# Local Include Dir
########################################################################
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
########################################################################
# Optional Compiler Flags
@@ -62,10 +59,10 @@ IF(NOT CMAKE_BUILD_TYPE)
ENDIF(NOT CMAKE_BUILD_TYPE)
IF(CMAKE_COMPILER_IS_GNUCXX)
- UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL)
- UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA)
- UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC)
- UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI)
+ ADD_DEFINITIONS(-Wall)
+ ADD_DEFINITIONS(-Wextra)
+ ADD_DEFINITIONS(-pedantic)
+ ADD_DEFINITIONS(-ansi)
#only export symbols that are declared to be part of the uhd api:
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
@@ -81,12 +78,12 @@ ENDIF(MSVC)
########################################################################
# Setup Boost
########################################################################
-IF(EXISTS "/usr/lib64")
+IF(UNIX AND EXISTS "/usr/lib64")
LIST(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
-ENDIF(EXISTS "/usr/lib64")
+ENDIF(UNIX AND EXISTS "/usr/lib64")
-SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42 1.43.0" "1.43")
-FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS
+SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42" "1.43.0" "1.43")
+FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} REQUIRED COMPONENTS
date_time
filesystem
program_options
@@ -103,7 +100,7 @@ LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
# Create Uninstall Target
########################################################################
CONFIGURE_FILE(
- ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in
+ ${CMAKE_SOURCE_DIR}/config/cmake_uninstall.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
@ONLY)
diff --git a/host/README b/host/README
index 6eaf6bb42..5018ef541 100644
--- a/host/README
+++ b/host/README
@@ -18,6 +18,7 @@ LF TX
RFX Series
XCVR 2450
WBX Series
+DBSRX
########################################################################
# Documentation
diff --git a/host/config/CPack.cmake b/host/config/CPack.cmake
new file mode 100644
index 000000000..a86f452f9
--- /dev/null
+++ b/host/config/CPack.cmake
@@ -0,0 +1,42 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# Setup CPack
+########################################################################
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ettus Research - Universal Hardware Driver")
+SET(CPACK_PACKAGE_VENDOR "Ettus Research LLC")
+SET(CPACK_PACKAGE_CONTACT "support@ettus.com")
+SET(CPACK_PACKAGE_VERSION_MAJOR ${UHD_VERSION_MAJOR})
+SET(CPACK_PACKAGE_VERSION_MINOR ${UHD_VERSION_MINOR})
+SET(CPACK_PACKAGE_VERSION_PATCH ${UHD_VERSION_PATCH})
+SET(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/README)
+SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE)
+SET(BOOST_MIN_VERSION 1.36) #used in setup for boost
+STRING(REPLACE "," ", " CPACK_DEBIAN_PACKAGE_DEPENDS
+ "libboost-date-time-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-filesystem-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-program-options-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-regex-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-system-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-test-dev (>= ${BOOST_MIN_VERSION}),"
+ "libboost-thread-dev (>= ${BOOST_MIN_VERSION})"
+)
+SET(CPACK_DEBIAN_PACKAGE_RECOMMENDS "python, python-tk")
+SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel >= ${BOOST_MIN_VERSION}")
+INCLUDE(CPack) #include after setting vars
+MESSAGE(STATUS "Version: ${CPACK_PACKAGE_VERSION}")
diff --git a/host/config/Python.cmake b/host/config/Python.cmake
new file mode 100644
index 000000000..55ef6acca
--- /dev/null
+++ b/host/config/Python.cmake
@@ -0,0 +1,49 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# Setup Python
+########################################################################
+INCLUDE(FindPythonInterp)
+
+IF(NOT PYTHONINTERP_FOUND)
+ MESSAGE(FATAL_ERROR "Error: Python interpretor required by the build system.")
+ENDIF(NOT PYTHONINTERP_FOUND)
+
+MACRO(PYTHON_CHECK_MODULE module have)
+ MESSAGE(STATUS "Checking for python module ${module}")
+ EXECUTE_PROCESS(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}"
+ RESULT_VARIABLE ${have}
+ )
+ IF(${have} EQUAL 0)
+ MESSAGE(STATUS "Checking for python module ${module} - found")
+ SET(${have} TRUE)
+ ELSE(${have} EQUAL 0)
+ MESSAGE(STATUS "Checking for python module ${module} - not found")
+ SET(${have} FALSE)
+ ENDIF(${have} EQUAL 0)
+ENDMACRO(PYTHON_CHECK_MODULE)
+
+########################################################################
+# Check Modules
+########################################################################
+PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH)
+
+IF(NOT HAVE_PYTHON_MODULE_CHEETAH)
+ MESSAGE(FATAL_ERROR "Error: Cheetah Templates required by the build system.")
+ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH)
diff --git a/host/config/Version.cmake b/host/config/Version.cmake
new file mode 100644
index 000000000..a592a4565
--- /dev/null
+++ b/host/config/Version.cmake
@@ -0,0 +1,71 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# Setup Version Numbers
+########################################################################
+SET(UHD_VERSION_MAJOR 0)
+SET(UHD_VERSION_MINOR 0)
+SET(UHD_VERSION_PATCH 0)
+
+########################################################################
+# Find GIT to get repo information
+########################################################################
+MESSAGE(STATUS "Checking for git")
+FIND_PROGRAM(GIT git)
+IF(${GIT} STREQUAL "GIT-NOTFOUND")
+ MESSAGE(STATUS "Checking for git - not found")
+ELSE(${GIT} STREQUAL "GIT-NOTFOUND")
+ MESSAGE(STATUS "Checking for git - found")
+
+ #grab the git log entry for the current head
+ EXECUTE_PROCESS(
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND ${GIT} log HEAD~..HEAD --date=raw
+ OUTPUT_VARIABLE _git_log OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ #extract the timestamp from the git log entry
+ EXECUTE_PROCESS(
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND ${PYTHON_EXECUTABLE} -c "import re; print re.match('^.*Date:\\s*(\\d*).*$', '''${_git_log}''', re.MULTILINE | re.DOTALL).groups()[0]"
+ OUTPUT_VARIABLE _git_timestamp OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ #format the timestamp into YYYY-MM-DD
+ EXECUTE_PROCESS(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import time; print time.strftime('%Y%m%d', time.gmtime(${_git_timestamp}))"
+ OUTPUT_VARIABLE _git_date OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ SET(UHD_VERSION_MAJOR ${_git_date})
+
+ #format the timestamp into HH-MM-SS
+ EXECUTE_PROCESS(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import time; print time.strftime('%H%M%S', time.gmtime(${_git_timestamp}))"
+ OUTPUT_VARIABLE _git_time OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ SET(UHD_VERSION_MINOR ${_git_time})
+
+ #grab the git ref id for the current head
+ EXECUTE_PROCESS(
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND ${GIT} rev-parse --short HEAD
+ OUTPUT_VARIABLE _git_rev OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ SET(UHD_VERSION_PATCH ${_git_rev})
+
+ENDIF(${GIT} STREQUAL "GIT-NOTFOUND")
diff --git a/host/cmake_uninstall.cmake.in b/host/config/cmake_uninstall.cmake.in
index 6031a6ca9..6031a6ca9 100644
--- a/host/cmake_uninstall.cmake.in
+++ b/host/config/cmake_uninstall.cmake.in
diff --git a/host/docs/build.rst b/host/docs/build.rst
index 6f0afdb6e..8f0d0db59 100644
--- a/host/docs/build.rst
+++ b/host/docs/build.rst
@@ -147,6 +147,12 @@ Build the project in MSVC
**Note:** you may not have permission to build the install target.
You need to be an administrator or to run MSVC as administrator.
+** alternative command line instructions **
+
+* Open the Visual Studio Command Prompt Shorcut
+* DevEnv <uhd-repo-path>\host\build\ALL_BUILD.vcproj /Build Release
+* DevEnv <uhd-repo-path>\host\build\INSTALL.vcproj /Build Release
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Setup the PATH environment variable
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst
index 9c496ebee..b66fd2069 100644
--- a/host/docs/dboards.rst
+++ b/host/docs/dboards.rst
@@ -32,7 +32,20 @@ The Basic TX and LFTX boards have 1 quadrature subdevice using both antennas.
The boards have no tunable elements or programmable gains.
Though the magic of aliasing, you can up-convert signals
-greater than the nyquist rate of the DAC.
+greater than the Nyquist rate of the DAC.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+DBSRX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The DBSRX board has 1 quadrature subdevice.
+
+Receive Antennas: **J3**
+
+The board has no user selectable antenna setting
+
+Recieve Gains:
+ **GC1**, Range: 0-56dB
+ **GC2**, Range: 0-24dB
^^^^^^^^^^^^^^^^^^^^^^^^^^^
RFX Series
@@ -45,7 +58,7 @@ The user may set the receive antenna to be TX/RX or RX2.
However, when using an RFX board in full-duplex mode,
the receive antenna will always be set to RX2, regardless of the settings.
-Recieve Gains: **PGA0**, Range: 0-45dB
+Recieve Gains: **PGA0**, Range: 0-70dB (except RFX400 range is 0-45dB)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
XCVR 2450
@@ -87,3 +100,44 @@ the receive antenna will always be set to RX2, regardless of the settings.
Transmit Gains: **PGA0**, Range: 0-25dB
Recieve Gains: **PGA0**, Range: 0-31.5dB
+
+------------------------------------------------------------------------
+Daughterboard Modifications
+------------------------------------------------------------------------
+
+Sometimes, daughterboards will require modification
+to work on certain frequencies or to work with certain hardware.
+Modification usually involves moving/removing a SMT component
+and burning a new daughterboard id into the eeprom.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+DBSRX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Due to different clocking capabilities,
+the DBSRX will require modifications to operate on a non-USRP1 motherboard.
+On a USRP1 motherboard, a divided clock is provided from an FPGA pin
+because the standard daughterboard clock lines cannot provided a divided clock.
+However, on other USRP motherboards, the divided clock is provided
+over the standard daughterboard clock lines.
+
+**Step 1: Move the clock configuration resistor**
+
+Remove R193 (which is 10 ohms, 0603 size) and put it on R194, which is empty.
+This is made somewhat more complicated by the fact that the silkscreen is not clear in that area.
+R193 is on the back, immediately below the large beige connector, J2.
+R194 is just below, and to the left of R193.
+The silkscreen for R193 is ok, but for R194,
+it is upside down, and partially cut off.
+If you lose R193, you can use anything from 0 to 10 ohms there.
+
+**Step 2: Burn a new daughterboard id into the EEPROM**
+
+With the daughterboard plugged-in, run the following commands:
+::
+
+ cd <prefix>/share/uhd/utils
+ ./usrp_burn_db_eeprom --id=0x000d --unit=RX --args=<args> --db=<db>
+
+* <args> are device address arguments (optional if only one USRP is on your machine)
+* <db> is the name of the daughterboard slot (optional if the USRP has only one slot)
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 76b27fd31..bc4ea0e44 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -38,7 +38,7 @@ Run the following commands:
./configure --host=mb
make
-*The image file will be ./apps/txrx_uhd.bin*
+*The image file will be ./usrp2/usrp2_txrx_uhd.bin*
------------------------------------------------------------------------
Load the images onto the SD card
@@ -161,7 +161,7 @@ The USRP2 will reply to icmp echo requests.
**Monitor the USRP2:**
You can read the serial port on the rear of the USRP2
to get debug verbose from the embedded microcontroller.
-Use a standard USB to tty-level serial converter at 230400 baud.
+Use a standard USB to 3.3v-level serial converter at 230400 baud.
The microcontroller prints useful information about IP addresses,
MAC addresses, control packets, and fast-path settings.
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 5071b114f..10a9a833a 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -15,6 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+
+ADD_EXECUTABLE(tx_continuous_samples tx_continuous_samples.cpp)
+TARGET_LINK_LIBRARIES(tx_continuous_samples uhd)
+
ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp)
TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd)
@@ -25,6 +29,7 @@ ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
INSTALL(TARGETS
+ tx_continuous_samples
benchmark_rx_rate
rx_timed_samples
tx_timed_samples
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 752facb0d..8fae813cf 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -66,7 +66,7 @@ static inline void test_device(
//handle the error codes
switch(md.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
- case uhd::rx_metadata_t::ERROR_CODE_OVERRUN:
+ case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
break;
default:
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index a72e1ec81..5fbf8b6c5 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -74,8 +74,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//setup streaming
std::cout << std::endl;
- std::cout << boost::format("Begin streaming %u samples, %d seconds in the future...")
- % total_num_samps % seconds_in_future << std::endl;
+ std::cout << boost::format(
+ "Begin streaming %u samples, %d seconds in the future..."
+ ) % total_num_samps % seconds_in_future << std::endl;
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = total_num_samps;
stream_cmd.stream_now = false;
@@ -102,7 +103,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (num_acc_samps == 0) continue;
std::cout << boost::format(
"Got timeout before all samples received, possible packet loss, exiting loop..."
- ) % md.error_code << std::endl;
+ ) << std::endl;
goto done_loop;
default:
diff --git a/host/examples/tx_continuous_samples.cpp b/host/examples/tx_continuous_samples.cpp
new file mode 100644
index 000000000..cf70b07fb
--- /dev/null
+++ b/host/examples/tx_continuous_samples.cpp
@@ -0,0 +1,110 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/thread/thread_time.hpp> //system time
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args;
+ size_t total_duration;
+ size_t samps_per_packet;
+ double tx_rate, freq;
+ float ampl;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("duration", po::value<size_t>(&total_duration)->default_value(3), "number of seconds to transmit")
+ ("spp", po::value<size_t>(&samps_per_packet)->default_value(1000), "number of samples per packet")
+ ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ("ampl", po::value<float>(&ampl)->default_value(float(0.3)), "amplitude of each sample")
+ ("dilv", "specify to disable inner-loop verbose")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD TX Continuous Samples %s") % desc << std::endl;
+ return ~0;
+ }
+
+ bool verbose = vm.count("dilv") == 0;
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
+
+ //set properties on the device
+ std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
+ sdev->set_tx_rate(tx_rate);
+ std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
+ sdev->set_tx_freq(freq);
+
+ //allocate data to send
+ std::vector<std::complex<float> > buff(samps_per_packet, std::complex<float>(ampl, ampl));
+
+ //setup the metadata flags
+ uhd::tx_metadata_t md;
+ md.start_of_burst = true; //always SOB (good for continuous streaming)
+ md.end_of_burst = false;
+
+ //send the data in multiple packets
+ boost::system_time end_time(boost::get_system_time() + boost::posix_time::seconds(total_duration));
+ while(end_time > boost::get_system_time()){
+ //send samples per packet (driver fragments internally)
+ size_t num_tx_samps = dev->send(
+ &buff.front(), samps_per_packet, md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::SEND_MODE_FULL_BUFF
+ );
+ if(verbose) std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl;
+ }
+
+ //send a mini EOB packet
+ if(verbose) std::cout << std::endl << boost::format("Sending packet with end-of-burst") << std::endl;
+ md.start_of_burst = false;
+ md.end_of_burst = true;
+ dev->send(
+ NULL, 0, md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::SEND_MODE_FULL_BUFF
+ );
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt
index c0339dbd3..ad528c9fb 100644
--- a/host/include/uhd/CMakeLists.txt
+++ b/host/include/uhd/CMakeLists.txt
@@ -25,6 +25,7 @@ INSTALL(FILES
config.hpp
device.hpp
device.ipp
+ version.hpp
wax.hpp
DESTINATION ${INCLUDE_DIR}/uhd
)
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index a19d22880..c48b3dfff 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -42,6 +42,9 @@ public:
typedef boost::function<device_addrs_t(const device_addr_t &)> find_t;
typedef boost::function<sptr(const device_addr_t &)> make_t;
+ //! A reasonable default timeout for receive
+ static const size_t default_recv_timeout_ms = 100;
+
/*!
* Register a device into the discovery and factory system.
*
@@ -158,12 +161,7 @@ public:
* See the rx metadata fragment flags and offset fields for details.
*
* This is a blocking call and will not return until the number
- * of samples returned have been written into each buffer.
- * However, a call to receive may timeout and return zero samples.
- * The timeout duration is decided by the underlying transport layer.
- * The caller should assume that the call to receive will not return
- * immediately when no packets are available to the transport layer,
- * and that the timeout duration is reasonably tuned for performance.
+ * of samples returned have been written into each buffer or timeout.
*
* When using the full buffer recv mode, the metadata only applies
* to the first packet received and written into the recv buffers.
@@ -174,6 +172,7 @@ public:
* \param metadata data to fill describing the buffer
* \param io_type the type of data to fill into the buffer
* \param recv_mode tells recv how to load the buffer
+ * \param timeout_ms the timeout in milliseconds to wait for a packet
* \return the number of samples received or 0 on error
*/
virtual size_t recv(
@@ -181,7 +180,8 @@ public:
size_t nsamps_per_buff,
rx_metadata_t &metadata,
const io_type_t &io_type,
- recv_mode_t recv_mode
+ recv_mode_t recv_mode,
+ size_t timeout_ms = default_recv_timeout_ms
) = 0;
/*!
@@ -192,7 +192,8 @@ public:
size_t nsamps_per_buff,
rx_metadata_t &metadata,
const io_type_t &io_type,
- recv_mode_t recv_mode
+ recv_mode_t recv_mode,
+ size_t timeout_ms = default_recv_timeout_ms
);
//! Deprecated
@@ -213,6 +214,17 @@ public:
*/
virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+ /*!
+ * Receive and asynchronous message from the device.
+ * \param async_metadata the metadata to be filled in
+ * \param timeout_ms the timeout in milliseconds to wait for a message
+ * \return true when the async_metadata is valid, false for timeout
+ */
+ virtual bool recv_async_msg(
+ async_metadata_t &async_metadata,
+ size_t timeout_ms = default_recv_timeout_ms
+ ) = 0;
+
};
} //namespace uhd
diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp
index c38a2e43e..603c52859 100644
--- a/host/include/uhd/device.ipp
+++ b/host/include/uhd/device.ipp
@@ -52,12 +52,13 @@ namespace uhd{
size_t nsamps_per_buff,
rx_metadata_t &metadata,
const io_type_t &io_type,
- recv_mode_t recv_mode
+ recv_mode_t recv_mode,
+ size_t timeout_ms
){
return this->recv(
std::vector<void *>(1, buff),
nsamps_per_buff, metadata,
- io_type, recv_mode
+ io_type, recv_mode, timeout_ms
);
}
diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp
index ed7cfd26c..61b3b60f5 100644
--- a/host/include/uhd/transport/alignment_buffer.ipp
+++ b/host/include/uhd/transport/alignment_buffer.ipp
@@ -57,12 +57,15 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/
std::vector<elem_type> &elems,
const time_duration_t &time
){
+ boost::system_time exit_time = boost::get_system_time() + time;
buff_contents_type buff_contents_tmp;
std::list<size_t> indexes_to_do(_all_indexes);
//do an initial pop to load an initial sequence id
size_t index = indexes_to_do.front();
- if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false;
+ if (not _buffs[index]->pop_with_timed_wait(
+ buff_contents_tmp, exit_time - boost::get_system_time()
+ )) return false;
elems[index] = buff_contents_tmp.first;
seq_type expected_seq_id = buff_contents_tmp.second;
indexes_to_do.pop_front();
@@ -75,7 +78,9 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/
_there_was_a_clear = false;
indexes_to_do = _all_indexes;
index = indexes_to_do.front();
- if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false;
+ if (not _buffs[index]->pop_with_timed_wait(
+ buff_contents_tmp, exit_time - boost::get_system_time()
+ )) return false;
elems[index] = buff_contents_tmp.first;
expected_seq_id = buff_contents_tmp.second;
indexes_to_do.pop_front();
@@ -83,7 +88,9 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/
//pop an element off for this index
index = indexes_to_do.front();
- if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false;
+ if (not _buffs[index]->pop_with_timed_wait(
+ buff_contents_tmp, exit_time - boost::get_system_time()
+ )) return false;
//if the sequence id matches:
// store the popped element into the output,
diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp
index 98dca02f0..c84393ecf 100644
--- a/host/include/uhd/transport/udp_simple.hpp
+++ b/host/include/uhd/transport/udp_simple.hpp
@@ -73,9 +73,10 @@ public:
* Receive into the provided buffer.
* Blocks until data is received or a timeout occurs.
* \param buff a mutable buffer to receive into
+ * \param timeout_ms the timeout in milliseconds
* \return the number of bytes received or zero on timeout
*/
- virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0;
+ virtual size_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms) = 0;
};
}} //namespace
diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp
index 50a2b5c3b..de96ea768 100644
--- a/host/include/uhd/types/dict.hpp
+++ b/host/include/uhd/types/dict.hpp
@@ -20,7 +20,10 @@
#include <uhd/config.hpp>
#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
#include <stdexcept>
+#include <typeinfo>
#include <vector>
#include <list>
@@ -117,7 +120,10 @@ namespace uhd{
BOOST_FOREACH(const pair_t &p, _map){
if (p.first == key) return p.second;
}
- throw std::invalid_argument("key not found in dict");
+ throw std::invalid_argument(str(boost::format(
+ "key \"%s\" not found in dict(%s, %s)"
+ ) % boost::lexical_cast<std::string>(key)
+ % typeid(Key).name() % typeid(Val).name()));
}
/*!
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 039196250..65952941c 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -26,7 +26,7 @@ namespace uhd{
/*!
* RX metadata structure for describing sent IF data.
- * Includes stream ID, time specification, and fragmentation flags.
+ * Includes time specification, fragmentation flags, burst flags, and error codes.
* The receive routines will convert IF data headers into metadata.
*/
struct UHD_API rx_metadata_t{
@@ -62,7 +62,7 @@ namespace uhd{
* - timeout: no packet received, underlying code timed-out
* - late command: a stream command was issued in the past
* - broken chain: expected another stream command
- * - overrun: an internal receive buffer has overrun
+ * - overflow: an internal receive buffer has filled
* - bad packet: the buffer was unrecognizable as a vrt packet
*
* Note: When an overrun occurs in continuous streaming mode,
@@ -74,27 +74,21 @@ namespace uhd{
* - none
* - late command
* - broken chain
- * - overrun
+ * - overflow
*/
enum error_code_t {
ERROR_CODE_NONE = 0x0,
ERROR_CODE_TIMEOUT = 0x1,
ERROR_CODE_LATE_COMMAND = 0x2,
ERROR_CODE_BROKEN_CHAIN = 0x4,
- ERROR_CODE_OVERRUN = 0x8,
+ ERROR_CODE_OVERFLOW = 0x8,
ERROR_CODE_BAD_PACKET = 0xf
} error_code;
-
- /*!
- * The default constructor:
- * Sets the fields to default values (flags set to false).
- */
- rx_metadata_t(void);
};
/*!
* TX metadata structure for describing received IF data.
- * Includes stream ID, time specification, and burst flags.
+ * Includes time specification, and start and stop burst flags.
* The send routines will convert the metadata to IF data headers.
*/
struct UHD_API tx_metadata_t{
@@ -121,6 +115,38 @@ namespace uhd{
tx_metadata_t(void);
};
+ /*!
+ * Async metadata structure for describing transmit related events.
+ */
+ struct UHD_API async_metadata_t{
+ //! The channel number in a mimo configuration
+ size_t channel;
+
+ /*!
+ * Time specification: when the async event occurred.
+ */
+ bool has_time_spec;
+ time_spec_t time_spec;
+
+ /*!
+ * Event codes:
+ * - success: a packet was successfully transmitted
+ * - underflow: an internal send buffer has emptied
+ * - sequence error: packet loss between host and device
+ * - time error: packet had time that was late (or too early)
+ * - underflow in packet: underflow occurred inside a packet
+ * - sequence error in burst: packet loss within a burst
+ */
+ enum event_code_t {
+ EVENT_CODE_SUCCESS = 0x1,
+ EVENT_CODE_UNDERFLOW = 0x2,
+ EVENT_CODE_SEQ_ERROR = 0x4,
+ EVENT_CODE_TIME_ERROR = 0x8,
+ EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
+ EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
+ } event_code;
+ };
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_METADATA_HPP */
diff --git a/host/include/uhd/types/tune_result.hpp b/host/include/uhd/types/tune_result.hpp
index c428a7692..9eebc161a 100644
--- a/host/include/uhd/types/tune_result.hpp
+++ b/host/include/uhd/types/tune_result.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_UHD_TYPES_TUNE_RESULT_HPP
#include <uhd/config.hpp>
+#include <string>
namespace uhd{
@@ -28,15 +29,18 @@ namespace uhd{
* the target and actual intermediate frequency.
* The struct hold the result of tuning the DSP as
* the target and actual digital converter frequency.
- * It also tell us weather or not the spectrum is inverted.
*/
struct UHD_API tune_result_t{
double target_inter_freq;
double actual_inter_freq;
double target_dsp_freq;
double actual_dsp_freq;
- bool spectrum_inverted;
- tune_result_t(void);
+
+ /*!
+ * Create a pretty print string for this tune result struct.
+ * \return the printable string
+ */
+ std::string to_pp_string(void) const;
};
} //namespace uhd
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index 6f8c1a2d8..76ee24e5f 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -18,6 +18,7 @@
INSTALL(FILES
#### props headers ###
+ codec_props.hpp
dboard_props.hpp
device_props.hpp
dsp_props.hpp
@@ -32,6 +33,7 @@ INSTALL(FILES
dboard_manager.hpp
### utilities ###
+ subdev_spec.hpp
tune_helper.hpp
### interfaces ###
diff --git a/host/include/uhd/usrp/codec_props.hpp b/host/include/uhd/usrp/codec_props.hpp
new file mode 100644
index 000000000..ab09b1703
--- /dev/null
+++ b/host/include/uhd/usrp/codec_props.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_CODEC_PROPS_HPP
+#define INCLUDED_UHD_USRP_CODEC_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device codec properties:
+ * A codec is expected to have a rate and gain elements.
+ * Other properties can be discovered through the others prop.
+ */
+ enum codec_prop_t{
+ CODEC_PROP_NAME = 'n', //ro, std::string
+ CODEC_PROP_OTHERS = 'o', //ro, prop_names_t
+ CODEC_PROP_GAIN_I = 'i', //rw, float
+ CODEC_PROP_GAIN_Q = 'q', //rw, float
+ CODEC_PROP_GAIN_RANGE = 'r', //ro, gain_range_t
+ CODEC_PROP_GAIN_NAMES = 'G' //ro, prop_names_t
+ };
+
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_CODEC_PROPS_HPP */
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
index e88d39876..9b75d791f 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -40,7 +40,7 @@ public:
* Derived classes should pass the args into the base class,
* but should not deal with the internals of the args.
*/
- struct ctor_args_impl; typedef ctor_args_impl* ctor_args_t;
+ typedef void * ctor_args_t;
//structors
dboard_base(ctor_args_t);
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
index caf1e6ee6..fc7ea3052 100644
--- a/host/include/uhd/usrp/dboard_iface.hpp
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -22,6 +22,7 @@
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/cstdint.hpp>
+#include <string>
#include <vector>
namespace uhd{ namespace usrp{
@@ -65,6 +66,12 @@ public:
};
/*!
+ * Get the motherboard name of the form: usrp1, usrp2...
+ * \return string representing the motherboard name
+ */
+ virtual std::string get_mboard_name(void) = 0;
+
+ /*!
* Write to an aux dac.
*
* \param unit which unit rx or tx
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
index 4d5c5efbd..aab6c31ce 100644
--- a/host/include/uhd/usrp/dboard_props.hpp
+++ b/host/include/uhd/usrp/dboard_props.hpp
@@ -23,16 +23,18 @@
namespace uhd{ namespace usrp{
/*!
- * Possible device dboard properties
+ * Possible device dboard properties:
+ * A dboard has an id, one or more subdevices, and a codec.
+ * A dboard is considered to be unidirectional (RX or TX).
*/
enum dboard_prop_t{
DBOARD_PROP_NAME = 'n', //ro, std::string
DBOARD_PROP_SUBDEV = 's', //ro, wax::obj
DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t
- DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t
DBOARD_PROP_DBOARD_ID = 'i', //rw, dboard_id_t
- DBOARD_PROP_DBOARD_IFACE = 'f' //ro, dboard_iface::sptr
- //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet
+ DBOARD_PROP_DBOARD_IFACE = 'f', //ro, dboard_iface::sptr
+ DBOARD_PROP_CODEC = 'c', //ro, wax::obj
+ DBOARD_PROP_GAIN_GROUP = 'g' //ro, gain_group
};
}} //namespace
diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp
index 983bcb672..346eec179 100644
--- a/host/include/uhd/usrp/device_props.hpp
+++ b/host/include/uhd/usrp/device_props.hpp
@@ -34,22 +34,6 @@ namespace uhd{ namespace usrp{
DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t
};
- ////////////////////////////////////////////////////////////////////////
- /*! ------ not dealing with yet, commented out ------------
- * Possible device codec properties:
- * A codec is expected to have a rate and gain elements.
- * Other properties can be discovered through the others prop.
- */
- /*enum codec_prop_t{
- CODEC_PROP_NAME, //ro, std::string
- CODEC_PROP_OTHERS, //ro, prop_names_t
- CODEC_PROP_GAIN, //rw, gain_t
- CODEC_PROP_GAIN_RANGE, //ro, gain_range_t
- CODEC_PROP_GAIN_NAMES, //ro, prop_names_t
- //CODEC_PROP_CLOCK_RATE //ro, freq_t //----> not sure we care to know
- };*/
-
-
}} //namespace
#endif /* INCLUDED_UHD_USRP_DEVICE_PROPS_HPP */
diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp
index a432ce50c..0f250f439 100644
--- a/host/include/uhd/usrp/mboard_props.hpp
+++ b/host/include/uhd/usrp/mboard_props.hpp
@@ -39,6 +39,8 @@ namespace uhd{ namespace usrp{
MBOARD_PROP_RX_DBOARD_NAMES = 'E', //ro, prop_names_t
MBOARD_PROP_TX_DBOARD = 'v', //ro, wax::obj
MBOARD_PROP_TX_DBOARD_NAMES = 'V', //ro, prop_names_t
+ MBOARD_PROP_RX_SUBDEV_SPEC = 'r', //rw, subdev_spec_t
+ MBOARD_PROP_TX_SUBDEV_SPEC = 'R', //rw, subdev_spec_t
MBOARD_PROP_CLOCK_CONFIG = 'C', //rw, clock_config_t
MBOARD_PROP_TIME_NOW = 't', //rw, time_spec_t
MBOARD_PROP_TIME_NEXT_PPS = 'T', //wo, time_spec_t
diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp
index 68a42cad8..10a404059 100644
--- a/host/include/uhd/usrp/mimo_usrp.hpp
+++ b/host/include/uhd/usrp/mimo_usrp.hpp
@@ -24,6 +24,7 @@
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/types/tune_result.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
@@ -119,11 +120,15 @@ public:
/*******************************************************************
* RX methods
******************************************************************/
+ virtual void set_rx_subdev_spec(size_t chan, const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(size_t chan) = 0;
+
virtual void set_rx_rate_all(double rate) = 0;
virtual double get_rx_rate_all(void) = 0;
virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0;
virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0;
+ virtual double get_rx_freq(size_t chan) = 0;
virtual freq_range_t get_rx_freq_range(size_t chan) = 0;
virtual void set_rx_gain(size_t chan, float gain) = 0;
@@ -147,11 +152,15 @@ public:
/*******************************************************************
* TX methods
******************************************************************/
+ virtual void set_tx_subdev_spec(size_t chan, const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(size_t chan) = 0;
+
virtual void set_tx_rate_all(double rate) = 0;
virtual double get_tx_rate_all(void) = 0;
virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0;
virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0;
+ virtual double get_tx_freq(size_t chan) = 0;
virtual freq_range_t get_tx_freq_range(size_t chan) = 0;
virtual void set_tx_gain(size_t chan, float gain) = 0;
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index 1d9136f08..4da63c929 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -24,6 +24,7 @@
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/types/tune_result.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
@@ -107,11 +108,15 @@ public:
/*******************************************************************
* RX methods
******************************************************************/
+ virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0;
+
virtual void set_rx_rate(double rate) = 0;
virtual double get_rx_rate(void) = 0;
virtual tune_result_t set_rx_freq(double freq) = 0;
virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0;
+ virtual double get_rx_freq(void) = 0;
virtual freq_range_t get_rx_freq_range(void) = 0;
virtual void set_rx_gain(float gain) = 0;
@@ -134,11 +139,15 @@ public:
/*******************************************************************
* TX methods
******************************************************************/
+ virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0;
+
virtual void set_tx_rate(double rate) = 0;
virtual double get_tx_rate(void) = 0;
virtual tune_result_t set_tx_freq(double freq) = 0;
virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0;
+ virtual double get_tx_freq(void) = 0;
virtual freq_range_t get_tx_freq_range(void) = 0;
virtual void set_tx_gain(float gain) = 0;
diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp
index 1f8e91d68..cd07cb7a8 100644
--- a/host/include/uhd/usrp/subdev_props.hpp
+++ b/host/include/uhd/usrp/subdev_props.hpp
@@ -23,6 +23,22 @@
namespace uhd{ namespace usrp{
/*!
+ * Possible subdev connection types:
+ *
+ * A complex subdevice is physically connected to both channels,
+ * which may be connected in one of two ways: IQ or QI (swapped).
+ *
+ * A real subdevice is only physically connected one channel,
+ * either only the I channel or only the Q channel.
+ */
+ enum subdev_conn_t{
+ SUBDEV_CONN_COMPLEX_IQ = 'C',
+ SUBDEV_CONN_COMPLEX_QI = 'c',
+ SUBDEV_CONN_REAL_I = 'R',
+ SUBDEV_CONN_REAL_Q = 'r'
+ };
+
+ /*!
* Possible device subdev properties
*/
enum subdev_prop_t{
@@ -36,9 +52,7 @@ namespace uhd{ namespace usrp{
SUBDEV_PROP_ANTENNA = 'a', //rw, std::string
SUBDEV_PROP_ANTENNA_NAMES = 'A', //ro, prop_names_t
SUBDEV_PROP_LO_LOCKED = 'L', //ro, bool
- SUBDEV_PROP_QUADRATURE = 'q', //ro, bool
- SUBDEV_PROP_IQ_SWAPPED = 'i', //ro, bool
- SUBDEV_PROP_SPECTRUM_INVERTED = 's', //ro, bool
+ SUBDEV_PROP_CONNECTION = 'c', //ro, subdev_conn_t
SUBDEV_PROP_USE_LO_OFFSET = 'l', //ro, bool
SUBDEV_PROP_RSSI = 'R', //ro, float
SUBDEV_PROP_BANDWIDTH = 'B' //rw, double
diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp
new file mode 100644
index 000000000..4d8f03b77
--- /dev/null
+++ b/host/include/uhd/usrp/subdev_spec.hpp
@@ -0,0 +1,95 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP
+#define INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP
+
+#include <uhd/config.hpp>
+#include <vector>
+#include <string>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * A subdevice specification (daughterboard, subdevice) name pairing.
+ */
+ struct UHD_API subdev_spec_pair_t{
+ //! The daughterboard name
+ std::string db_name;
+
+ //! The subdevice name
+ std::string sd_name;
+
+ /*!
+ * Create a new subdevice specification pair from dboard and subdev names.
+ * \param db_name the name of a daughterboard slot
+ * \param sd_name the name of a subdevice on that daughterboard
+ */
+ subdev_spec_pair_t(
+ const std::string &db_name, const std::string &sd_name
+ );
+ };
+
+ /*!
+ * A list of (daughterboard name, subdevice name) pairs:
+ *
+ * A subdevice specification represents a list of subdevices on a motherboard.
+ * The subdevices specified may span across multiple daughterboards;
+ * Hence the need for a subdevice specification over a simple list of strings.
+ * Typically, the user will pass a RX or TX subdevice specification into the API,
+ * and the implementation will infer the channel configuration from the specification.
+ *
+ * The subdevice specification can be represented as a markup-string.
+ * The markup-string is a whitespace separated list of dboard:subdev pairs.
+ * The "dboard:" part is optional on boards with only one daughterboard slot.
+ * The first pair represents the subdevice for channel zero,
+ * the second pair represents the subdevice for channel one, and so on.
+ *
+ * Examples:
+ * - Use subdevice AB on daughterboard A (USRP1): "A:AB"
+ * - Use subdevice A on daughterboard A for channel zero and subdevice A on daughterboard B for channel one (USRP1): "A:A B:A"
+ * - Use subdevice AB (USRP2): "AB" or ":AB"
+ *
+ * An empty subdevice specification can be used to automatically
+ * select the first subdevice on the first present daughterboard.
+ */
+ class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{
+ public:
+
+ /*!
+ * Create a subdev specification from a markup string.
+ * \param markup the markup string
+ */
+ subdev_spec_t(const std::string &markup = "");
+
+ /*!
+ * Convert a subdev specification into a pretty print string.
+ * \return a printable string representing the subdev specification
+ */
+ std::string to_pp_string(void) const;
+
+ /*!
+ * Convert the subdevice specification into a markup string.
+ * The markup string contains the delimiter symbols.
+ * \return a string with delimiter markup
+ */
+ std::string to_string(void) const;
+ };
+
+}}
+
+#endif /* INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP */
diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp
index f1e276d4f..df3907b3e 100644
--- a/host/include/uhd/usrp/tune_helper.hpp
+++ b/host/include/uhd/usrp/tune_helper.hpp
@@ -24,55 +24,75 @@
namespace uhd{ namespace usrp{
-/*!
- * Tune a rx chain to the desired frequency:
- * The IF of the subdevice is set as close as possible to
- * the given target frequency + the LO offset (when applicable).
- * The ddc cordic is setup to bring the IF down to baseband.
- * \param subdev the dboard subdevice object with properties
- * \param ddc the ddc properties object (with "if_rate", "bb_rate", "freq")
- * \param target_freq the desired center frequency
- * \param lo_offset an offset for the subdevice IF from center
- * \return a tune result struct
- */
-UHD_API tune_result_t tune_rx_subdev_and_ddc(
- wax::obj subdev, wax::obj ddc,
- double target_freq, double lo_offset
-);
+ /*!
+ * Tune a rx chain to the desired frequency:
+ * The IF of the subdevice is set as close as possible to
+ * the given target frequency + the LO offset (when applicable).
+ * The ddc cordic is setup to bring the IF down to baseband.
+ * \param subdev the dboard subdevice object with properties
+ * \param ddc the mboard dsp object with properties
+ * \param target_freq the desired center frequency
+ * \param lo_offset an offset for the subdevice IF from center
+ * \return a tune result struct
+ */
+ UHD_API tune_result_t tune_rx_subdev_and_dsp(
+ wax::obj subdev, wax::obj ddc,
+ double target_freq, double lo_offset
+ );
-/*!
- * Tune a rx chain to the desired frequency:
- * Same as the above, except the LO offset
- * is calculated based on the subdevice and BW.
- */
-UHD_API tune_result_t tune_rx_subdev_and_ddc(
- wax::obj subdev, wax::obj ddc, double target_freq
-);
+ /*!
+ * Tune a rx chain to the desired frequency:
+ * Same as the above, except the LO offset
+ * is calculated based on the subdevice and BW.
+ */
+ UHD_API tune_result_t tune_rx_subdev_and_dsp(
+ wax::obj subdev, wax::obj ddc, double target_freq
+ );
-/*!
- * Tune a tx chain to the desired frequency:
- * The IF of the subdevice is set as close as possible to
- * the given target frequency + the LO offset (when applicable).
- * The duc cordic is setup to bring the baseband up to IF.
- * \param subdev the dboard subdevice object with properties
- * \param duc the duc properties object (with "if_rate", "bb_rate", "freq")
- * \param target_freq the desired center frequency
- * \param lo_offset an offset for the subdevice IF from center
- * \return a tune result struct
- */
-UHD_API tune_result_t tune_tx_subdev_and_duc(
- wax::obj subdev, wax::obj duc,
- double target_freq, double lo_offset
-);
+ /*!
+ * Calculate the overall frequency from the combination of dboard IF and DDC shift.
+ * \param subdev the dboard subdevice object with properties
+ * \param ddc the mboard dsp object with properties
+ * \return the overall tune frequency of the system in Hz
+ */
+ UHD_API double derive_freq_from_rx_subdev_and_dsp(
+ wax::obj subdev, wax::obj ddc
+ );
-/*!
- * Tune a tx chain to the desired frequency:
- * Same as the above, except the LO offset
- * is calculated based on the subdevice and BW.
- */
-UHD_API tune_result_t tune_tx_subdev_and_duc(
- wax::obj subdev, wax::obj duc, double target_freq
-);
+ /*!
+ * Tune a tx chain to the desired frequency:
+ * The IF of the subdevice is set as close as possible to
+ * the given target frequency + the LO offset (when applicable).
+ * The duc cordic is setup to bring the baseband up to IF.
+ * \param subdev the dboard subdevice object with properties
+ * \param duc the mboard dsp object with properties
+ * \param target_freq the desired center frequency
+ * \param lo_offset an offset for the subdevice IF from center
+ * \return a tune result struct
+ */
+ UHD_API tune_result_t tune_tx_subdev_and_dsp(
+ wax::obj subdev, wax::obj duc,
+ double target_freq, double lo_offset
+ );
+
+ /*!
+ * Tune a tx chain to the desired frequency:
+ * Same as the above, except the LO offset
+ * is calculated based on the subdevice and BW.
+ */
+ UHD_API tune_result_t tune_tx_subdev_and_dsp(
+ wax::obj subdev, wax::obj duc, double target_freq
+ );
+
+ /*!
+ * Calculate the overall frequency from the combination of dboard IF and DUC shift.
+ * \param subdev the dboard subdevice object with properties
+ * \param duc the mboard dsp object with properties
+ * \return the overall tune frequency of the system in Hz
+ */
+ UHD_API double derive_freq_from_tx_subdev_and_dsp(
+ wax::obj subdev, wax::obj duc
+ );
}}
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index d484788b2..ef8e64ce0 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -22,11 +22,12 @@ INSTALL(FILES
byteswap.hpp
byteswap.ipp
exception.hpp
- gain_handler.hpp
+ gain_group.hpp
pimpl.hpp
props.hpp
safe_main.hpp
static.hpp
thread_priority.hpp
+ warning.hpp
DESTINATION ${INCLUDE_DIR}/uhd/utils
)
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
index b52edc6b5..1b5eacfa9 100644
--- a/host/include/uhd/utils/algorithm.hpp
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -69,6 +69,31 @@ namespace std{
}
/*!
+ * A wrapper around std::reverse that takes a range instead of an iterator.
+ *
+ * The elements are reversed into descending order using the less-than operator.
+ *
+ * \param range the range of elements to be reversed
+ */
+ template<typename Range> inline void reverse(Range &range){
+ return std::reverse(boost::begin(range), boost::end(range));
+ }
+
+ /*!
+ * A wrapper around std::reverse that takes a range instead of an iterator.
+ *
+ * The elements are reversed into descending order using the less-than operator.
+ * This wrapper reverses the elements non-destructively into a new range.
+ * Based on the builtin python function reversed(...)
+ *
+ * \param range the range of elements to be reversed
+ * \return a new range with the elements reversed
+ */
+ template<typename Range> inline Range reversed(const Range &range){
+ Range srange(range); std::reverse(srange); return srange;
+ }
+
+ /*!
* Is the value found within the elements in this range?
*
* Uses std::find to search the iterable for an element.
@@ -112,17 +137,6 @@ namespace std{
}
/*!
- * A templated signum implementation.
- * \param n the comparable to process
- * \return -1 when n negative, +1 when n positive, otherwise 0
- */
- template<typename T> inline int signum(T n){
- if (n < 0) return -1;
- if (n > 0) return +1;
- return 0;
- }
-
- /*!
* A templated clip implementation.
* \param val the value to clip between an upper and lower limit
* \param bound1 the upper or lower bound
diff --git a/host/include/uhd/utils/gain_group.hpp b/host/include/uhd/utils/gain_group.hpp
new file mode 100644
index 000000000..3955dfa9a
--- /dev/null
+++ b/host/include/uhd/utils/gain_group.hpp
@@ -0,0 +1,85 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_UTILS_GAIN_GROUP_HPP
+#define INCLUDED_UHD_UTILS_GAIN_GROUP_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/utility.hpp>
+
+namespace uhd{
+
+/*!
+ * A set of function to control a gain element.
+ */
+struct UHD_API gain_fcns_t{
+ boost::function<gain_range_t(void)> get_range;
+ boost::function<float(void)> get_value;
+ boost::function<void(float)> set_value;
+};
+
+class UHD_API gain_group : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<gain_group> sptr;
+
+ /*!
+ * Get the overall gain range for this group.
+ * Overall step is defined as the minimum step size.
+ * \return a gain range with overall min, max, step
+ */
+ virtual gain_range_t get_range(void) = 0;
+
+ /*!
+ * Get the overall gain value for this group.
+ * \return a summation of all the gain values
+ */
+ virtual float get_value(void) = 0;
+
+ /*!
+ * Set the overall gain value for this group.
+ * The power will be distributed across individual gain elements.
+ * The semantics of how to do this are determined by the priority.
+ * \param gain the gain to set across the group
+ */
+ virtual void set_value(float gain) = 0;
+
+ /*!
+ * Register a set of gain functions into this group.
+ * Priority determines how power will be distributed
+ * with higher priorities getting the power first,
+ * and lower priorities getting the remainder power.
+ * \param gain_fcns the set of gain functions
+ * \param priority the priority of the gain element
+ */
+ virtual void register_fcns(
+ const gain_fcns_t &gain_fcns, size_t priority = 0
+ ) = 0;
+
+ /*!
+ * Make a new empty gain group.
+ * \return a gain group object.
+ */
+ static sptr make(void);
+};
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_GAIN_GROUP_HPP */
+
diff --git a/host/include/uhd/utils/gain_handler.hpp b/host/include/uhd/utils/gain_handler.hpp
deleted file mode 100644
index f4629e6a7..000000000
--- a/host/include/uhd/utils/gain_handler.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP
-#define INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP
-
-#include <uhd/config.hpp>
-#include <uhd/wax.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
-
-namespace uhd{
-
-class UHD_API gain_handler{
-public:
- typedef boost::shared_ptr<gain_handler> sptr;
- typedef boost::function<bool(const wax::obj &, const wax::obj &)> is_equal_t;
-
- /*!
- * A set of properties for dealing with gains.
- */
- struct UHD_API props_t{
- wax::obj value, range, names;
- props_t(void); //default constructor
- };
-
- /*!
- * Make a new gain handler.
- * The construction arguments are agnostic to the property type.
- * It is up to the caller to provide an "is_equal" function that
- * can tell weather two properties (in a wax obj) are equal.
- * \param link a link to the wax obj with properties
- * \param props a struct of properties keys
- * \param is_equal the function that tests for equal properties
- */
- static sptr make(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
- );
-
- /*!
- * Intercept gets for overall gain, min, max, step.
- * Ensures that the gain name is valid.
- * \return true for handled, false to pass on
- */
- virtual bool intercept_get(const wax::obj &key, wax::obj &val) = 0;
-
- /*!
- * Intercept sets for overall gain.
- * Ensures that the gain name is valid.
- * Ensures that the new gain is within range.
- * \return true for handled, false to pass on
- */
- virtual bool intercept_set(const wax::obj &key, const wax::obj &val) = 0;
-
- /*!
- * Function template to test if two wax types are equal:
- * The constructor will bind an instance of this for a specific type.
- * This bound equals functions allows the intercept methods to be non-templated.
- */
- template <class T> static bool is_equal(const wax::obj &a, const wax::obj &b){
- try{
- return a.as<T>() == b.as<T>();
- }
- catch(const wax::bad_cast &){
- return false;
- }
- }
-
-};
-
-} //namespace uhd
-
-#endif /* INCLUDED_UHD_UTILS_GAIN_HANDLER_HPP */
-
diff --git a/host/include/uhd/utils/pimpl.hpp b/host/include/uhd/utils/pimpl.hpp
index 09bf0c0a2..18454f0c4 100644
--- a/host/include/uhd/utils/pimpl.hpp
+++ b/host/include/uhd/utils/pimpl.hpp
@@ -20,6 +20,7 @@
#include <uhd/config.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
/*! \file pimpl.hpp
* "Pimpl idiom" (pointer to implementation idiom).
@@ -50,6 +51,6 @@
* \param _args the constructor args for the pimpl
*/
#define UHD_PIMPL_MAKE(_name, _args) \
- boost::shared_ptr<_name>(new _name _args)
+ boost::make_shared<_name> _args
#endif /* INCLUDED_UHD_UTILS_PIMPL_HPP */
diff --git a/host/include/uhd/utils/warning.hpp b/host/include/uhd/utils/warning.hpp
new file mode 100644
index 000000000..91d8400ab
--- /dev/null
+++ b/host/include/uhd/utils/warning.hpp
@@ -0,0 +1,34 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_UTILS_WARNING_HPP
+#define INCLUDED_UHD_UTILS_WARNING_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+
+namespace uhd{
+
+ /*!
+ * Print a formatted warning string to stderr.
+ * \param msg the multiline warning message
+ */
+ UHD_API void print_warning(const std::string &msg);
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_WARNING_HPP */
diff --git a/host/include/uhd/version.hpp b/host/include/uhd/version.hpp
new file mode 100644
index 000000000..19d672e65
--- /dev/null
+++ b/host/include/uhd/version.hpp
@@ -0,0 +1,28 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_VERSION_HPP
+#define INCLUDED_UHD_VERSION_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+
+namespace uhd{
+ UHD_API std::string get_version_string(void);
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_VERSION_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 77b04af0c..48cfe742e 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -16,38 +16,16 @@
#
########################################################################
-# Setup Python
-########################################################################
-INCLUDE(FindPythonInterp)
-
-MACRO(PYTHON_CHECK_MODULE module have)
- MESSAGE(STATUS "Checking for python module ${module}")
- EXECUTE_PROCESS(
- COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}"
- RESULT_VARIABLE ${have}
- )
- IF(${have} EQUAL 0)
- MESSAGE(STATUS "Checking for python module ${module} - found")
- SET(${have} TRUE)
- ELSE(${have} EQUAL 0)
- MESSAGE(STATUS "Checking for python module ${module} - not found")
- SET(${have} FALSE)
- ENDIF(${have} EQUAL 0)
-ENDMACRO(PYTHON_CHECK_MODULE)
-
-PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH)
-
-IF(NOT HAVE_PYTHON_MODULE_CHEETAH)
- MESSAGE(FATAL_ERROR "Error: Cheetah Templates needed for pre-build generation.")
-ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH)
-
-########################################################################
# Helpful Macros
########################################################################
MACRO(LIBUHD_APPEND_SOURCES)
LIST(APPEND libuhd_sources ${ARGV})
ENDMACRO(LIBUHD_APPEND_SOURCES)
+MACRO(LIBUHD_APPEND_LIBS)
+ LIST(APPEND libuhd_libs ${ARGV})
+ENDMACRO(LIBUHD_APPEND_LIBS)
+
MACRO(LIBUHD_PYTHON_GEN_SOURCE pyfile outfile)
#ensure that the directory exists for outfile
GET_FILENAME_COMPONENT(outfile_dir ${outfile} PATH)
@@ -70,75 +48,22 @@ ENDMACRO(LIBUHD_PYTHON_GEN_SOURCE)
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/CMakeLists.txt)
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/transport/CMakeLists.txt)
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/CMakeLists.txt)
-INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/dboard/CMakeLists.txt)
-INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp2/CMakeLists.txt)
-INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp_e/CMakeLists.txt)
-
-########################################################################
-# Setup defines for process scheduling
-########################################################################
-MESSAGE(STATUS "Configuring priority scheduling...")
-
-INCLUDE(CheckCXXSourceCompiles)
-CHECK_CXX_SOURCE_COMPILES("
- #include <pthread.h>
- int main(){
- struct sched_param sp;
- pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
- return 0;
- }
- " HAVE_PTHREAD_SETSCHEDPARAM
-)
-
-CHECK_CXX_SOURCE_COMPILES("
- #include <windows.h>
- int main(){
- SetThreadPriority(GetCurrentThread(), 0);
- SetPriorityClass(GetCurrentProcess(), 0);
- return 0;
- }
- " HAVE_WIN_SETTHREADPRIORITY
-)
-
-IF(HAVE_PTHREAD_SETSCHEDPARAM)
- MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.")
- ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM)
-ELSEIF(HAVE_WIN_SETTHREADPRIORITY)
- MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.")
- ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY)
-ELSE(HAVE_PTHREAD_SETSCHEDPARAM)
- MESSAGE(STATUS " Priority scheduling not supported.")
-ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)
-
-########################################################################
-# Setup defines for module loading
-########################################################################
-MESSAGE(STATUS "Configuring module loading...")
-
-INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H)
-CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H)
-
-IF(HAVE_DLFCN_H)
- MESSAGE(STATUS " Module loading supported through dlopen.")
- ADD_DEFINITIONS(-DHAVE_DLFCN_H)
-ELSEIF(HAVE_WINDOWS_H)
- MESSAGE(STATUS " Module loading supported through LoadLibrary.")
- ADD_DEFINITIONS(-DHAVE_WINDOWS_H)
-ELSE(HAVE_DLFCN_H)
- MESSAGE(STATUS " Module loading not supported.")
-ENDIF(HAVE_DLFCN_H)
+INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/utils/CMakeLists.txt)
########################################################################
# Append to the list of sources for lib uhd
########################################################################
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/constants.hpp.in
+ ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp
+@ONLY)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_BINARY_DIR}/constants.hpp
${CMAKE_CURRENT_SOURCE_DIR}/device.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp
)
@@ -146,9 +71,7 @@ LIBUHD_APPEND_SOURCES(
# Setup libuhd library
########################################################################
ADD_LIBRARY(uhd SHARED ${libuhd_sources})
-
-TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
-
+TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${libuhd_libs})
SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")
INSTALL(TARGETS uhd
diff --git a/host/lib/constants.hpp.in b/host/lib/constants.hpp.in
new file mode 100644
index 000000000..295c8f16c
--- /dev/null
+++ b/host/lib/constants.hpp.in
@@ -0,0 +1,28 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_CONSTANTS_HPP
+#define INCLUDED_LIBUHD_CONSTANTS_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+
+static const std::string UHD_VERSION_STRING = "@CPACK_PACKAGE_VERSION@";
+static const std::string UHD_INSTALL_PREFIX = "@CMAKE_INSTALL_PREFIX@";
+static const std::string UHD_PKG_DATA_DIR = "@PKG_DATA_DIR@";
+
+#endif /* INCLUDED_LIBUHD_CONSTANTS_HPP */
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
index 431595c4f..d575ebaab 100644
--- a/host/lib/device.cpp
+++ b/host/lib/device.cpp
@@ -12,7 +12,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// asize_t with this program. If not, see <http://www.gnu.org/licenses/>.
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <uhd/device.hpp>
diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp
deleted file mode 100644
index 36e2e8ed3..000000000
--- a/host/lib/gain_handler.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/utils/gain_handler.hpp>
-#include <uhd/utils/assert.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/props.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <cmath>
-#include <vector>
-
-using namespace uhd;
-
-/***********************************************************************
- * gain handler implementation interface
- **********************************************************************/
-class gain_handler_impl : public gain_handler{
-public:
- gain_handler_impl(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
- );
- ~gain_handler_impl(void);
- bool intercept_get(const wax::obj &key, wax::obj &val);
- bool intercept_set(const wax::obj &key, const wax::obj &val);
-
-private:
- wax::obj _link;
- props_t _props;
- is_equal_t _is_equal;
-
- prop_names_t get_gain_names(void);
- float get_overall_gain_val(void);
- gain_range_t get_overall_gain_range(void);
- template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){
- return _link[named_prop_t(prop, name)].as<T>();
- }
-};
-
-/***********************************************************************
- * the make function
- **********************************************************************/
-gain_handler::sptr gain_handler::make(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
-){
- return sptr(new gain_handler_impl(link, props, is_equal));
-}
-
-/***********************************************************************
- * gain handler implementation methods
- **********************************************************************/
-gain_handler::props_t::props_t(void){
- /* NOP */
-}
-
-gain_handler_impl::gain_handler_impl(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
-){
- _link = link;
- _props = props;
- _is_equal = is_equal;
-}
-
-gain_handler_impl::~gain_handler_impl(void){
- /* NOP */
-}
-
-prop_names_t gain_handler_impl::get_gain_names(void){
- return _link[_props.names].as<prop_names_t>();
-}
-
-float gain_handler_impl::get_overall_gain_val(void){
- float gain_val = 0;
- BOOST_FOREACH(std::string name, get_gain_names()){
- gain_val += get_named_prop<float>(_props.value, name);
- }
- return gain_val;
-}
-
-gain_range_t gain_handler_impl::get_overall_gain_range(void){
- float gain_min = 0, gain_max = 0, gain_step = 0;
- BOOST_FOREACH(std::string name, get_gain_names()){
- gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name);
- gain_min += floatmp.min;
- gain_max += floatmp.max;
- gain_step = std::max(gain_step, floatmp.step);
- }
- return gain_range_t(gain_min, gain_max, gain_step);
-}
-
-/***********************************************************************
- * gain handler implementation get method
- **********************************************************************/
-bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //not a wildcard... dont handle (but check name)
- if (name != ""){
- assert_has(get_gain_names(), name, "gain name");
- return false;
- }
-
- if (_is_equal(key, _props.value)){
- val = get_overall_gain_val();
- return true;
- }
-
- if (_is_equal(key, _props.range)){
- val = get_overall_gain_range();
- return true;
- }
-
- return false; //not handled
-}
-
-/***********************************************************************
- * gain handler implementation set method
- **********************************************************************/
-bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //not a gain value key... dont handle
- if (not _is_equal(key, _props.value)) return false;
-
- float gain_val = val.as<float>();
-
- //not a wildcard... dont handle (but check name and range)
- if (name != ""){
- assert_has(get_gain_names(), name, "gain name");
- gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
- if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str(
- boost::format("A value of %f for gain %s is out of range of (%f, %f)")
- % gain_val % name % gain.min % gain.max
- ));
- return false;
- }
-
- //set the overall gain
- BOOST_FOREACH(std::string name, get_gain_names()){
- //get the min, max, step for this gain name
- gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
-
- //clip g to be within the allowed range
- float g = std::min(std::max(gain_val, gain.min), gain.max);
- //set g to be a multiple of the step size
- g -= std::fmod(g, gain.step);
- //set g to be the new gain
- _link[named_prop_t(_props.value, name)] = g;
- //subtract g out of the total gain left to apply
- gain_val -= g;
- }
-
- return true;
-}
diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt
index ba1bbc9f0..f8e15c13d 100644
--- a/host/lib/ic_reg_maps/CMakeLists.txt
+++ b/host/lib/ic_reg_maps/CMakeLists.txt
@@ -55,6 +55,11 @@ LIBUHD_PYTHON_GEN_SOURCE(
)
LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_max2118_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/max2118_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9862_regs.py
${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9862_regs.hpp
)
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
index 47325a7e3..986093004 100644
--- a/host/lib/ic_reg_maps/common.py
+++ b/host/lib/ic_reg_maps/common.py
@@ -173,7 +173,7 @@ class mreg:
def get_type(self):
return 'boost::uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8)
-def generate(name, regs_tmpl, body_tmpl='', file=__file__):
+def generate(name, regs_tmpl, body_tmpl='', file=__file__, append=False):
#evaluate the regs template and parse each line into a register
regs = list(); mregs = list()
for entry in parse_tmpl(regs_tmpl).splitlines():
@@ -193,4 +193,4 @@ def generate(name, regs_tmpl, body_tmpl='', file=__file__):
)
#write the generated code to file specified by argv1
- open(sys.argv[1], 'w').write(code)
+ open(sys.argv[1], 'a' if append else 'w').write(code)
diff --git a/host/lib/ic_reg_maps/gen_max2118_regs.py b/host/lib/ic_reg_maps/gen_max2118_regs.py
new file mode 100644
index 000000000..506fbaec8
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_max2118_regs.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# Template for raw text data describing write registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+WRITE_REGS_TMPL="""\
+########################################################################
+## Note: offsets given from perspective of data bits (excludes address)
+########################################################################
+##
+########################################################################
+## N-Divider MSB (0) Write
+########################################################################
+div2 0[7] 0 div4, div2
+n_divider_msb 0[0:6] 3
+########################################################################
+## N-Divider LSB (1) Write
+########################################################################
+n_divider_lsb 1[0:7] 0xB6
+~n_divider n_divider_lsb, n_divider_msb
+########################################################################
+## R, Charge Pump, and VCO (2) Write
+########################################################################
+#set $r_divider_names = ', '.join(map(lambda x: 'div' + str(2**(x+1)), range(0,8)))
+r_divider 2[5:7] 1 $r_divider_names
+#set $cp_current_bias = ', '.join(map(lambda x: 'i_cp_%dua'%(50*2**x), range(0,4)))
+cp_current 2[3:4] 3 $cp_current_bias
+osc_band 2[0:2] 5
+########################################################################
+## I/Q Filter DAC (3) Write
+########################################################################
+##unused 3[7] 0
+f_dac 3[0:6] 0x7F ## filter tuning dac, depends on m
+########################################################################
+## LPF Divider DAC (4) Write
+########################################################################
+adl_vco_adc_latch 4[7] 0 disabled, enabled
+ade_vco_ade_read 4[6] 0 disabled, enabled
+dl_output_drive 4[5] 0 iq_590m_vpp, iq_1_vpp
+m_divider 4[0:4] 2 ## filter tuning counter
+########################################################################
+## GC2 and Diag (5) Write
+########################################################################
+diag 5[5:7] 0 normal, cp_i_source, cp_i_sink, cp_high_z, unused, n_and_filt, r_and_gc2, m_div
+gc2 5[0:4] 0x1F ## Step Size: 0-1: 0dB, 2-22: 1dB, 23-31: 0.5dB
+"""
+
+########################################################################
+# Template for raw text data describing read registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+READ_REGS_TMPL="""\
+########################################################################
+## Status (0) Read
+########################################################################
+pwr 0[6] 0 not_reset, reset
+adc 0[2:4] 0 ## VCO tuning voltage, Lock Status
+########################################################################
+## I/Q Filter DAC (1) Read
+########################################################################
+filter_dac 1[0:6] 0 ## I/Q Filter tuning DAC, current
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint8_t get_reg(boost::uint8_t addr){
+ boost::uint8_t reg = 0;
+ switch(addr){
+ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs)))
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return boost::uint8_t(reg);
+}
+
+void set_reg(boost::uint8_t addr, boost::uint8_t reg){
+ switch(addr){
+ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs)))
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask());
+ #end for
+ break;
+ #end for
+ }
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='max2118_write_regs',
+ regs_tmpl=WRITE_REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
+
+ import common; common.generate(
+ name='max2118_read_regs',
+ regs_tmpl=READ_REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ append=True,
+ )
diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp
index f339127ad..89750f99d 100644
--- a/host/lib/transport/udp_simple.cpp
+++ b/host/lib/transport/udp_simple.cpp
@@ -34,12 +34,13 @@ using namespace uhd::transport;
* This is okay bacause this is the slow-path implementation.
*
* \param socket the asio socket
+ * \param timeout_ms the timeout in milliseconds
*/
static void reasonable_recv_timeout(
- boost::asio::ip::udp::socket &socket
+ boost::asio::ip::udp::socket &socket, size_t timeout_ms
){
boost::asio::deadline_timer timer(socket.get_io_service());
- timer.expires_from_now(boost::posix_time::milliseconds(100));
+ timer.expires_from_now(boost::posix_time::milliseconds(timeout_ms));
while (not (socket.available() or timer.expires_from_now().is_negative())){
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
@@ -55,8 +56,8 @@ public:
~udp_connected_impl(void);
//send/recv
- size_t send(const boost::asio::const_buffer &buff);
- size_t recv(const boost::asio::mutable_buffer &buff);
+ size_t send(const boost::asio::const_buffer &);
+ size_t recv(const boost::asio::mutable_buffer &, size_t);
private:
boost::asio::ip::udp::socket *_socket;
@@ -85,8 +86,8 @@ size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){
return _socket->send(boost::asio::buffer(buff));
}
-size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){
- reasonable_recv_timeout(*_socket);
+size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){
+ reasonable_recv_timeout(*_socket, timeout_ms);
if (not _socket->available()) return 0;
return _socket->receive(boost::asio::buffer(buff));
}
@@ -101,8 +102,8 @@ public:
~udp_broadcast_impl(void);
//send/recv
- size_t send(const boost::asio::const_buffer &buff);
- size_t recv(const boost::asio::mutable_buffer &buff);
+ size_t send(const boost::asio::const_buffer &);
+ size_t recv(const boost::asio::mutable_buffer &, size_t);
private:
boost::asio::ip::udp::socket *_socket;
@@ -136,8 +137,8 @@ size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){
return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint);
}
-size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){
- reasonable_recv_timeout(*_socket);
+size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){
+ reasonable_recv_timeout(*_socket, timeout_ms);
if (not _socket->available()) return 0;
boost::asio::ip::udp::endpoint sender_endpoint;
return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint);
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index bfbcf62d8..ee989ee2b 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -18,6 +18,7 @@
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/warning.hpp>
#include <boost/cstdint.hpp>
#include <boost/asio.hpp>
#include <boost/format.hpp>
@@ -29,7 +30,11 @@ using namespace uhd::transport;
* Constants
**********************************************************************/
//enough buffering for half a second of samples at full rate on usrp2
-static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5);
+static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5);
+//Large buffers cause more underflow at high rates.
+//Perhaps this is due to the kernel scheduling,
+//but may change with host-based flow control.
+static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3);
static const double RECV_TIMEOUT = 0.1; //100 ms
/***********************************************************************
@@ -143,6 +148,10 @@ template<typename Opt> static void resize_buff_helper(
size_t target_size,
const std::string &name
){
+ size_t min_sock_buff_size = 0;
+ if (name == "recv") min_sock_buff_size = MIN_RECV_SOCK_BUFF_SIZE;
+ if (name == "send") min_sock_buff_size = MIN_SEND_SOCK_BUFF_SIZE;
+
//resize the buffer if size was provided
if (target_size > 0){
size_t actual_size = udp_trans->resize_buff<Opt>(target_size);
@@ -153,19 +162,18 @@ template<typename Opt> static void resize_buff_helper(
else std::cout << boost::format(
"Current %s sock buff size: %d bytes"
) % name % actual_size << std::endl;
- if (actual_size < target_size) std::cerr << boost::format(
- "Warning:\n"
- " The %s buffer is smaller than the requested size.\n"
- " The minimum recommended buffer size is %d bytes.\n"
- " See the USRP2 application notes on buffer resizing.\n"
- ) % name % MIN_SOCK_BUFF_SIZE << std::endl;
+ if (actual_size < target_size) uhd::print_warning(str(boost::format(
+ "The %s buffer is smaller than the requested size.\n"
+ "The minimum recommended buffer size is %d bytes.\n"
+ "See the USRP2 application notes on buffer resizing.\n"
+ ) % name % min_sock_buff_size));
}
//only enable on platforms that are happy with the large buffer resize
#if defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)
//otherwise, ensure that the buffer is at least the minimum size
- else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){
- resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name);
+ else if (udp_trans->get_buff_size<Opt>() < min_sock_buff_size){
+ resize_buff_helper<Opt>(udp_trans, min_sock_buff_size, name);
}
#endif /*defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32)*/
}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
index bd76cbb8f..7e0588f03 100644
--- a/host/lib/transport/vrt_packet_handler.hpp
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -35,14 +35,25 @@
namespace vrt_packet_handler{
+template <typename T> UHD_INLINE T get_context_code(
+ const boost::uint32_t *vrt_hdr,
+ const uhd::transport::vrt::if_packet_info_t &if_packet_info
+){
+ //extract the context word (we dont know the endianness so mirror the bytes)
+ boost::uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] |
+ uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]);
+ return T(word0 & 0xff);
+}
+
/***********************************************************************
* vrt packet handler for recv
**********************************************************************/
typedef std::vector<uhd::transport::managed_recv_buffer::sptr> managed_recv_buffs_t;
typedef boost::function<bool(managed_recv_buffs_t &)> get_recv_buffs_t;
- typedef boost::function<void(size_t /*which channel*/)> handle_overrun_t;
+ typedef boost::function<void(size_t /*which channel*/)> handle_overflow_t;
+ typedef boost::function<void(const boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_unpacker_t;
- static inline void handle_overrun_nop(size_t){}
+ static inline void handle_overflow_nop(size_t){}
struct recv_state{
//width of the receiver in channels
@@ -69,13 +80,12 @@ namespace vrt_packet_handler{
* Unpack a received vrt header and set the copy buffer.
* - helper function for vrt_packet_handler::_recv1
******************************************************************/
- template<typename vrt_unpacker_type>
static UHD_INLINE void _recv1_helper(
recv_state &state,
uhd::rx_metadata_t &metadata,
double tick_rate,
- vrt_unpacker_type vrt_unpacker,
- const handle_overrun_t &handle_overrun,
+ const vrt_unpacker_t &vrt_unpacker,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
//vrt unpack each managed buffer
@@ -92,22 +102,19 @@ namespace vrt_packet_handler{
const boost::uint32_t *vrt_hdr = state.managed_buffs[i]->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
if_packet_info.num_packet_words32 = num_packet_words32 - vrt_header_offset_words32;
vrt_unpacker(vrt_hdr, if_packet_info);
- const boost::uint32_t *vrt_data = vrt_hdr + if_packet_info.num_header_words32;
//handle the non-data packet case and parse its contents
if (if_packet_info.packet_type != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA){
- //extract the context word (we dont know the endianness so mirror the bytes)
- boost::uint32_t word0 = vrt_data[0] | uhd::byteswap(vrt_data[0]);
- if (word0 & uhd::rx_metadata_t::ERROR_CODE_OVERRUN) handle_overrun(i);
- metadata.error_code = uhd::rx_metadata_t::error_code_t(word0 & 0xf);
+ metadata.error_code = get_context_code<uhd::rx_metadata_t::error_code_t>(vrt_hdr, if_packet_info);
+ if (metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) handle_overflow(i);
//break to exit loop and store metadata below
state.size_of_copy_buffs = 0; break;
}
//setup the buffer to point to the data
- state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_data);
+ state.copy_buffs[i] = reinterpret_cast<const boost::uint8_t *>(vrt_hdr + if_packet_info.num_header_words32);
//store the minimum payload length into the copy buffer length
size_t num_payload_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t);
@@ -131,7 +138,6 @@ namespace vrt_packet_handler{
* Recv data, unpack a vrt header, and copy-convert the data.
* - helper function for vrt_packet_handler::recv
******************************************************************/
- template<typename vrt_unpacker_type>
static UHD_INLINE size_t _recv1(
recv_state &state,
const std::vector<void *> &buffs,
@@ -141,9 +147,9 @@ namespace vrt_packet_handler{
const uhd::io_type_t &io_type,
const uhd::otw_type_t &otw_type,
double tick_rate,
- vrt_unpacker_type vrt_unpacker,
+ const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun,
+ const handle_overflow_t &handle_overflow,
size_t vrt_header_offset_words32
){
metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE;
@@ -158,7 +164,7 @@ namespace vrt_packet_handler{
try{
_recv1_helper(
state, metadata, tick_rate,
- vrt_unpacker, handle_overrun,
+ vrt_unpacker, handle_overflow,
vrt_header_offset_words32
);
}catch(const std::exception &e){
@@ -206,7 +212,6 @@ namespace vrt_packet_handler{
/*******************************************************************
* Recv vrt packets and copy convert the samples into the buffer.
******************************************************************/
- template<typename vrt_unpacker_type>
static UHD_INLINE size_t recv(
recv_state &state,
const std::vector<void *> &buffs,
@@ -216,9 +221,9 @@ namespace vrt_packet_handler{
const uhd::io_type_t &io_type,
const uhd::otw_type_t &otw_type,
double tick_rate,
- vrt_unpacker_type vrt_unpacker,
+ const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
- const handle_overrun_t &handle_overrun = &handle_overrun_nop,
+ const handle_overflow_t &handle_overflow = &handle_overflow_nop,
size_t vrt_header_offset_words32 = 0
){
switch(recv_mode){
@@ -235,7 +240,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
}
@@ -255,7 +260,7 @@ namespace vrt_packet_handler{
tick_rate,
vrt_unpacker,
get_recv_buffs,
- handle_overrun,
+ handle_overflow,
vrt_header_offset_words32
);
if (num_samps == 0) break; //had a recv timeout or error, break loop
@@ -273,6 +278,7 @@ namespace vrt_packet_handler{
**********************************************************************/
typedef std::vector<uhd::transport::managed_send_buffer::sptr> managed_send_buffs_t;
typedef boost::function<bool(managed_send_buffs_t &)> get_send_buffs_t;
+ typedef boost::function<void(boost::uint32_t *, uhd::transport::vrt::if_packet_info_t &)> vrt_packer_t;
struct send_state{
//init the expected seq number
@@ -287,7 +293,6 @@ namespace vrt_packet_handler{
* Pack a vrt header, copy-convert the data, and send it.
* - helper function for vrt_packet_handler::send
******************************************************************/
- template<typename vrt_packer_type>
static UHD_INLINE void _send1(
send_state &state,
const std::vector<const void *> &buffs,
@@ -296,7 +301,7 @@ namespace vrt_packet_handler{
uhd::transport::vrt::if_packet_info_t &if_packet_info,
const uhd::io_type_t &io_type,
const uhd::otw_type_t &otw_type,
- vrt_packer_type vrt_packer,
+ const vrt_packer_t &vrt_packer,
const get_send_buffs_t &get_send_buffs,
size_t vrt_header_offset_words32
){
@@ -334,7 +339,6 @@ namespace vrt_packet_handler{
/*******************************************************************
* Send vrt packets and copy convert the samples into the buffer.
******************************************************************/
- template<typename vrt_packer_type>
static UHD_INLINE size_t send(
send_state &state,
const std::vector<const void *> &buffs,
@@ -344,7 +348,7 @@ namespace vrt_packet_handler{
const uhd::io_type_t &io_type,
const uhd::otw_type_t &otw_type,
double tick_rate,
- vrt_packer_type vrt_packer,
+ const vrt_packer_t &vrt_packer,
const get_send_buffs_t &get_send_buffs,
size_t max_samples_per_packet,
size_t vrt_header_offset_words32 = 0
diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp
index 42f69d77b..8a1cde694 100644
--- a/host/lib/transport/zero_copy.cpp
+++ b/host/lib/transport/zero_copy.cpp
@@ -54,12 +54,14 @@ private:
//! phony zero-copy recv interface implementation
struct phony_zero_copy_recv_if::impl{
+ impl(size_t max_buff_size) : max_buff_size(max_buff_size){
+ /* NOP */
+ }
size_t max_buff_size;
};
phony_zero_copy_recv_if::phony_zero_copy_recv_if(size_t max_buff_size){
- _impl = UHD_PIMPL_MAKE(impl, ());
- _impl->max_buff_size = max_buff_size;
+ _impl = UHD_PIMPL_MAKE(impl, (max_buff_size));
}
phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index e0ce61058..5c0fb1f42 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -36,6 +36,7 @@
#include <boost/thread.hpp>
#include <stdexcept>
#include <complex>
+#include <sstream>
using namespace uhd;
@@ -60,14 +61,17 @@ freq_range_t::freq_range_t(double min, double max):
/***********************************************************************
* tune result
**********************************************************************/
-tune_result_t::tune_result_t(void):
- target_inter_freq(0.0),
- actual_inter_freq(0.0),
- target_dsp_freq(0.0),
- actual_dsp_freq(0.0),
- spectrum_inverted(false)
-{
- /* NOP */
+std::string tune_result_t::to_pp_string(void) const{
+ return str(boost::format(
+ "Tune Result:\n"
+ " Target Intermediate Freq: %f (MHz)\n"
+ " Actual Intermediate Freq: %f (MHz)\n"
+ " Target DSP Freq Shift: %f (MHz)\n"
+ " Actual DSP Freq Shift: %f (MHz)\n"
+ )
+ % (target_inter_freq/1e6) % (actual_inter_freq/1e6)
+ % (target_dsp_freq/1e6) % (actual_dsp_freq/1e6)
+ );
}
/***********************************************************************
@@ -95,18 +99,6 @@ stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
/***********************************************************************
* metadata
**********************************************************************/
-rx_metadata_t::rx_metadata_t(void):
- has_time_spec(false),
- time_spec(time_spec_t()),
- more_fragments(false),
- fragment_offset(0),
- start_of_burst(false),
- end_of_burst(false),
- error_code(ERROR_CODE_NONE)
-{
- /* NOP */
-}
-
tx_metadata_t::tx_metadata_t(void):
has_time_spec(false),
time_spec(time_spec_t()),
@@ -199,7 +191,7 @@ device_addr_t::device_addr_t(const std::string &args){
std::vector<std::string> key_val;
boost::split(key_val, pair, boost::is_any_of(pair_delim));
if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args);
- (*this)[trim(key_val[0])] = trim(key_val[1]);
+ (*this)[trim(key_val.front())] = trim(key_val.back());
}
}
@@ -207,16 +199,18 @@ std::string device_addr_t::to_pp_string(void) const{
if (this->size() == 0) return "Empty Device Address";
std::stringstream ss;
+ ss << "Device Address:" << std::endl;
BOOST_FOREACH(std::string key, this->keys()){
- ss << boost::format("%s: %s") % key % (*this)[key] << std::endl;
+ ss << boost::format(" %s: %s") % key % (*this)[key] << std::endl;
}
return ss.str();
}
std::string device_addr_t::to_string(void) const{
std::string args_str;
+ size_t count = 0;
BOOST_FOREACH(const std::string &key, this->keys()){
- args_str += key + pair_delim + (*this)[key] + arg_delim;
+ args_str += ((count++)? arg_delim : "") + key + pair_delim + (*this)[key];
}
return args_str;
}
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 814affdd0..4a45c263e 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -24,6 +24,13 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp
)
+
+INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/dboard/CMakeLists.txt)
+INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/CMakeLists.txt)
+INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/CMakeLists.txt)
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
index 6093583d3..3e995009e 100644
--- a/host/lib/usrp/dboard/CMakeLists.txt
+++ b/host/lib/usrp/dboard/CMakeLists.txt
@@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_rfx.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_xcvr2450.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp
)
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index 766deac78..9180828d8 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -16,6 +16,7 @@
//
#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/dict.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
@@ -138,17 +139,14 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_QUADRATURE:
- val = (get_subdev_name() == "AB"); //only quadrature in ab mode
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
- return;
+ case SUBDEV_PROP_CONNECTION:{
+ static const uhd::dict<std::string, subdev_conn_t> name_to_conn = map_list_of
+ ("A", SUBDEV_CONN_REAL_I)
+ ("B", SUBDEV_CONN_REAL_Q)
+ ("AB", SUBDEV_CONN_COMPLEX_IQ)
+ ;
+ val = name_to_conn[get_subdev_name()];
+ } return;
case SUBDEV_PROP_USE_LO_OFFSET:
val = false;
@@ -237,16 +235,8 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
new file mode 100644
index 000000000..03e6b6255
--- /dev/null
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -0,0 +1,610 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// No RX IO Pins Used
+
+// RX IO Functions
+
+#include "max2118_regs.hpp"
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/warning.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <utility>
+#include <cmath>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The DBSRX constants
+ **********************************************************************/
+static const bool dbsrx_debug = false;
+
+static const freq_range_t dbsrx_freq_range(0.8e9, 2.4e9);
+
+static const freq_range_t dbsrx_pfd_freq_range(0.15e6, 2.01e6);
+
+static const prop_names_t dbsrx_antennas = list_of("J3");
+
+static const uhd::dict<std::string, gain_range_t> dbsrx_gain_ranges = map_list_of
+ ("GC1", gain_range_t(0, 56, 0.5))
+ ("GC2", gain_range_t(0, 24, 1))
+;
+
+/***********************************************************************
+ * The DBSRX dboard class
+ **********************************************************************/
+class dbsrx : public rx_dboard_base{
+public:
+ dbsrx(ctor_args_t args, boost::uint8_t max2118_addr);
+ ~dbsrx(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ double _lo_freq;
+ float _bandwidth;
+ uhd::dict<std::string, float> _gains;
+ max2118_write_regs_t _max2118_write_regs;
+ max2118_read_regs_t _max2118_read_regs;
+ boost::uint8_t _max2118_addr; //0x67 or 0x65 depending on which side
+
+ void set_lo_freq(double target_freq);
+ void set_gain(float gain, const std::string &name);
+ void set_bandwidth(float bandwidth);
+
+ void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){
+ start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5));
+ stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5));
+
+ for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){
+ int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1;
+
+ //create buffer for register data (+1 for start address)
+ byte_vector_t regs_vector(num_bytes + 1);
+
+ //first byte is the address of first register
+ regs_vector[0] = start_addr;
+
+ //get the register data
+ for(int i=0; i<num_bytes; i++){
+ regs_vector[1+i] = _max2118_write_regs.get_reg(start_addr+i);
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: send reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d"
+ ) % int(start_addr+i) % int(regs_vector[1+i]) % int(start_addr) % num_bytes << std::endl;
+ }
+
+ //send the data
+ this->get_iface()->write_i2c(
+ _max2118_addr, regs_vector
+ );
+ }
+ }
+
+ void read_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){
+ static const boost::uint8_t status_addr = 0x0;
+ start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x1));
+ stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x1));
+
+ for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t)){
+ int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) ? sizeof(boost::uint32_t) : stop_reg - start_addr + 1;
+
+ //create buffer for register data
+ byte_vector_t regs_vector(num_bytes);
+
+ //read from i2c
+ regs_vector = this->get_iface()->read_i2c(
+ _max2118_addr, num_bytes
+ );
+
+ for(boost::uint8_t i=0; i < num_bytes; i++){
+ if (i + start_addr >= status_addr){
+ _max2118_read_regs.set_reg(i + start_addr, regs_vector[i]);
+ }
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: read reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d"
+ ) % int(start_addr+i) % int(regs_vector[i]) % int(start_addr) % num_bytes << std::endl;
+ }
+ }
+ }
+
+ /*!
+ * Is the LO locked?
+ * \return true for locked
+ */
+ bool get_locked(void){
+ read_reg(0x0, 0x0);
+
+ //mask and return lock detect
+ bool locked = 5 >= _max2118_read_regs.adc and _max2118_read_regs.adc >= 2;
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: locked %d"
+ ) % locked << std::endl;
+
+ return locked;
+ }
+
+};
+
+/***********************************************************************
+ * Register the DBSRX dboard
+ **********************************************************************/
+// FIXME 0x67 is the default i2c address on USRP2
+// need to handle which side for USRP1 with different address
+static dboard_base::sptr make_dbsrx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new dbsrx(args, 0x67));
+}
+
+//dbid for USRP2 version
+UHD_STATIC_BLOCK(reg_dbsrx_dboard){
+ //register the factory function for the rx dbid
+ dboard_manager::register_dboard(0x000D, &make_dbsrx, "DBSRX");
+}
+
+//dbid for USRP1 version
+UHD_STATIC_BLOCK(reg_dbsrx_on_usrp1_dboard){
+ //register the factory function for the rx dbid
+ dboard_manager::register_dboard(0x0002, &make_dbsrx, "DBSRX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+dbsrx::dbsrx(ctor_args_t args, boost::uint8_t max2118_addr) : rx_dboard_base(args){
+ //warn user about incorrect DBID on USRP1, requires R193 populated
+ if (this->get_iface()->get_mboard_name() == "usrp1" and this->get_rx_id() == 0x000D)
+ uhd::print_warning(
+ str(boost::format(
+ "DBSRX: incorrect dbid\n"
+ "%s expects dbid 0x0002 and R193\n"
+ "found dbid == %d\n"
+ "Please see the daughterboard app notes"
+ ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string()))
+ );
+
+ //warn user about incorrect DBID on non-USRP1, requires R194 populated
+ if (this->get_iface()->get_mboard_name() != "usrp1" and this->get_rx_id() == 0x0002)
+ uhd::print_warning(
+ str(boost::format(
+ "DBSRX: incorrect dbid\n"
+ "%s expects dbid 0x000D and R194\n"
+ "found dbid == %d\n"
+ "Please see the daughterboard app notes"
+ ) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string()))
+ );
+
+ //enable only the clocks we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
+
+ //set the gpio directions and atr controls (identically)
+ this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs
+
+ //set the i2c address for the max2118
+ _max2118_addr = max2118_addr;
+
+ //send initial register settings
+ this->send_reg(0x0, 0x5);
+
+ //set defaults for LO, gains, and filter bandwidth
+ _bandwidth = 33e6;
+ set_lo_freq(dbsrx_freq_range.min);
+
+ BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){
+ set_gain(dbsrx_gain_ranges[name].min, name);
+ }
+
+ set_bandwidth(33e6); // default bandwidth from datasheet
+}
+
+dbsrx::~dbsrx(void){
+}
+
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void dbsrx::set_lo_freq(double target_freq){
+ target_freq = std::clip(target_freq, dbsrx_freq_range.min, dbsrx_freq_range.max);
+
+ double actual_freq=0.0, pfd_freq=0.0, ref_clock=0.0;
+ int R=0, N=0, r=0, m=0;
+ bool update_filter_settings = false;
+
+ //choose refclock
+ std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX);
+ BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){
+ if (ref_clock > 27.0e6) continue;
+
+ //choose m_divider such that filter tuning constraint is met
+ m = 31;
+ while ((ref_clock/m < 1e6 or ref_clock/m > 2.5e6) and m > 0){ m--; }
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: trying ref_clock %f and m_divider %d"
+ ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl;
+
+ if (m >= 32) continue;
+
+ //choose R
+ for(r = 0; r <= 6; r += 1) {
+ //compute divider from setting
+ R = 1 << (r+1);
+ if (dbsrx_debug) std::cerr << boost::format("DBSRX R:%d\n") % R << std::endl;
+
+ //compute PFD compare frequency = ref_clock/R
+ pfd_freq = ref_clock / R;
+
+ //constrain the PFD frequency to specified range
+ if ((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max)) continue;
+
+ //compute N
+ N = int(std::floor(target_freq/pfd_freq));
+
+ //constrain N to specified range
+ if ((N < 256) or (N > 32768)) continue;
+
+ goto done_loop;
+ }
+ }
+
+ //Assert because we failed to find a suitable combination of ref_clock, R and N
+ UHD_ASSERT_THROW(ref_clock/(1 << m) < 1e6 or ref_clock/(1 << m) > 2.5e6);
+ UHD_ASSERT_THROW((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max));
+ UHD_ASSERT_THROW((N < 256) or (N > 32768));
+ done_loop:
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: choose ref_clock %f and m_divider %d"
+ ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl;
+
+ //if ref_clock or m divider changed, we need to update the filter settings
+ if (ref_clock != this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) or m != _max2118_write_regs.m_divider) update_filter_settings = true;
+
+ //compute resulting output frequency
+ actual_freq = pfd_freq * N;
+
+ //apply ref_clock, R, and N settings
+ this->get_iface()->set_clock_rate(dboard_iface::UNIT_RX, ref_clock);
+ ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX);
+ _max2118_write_regs.m_divider = m;
+ _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;
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: scaler %d, actual_freq %f MHz, register bit: %d"
+ ) % scaler % (actual_freq/1e6) % int(_max2118_write_regs.div2) << std::endl;
+
+ //compute vco frequency and select vco
+ double vco_freq = actual_freq * scaler;
+ if (vco_freq < 2433e6)
+ _max2118_write_regs.osc_band = 0;
+ else if (vco_freq < 2711e6)
+ _max2118_write_regs.osc_band = 1;
+ else if (vco_freq < 3025e6)
+ _max2118_write_regs.osc_band = 2;
+ else if (vco_freq < 3341e6)
+ _max2118_write_regs.osc_band = 3;
+ else if (vco_freq < 3727e6)
+ _max2118_write_regs.osc_band = 4;
+ else if (vco_freq < 4143e6)
+ _max2118_write_regs.osc_band = 5;
+ else if (vco_freq < 4493e6)
+ _max2118_write_regs.osc_band = 6;
+ else
+ _max2118_write_regs.osc_band = 7;
+
+ //send settings over i2c
+ send_reg(0x0, 0x4);
+
+ //check vtune for lock condition
+ read_reg(0x0, 0x0);
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: initial guess for vco %d, vtune adc %d"
+ ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;
+
+ //if we are out of lock for chosen vco, change vco
+ while ((_max2118_read_regs.adc == 0) or (_max2118_read_regs.adc == 7)){
+
+ //vtune is too low, try lower frequency vco
+ if (_max2118_read_regs.adc == 0){
+ if (_max2118_write_regs.osc_band == 0){
+ uhd::print_warning(
+ str(boost::format(
+ "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);
+ }
+ if (_max2118_write_regs.osc_band <= 0) break;
+ _max2118_write_regs.osc_band -= 1;
+ }
+
+ //vtune is too high, try higher frequency vco
+ if (_max2118_read_regs.adc == 7){
+ if (_max2118_write_regs.osc_band == 7){
+ uhd::print_warning(
+ str(boost::format(
+ "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);
+ }
+ if (_max2118_write_regs.osc_band >= 7) break;
+ _max2118_write_regs.osc_band += 1;
+ }
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: trying vco %d, vtune adc %d"
+ ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;
+
+ //update vco selection and check vtune
+ send_reg(0x2, 0x2);
+ read_reg(0x0, 0x0);
+ }
+
+ if(dbsrx_debug) std::cerr << boost::format(
+ "DBSRX: final vco %d, vtune adc %d"
+ ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;
+
+ //select charge pump bias current
+ 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);
+
+ //compute actual tuned frequency
+ _lo_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) / std::pow(2.0,(1 + _max2118_write_regs.r_divider)) * _max2118_write_regs.get_n_divider();
+
+ //debug output of calculated variables
+ if (dbsrx_debug) std::cerr
+ << boost::format("DBSRX tune:\n")
+ << boost::format(" VCO=%d, CP=%d, PFD Freq=%fMHz\n") % int(_max2118_write_regs.osc_band) % _max2118_write_regs.cp_current % (pfd_freq/1e6)
+ << boost::format(" R=%d, N=%f, scaler=%d, div2=%d\n") % R % N % scaler % int(_max2118_write_regs.div2)
+ << boost::format(" Ref Freq=%fMHz\n") % (ref_clock/1e6)
+ << boost::format(" Target Freq=%fMHz\n") % (target_freq/1e6)
+ << boost::format(" Actual Freq=%fMHz\n") % (_lo_freq/1e6)
+ << std::endl;
+
+ if (update_filter_settings) set_bandwidth(_bandwidth);
+ get_locked();
+}
+
+/***********************************************************************
+ * Gain Handling
+ **********************************************************************/
+/*!
+ * Convert a requested gain for the GC2 vga into the integer register value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return 5 bit the register value
+ */
+static int gain_to_gc2_vga_reg(float &gain){
+ int reg = 0;
+ gain = std::clip<float>(float(boost::math::iround(gain)), dbsrx_gain_ranges["GC2"].min, dbsrx_gain_ranges["GC2"].max);
+
+ // Half dB steps from 0-5dB, 1dB steps from 5-24dB
+ if (gain < 5) {
+ reg = boost::math::iround(31.0 - gain/0.5);
+ gain = float(boost::math::iround(gain) * 0.5);
+ } else {
+ reg = boost::math::iround(22.0 - (gain - 4.0));
+ gain = float(boost::math::iround(gain));
+ }
+
+ if (dbsrx_debug) std::cerr << boost::format(
+ "DBSRX GC2 Gain: %f dB, reg: %d"
+ ) % gain % reg << std::endl;
+
+ return reg;
+}
+
+/*!
+ * Convert a requested gain for the GC1 rf vga into the dac_volts value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return dac voltage value
+ */
+static float gain_to_gc1_rfvga_dac(float &gain){
+ //clip the input
+ gain = std::clip<float>(gain, dbsrx_gain_ranges["GC1"].min, dbsrx_gain_ranges["GC1"].max);
+
+ //voltage level constants
+ static const float max_volts = float(1.2), min_volts = float(2.7);
+ static const float slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].max;
+
+ //calculate the voltage for the aux dac
+ float dac_volts = gain*slope + min_volts;
+
+ if (dbsrx_debug) std::cerr << boost::format(
+ "DBSRX GC1 Gain: %f dB, dac_volts: %f V"
+ ) % gain % dac_volts << std::endl;
+
+ //the actual gain setting
+ gain = (dac_volts - min_volts)/slope;
+
+ return dac_volts;
+}
+
+void dbsrx::set_gain(float gain, const std::string &name){
+ assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name");
+ if (name == "GC2"){
+ _max2118_write_regs.gc2 = gain_to_gc2_vga_reg(gain);
+ send_reg(0x5, 0x5);
+ }
+ else if(name == "GC1"){
+ //write the new voltage to the aux dac
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain));
+ }
+ else UHD_THROW_INVALID_CODE_PATH();
+ _gains[name] = gain;
+}
+
+/***********************************************************************
+ * Bandwidth Handling
+ **********************************************************************/
+void dbsrx::set_bandwidth(float bandwidth){
+ //clip the input
+ bandwidth = std::clip<float>(bandwidth, 4e6, 33e6);
+
+ 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
+ _max2118_write_regs.f_dac = std::clip<int>(int((((bandwidth*_max2118_write_regs.m_divider)/ref_clock) - 4)/0.145),0,127);
+
+ //determine actual bandwidth
+ _bandwidth = float((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac));
+
+ if (dbsrx_debug) std::cerr << boost::format(
+ "DBSRX Filter Bandwidth: %f MHz, m: %d, f_dac: %d\n"
+ ) % (_bandwidth/1e6) % int(_max2118_write_regs.m_divider) % int(_max2118_write_regs.f_dac) << std::endl;
+
+ this->send_reg(0x3, 0x4);
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void dbsrx::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = get_rx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_gains.keys(), name, "dbsrx gain name");
+ val = _gains[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(dbsrx_gain_ranges.keys(), name, "dbsrx gain name");
+ val = dbsrx_gain_ranges[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(dbsrx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = dbsrx_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("J3");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = dbsrx_antennas;
+ return;
+
+/*
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+*/
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked();
+ return;
+
+/*
+ case SUBDEV_PROP_RSSI:
+ val = this->get_rssi();
+ return;
+*/
+
+ case SUBDEV_PROP_BANDWIDTH:
+ val = _bandwidth;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void dbsrx::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_gain(val.as<float>(), name);
+ return;
+
+ case SUBDEV_PROP_BANDWIDTH:
+ this->set_bandwidth(val.as<float>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 2d6088983..b6b44199a 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -43,6 +43,7 @@
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
@@ -65,6 +66,10 @@ static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2");
static const uhd::dict<std::string, gain_range_t> rfx_tx_gain_ranges; //empty
static const uhd::dict<std::string, gain_range_t> rfx_rx_gain_ranges = map_list_of
+ ("PGA0", gain_range_t(0, 70, float(0.022)))
+;
+
+static const uhd::dict<std::string, gain_range_t> rfx400_rx_gain_ranges = map_list_of
("PGA0", gain_range_t(0, 45, float(0.022)))
;
@@ -88,6 +93,7 @@ public:
private:
freq_range_t _freq_range;
+ uhd::dict<std::string, gain_range_t> _rx_gain_ranges;
uhd::dict<dboard_iface::unit_t, bool> _div2;
double _rx_lo_freq, _tx_lo_freq;
std::string _rx_ant;
@@ -166,6 +172,14 @@ rfx_xcvr::rfx_xcvr(
_div2[dboard_iface::UNIT_RX] = rx_div2;
_div2[dboard_iface::UNIT_TX] = tx_div2;
+ if(this->get_rx_id() == 0x0024) { //RFX400
+ _rx_gain_ranges = rfx400_rx_gain_ranges;
+ }
+ else {
+ _rx_gain_ranges = rfx_rx_gain_ranges;
+ }
+
+
//enable the clocks that we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
@@ -193,8 +207,8 @@ rfx_xcvr::rfx_xcvr(
set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
set_rx_ant("RX2");
- BOOST_FOREACH(const std::string &name, rfx_rx_gain_ranges.keys()){
- set_rx_gain(rfx_rx_gain_ranges[name].min, name);
+ BOOST_FOREACH(const std::string &name, _rx_gain_ranges.keys()){
+ set_rx_gain(_rx_gain_ranges[name].min, name);
}
}
@@ -227,10 +241,10 @@ void rfx_xcvr::set_tx_ant(const std::string &ant){
/***********************************************************************
* Gain Handling
**********************************************************************/
-static float rx_pga0_gain_to_dac_volts(float &gain){
+static float rx_pga0_gain_to_dac_volts(float &gain, float range){
//voltage level constants (negative slope)
static const float max_volts = float(.2), min_volts = float(1.2);
- static const float slope = (max_volts-min_volts)/45;
+ static const float slope = (max_volts-min_volts)/(range);
//calculate the voltage for the aux dac
float dac_volts = std::clip<float>(gain*slope + min_volts, max_volts, min_volts);
@@ -247,9 +261,10 @@ void rfx_xcvr::set_tx_gain(float, const std::string &name){
}
void rfx_xcvr::set_rx_gain(float gain, const std::string &name){
- assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name");
+ assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name");
if(name == "PGA0"){
- float dac_volts = rx_pga0_gain_to_dac_volts(gain);
+ float dac_volts = rx_pga0_gain_to_dac_volts(gain,
+ (_rx_gain_ranges["PGA0"].max - _rx_gain_ranges["PGA0"].min));
_rx_gains[name] = gain;
//write the new voltage to the aux dac
@@ -402,12 +417,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN_RANGE:
- assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name");
- val = rfx_rx_gain_ranges[name];
+ assert_has(_rx_gain_ranges.keys(), name, "rfx rx gain name");
+ val = _rx_gain_ranges[name];
return;
case SUBDEV_PROP_GAIN_NAMES:
- val = prop_names_t(rfx_rx_gain_ranges.keys());
+ val = prop_names_t(_rx_gain_ranges.keys());
return;
case SUBDEV_PROP_FREQ:
@@ -426,16 +441,8 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
val = rfx_rx_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = true;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_QI;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -516,16 +523,8 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
val = rfx_tx_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp
index ced27e34d..9dd9b550b 100644
--- a/host/lib/usrp/dboard/db_unknown.cpp
+++ b/host/lib/usrp/dboard/db_unknown.cpp
@@ -119,16 +119,8 @@ void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_QUADRATURE:
- val = false;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -218,16 +210,8 @@ void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index 2b2822b6b..3038ce30b 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -86,7 +86,7 @@ using namespace boost::assign;
**********************************************************************/
static const bool wbx_debug = false;
-static const freq_range_t wbx_freq_range(50e6, 2.22e9);
+static const freq_range_t wbx_freq_range(68.75e6, 2.2e9);
static const prop_names_t wbx_tx_antennas = list_of("TX/RX");
@@ -439,6 +439,7 @@ double wbx_xcvr::set_lo_freq(
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];
//write the registers
@@ -509,16 +510,8 @@ void wbx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
val = wbx_rx_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -603,16 +596,8 @@ void wbx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
val = wbx_tx_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 5032b6f31..2c94bcd2d 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -481,16 +481,8 @@ void xcvr2450::rx_get(const wax::obj &key_, wax::obj &val){
val = xcvr_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = false;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_IQ;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
@@ -579,16 +571,8 @@ void xcvr2450::tx_get(const wax::obj &key_, wax::obj &val){
val = xcvr_antennas;
return;
- case SUBDEV_PROP_QUADRATURE:
- val = true;
- return;
-
- case SUBDEV_PROP_IQ_SWAPPED:
- val = true;
- return;
-
- case SUBDEV_PROP_SPECTRUM_INVERTED:
- val = false;
+ case SUBDEV_PROP_CONNECTION:
+ val = SUBDEV_CONN_COMPLEX_QI;
return;
case SUBDEV_PROP_USE_LO_OFFSET:
diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp
index eafb8897f..6c4e29d9e 100644
--- a/host/lib/usrp/dboard_base.cpp
+++ b/host/lib/usrp/dboard_base.cpp
@@ -26,12 +26,12 @@ using namespace uhd::usrp;
* dboard_base dboard dboard_base class
**********************************************************************/
struct dboard_base::impl{
- ctor_args_impl args;
- impl(ctor_args_t args) : args(*args){}
+ dboard_ctor_args_t args;
};
dboard_base::dboard_base(ctor_args_t args){
- _impl = UHD_PIMPL_MAKE(impl, (args));
+ _impl = UHD_PIMPL_MAKE(impl, ());
+ _impl->args = *static_cast<dboard_ctor_args_t *>(args);
}
dboard_base::~dboard_base(void){
diff --git a/host/lib/usrp/dboard_ctor_args.hpp b/host/lib/usrp/dboard_ctor_args.hpp
index 13abe79e8..708f2ea08 100644
--- a/host/lib/usrp/dboard_ctor_args.hpp
+++ b/host/lib/usrp/dboard_ctor_args.hpp
@@ -15,18 +15,22 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_DBOARD_CTOR_ARGS_HPP
-#define INCLUDED_DBOARD_CTOR_ARGS_HPP
+#ifndef INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP
+#define INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP
#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_iface.hpp>
#include <string>
-struct uhd::usrp::dboard_base::ctor_args_impl{
- std::string sd_name;
- dboard_iface::sptr db_iface;
- dboard_id_t rx_id, tx_id;
-};
+namespace uhd{ namespace usrp{
-#endif /* INCLUDED_DBOARD_CTOR_ARGS_HPP */
+ struct dboard_ctor_args_t{
+ std::string sd_name;
+ dboard_iface::sptr db_iface;
+ dboard_id_t rx_id, tx_id;
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_LIBUHD_USRP_DBOARD_CTOR_ARGS_HPP */
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 6321e018f..ab80875f5 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -18,7 +18,6 @@
#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/utils/gain_handler.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/dict.hpp>
@@ -98,33 +97,18 @@ public:
enum type_t{RX_TYPE, TX_TYPE};
//structors
- subdev_proxy(dboard_base::sptr subdev, type_t type)
- : _subdev(subdev), _type(type){
- //initialize gain props struct
- gain_handler::props_t gain_props;
- gain_props.value = SUBDEV_PROP_GAIN;
- gain_props.range = SUBDEV_PROP_GAIN_RANGE;
- gain_props.names = SUBDEV_PROP_GAIN_NAMES;
-
- //make a new gain handler
- _gain_handler = gain_handler::make(
- this->get_link(), gain_props,
- boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2)
- );
- }
-
- ~subdev_proxy(void){
+ subdev_proxy(dboard_base::sptr subdev, type_t type):
+ _subdev(subdev), _type(type)
+ {
/* NOP */
}
private:
- gain_handler::sptr _gain_handler;
dboard_base::sptr _subdev;
type_t _type;
//forward the get calls to the rx or tx
void get(const wax::obj &key, wax::obj &val){
- if (_gain_handler->intercept_get(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_get(key, val);
case TX_TYPE: return _subdev->tx_get(key, val);
@@ -133,7 +117,6 @@ private:
//forward the set calls to the rx or tx
void set(const wax::obj &key, const wax::obj &val){
- if (_gain_handler->intercept_set(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_set(key, val);
case TX_TYPE: return _subdev->tx_set(key, val);
@@ -242,7 +225,7 @@ dboard_manager_impl::dboard_manager_impl(
set_nice_dboard_if();
//dboard constructor args
- dboard_base::ctor_args_impl db_ctor_args;
+ dboard_ctor_args_t db_ctor_args;
db_ctor_args.db_iface = iface;
//make xcvr subdevs (make one subdev for both rx and tx dboards)
diff --git a/host/lib/usrp/dsp_utils.hpp b/host/lib/usrp/dsp_utils.hpp
index 13186f354..ebed12c41 100644
--- a/host/lib/usrp/dsp_utils.hpp
+++ b/host/lib/usrp/dsp_utils.hpp
@@ -22,6 +22,7 @@
#include <uhd/types/dict.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/stream_cmd.hpp>
+#include <uhd/usrp/subdev_props.hpp>
#include <boost/cstdint.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
@@ -37,37 +38,36 @@ namespace dsp_type1{
/*!
* Calculate the rx mux word from properties.
- * \param is_quadrature true if the subdev is complex
- * \param is_iq_swapped true if the i and q are reversed
+ * \param subdev_conn the subdev connection type
* \param the 32-bit rx mux control word
*/
static inline boost::uint32_t calc_rx_mux_word(
- bool is_quadrature,
- bool is_iq_swapped
+ subdev_conn_t subdev_conn
){
- boost::uint32_t rx_mux = 0;
- if (is_quadrature){
- rx_mux = (0x01 << 2) | (0x00 << 0); //Q=ADC1, I=ADC0
- }else{
- rx_mux = (0x11 << 2) | (0x00 << 0); //Q=ZERO, I=ADC0
+ switch(subdev_conn){
+ case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 2) | (0x0 << 0); //DDC0Q=ADC1, DDC0I=ADC0
+ case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 2) | (0x1 << 0); //DDC0Q=ADC0, DDC0I=ADC1
+ case SUBDEV_CONN_REAL_I: return (0x3 << 2) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0
+ case SUBDEV_CONN_REAL_Q: return (0x1 << 2) | (0x3 << 0); //DDC0Q=ADC1, DDC0I=ZERO
+ default: UHD_THROW_INVALID_CODE_PATH();
}
- if (is_iq_swapped){
- rx_mux = (rx_mux << 2) | (rx_mux >> 2);
- }
- return rx_mux;
}
/*!
* Calculate the tx mux word from properties.
- * \param is_iq_swapped true if the i and q are reversed
+ * \param subdev_conn the subdev connection type
* \param the 32-bit tx mux control word
*/
- static inline boost::uint32_t calc_tx_mux_word(bool is_iq_swapped){
- boost::uint32_t tx_mux = 0x10;
- if (is_iq_swapped){
- tx_mux = (tx_mux << 4) | (tx_mux >> 4);
+ static inline boost::uint32_t calc_tx_mux_word(
+ subdev_conn_t subdev_conn
+ ){
+ switch(subdev_conn){
+ case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC1=DUC0Q, DAC0=DUC0I
+ case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC1=DUC0I, DAC0=DUC0Q
+ case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC1=ZERO, DAC0=DUC0I
+ case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC1=DUC0I, DAC0=ZERO
+ default: UHD_THROW_INVALID_CODE_PATH();
}
- return tx_mux;
}
/*!
@@ -82,11 +82,11 @@ namespace dsp_type1{
double &freq,
double codec_rate
){
- UHD_ASSERT_THROW(std::abs(freq) < codec_rate/2.0);
+ UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0);
static const double scale_factor = std::pow(2.0, 32);
//calculate the freq register word (signed)
- boost::int32_t freq_word = boost::math::iround((freq / codec_rate) * scale_factor);
+ boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / codec_rate) * scale_factor));
//update the actual frequency
freq = (double(freq_word) / scale_factor) * codec_rate;
diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp
index b40f98226..e78d38fc0 100644
--- a/host/lib/usrp/mimo_usrp.cpp
+++ b/host/lib/usrp/mimo_usrp.cpp
@@ -18,7 +18,9 @@
#include <uhd/usrp/mimo_usrp.hpp>
#include <uhd/usrp/tune_helper.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/gain_group.hpp>
#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/usrp/device_props.hpp>
@@ -33,6 +35,11 @@
using namespace uhd;
using namespace uhd::usrp;
+static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){
+ double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>();
+ return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0);
+}
+
/***********************************************************************
* MIMO USRP Implementation
**********************************************************************/
@@ -41,29 +48,12 @@ public:
mimo_usrp_impl(const device_addr_t &addr){
_dev = device::make(addr);
- //extract each mboard and its sub-devices
- BOOST_FOREACH(const std::string &name, (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>()){
- _mboards.push_back((*_dev)[named_prop_t(DEVICE_PROP_MBOARD, name)]);
- _rx_dsps.push_back(_mboards.back()[MBOARD_PROP_RX_DSP]);
- _tx_dsps.push_back(_mboards.back()[MBOARD_PROP_TX_DSP]);
-
- //extract rx subdevice
- _rx_dboards.push_back(_mboards.back()[MBOARD_PROP_RX_DBOARD]);
- std::string rx_subdev_in_use = _rx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
- _rx_subdevs.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]);
-
- //extract tx subdevice
- _tx_dboards.push_back(_mboards.back()[MBOARD_PROP_TX_DBOARD]);
- std::string tx_subdev_in_use = _tx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
- _tx_subdevs.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]);
- }
-
//set the clock config across all mboards (TODO set through api)
clock_config_t clock_config;
clock_config.ref_source = clock_config_t::REF_SMA;
clock_config.pps_source = clock_config_t::PPS_SMA;
- BOOST_FOREACH(wax::obj mboard, _mboards){
- mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
+ _mboard(chan)[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
}
}
@@ -82,7 +72,7 @@ public:
)
% (*_dev)[DEVICE_PROP_NAME].as<std::string>()
);
- for (size_t i = 0; i < get_num_channels(); i++){
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
buff += str(boost::format(
" Channel: %u\n"
" Mboard: %s\n"
@@ -92,21 +82,21 @@ public:
" TX DSP: %s\n"
" TX Dboard: %s\n"
" TX Subdev: %s\n"
- ) % i
- % _mboards.at(i)[MBOARD_PROP_NAME].as<std::string>()
- % _rx_dsps.at(i)[DSP_PROP_NAME].as<std::string>()
- % _rx_dboards.at(i)[DBOARD_PROP_NAME].as<std::string>()
- % _rx_subdevs.at(i)[SUBDEV_PROP_NAME].as<std::string>()
- % _tx_dsps.at(i)[DSP_PROP_NAME].as<std::string>()
- % _tx_dboards.at(i)[DBOARD_PROP_NAME].as<std::string>()
- % _tx_subdevs.at(i)[SUBDEV_PROP_NAME].as<std::string>()
+ ) % chan
+ % _mboard(chan)[MBOARD_PROP_NAME].as<std::string>()
+ % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
+ % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
+ % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
+ % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
+ % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
+ % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
);
}
return buff;
}
size_t get_num_channels(void){
- return _mboards.size();
+ return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().size();
}
/*******************************************************************
@@ -114,12 +104,12 @@ public:
******************************************************************/
time_spec_t get_time_now(void){
//the time on the first mboard better be the same on all
- return _mboards.front()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ return _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
}
void set_time_next_pps(const time_spec_t &time_spec){
- BOOST_FOREACH(wax::obj mboard, _mboards){
- mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
+ _mboard(chan)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
}
}
@@ -141,33 +131,42 @@ public:
boost::this_thread::sleep(boost::posix_time::seconds(1));
//verify that the time registers are read to be within a few RTT
- for (size_t i = 1; i < get_num_channels(); i++){
- time_spec_t time_0 = _mboards.front()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
- time_spec_t time_i = _mboards.at(i)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ for (size_t chan = 1; chan < get_num_channels(); chan++){
+ time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big
- std::cerr << boost::format(
- "Error: time deviation between board %d and board 0.\n"
- " Board 0 time is %f seconds.\n"
- " Board %d time is %f seconds.\n"
- ) % i % time_0.get_real_secs() % i % time_i.get_real_secs() << std::endl;
+ uhd::print_warning(str(boost::format(
+ "Detected time deviation between board %d and board 0.\n"
+ "Board 0 time is %f seconds.\n"
+ "Board %d time is %f seconds.\n"
+ ) % chan % time_0.get_real_secs() % chan % time_i.get_real_secs()));
}
}
}
void issue_stream_cmd(const stream_cmd_t &stream_cmd){
- BOOST_FOREACH(wax::obj mboard, _mboards){
- mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd;
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
+ _mboard(chan)[MBOARD_PROP_STREAM_CMD] = stream_cmd;
}
}
/*******************************************************************
* RX methods
******************************************************************/
+ void set_rx_subdev_spec(size_t chan, const subdev_spec_t &spec){
+ UHD_ASSERT_THROW(spec.size() <= 1);
+ _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec;
+ }
+
+ subdev_spec_t get_rx_subdev_spec(size_t chan){
+ return _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
void set_rx_rate_all(double rate){
std::vector<double> _actual_rates;
- BOOST_FOREACH(wax::obj rx_dsp, _rx_dsps){
- rx_dsp[DSP_PROP_HOST_RATE] = rate;
- _actual_rates.push_back(rx_dsp[DSP_PROP_HOST_RATE].as<double>());
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
+ _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ _actual_rates.push_back(_rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>());
}
_rx_rate = _actual_rates.front();
if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error(
@@ -180,57 +179,70 @@ public:
}
tune_result_t set_rx_freq(size_t chan, double target_freq){
- return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq);
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq);
}
tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){
- return tune_rx_subdev_and_ddc(_rx_subdevs.at(chan), _rx_dsps.at(chan), target_freq, lo_off);
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq, lo_off);
+ }
+
+ double get_rx_freq(size_t chan){
+ return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan));
}
freq_range_t get_rx_freq_range(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan));
}
void set_rx_gain(size_t chan, float gain){
- _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain;
+ return _rx_gain_group(chan)->set_value(gain);
}
float get_rx_gain(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>();
+ return _rx_gain_group(chan)->get_value();
}
gain_range_t get_rx_gain_range(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _rx_gain_group(chan)->get_range();
}
void set_rx_antenna(size_t chan, const std::string &ant){
- _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
}
std::string get_rx_antenna(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
}
std::vector<std::string> get_rx_antennas(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
}
bool get_rx_lo_locked(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
float read_rssi(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_RSSI].as<float>();
+ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>();
}
/*******************************************************************
* TX methods
******************************************************************/
+ void set_tx_subdev_spec(size_t chan, const subdev_spec_t &spec){
+ UHD_ASSERT_THROW(spec.size() <= 1);
+ _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec;
+ }
+
+ subdev_spec_t get_tx_subdev_spec(size_t chan){
+ return _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
void set_tx_rate_all(double rate){
std::vector<double> _actual_rates;
- BOOST_FOREACH(wax::obj tx_dsp, _tx_dsps){
- tx_dsp[DSP_PROP_HOST_RATE] = rate;
- _actual_rates.push_back(tx_dsp[DSP_PROP_HOST_RATE].as<double>());
+ for (size_t chan = 0; chan < get_num_channels(); chan++){
+ _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ _actual_rates.push_back(_tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>());
}
_tx_rate = _actual_rates.front();
if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error(
@@ -243,54 +255,85 @@ public:
}
tune_result_t set_tx_freq(size_t chan, double target_freq){
- return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq);
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq);
}
tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){
- return tune_tx_subdev_and_duc(_tx_subdevs.at(chan), _tx_dsps.at(chan), target_freq, lo_off);
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq, lo_off);
+ }
+
+ double get_tx_freq(size_t chan){
+ return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan));
}
freq_range_t get_tx_freq_range(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan));
}
void set_tx_gain(size_t chan, float gain){
- _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain;
+ return _tx_gain_group(chan)->set_value(gain);
}
float get_tx_gain(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>();
+ return _tx_gain_group(chan)->get_value();
}
gain_range_t get_tx_gain_range(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _tx_gain_group(chan)->get_range();
}
void set_tx_antenna(size_t chan, const std::string &ant){
- _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
}
std::string get_tx_antenna(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
}
std::vector<std::string> get_tx_antennas(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
}
bool get_tx_lo_locked(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
private:
device::sptr _dev;
- std::vector<wax::obj> _mboards;
- std::vector<wax::obj> _rx_dsps;
- std::vector<wax::obj> _tx_dsps;
- std::vector<wax::obj> _rx_dboards;
- std::vector<wax::obj> _tx_dboards;
- std::vector<wax::obj> _rx_subdevs;
- std::vector<wax::obj> _tx_subdevs;
+ wax::obj _mboard(size_t chan){
+ prop_names_t names = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>();
+ return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, names.at(chan))];
+ }
+ wax::obj _rx_dsp(size_t chan){
+ return _mboard(chan)[MBOARD_PROP_RX_DSP];
+ }
+ wax::obj _tx_dsp(size_t chan){
+ return _mboard(chan)[MBOARD_PROP_TX_DSP];
+ }
+ wax::obj _rx_dboard(size_t chan){
+ std::string db_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
+ return _mboard(chan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)];
+ }
+ wax::obj _tx_dboard(size_t chan){
+ std::string db_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
+ return _mboard(chan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)];
+ }
+ wax::obj _rx_subdev(size_t chan){
+ std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ wax::obj _tx_subdev(size_t chan){
+ std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ gain_group::sptr _rx_gain_group(size_t chan){
+ std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
+ gain_group::sptr _tx_gain_group(size_t chan){
+ std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
//shadows
double _rx_rate, _tx_rate;
diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp
new file mode 100644
index 000000000..0aa03a6cc
--- /dev/null
+++ b/host/lib/usrp/misc_utils.cpp
@@ -0,0 +1,114 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "misc_utils.hpp"
+#include <uhd/utils/gain_group.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/codec_props.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+static const size_t subdev_gain_priority = 1; //higher, closer to the antenna
+static const size_t codec_gain_priority = 0;
+
+/***********************************************************************
+ * codec gain group helper functions:
+ * do this so we dont have to bind a templated function
+ **********************************************************************/
+static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>();
+}
+
+static float get_codec_gain_i(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>();
+}
+
+static float get_codec_gain_q(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>();
+}
+
+static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
+ codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
+}
+
+static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
+}
+
+static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
+}
+
+/***********************************************************************
+ * subdev gain group helper functions:
+ * do this so we dont have to bind a templated function
+ **********************************************************************/
+static float get_subdev_gain(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>();
+}
+
+static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>();
+}
+
+static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){
+ subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
+}
+
+/***********************************************************************
+ * gain group factory function for usrp
+ **********************************************************************/
+gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){
+ gain_group::sptr gg = gain_group::make();
+ gain_fcns_t fcns;
+ //add all the subdev gains first (antenna to dsp order)
+ BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){
+ fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name);
+ fcns.get_value = boost::bind(&get_subdev_gain, subdev, name);
+ fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1);
+ gg->register_fcns(fcns, subdev_gain_priority);
+ }
+ //add all the codec gains last (antenna to dsp order)
+ BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){
+ fcns.get_range = boost::bind(&get_codec_gain_range, codec, name);
+
+ //register the value functions depending upon the connection type
+ switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
+ case SUBDEV_CONN_COMPLEX_IQ:
+ case SUBDEV_CONN_COMPLEX_QI:
+ fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q
+ fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both
+ break;
+
+ case SUBDEV_CONN_REAL_I:
+ fcns.get_value = boost::bind(&get_codec_gain_i, codec, name);
+ fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1);
+ break;
+
+ case SUBDEV_CONN_REAL_Q:
+ fcns.get_value = boost::bind(&get_codec_gain_q, codec, name);
+ fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1);
+ break;
+ }
+ gg->register_fcns(fcns, codec_gain_priority);
+ }
+ return gg;
+}
diff --git a/host/lib/usrp/misc_utils.hpp b/host/lib/usrp/misc_utils.hpp
new file mode 100644
index 000000000..7fe3c899d
--- /dev/null
+++ b/host/lib/usrp/misc_utils.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP
+#define INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <uhd/utils/gain_group.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Create a gain group that represents the subdevice and its codec.
+ */
+ gain_group::sptr make_gain_group(wax::obj subdev, wax::obj codec);
+
+}} //namespace
+
+#endif /* INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP */
+
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index 56e82d7ee..60b25a647 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -18,6 +18,7 @@
#include <uhd/usrp/simple_usrp.hpp>
#include <uhd/usrp/tune_helper.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/gain_group.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/usrp/device_props.hpp>
@@ -26,10 +27,16 @@
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <stdexcept>
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
+static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){
+ double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>();
+ return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0);
+}
+
/***********************************************************************
* Simple USRP Implementation
**********************************************************************/
@@ -37,19 +44,6 @@ class simple_usrp_impl : public simple_usrp{
public:
simple_usrp_impl(const device_addr_t &addr){
_dev = device::make(addr);
- _mboard = (*_dev)[DEVICE_PROP_MBOARD];
- _rx_dsp = _mboard[MBOARD_PROP_RX_DSP];
- _tx_dsp = _mboard[MBOARD_PROP_TX_DSP];
-
- //extract rx subdevice
- _rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD];
- std::string rx_subdev_in_use = _rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
- _rx_subdev = _rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)];
-
- //extract tx subdevice
- _tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD];
- std::string tx_subdev_in_use = _tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
- _tx_subdev = _tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)];
}
~simple_usrp_impl(void){
@@ -73,13 +67,13 @@ public:
" TX Subdev: %s\n"
)
% (*_dev)[DEVICE_PROP_NAME].as<std::string>()
- % _mboard[MBOARD_PROP_NAME].as<std::string>()
- % _rx_dsp[DSP_PROP_NAME].as<std::string>()
- % _rx_dboard[DBOARD_PROP_NAME].as<std::string>()
- % _rx_subdev[SUBDEV_PROP_NAME].as<std::string>()
- % _tx_dsp[DSP_PROP_NAME].as<std::string>()
- % _tx_dboard[DBOARD_PROP_NAME].as<std::string>()
- % _tx_subdev[SUBDEV_PROP_NAME].as<std::string>()
+ % _mboard()[MBOARD_PROP_NAME].as<std::string>()
+ % _rx_dsp()[DSP_PROP_NAME].as<std::string>()
+ % _rx_dboard()[DBOARD_PROP_NAME].as<std::string>()
+ % _rx_subdev()[SUBDEV_PROP_NAME].as<std::string>()
+ % _tx_dsp()[DSP_PROP_NAME].as<std::string>()
+ % _tx_dboard()[DBOARD_PROP_NAME].as<std::string>()
+ % _tx_subdev()[SUBDEV_PROP_NAME].as<std::string>()
);
}
@@ -87,140 +81,192 @@ public:
* Misc
******************************************************************/
time_spec_t get_time_now(void){
- return _mboard[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
}
void set_time_now(const time_spec_t &time_spec){
- _mboard[MBOARD_PROP_TIME_NOW] = time_spec;
+ _mboard()[MBOARD_PROP_TIME_NOW] = time_spec;
}
void set_time_next_pps(const time_spec_t &time_spec){
- _mboard[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
}
void issue_stream_cmd(const stream_cmd_t &stream_cmd){
- _mboard[MBOARD_PROP_STREAM_CMD] = stream_cmd;
+ _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd;
}
void set_clock_config(const clock_config_t &clock_config){
- _mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
+ _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
}
/*******************************************************************
* RX methods
******************************************************************/
+ void set_rx_subdev_spec(const subdev_spec_t &spec){
+ _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec;
+ std::cout << "RX " << _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl;
+ }
+
+ subdev_spec_t get_rx_subdev_spec(void){
+ return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
void set_rx_rate(double rate){
- _rx_dsp[DSP_PROP_HOST_RATE] = rate;
+ _rx_dsp()[DSP_PROP_HOST_RATE] = rate;
}
double get_rx_rate(void){
- return _rx_dsp[DSP_PROP_HOST_RATE].as<double>();
+ return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();
}
tune_result_t set_rx_freq(double target_freq){
- return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq);
+ return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq);
}
tune_result_t set_rx_freq(double target_freq, double lo_off){
- return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq, lo_off);
+ return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq, lo_off);
+ }
+
+ double get_rx_freq(void){
+ return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp());
}
freq_range_t get_rx_freq_range(void){
- return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ return add_dsp_shift(_rx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());
}
void set_rx_gain(float gain){
- _rx_subdev[SUBDEV_PROP_GAIN] = gain;
+ return _rx_gain_group()->set_value(gain);
}
float get_rx_gain(void){
- return _rx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ return _rx_gain_group()->get_value();
}
gain_range_t get_rx_gain_range(void){
- return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _rx_gain_group()->get_range();
}
void set_rx_antenna(const std::string &ant){
- _rx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ _rx_subdev()[SUBDEV_PROP_ANTENNA] = ant;
}
std::string get_rx_antenna(void){
- return _rx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _rx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();
}
std::vector<std::string> get_rx_antennas(void){
- return _rx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _rx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
}
bool get_rx_lo_locked(void){
- return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _rx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
float read_rssi(void){
- return _rx_subdev[SUBDEV_PROP_RSSI].as<float>();
+ return _rx_subdev()[SUBDEV_PROP_RSSI].as<float>();
}
/*******************************************************************
* TX methods
******************************************************************/
+ void set_tx_subdev_spec(const subdev_spec_t &spec){
+ _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec;
+ std::cout << "TX " << _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl;
+ }
+
+ subdev_spec_t get_tx_subdev_spec(void){
+ return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
void set_tx_rate(double rate){
- _tx_dsp[DSP_PROP_HOST_RATE] = rate;
+ _tx_dsp()[DSP_PROP_HOST_RATE] = rate;
}
double get_tx_rate(void){
- return _tx_dsp[DSP_PROP_HOST_RATE].as<double>();
+ return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();
}
tune_result_t set_tx_freq(double target_freq){
- return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq);
+ return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq);
}
tune_result_t set_tx_freq(double target_freq, double lo_off){
- return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq, lo_off);
+ return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq, lo_off);
+ }
+
+ double get_tx_freq(void){
+ return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp());
}
freq_range_t get_tx_freq_range(void){
- return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ return add_dsp_shift(_tx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());
}
void set_tx_gain(float gain){
- _tx_subdev[SUBDEV_PROP_GAIN] = gain;
+ return _tx_gain_group()->set_value(gain);
}
float get_tx_gain(void){
- return _tx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ return _tx_gain_group()->get_value();
}
gain_range_t get_tx_gain_range(void){
- return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _tx_gain_group()->get_range();
}
void set_tx_antenna(const std::string &ant){
- _tx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ _tx_subdev()[SUBDEV_PROP_ANTENNA] = ant;
}
std::string get_tx_antenna(void){
- return _tx_subdev[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _tx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();
}
std::vector<std::string> get_tx_antennas(void){
- return _tx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _tx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
}
bool get_tx_lo_locked(void){
- return _tx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _tx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
private:
device::sptr _dev;
- wax::obj _mboard;
- wax::obj _rx_dsp;
- wax::obj _tx_dsp;
- wax::obj _rx_dboard;
- wax::obj _tx_dboard;
- wax::obj _rx_subdev;
- wax::obj _tx_subdev;
+ wax::obj _mboard(void){
+ return (*_dev)[DEVICE_PROP_MBOARD];
+ }
+ wax::obj _rx_dsp(void){
+ return _mboard()[MBOARD_PROP_RX_DSP];
+ }
+ wax::obj _tx_dsp(void){
+ return _mboard()[MBOARD_PROP_TX_DSP];
+ }
+ wax::obj _rx_dboard(void){
+ std::string db_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
+ return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)];
+ }
+ wax::obj _tx_dboard(void){
+ std::string db_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
+ return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)];
+ }
+ wax::obj _rx_subdev(void){
+ std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _rx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ wax::obj _tx_subdev(void){
+ std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ gain_group::sptr _rx_gain_group(void){
+ std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
+ gain_group::sptr _tx_gain_group(void){
+ std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
+ return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
};
/***********************************************************************
diff --git a/host/lib/usrp/subdev_spec.cpp b/host/lib/usrp/subdev_spec.cpp
new file mode 100644
index 000000000..0f00e2f74
--- /dev/null
+++ b/host/lib/usrp/subdev_spec.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/usrp/subdev_spec.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <stdexcept>
+#include <sstream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+subdev_spec_pair_t::subdev_spec_pair_t(
+ const std::string &db_name, const std::string &sd_name
+):
+ db_name(db_name),
+ sd_name(sd_name)
+{
+ /* NOP */
+}
+
+subdev_spec_t::subdev_spec_t(const std::string &markup){
+ std::vector<std::string> pairs;
+ boost::split(pairs, markup, boost::is_any_of("\t "));
+ BOOST_FOREACH(const std::string &pair, pairs){
+ if (pair == "") continue;
+ std::vector<std::string> db_sd;
+ boost::split(db_sd, pair, boost::is_any_of(":"));
+ switch(db_sd.size()){
+ case 1: this->push_back(subdev_spec_pair_t("", db_sd.front())); break;
+ case 2: this->push_back(subdev_spec_pair_t(db_sd.front(), db_sd.back())); break;
+ default: throw std::runtime_error("invalid subdev-spec markup string: "+markup);
+ }
+ }
+}
+
+std::string subdev_spec_t::to_pp_string(void) const{
+ if (this->size() == 0) return "Empty Subdevice Specification";
+
+ std::stringstream ss;
+ size_t count = 0;
+ ss << "Subdevice Specification:" << std::endl;
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, *this){
+ std::string db_name = pair.db_name;
+ if (db_name == "") db_name = "0";
+ std::string sd_name = pair.sd_name;
+ if (sd_name == "") sd_name = "0";
+ ss << boost::format(
+ " Channel %d: Daughterboard %s, Subdevice %s"
+ ) % (count++) % db_name % sd_name << std::endl;
+ }
+ return ss.str();
+}
+
+std::string subdev_spec_t::to_string(void) const{
+ std::string markup;
+ size_t count = 0;
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, *this){
+ markup += ((count++)? " " : "") + pair.db_name + ":" + pair.sd_name;
+ }
+ return markup;
+}
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
index 082c39f6d..e516477d3 100644
--- a/host/lib/usrp/tune_helper.cpp
+++ b/host/lib/usrp/tune_helper.cpp
@@ -16,25 +16,24 @@
//
#include <uhd/usrp/tune_helper.hpp>
-#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dsp_props.hpp>
+#include <uhd/usrp/dboard_iface.hpp> //unit_t
+#include <boost/math/special_functions/sign.hpp>
#include <cmath>
using namespace uhd;
using namespace uhd::usrp;
/***********************************************************************
- * Tune Helper Function
+ * Tune Helper Functions
**********************************************************************/
static tune_result_t tune_xx_subdev_and_dxc(
- bool is_tx,
+ dboard_iface::unit_t unit,
wax::obj subdev, wax::obj dxc,
double target_freq, double lo_offset
){
wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
- bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as<bool>();
- bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>();
wax::obj dxc_freq_proxy = dxc[DSP_PROP_FREQ_SHIFT];
double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>();
@@ -43,55 +42,52 @@ static tune_result_t tune_xx_subdev_and_dxc(
subdev_freq_proxy = target_inter_freq;
double actual_inter_freq = subdev_freq_proxy.as<double>();
- // Calculate the DDC setting that will downconvert the baseband from the
- // daughterboard to our target frequency.
- double delta_freq = target_freq - actual_inter_freq;
- int delta_sign = std::signum(delta_freq);
- delta_freq *= delta_sign;
- delta_freq = std::fmod(delta_freq, dxc_sample_rate);
- bool inverted = delta_freq > dxc_sample_rate/2.0;
- double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq);
- target_dxc_freq *= delta_sign;
-
- // If the spectrum is inverted, and the daughterboard doesn't do
- // quadrature downconversion, we can fix the inversion by flipping the
- // sign of the dxc_freq... (This only happens using the basic_rx board)
- if (subdev_spectrum_inverted){
- inverted = not inverted;
- }
- if (inverted and not subdev_quadrature){
- target_dxc_freq *= -1.0;
- inverted = not inverted;
- }
- // down conversion versus up conversion, fight!
- // your mother is ugly and your going down...
- target_dxc_freq *= (is_tx)? -1.0 : +1.0;
+ //perform the correction correction for dxc rates outside of nyquist
+ double delta_freq = std::fmod(target_freq - actual_inter_freq, dxc_sample_rate);
+ bool outside_of_nyquist = std::abs(delta_freq) > dxc_sample_rate/2.0;
+ double target_dxc_freq = (outside_of_nyquist)?
+ boost::math::sign(delta_freq)*dxc_sample_rate - delta_freq : -delta_freq;
+
+ //invert the sign on the dxc freq given the following conditions
+ if (unit == dboard_iface::UNIT_TX) target_dxc_freq *= -1.0;
dxc_freq_proxy = target_dxc_freq;
double actual_dxc_freq = dxc_freq_proxy.as<double>();
- //return some kind of tune result tuple/struct
+ //load and return the tune result
tune_result_t tune_result;
tune_result.target_inter_freq = target_inter_freq;
tune_result.actual_inter_freq = actual_inter_freq;
tune_result.target_dsp_freq = target_dxc_freq;
tune_result.actual_dsp_freq = actual_dxc_freq;
- tune_result.spectrum_inverted = inverted;
return tune_result;
}
+static double derive_freq_from_xx_subdev_and_dxc(
+ dboard_iface::unit_t unit,
+ wax::obj subdev, wax::obj dxc
+){
+ //extract actual dsp and IF frequencies
+ double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>();
+ double actual_dxc_freq = dxc[DSP_PROP_FREQ_SHIFT].as<double>();
+
+ //invert the sign on the dxc freq given the following conditions
+ if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0;
+
+ return actual_inter_freq - actual_dxc_freq;
+}
+
/***********************************************************************
* RX Tune
**********************************************************************/
-tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(
+tune_result_t usrp::tune_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc,
double target_freq, double lo_offset
){
- bool is_tx = false;
- return tune_xx_subdev_and_dxc(is_tx, subdev, ddc, target_freq, lo_offset);
+ return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, target_freq, lo_offset);
}
-tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(
+tune_result_t usrp::tune_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc,
double target_freq
){
@@ -100,21 +96,24 @@ tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(
if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>();
}
- return tune_rx_subdev_and_ddc(subdev, ddc, target_freq, lo_offset);
+ return tune_rx_subdev_and_dsp(subdev, ddc, target_freq, lo_offset);
+}
+
+double usrp::derive_freq_from_rx_subdev_and_dsp(wax::obj subdev, wax::obj ddc){
+ return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc);
}
/***********************************************************************
* TX Tune
**********************************************************************/
-tune_result_t uhd::usrp::tune_tx_subdev_and_duc(
+tune_result_t usrp::tune_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc,
double target_freq, double lo_offset
){
- bool is_tx = true;
- return tune_xx_subdev_and_dxc(is_tx, subdev, duc, target_freq, lo_offset);
+ return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, target_freq, lo_offset);
}
-tune_result_t uhd::usrp::tune_tx_subdev_and_duc(
+tune_result_t usrp::tune_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc,
double target_freq
){
@@ -123,5 +122,9 @@ tune_result_t uhd::usrp::tune_tx_subdev_and_duc(
if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>();
}
- return tune_tx_subdev_and_duc(subdev, duc, target_freq, lo_offset);
+ return tune_tx_subdev_and_dsp(subdev, duc, target_freq, lo_offset);
+}
+
+double usrp::derive_freq_from_tx_subdev_and_dsp(wax::obj subdev, wax::obj duc){
+ return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc);
}
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index 99d0b8bdd..796126d07 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index b9be037c0..02227afad 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -86,7 +86,7 @@ public:
void set_rate_rx_dboard_clock(double rate){
assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate");
- size_t divider = size_t(rate/get_master_clock_rate());
+ size_t divider = size_t(get_master_clock_rate()/rate);
//bypass when the divider ratio is one
_ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0;
//calculate the low and high dividers
@@ -118,7 +118,7 @@ public:
void set_rate_tx_dboard_clock(double rate){
assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate");
- size_t divider = size_t(rate/get_master_clock_rate());
+ size_t divider = size_t(get_master_clock_rate()/rate);
//bypass when the divider ratio is one
_ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
//calculate the low and high dividers
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
new file mode 100644
index 000000000..b9d51abf5
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_impl.cpp
@@ -0,0 +1,96 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_impl.hpp"
+#include <uhd/usrp/codec_props.hpp>
+#include <boost/bind.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void usrp2_mboard_impl::codec_init(void){
+ //make proxies
+ _rx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2)
+ );
+ _tx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * RX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 adc");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ val = prop_names_t(); //no gain elements to be controlled
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::rx_codec_set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
+
+/***********************************************************************
+ * TX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 dac - ad9777");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ val = prop_names_t(); //no gain elements to be controlled
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 6f2fb9396..1b9a4bb97 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -37,6 +37,8 @@ public:
usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);
~usrp2_dboard_iface(void);
+ std::string get_mboard_name(void){return "usrp2";}
+
void write_aux_dac(unit_t, aux_dac_t, float);
float read_aux_adc(unit_t, aux_adc_t);
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index fa8d1a674..075f22388 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -15,10 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
#include "../dsp_utils.hpp"
+#include "../misc_utils.hpp"
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dboard_props.hpp>
#include <uhd/utils/assert.hpp>
@@ -35,8 +35,8 @@ using namespace uhd::usrp;
**********************************************************************/
void usrp2_mboard_impl::dboard_init(void){
//read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
- _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
//create a new dboard interface and manager
_dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
@@ -53,10 +53,6 @@ void usrp2_mboard_impl::dboard_init(void){
boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2),
boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2)
);
-
- //init the subdevs in use (use the first subdevice)
- rx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0)));
- tx_dboard_set(DBOARD_PROP_USED_SUBDEVS, prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0)));
}
/***********************************************************************
@@ -80,10 +76,6 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_rx_subdev_names();
return;
- case DBOARD_PROP_USED_SUBDEVS:
- val = _rx_subdevs_in_use;
- return;
-
case DBOARD_PROP_DBOARD_ID:
val = _rx_db_eeprom.id;
return;
@@ -92,27 +84,26 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _rx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_USED_SUBDEVS:{
- _rx_subdevs_in_use = val.as<prop_names_t>();
- UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1);
- wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0));
- std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word(
- rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>(),
- rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()
- ));
- }
- return;
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -140,10 +131,6 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_manager->get_tx_subdev_names();
return;
- case DBOARD_PROP_USED_SUBDEVS:
- val = _tx_subdevs_in_use;
- return;
-
case DBOARD_PROP_DBOARD_ID:
val = _tx_db_eeprom.id;
return;
@@ -152,26 +139,26 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _tx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_USED_SUBDEVS:{
- _tx_subdevs_in_use = val.as<prop_names_t>();
- UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1);
- wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0));
- std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
- tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()
- ));
- }
- return;
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index fd728e393..a781c1a21 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -32,9 +32,9 @@ extern "C" {
#define __stdint(type) type
#endif
-//defines the protocol version in this shared header
-//increment this value when the protocol is changed
-#define USRP2_PROTO_VERSION 5
+//fpga and firmware compatibility numbers
+#define USRP2_FPGA_COMPAT_NUM 1
+#define USRP2_FW_COMPAT_NUM 5
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -44,6 +44,22 @@ extern "C" {
#define USRP2_UDP_CTRL_PORT 49152
#define USRP2_UDP_DATA_PORT 49153
+////////////////////////////////////////////////////////////////////////
+// I2C addresses
+////////////////////////////////////////////////////////////////////////
+#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
+#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0)
+#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4)
+#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5)
+
+////////////////////////////////////////////////////////////////////////
+// EEPROM Layout
+////////////////////////////////////////////////////////////////////////
+#define USRP2_EE_MBOARD_REV_LSB 0x00 //1 byte
+#define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte
+#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes
+#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
+
typedef enum{
USRP2_CTRL_ID_HUH_WHAT = ' ',
//USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 430f28390..9e29edd82 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -32,6 +32,8 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
+
/***********************************************************************
* io impl details (internal to this file)
* - pirate crew
@@ -44,7 +46,8 @@ struct usrp2_impl::io_impl{
io_impl(size_t num_frames, size_t width):
packet_handler_recv_state(width),
- recv_pirate_booty(alignment_buffer_type::make(num_frames, width))
+ recv_pirate_booty(alignment_buffer_type::make(num_frames, width)),
+ async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/))
{
/* NOP */
}
@@ -55,9 +58,9 @@ struct usrp2_impl::io_impl{
recv_pirate_crew.join_all();
}
- bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, size_t timeout_ms){
boost::this_thread::disable_interruption di; //disable because the wait can throw
- return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100));
+ return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(timeout_ms));
}
//state management for the vrt packet handler code
@@ -69,6 +72,7 @@ struct usrp2_impl::io_impl{
boost::thread_group recv_pirate_crew;
bool recv_pirate_crew_raiding;
alignment_buffer_type::sptr recv_pirate_booty;
+ bounded_buffer<async_metadata_t>::sptr async_msg_fifo;
};
/***********************************************************************
@@ -93,12 +97,31 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//extract the vrt header packet info
vrt::if_packet_info_t if_packet_info;
if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t);
- vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info);
+ const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
+ vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
+
+ //handle a tx async report message
+ if (if_packet_info.sid == 1 and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+
+ //fill in the async metadata
+ async_metadata_t metadata;
+ metadata.channel = index;
+ metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t(
+ time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq()
+ );
+ metadata.event_code = vrt_packet_handler::get_context_code<async_metadata_t::event_code_t>(vrt_hdr, if_packet_info);
+
+ //print the famous U, and push the metadata into the message queue
+ if (metadata.event_code & underflow_flags) std::cerr << "U";
+ async_msg_fifo->push_with_pop_on_full(metadata);
+ continue;
+ }
//handle the packet count / sequence number
if (if_packet_info.packet_count != next_packet_seq){
//std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16;
- std::cerr << "O"; //report overrun (drops in the kernel)
+ std::cerr << "O"; //report overflow (drops in the kernel)
}
next_packet_seq = (if_packet_info.packet_count+1)%16;
@@ -121,11 +144,13 @@ void usrp2_impl::io_impl::recv_pirate_loop(
**********************************************************************/
void usrp2_impl::io_init(void){
//send a small data packet so the usrp2 knows the udp source port
- for(size_t i = 0; i < _data_transports.size(); i++){
- managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff();
- boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
- memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ BOOST_FOREACH(zero_copy_if::sptr data_transport, _data_transports){
+ managed_send_buffer::sptr send_buff = data_transport->get_send_buff();
+ static const boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
+ std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
send_buff->commit(sizeof(data));
+ //drain the recv buffers (may have junk)
+ while (data_transport->get_recv_buff().get());
}
//the number of recv frames is the number for the first transport
@@ -150,6 +175,18 @@ void usrp2_impl::io_init(void){
}
/***********************************************************************
+ * Async Data
+ **********************************************************************/
+bool usrp2_impl::recv_async_msg(
+ async_metadata_t &async_metadata, size_t timeout_ms
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo->pop_with_timed_wait(
+ async_metadata, boost::posix_time::milliseconds(timeout_ms)
+ );
+}
+
+/***********************************************************************
* Send Data
**********************************************************************/
bool get_send_buffs(
@@ -164,10 +201,8 @@ bool get_send_buffs(
}
size_t usrp2_impl::send(
- const std::vector<const void *> &buffs,
- size_t num_samps,
- const tx_metadata_t &metadata,
- const io_type_t &io_type,
+ const std::vector<const void *> &buffs, size_t num_samps,
+ const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode
){
return vrt_packet_handler::send(
@@ -186,11 +221,9 @@ size_t usrp2_impl::send(
* Receive Data
**********************************************************************/
size_t usrp2_impl::recv(
- const std::vector<void *> &buffs,
- size_t num_samps,
- rx_metadata_t &metadata,
- const io_type_t &io_type,
- recv_mode_t recv_mode
+ const std::vector<void *> &buffs, size_t num_samps,
+ rx_metadata_t &metadata, const io_type_t &io_type,
+ recv_mode_t recv_mode, size_t timeout_ms
){
return vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
@@ -199,6 +232,6 @@ size_t usrp2_impl::recv(
io_type, _io_helper.get_rx_otw_type(), //input and output types to convert
_mboards.front()->get_master_clock_freq(), //master clock tick rate
uhd::transport::vrt::if_hdr_unpack_be,
- boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1)
+ boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout_ms)
);
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 7518d3114..610aade14 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -45,8 +45,8 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface = usrp2_iface::make(ctrl_transport);
//extract the mboard rev numbers
- _rev_lo = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_LSB, 1).at(0);
- _rev_hi = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_MSB, 1).at(0);
+ _rev_lo = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, 1).at(0);
+ _rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0);
//contruct the interfaces to mboard perifs
_clock_ctrl = usrp2_clock_ctrl::make(_iface);
@@ -67,7 +67,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_allowed_decim_and_interp_rates.push_back(i);
}
- //setup the vrt rx registers
+ //init the rx control registers
_iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet());
_iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);
_iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset
@@ -81,6 +81,12 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0);
_iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
+ //init the tx control registers
+ _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
+ _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1); //sid 1 (different from rx)
+ _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
+
//init the ddc
init_ddc_config();
@@ -90,8 +96,20 @@ usrp2_mboard_impl::usrp2_mboard_impl(
//initialize the clock configuration
init_clock_config();
+ //init the codec before the dboard
+ codec_init();
+
//init the tx and rx dboards (do last)
dboard_init();
+
+ //set default subdev specs
+ (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t();
+ (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t();
+
+ //Issue a stop streaming command (in case it was left running).
+ //Since this command is issued before the networking is setup,
+ //most if not all junk packets will never make it to the socket.
+ this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
}
usrp2_mboard_impl::~usrp2_mboard_impl(void){
@@ -174,14 +192,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
//handle the other props
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
- byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6);
+ byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6);
val = mac_addr_t::from_bytes(bytes).to_string();
return;
}
if (key.as<std::string>() == "ip-addr"){
boost::asio::ip::address_v4::bytes_type bytes;
- std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes);
+ std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes);
val = boost::asio::ip::address_v4(bytes).to_string();
return;
}
@@ -252,6 +270,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
}
return;
+ case MBOARD_PROP_RX_SUBDEV_SPEC:
+ val = _rx_subdev_spec;
+ return;
+
+ case MBOARD_PROP_TX_SUBDEV_SPEC:
+ val = _tx_subdev_spec;
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -264,14 +290,14 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes();
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes);
return;
}
if (key.as<std::string>() == "ip-addr"){
byte_vector_t bytes(4);
std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes);
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes);
return;
}
}
@@ -296,6 +322,38 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
issue_ddc_stream_cmd(val.as<stream_cmd_t>());
return;
+ case MBOARD_PROP_RX_SUBDEV_SPEC:
+ _rx_subdev_spec = val.as<subdev_spec_t>();
+ //handle automatic
+ if (_rx_subdev_spec.empty()) _rx_subdev_spec.push_back(
+ subdev_spec_pair_t("", _dboard_manager->get_rx_subdev_names().front())
+ );
+ //sanity check
+ UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
+ uhd::assert_has((*this)[MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>(), _rx_subdev_spec.front().db_name, "rx dboard names");
+ uhd::assert_has(_dboard_manager->get_rx_subdev_names(), _rx_subdev_spec.front().sd_name, "rx subdev names");
+ //set the mux
+ _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word(
+ _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ ));
+ return;
+
+ case MBOARD_PROP_TX_SUBDEV_SPEC:
+ _tx_subdev_spec = val.as<subdev_spec_t>();
+ //handle automatic
+ if (_tx_subdev_spec.empty()) _tx_subdev_spec.push_back(
+ subdev_spec_pair_t("", _dboard_manager->get_tx_subdev_names().front())
+ );
+ //sanity check
+ UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1);
+ uhd::assert_has((*this)[MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>(), _tx_subdev_spec.front().db_name, "tx dboard names");
+ uhd::assert_has(_dboard_manager->get_tx_subdev_names(), _tx_subdev_spec.front().sd_name, "tx subdev names");
+ //set the mux
+ _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
+ _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ ));
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index eaaa722ac..4124221ef 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "usrp2_regs.hpp"
#include "usrp2_iface.hpp"
#include <uhd/utils/assert.hpp>
#include <uhd/types/dict.hpp>
@@ -22,12 +23,25 @@
#include <boost/foreach.hpp>
#include <boost/asio.hpp> //used for htonl and ntohl
#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
#include <stdexcept>
#include <algorithm>
using namespace uhd;
using namespace uhd::transport;
+/*!
+ * FIXME: large timeout, ethernet pause frames...
+ *
+ * Use a large timeout to work-around the fact that
+ * flow-control may throttle outgoing control packets
+ * due to its use of ethernet pause frames.
+ *
+ * This will be fixed when host-based flow control is implemented,
+ * along with larger incoming send buffers using the on-board SRAM.
+ */
+static const size_t CONTROL_TIMEOUT_MS = 3000; //3 seconds
+
class usrp2_iface_impl : public usrp2_iface{
public:
/***********************************************************************
@@ -35,6 +49,15 @@ public:
**********************************************************************/
usrp2_iface_impl(udp_simple::sptr ctrl_transport){
_ctrl_transport = ctrl_transport;
+
+ //check the fpga compatibility number
+ const boost::uint32_t fpga_compat_num = this->peek32(U2_REG_COMPAT_NUM_RB);
+ if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){
+ throw std::runtime_error(str(boost::format(
+ "Expected fpga compatibility number %d, but got %d:\n"
+ "The fpga build is not compatible with the host code build."
+ ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_compat_num));
+ }
}
~usrp2_iface_impl(void){
@@ -156,7 +179,7 @@ public:
//fill in the seq number and send
usrp2_ctrl_data_t out_copy = out_data;
- out_copy.proto_ver = htonl(USRP2_PROTO_VERSION);
+ out_copy.proto_ver = htonl(USRP2_FW_COMPAT_NUM);
out_copy.seq = htonl(++_ctrl_seq_num);
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
@@ -164,13 +187,12 @@ public:
boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
- size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem));
- if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_PROTO_VERSION){
- throw std::runtime_error(str(
- boost::format("Expected protocol version %d, but got %d\n"
- "The firmware build does not match the host code build."
- ) % int(USRP2_PROTO_VERSION) % ntohl(ctrl_data_in->proto_ver)
- ));
+ size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem), CONTROL_TIMEOUT_MS);
+ if(len >= sizeof(boost::uint32_t) and ntohl(ctrl_data_in->proto_ver) != USRP2_FW_COMPAT_NUM){
+ throw std::runtime_error(str(boost::format(
+ "Expected protocol compatibility number %d, but got %d:\n"
+ "The firmware build is not compatible with the host code build."
+ ) % int(USRP2_FW_COMPAT_NUM) % ntohl(ctrl_data_in->proto_ver)));
}
if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(ctrl_data_in->seq) == _ctrl_seq_num){
return *ctrl_data_in;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 9cc32104e..12fd4730a 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -26,22 +26,6 @@
#include <utility>
#include "fw_common.h"
-////////////////////////////////////////////////////////////////////////
-// I2C addresses
-////////////////////////////////////////////////////////////////////////
-#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
-#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0)
-#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4)
-#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5)
-
-////////////////////////////////////////////////////////////////////////
-// EEPROM Layout
-////////////////////////////////////////////////////////////////////////
-#define EE_MBOARD_REV_LSB 0x00 //1 byte
-#define EE_MBOARD_REV_MSB 0x01 //1 byte
-#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes
-#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
-
/*!
* The usrp2 interface class:
* Provides a set of functions to implementation layer.
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 02f53bc69..21f411afe 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -35,6 +35,9 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
+//! wait this long for a control response when discovering devices
+static const size_t DISCOVERY_TIMEOUT_MS = 100;
+
/***********************************************************************
* Helper Functions
**********************************************************************/
@@ -94,7 +97,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
- ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);
+ ctrl_data_out.proto_ver = htonl(USRP2_FW_COMPAT_NUM);
ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
@@ -102,7 +105,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){
boost::uint8_t usrp2_ctrl_data_in_mem[udp_simple::mtu]; //allocate max bytes for recv
const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<const usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
- size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));
+ size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem), DISCOVERY_TIMEOUT_MS);
//std::cout << len << "\n";
if (len > offsetof(usrp2_ctrl_data_t, data)){
//handle the received data
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index ab23830c0..157d17057 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -35,6 +35,7 @@
#include <uhd/transport/udp_simple.hpp> //mtu
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
/*!
* Make a usrp2 dboard interface.
@@ -143,6 +144,7 @@ private:
//properties for this mboard
void get(const wax::obj &, wax::obj &);
void set(const wax::obj &, const wax::obj &);
+ uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
//interfaces
usrp2_iface::sptr _iface;
@@ -161,18 +163,25 @@ private:
void update_clock_config(void);
void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
+ //properties interface for the codec
+ void codec_init(void);
+ void rx_codec_get(const wax::obj &, wax::obj &);
+ void rx_codec_set(const wax::obj &, const wax::obj &);
+ void tx_codec_get(const wax::obj &, wax::obj &);
+ void tx_codec_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_codec_proxy;
+ wax_obj_proxy::sptr _tx_codec_proxy;
+
//properties interface for rx dboard
void rx_dboard_get(const wax::obj &, wax::obj &);
void rx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _rx_dboard_proxy;
- uhd::prop_names_t _rx_subdevs_in_use;
uhd::usrp::dboard_eeprom_t _rx_db_eeprom;
//properties interface for tx dboard
void tx_dboard_get(const wax::obj &, wax::obj &);
void tx_dboard_set(const wax::obj &, const wax::obj &);
wax_obj_proxy::sptr _tx_dboard_proxy;
- uhd::prop_names_t _tx_subdevs_in_use;
uhd::usrp::dboard_eeprom_t _tx_db_eeprom;
//methods and shadows for the ddc dsp
@@ -224,8 +233,7 @@ public:
}
size_t send(
const std::vector<const void *> &, size_t,
- const uhd::tx_metadata_t &,
- const uhd::io_type_t &,
+ const uhd::tx_metadata_t &, const uhd::io_type_t &,
uhd::device::send_mode_t
);
size_t get_max_recv_samps_per_packet(void) const{
@@ -233,10 +241,10 @@ public:
}
size_t recv(
const std::vector<void *> &, size_t,
- uhd::rx_metadata_t &,
- const uhd::io_type_t &,
- uhd::device::recv_mode_t
+ uhd::rx_metadata_t &, const uhd::io_type_t &,
+ uhd::device::recv_mode_t, size_t
);
+ bool recv_async_msg(uhd::async_metadata_t &, size_t);
private:
//device properties interface
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 1a5864c85..9d306090b 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -107,6 +107,7 @@
#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10)
#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11)
+#define U2_REG_COMPAT_NUM_RB (0xCC00 + 4*12)
//pps flags (see above)
#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
@@ -226,7 +227,7 @@
#define U2_REG_ATR_FULL_RXSIDE U2_REG_ATR_BASE + 14
///////////////////////////////////////////////////
-// VITA RX CTRL regs
+// RX CTRL regs
///////////////////////////////////////////////////
// The following 3 are logically a single command register.
// They are clocked into the underlying fifo when time_ticks is written.
@@ -241,4 +242,16 @@
#define U2_REG_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
#define U2_REG_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+///////////////////////////////////////////////////
+// TX CTRL regs
+///////////////////////////////////////////////////
+#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
+#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
+#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
+#define U2_REG_TX_CTRL_POLICY _SR_ADDR(SR_TX_CTRL + 3)
+
+#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
+#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)
+#define U2_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2)
+
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/lib/usrp/usrp_e/CMakeLists.txt b/host/lib/usrp/usrp_e/CMakeLists.txt
index db6d162d4..1d64d29d2 100644
--- a/host/lib/usrp/usrp_e/CMakeLists.txt
+++ b/host/lib/usrp/usrp_e/CMakeLists.txt
@@ -18,27 +18,14 @@
#This file will be included by cmake, use absolute paths!
########################################################################
-# Helpful macro to check for required headers
-########################################################################
-INCLUDE(CheckIncludeFileCXX)
-SET(HAVE_USRP_E_REQUIRED_HEADERS TRUE)
-MACRO(USRP_E_REQUIRE_HEADER header variable)
- CHECK_INCLUDE_FILE_CXX(${header} ${variable})
- IF(NOT ${variable})
- SET(HAVE_USRP_E_REQUIRED_HEADERS FALSE)
- ENDIF(NOT ${variable})
-ENDMACRO(USRP_E_REQUIRE_HEADER)
-
-########################################################################
# Conditionally configure the USRP-E support
########################################################################
MESSAGE(STATUS "Configuring usrp-e support...")
-USRP_E_REQUIRE_HEADER(linux/ioctl.h HAVE_LINUX_IOCTL_H)
-USRP_E_REQUIRE_HEADER(linux/spi/spidev.h HAVE_LINUX_SPI_SPIDEV_H)
-USRP_E_REQUIRE_HEADER(linux/usrp_e.h HAVE_LINUX_USRP_E_H)
+INCLUDE(CheckIncludeFileCXX)
+CHECK_INCLUDE_FILE_CXX(linux/usrp_e.h HAVE_LINUX_USRP_E_H)
-IF(HAVE_USRP_E_REQUIRED_HEADERS)
+IF(HAVE_LINUX_USRP_E_H)
MESSAGE(STATUS " Building usrp-e support.")
LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/clock_ctrl.cpp
@@ -57,6 +44,6 @@ IF(HAVE_USRP_E_REQUIRED_HEADERS)
${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_iface.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_regs.hpp
)
-ELSE(HAVE_USRP_E_REQUIRED_HEADERS)
+ELSE(HAVE_LINUX_USRP_E_H)
MESSAGE(STATUS " Skipping usrp-e support.")
-ENDIF(HAVE_USRP_E_REQUIRED_HEADERS)
+ENDIF(HAVE_LINUX_USRP_E_H)
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt
new file mode 100644
index 000000000..68945545a
--- /dev/null
+++ b/host/lib/utils/CMakeLists.txt
@@ -0,0 +1,87 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#This file will be included by cmake, use absolute paths!
+
+########################################################################
+# Setup defines for process scheduling
+########################################################################
+MESSAGE(STATUS "Configuring priority scheduling...")
+
+INCLUDE(CheckCXXSourceCompiles)
+CHECK_CXX_SOURCE_COMPILES("
+ #include <pthread.h>
+ int main(){
+ struct sched_param sp;
+ pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
+ return 0;
+ }
+ " HAVE_PTHREAD_SETSCHEDPARAM
+)
+
+CHECK_CXX_SOURCE_COMPILES("
+ #include <windows.h>
+ int main(){
+ SetThreadPriority(GetCurrentThread(), 0);
+ SetPriorityClass(GetCurrentProcess(), 0);
+ return 0;
+ }
+ " HAVE_WIN_SETTHREADPRIORITY
+)
+
+IF(HAVE_PTHREAD_SETSCHEDPARAM)
+ MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.")
+ ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM)
+ELSEIF(HAVE_WIN_SETTHREADPRIORITY)
+ MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.")
+ ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY)
+ELSE(HAVE_PTHREAD_SETSCHEDPARAM)
+ MESSAGE(STATUS " Priority scheduling not supported.")
+ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)
+
+########################################################################
+# Setup defines for module loading
+########################################################################
+MESSAGE(STATUS "Configuring module loading...")
+
+INCLUDE(CheckIncludeFileCXX)
+CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H)
+CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H)
+
+IF(HAVE_DLFCN_H)
+ MESSAGE(STATUS " Module loading supported through dlopen.")
+ ADD_DEFINITIONS(-DHAVE_DLFCN_H)
+ LIBUHD_APPEND_LIBS(${CMAKE_DL_LIBS})
+ELSEIF(HAVE_WINDOWS_H)
+ MESSAGE(STATUS " Module loading supported through LoadLibrary.")
+ ADD_DEFINITIONS(-DHAVE_WINDOWS_H)
+ELSE(HAVE_DLFCN_H)
+ MESSAGE(STATUS " Module loading not supported.")
+ENDIF(HAVE_DLFCN_H)
+
+########################################################################
+# Append sources
+########################################################################
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/utils/assert.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/gain_group.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/load_modules.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/paths.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/props.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/thread_priority.cpp
+ ${CMAKE_SOURCE_DIR}/lib/utils/warning.cpp
+)
diff --git a/host/lib/utils/assert.cpp b/host/lib/utils/assert.cpp
new file mode 100644
index 000000000..7ace9024c
--- /dev/null
+++ b/host/lib/utils/assert.cpp
@@ -0,0 +1,24 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/assert.hpp>
+
+using namespace uhd;
+
+assert_error::assert_error(const std::string &what) : std::runtime_error(what){
+ /* NOP */
+}
diff --git a/host/lib/utils/gain_group.cpp b/host/lib/utils/gain_group.cpp
new file mode 100644
index 000000000..c113719c8
--- /dev/null
+++ b/host/lib/utils/gain_group.cpp
@@ -0,0 +1,149 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/gain_group.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+using namespace uhd;
+
+static const bool verbose = false;
+
+static bool compare_by_step_size(
+ const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns
+){
+ return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step;
+}
+
+/***********************************************************************
+ * gain group implementation
+ **********************************************************************/
+class gain_group_impl : public gain_group{
+public:
+ gain_group_impl(void){
+ /*NOP*/
+ }
+
+ gain_range_t get_range(void){
+ float overall_min = 0, overall_max = 0, overall_step = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){
+ const gain_range_t range = fcns.get_range();
+ overall_min += range.min;
+ overall_max += range.max;
+ //the overall step is the min (zero is invalid, first run)
+ if (overall_step == 0) overall_step = range.step;
+ overall_step = std::min(overall_step, range.step);
+ }
+ return gain_range_t(overall_min, overall_max, overall_step);
+ }
+
+ float get_value(void){
+ float overall_gain = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){
+ overall_gain += fcns.get_value();
+ }
+ return overall_gain;
+ }
+
+ void set_value(float gain){
+ std::vector<gain_fcns_t> all_fcns = get_all_fcns();
+ if (all_fcns.size() == 0) return; //nothing to set!
+
+ //get the max step size among the gains
+ float max_step = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){
+ max_step = std::max(max_step, fcns.get_range().step);
+ }
+
+ //create gain bucket to distribute power
+ std::vector<float> gain_bucket;
+
+ //distribute power according to priority (round to max step)
+ float gain_left_to_distribute = gain;
+ BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){
+ const gain_range_t range = fcns.get_range();
+ gain_bucket.push_back(
+ max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step)
+ );
+ gain_left_to_distribute -= gain_bucket.back();
+ }
+
+ //get a list of indexes sorted by step size large to small
+ std::vector<size_t> indexes_step_size_dec;
+ for (size_t i = 0; i < all_fcns.size(); i++){
+ indexes_step_size_dec.push_back(i);
+ }
+ std::sort(
+ indexes_step_size_dec.begin(), indexes_step_size_dec.end(),
+ boost::bind(&compare_by_step_size, _1, _2, all_fcns)
+ );
+ UHD_ASSERT_THROW(
+ all_fcns.at(indexes_step_size_dec.front()).get_range().step >=
+ all_fcns.at(indexes_step_size_dec.back()).get_range().step
+ );
+
+ //distribute the remainder (less than max step)
+ //fill in the largest step sizes first that are less than the remainder
+ BOOST_FOREACH(size_t i, indexes_step_size_dec){
+ const gain_range_t range = all_fcns.at(i).get_range();
+ float additional_gain = range.step*int(
+ std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max
+ )/range.step) - gain_bucket.at(i);
+ gain_bucket.at(i) += additional_gain;
+ gain_left_to_distribute -= additional_gain;
+ }
+ if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl;
+
+ //now write the bucket out to the individual gain values
+ for (size_t i = 0; i < gain_bucket.size(); i++){
+ if (verbose) std::cout << gain_bucket.at(i) << std::endl;
+ all_fcns.at(i).set_value(gain_bucket.at(i));
+ }
+ }
+
+ void register_fcns(
+ const gain_fcns_t &gain_fcns, size_t priority
+ ){
+ _registry[priority].push_back(gain_fcns);
+ }
+
+private:
+ //! get the gain function sets in order (highest priority first)
+ std::vector<gain_fcns_t> get_all_fcns(void){
+ std::vector<gain_fcns_t> all_fcns;
+ BOOST_FOREACH(size_t key, std::sorted(_registry.keys())){
+ const std::vector<gain_fcns_t> &fcns = _registry[key];
+ all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end());
+ }
+ return all_fcns;
+ }
+
+ uhd::dict<size_t, std::vector<gain_fcns_t> > _registry;
+};
+
+/***********************************************************************
+ * gain group factory function
+ **********************************************************************/
+gain_group::sptr gain_group::make(void){
+ return sptr(new gain_group_impl());
+}
diff --git a/host/lib/load_modules.cpp b/host/lib/utils/load_modules.cpp
index dbb8d0695..623d31eb6 100644
--- a/host/lib/load_modules.cpp
+++ b/host/lib/utils/load_modules.cpp
@@ -18,13 +18,12 @@
#include <uhd/utils/static.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
-#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
#include <iostream>
#include <stdexcept>
+#include <string>
+#include <vector>
-namespace po = boost::program_options;
namespace fs = boost::filesystem;
/***********************************************************************
@@ -32,7 +31,6 @@ namespace fs = boost::filesystem;
**********************************************************************/
#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
-static const std::string env_path_sep = ":";
static void load_module(const std::string &file_name){
if (dlopen(file_name.c_str(), RTLD_LAZY) == NULL){
@@ -44,7 +42,6 @@ static void load_module(const std::string &file_name){
#elif defined(HAVE_WINDOWS_H)
#include <windows.h>
-static const std::string env_path_sep = ";";
static void load_module(const std::string &file_name){
if (LoadLibrary(file_name.c_str()) == NULL){
@@ -55,7 +52,6 @@ static void load_module(const std::string &file_name){
}
#else
-static const std::string env_path_sep = ":";
static void load_module(const std::string &file_name){
throw std::runtime_error(str(
@@ -74,9 +70,9 @@ static void load_module(const std::string &file_name){
* Does not throw, prints to std error.
* \param path the filesystem path
*/
-static void load_path(const fs::path &path){
+static void load_module_path(const fs::path &path){
if (not fs::exists(path)){
- std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl;
+ //std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl;
return;
}
@@ -87,7 +83,7 @@ static void load_path(const fs::path &path){
dir_itr != fs::directory_iterator();
++dir_itr
){
- load_path(dir_itr->path());
+ load_module_path(dir_itr->path());
}
return;
}
@@ -101,46 +97,13 @@ static void load_path(const fs::path &path){
}
}
-//! The string constant for the module path environment variable
-static const std::string MODULE_PATH_KEY = "UHD_MODULE_PATH";
+std::vector<fs::path> get_module_paths(void); //defined in paths.cpp
/*!
- * Name mapper function for the environment variable parser.
- * Map environment variable names (that we use) to option names.
- * \param the variable name
- * \return the option name or blank string
- */
-static std::string name_mapper(const std::string &var_name){
- if (var_name == MODULE_PATH_KEY) return var_name;
- return "";
-}
-
-/*!
- * Load all the modules given by the module path enviroment variable.
- * The path variable may be several paths split by path separators.
+ * Load all the modules given in the module paths.
*/
UHD_STATIC_BLOCK(load_modules){
- //register the options
- std::string env_module_path;
- po::options_description desc("UHD Module Options");
- desc.add_options()
- (MODULE_PATH_KEY.c_str(), po::value<std::string>(&env_module_path)->default_value(""))
- ;
-
- //parse environment variables
- po::variables_map vm;
- po::store(po::parse_environment(desc, &name_mapper), vm);
- po::notify(vm);
-
- if (env_module_path == "") return;
- //std::cout << "env_module_path: " << env_module_path << std::endl;
-
- //split the path at the path separators
- std::vector<std::string> module_paths;
- boost::split(module_paths, env_module_path, boost::is_any_of(env_path_sep));
-
- //load modules in each path
- BOOST_FOREACH(const std::string &module_path, module_paths){
- load_path(fs::system_complete(fs::path(module_path)));
+ BOOST_FOREACH(const fs::path &path, get_module_paths()){
+ load_module_path(path);
}
}
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
new file mode 100644
index 000000000..0805a44fe
--- /dev/null
+++ b/host/lib/utils/paths.cpp
@@ -0,0 +1,103 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "constants.hpp"
+#include <uhd/config.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+/***********************************************************************
+ * Determine the paths separator
+ **********************************************************************/
+#ifdef UHD_PLATFORM_WIN32
+ static const std::string env_path_sep = ";";
+#else
+ static const std::string env_path_sep = ":";
+#endif /*UHD_PLATFORM_WIN32*/
+
+/***********************************************************************
+ * Get a list of paths for an environment variable
+ **********************************************************************/
+static std::string name_mapper(const std::string &key, const std::string &var_name){
+ return (var_name == key)? var_name : "";
+}
+
+static std::vector<fs::path> get_env_paths(const std::string &var_name){
+ //register the options
+ std::string var_value;
+ po::options_description desc;
+ desc.add_options()
+ (var_name.c_str(), po::value<std::string>(&var_value)->default_value(""))
+ ;
+
+ //parse environment variables
+ po::variables_map vm;
+ po::store(po::parse_environment(desc, boost::bind(&name_mapper, var_name, _1)), vm);
+ po::notify(vm);
+
+ //split the path at the path separators
+ std::vector<std::string> path_strings;
+ boost::split(path_strings, var_value, boost::is_any_of(env_path_sep));
+
+ //convert to filesystem path, filter blank paths
+ std::vector<fs::path> paths;
+ BOOST_FOREACH(std::string &path_string, path_strings){
+ if (path_string.size() == 0) continue;
+ paths.push_back(fs::system_complete(path_string));
+ }
+ return paths;
+}
+
+/***********************************************************************
+ * Get a list of special purpose paths
+ **********************************************************************/
+static const fs::path pkg_data_path = fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR;
+
+std::vector<fs::path> get_image_paths(void){
+ std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH");
+ paths.push_back(pkg_data_path / "images");
+ return paths;
+}
+
+std::vector<fs::path> get_module_paths(void){
+ std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH");
+ paths.push_back(pkg_data_path / "modules");
+ return paths;
+}
+
+/***********************************************************************
+ * Find a image in the image paths
+ **********************************************************************/
+std::string find_image_path(const std::string &image_name){
+ if (fs::exists(image_name)){
+ return fs::system_complete(image_name).file_string();
+ }
+ BOOST_FOREACH(const fs::path &path, get_image_paths()){
+ fs::path image_path = path / image_name;
+ if (fs::exists(image_path)) return image_path.file_string();
+ }
+ throw std::runtime_error("Could not find path for image: " + image_name);
+}
diff --git a/host/lib/utils.cpp b/host/lib/utils/props.cpp
index d2f4dfc6e..fac5fe24f 100644
--- a/host/lib/utils.cpp
+++ b/host/lib/utils/props.cpp
@@ -15,28 +15,18 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/utils/assert.hpp>
#include <uhd/utils/props.hpp>
-#include <stdexcept>
using namespace uhd;
-/***********************************************************************
- * Assert
- **********************************************************************/
-assert_error::assert_error(const std::string &what) : std::runtime_error(what){
- /* NOP */
-}
-
-/***********************************************************************
- * Props
- **********************************************************************/
named_prop_t::named_prop_t(
- const wax::obj &key_,
- const std::string &name_
-){
- key = key_;
- name = name_;
+ const wax::obj &key,
+ const std::string &name
+):
+ key(key),
+ name(name)
+{
+ /* NOP */
}
typedef boost::tuple<wax::obj, std::string> named_prop_tuple;
diff --git a/host/lib/thread_priority.cpp b/host/lib/utils/thread_priority.cpp
index c35e5fcb1..c35e5fcb1 100644
--- a/host/lib/thread_priority.cpp
+++ b/host/lib/utils/thread_priority.cpp
diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp
new file mode 100644
index 000000000..ae4d4c7aa
--- /dev/null
+++ b/host/lib/utils/warning.cpp
@@ -0,0 +1,36 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/warning.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+#include <vector>
+
+using namespace uhd;
+
+void uhd::print_warning(const std::string &msg){
+ //extract the message lines
+ std::vector<std::string> lines;
+ boost::split(lines, msg, boost::is_any_of("\n"));
+
+ //print the warning message
+ std::cerr << std::endl << "Warning:" << std::endl;
+ BOOST_FOREACH(const std::string &line, lines){
+ std::cerr << " " << line << std::endl;
+ }
+}
diff --git a/host/lib/version.cpp b/host/lib/version.cpp
new file mode 100644
index 000000000..5edbca09b
--- /dev/null
+++ b/host/lib/version.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "constants.hpp"
+#include <uhd/version.hpp>
+
+std::string uhd::get_version_string(void){
+ return UHD_VERSION_STRING;
+}
diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt
index 74f3376e6..c620fd641 100644
--- a/host/test/CMakeLists.txt
+++ b/host/test/CMakeLists.txt
@@ -26,8 +26,11 @@ ADD_EXECUTABLE(main_test
convert_types_test.cpp
dict_test.cpp
error_test.cpp
- gain_handler_test.cpp
+ gain_group_test.cpp
+ subdev_spec_test.cpp
+ tune_helper_test.cpp
vrt_test.cpp
+ warning_test.cpp
wax_test.cpp
)
TARGET_LINK_LIBRARIES(main_test uhd)
diff --git a/host/test/addr_test.cpp b/host/test/addr_test.cpp
index 0c50200d6..d4b45aa1a 100644
--- a/host/test/addr_test.cpp
+++ b/host/test/addr_test.cpp
@@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(test_device_addr){
uhd::device_addr_t new_dev_addr(args_str);
//they should be the same size
- BOOST_CHECK_EQUAL(dev_addr.size(), new_dev_addr.size());
+ BOOST_REQUIRE_EQUAL(dev_addr.size(), new_dev_addr.size());
//the keys should match
std::vector<std::string> old_dev_addr_keys = dev_addr.keys();
diff --git a/host/test/gain_group_test.cpp b/host/test/gain_group_test.cpp
new file mode 100644
index 000000000..6a6af8eb2
--- /dev/null
+++ b/host/test/gain_group_test.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <boost/test/unit_test.hpp>
+#include <uhd/utils/gain_group.hpp>
+#include <boost/bind.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <iostream>
+
+#define rint(x) boost::math::iround(x)
+
+using namespace uhd;
+
+/***********************************************************************
+ * Define gain element classes with needed functions
+ **********************************************************************/
+class gain_element1{
+public:
+
+ gain_range_t get_range(void){
+ return gain_range_t(0, 90, 1);
+ }
+
+ float get_value(void){
+ return _gain;
+ }
+
+ void set_value(float gain){
+ float step = get_range().step;
+ _gain = step*rint(gain/step);
+ }
+
+private:
+ float _gain;
+};
+
+class gain_element2{
+public:
+
+ gain_range_t get_range(void){
+ return gain_range_t(-20, 10, 0.1);
+ }
+
+ float get_value(void){
+ return _gain;
+ }
+
+ void set_value(float gain){
+ float step = get_range().step;
+ _gain = step*rint(gain/step);
+ }
+
+private:
+ float _gain;
+};
+
+//create static instances of gain elements to be shared by the tests
+static gain_element1 g1;
+static gain_element2 g2;
+
+static gain_group::sptr get_gain_group(size_t pri1 = 0, size_t pri2 = 0){
+ //create instance of gain group
+ gain_fcns_t gain_fcns;
+ gain_group::sptr gg(gain_group::make());
+
+ //load gain group with function sets
+ gain_fcns.get_range = boost::bind(&gain_element1::get_range, &g1);
+ gain_fcns.get_value = boost::bind(&gain_element1::get_value, &g1);
+ gain_fcns.set_value = boost::bind(&gain_element1::set_value, &g1, _1);
+ gg->register_fcns(gain_fcns, pri1);
+
+ gain_fcns.get_range = boost::bind(&gain_element2::get_range, &g2);
+ gain_fcns.get_value = boost::bind(&gain_element2::get_value, &g2);
+ gain_fcns.set_value = boost::bind(&gain_element2::set_value, &g2, _1);
+ gg->register_fcns(gain_fcns, pri2);
+
+ return gg;
+}
+
+/***********************************************************************
+ * Test cases
+ **********************************************************************/
+static const double tolerance = 0.001;
+
+BOOST_AUTO_TEST_CASE(test_gain_group_overall){
+ gain_group::sptr gg = get_gain_group();
+
+ //test the overall stuff
+ gg->set_value(80);
+ BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_gain_group_priority){
+ gain_group::sptr gg = get_gain_group(0, 1);
+
+ //test the overall stuff
+ gg->set_value(80);
+ BOOST_CHECK_CLOSE(gg->get_value(), float(80), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().min, float(-20), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().max, float(100), tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().step, float(0.1), tolerance);
+
+ //test the the higher priority gain got filled first (gain 2)
+ BOOST_CHECK_CLOSE(g2.get_value(), g2.get_range().max, tolerance);
+}
diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp
deleted file mode 100644
index 5a9f2b714..000000000
--- a/host/test/gain_handler_test.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <boost/test/unit_test.hpp>
-#include <uhd/utils/gain_handler.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/types/dict.hpp>
-#include <uhd/utils/props.hpp>
-#include <boost/bind.hpp>
-#include <iostream>
-
-using namespace uhd;
-
-enum prop_t{
- PROP_GAIN_VALUE,
- PROP_GAIN_RANGE,
- PROP_GAIN_NAMES
-};
-
-class gainful_obj : public wax::obj{
-public:
- gainful_obj(void){
- //initialize gain props struct
- gain_handler::props_t gain_props;
- gain_props.value = PROP_GAIN_VALUE;
- gain_props.range = PROP_GAIN_RANGE;
- gain_props.names = PROP_GAIN_NAMES;
- //make a new gain handler
- _gain_handler = gain_handler::make(
- this->get_link(), gain_props,
- boost::bind(&gain_handler::is_equal<prop_t>, _1, _2)
- );
- _gain_values["g0"] = 0;
- _gain_values["g1"] = 0;
- _gain_ranges["g0"] = gain_range_t(-10, 0, float(.1));
- _gain_ranges["g1"] = gain_range_t(0, 100, float(1.5));
- }
-
- ~gainful_obj(void){}
-
-private:
- void get(const wax::obj &key_, wax::obj &val){
- if (_gain_handler->intercept_get(key_, val)) return;
-
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<prop_t>()){
- case PROP_GAIN_VALUE:
- val = _gain_values[name];
- return;
-
- case PROP_GAIN_RANGE:
- val = _gain_ranges[name];
- return;
-
- case PROP_GAIN_NAMES:
- val = _gain_values.keys();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
- }
-
- void set(const wax::obj &key_, const wax::obj &val){
- if (_gain_handler->intercept_set(key_, val)) return;
-
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<prop_t>()){
- case PROP_GAIN_VALUE:
- _gain_values[name] = val.as<float>();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
- }
-
- gain_handler::sptr _gain_handler;
- uhd::dict<std::string, float> _gain_values;
- uhd::dict<std::string, gain_range_t> _gain_ranges;
-
-};
-
-BOOST_AUTO_TEST_CASE(test_gain_handler){
- std::cout << "Testing the gain handler..." << std::endl;
- gainful_obj go0;
-
- BOOST_CHECK_THROW(
- go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as<float>(),
- std::exception
- );
-
- std::cout << "verifying the overall min, max, step" << std::endl;
- gain_range_t gain = go0[PROP_GAIN_RANGE].as<gain_range_t>();
- BOOST_CHECK_EQUAL(gain.min, float(-10));
- BOOST_CHECK_EQUAL(gain.max, float(100));
- BOOST_CHECK_EQUAL(gain.step, float(1.5));
-
- std::cout << "verifying the overall gain" << std::endl;
- go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = float(-5);
- go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = float(30);
- BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as<float>(), float(25));
-}
diff --git a/host/test/subdev_spec_test.cpp b/host/test/subdev_spec_test.cpp
new file mode 100644
index 000000000..8817d5eee
--- /dev/null
+++ b/host/test/subdev_spec_test.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <boost/test/unit_test.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_subdevice_spec){
+ std::cout << "Testing subdevice specification..." << std::endl;
+
+ //load the subdev spec with something
+ uhd::usrp::subdev_spec_t sd_spec;
+ sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("A", "AB"));
+ sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("B", "AB"));
+
+ //convert to and from args string
+ std::cout << "Pretty Print: " << std::endl << sd_spec.to_pp_string();
+ std::string markup_str = sd_spec.to_string();
+ std::cout << "Markup String: " << markup_str << std::endl;
+ uhd::usrp::subdev_spec_t new_sd_spec(markup_str);
+
+ //they should be the same size
+ BOOST_REQUIRE_EQUAL(sd_spec.size(), new_sd_spec.size());
+
+ //the contents should match
+ for (size_t i = 0; i < sd_spec.size(); i++){
+ BOOST_CHECK_EQUAL(sd_spec.at(i).db_name, new_sd_spec.at(i).db_name);
+ BOOST_CHECK_EQUAL(sd_spec.at(i).sd_name, new_sd_spec.at(i).sd_name);
+ }
+}
diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp
new file mode 100644
index 000000000..570f47293
--- /dev/null
+++ b/host/test/tune_helper_test.cpp
@@ -0,0 +1,174 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <boost/test/unit_test.hpp>
+#include <uhd/usrp/tune_helper.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dsp_props.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Dummy properties objects
+ **********************************************************************/
+class dummy_subdev : public wax::obj{
+public:
+ dummy_subdev(double resolution):
+ _resolution(resolution)
+ {
+ /* NOP */
+ }
+private:
+ void get(const wax::obj &key, wax::obj &val){
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ val = _freq;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+ }
+
+ void set(const wax::obj &key, const wax::obj &val){
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_FREQ:
+ _freq = _resolution*int(val.as<double>()/_resolution);
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+ }
+
+ double _freq, _resolution;
+};
+
+class dummy_subdev_basic : public wax::obj{
+private:
+ void get(const wax::obj &key, wax::obj &val){
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ val = double(0.0); //always zero
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+ }
+
+ void set(const wax::obj &key, const wax::obj &){
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_FREQ:
+ // do nothing
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+ }
+};
+
+class dummy_dsp : public wax::obj{
+public:
+ dummy_dsp(double codec_rate):
+ _codec_rate(codec_rate)
+ {
+ /* NOP */
+ }
+private:
+ void get(const wax::obj &key, wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+ case DSP_PROP_CODEC_RATE:
+ val = _codec_rate;
+ return;
+
+ case DSP_PROP_FREQ_SHIFT:
+ val = _freq_shift;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+ }
+
+ void set(const wax::obj &key, const wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+ case DSP_PROP_FREQ_SHIFT:
+ _freq_shift = val.as<double>();
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+ }
+
+ double _codec_rate, _freq_shift;
+};
+
+/***********************************************************************
+ * Test cases
+ **********************************************************************/
+static const double tolerance = 0.001;
+
+BOOST_AUTO_TEST_CASE(test_tune_helper_rx){
+ dummy_subdev subdev(1e6);
+ dummy_dsp dsp(100e6);
+
+ std::cout << "Testing tune helper RX automatic LO offset" << std::endl;
+ tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
+ BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance);
+
+ double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_tune_helper_tx){
+ dummy_subdev subdev(1e6);
+ dummy_dsp dsp(100e6);
+
+ std::cout << "Testing tune helper TX automatic LO offset" << std::endl;
+ tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
+ BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance);
+
+ double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){
+ dummy_subdev_basic subdev;
+ dummy_dsp dsp(100e6);
+
+ std::cout << "Testing tune helper RX dummy basic board" << std::endl;
+ tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6);
+ std::cout << tr.to_pp_string() << std::endl;
+ BOOST_CHECK_CLOSE(tr.actual_inter_freq, 0.0, tolerance);
+ BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance);
+
+ double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance);
+}
diff --git a/host/test/warning_test.cpp b/host/test/warning_test.cpp
new file mode 100644
index 000000000..6202c4270
--- /dev/null
+++ b/host/test/warning_test.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <boost/test/unit_test.hpp>
+#include <uhd/utils/warning.hpp>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_print_warning){
+ std::cerr << "---begin print test ---" << std::endl;
+ uhd::print_warning(
+ "This is a test print for a warning message.\n"
+ "And this is the second line of the test print.\n"
+ );
+ std::cerr << "---end print test ---" << std::endl;
+}
diff --git a/host/uhd.pc.in b/host/uhd.pc.in
index 2a34e9cfd..536f254ed 100644
--- a/host/uhd.pc.in
+++ b/host/uhd.pc.in
@@ -1,10 +1,10 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${prefix}/@LIBRARY_DIR@
+libdir=${exec_prefix}/@LIBRARY_DIR@
includedir=${prefix}/@INCLUDE_DIR@
Name: @CPACK_PACKAGE_NAME@
-Description: Universal Hardware Driver
+Description: @CPACK_PACKAGE_DESCRIPTION_SUMMARY@
Requires:
Version: @CPACK_PACKAGE_VERSION@
Libs: -L${libdir} -luhd
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
index 1e8e726d2..097317516 100644
--- a/host/utils/uhd_usrp_probe.cpp
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -21,6 +21,7 @@
#include <uhd/usrp/device_props.hpp>
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/usrp/dboard_props.hpp>
+#include <uhd/usrp/codec_props.hpp>
#include <uhd/usrp/dsp_props.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dboard_id.hpp>
@@ -88,14 +89,25 @@ static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev
ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl;
}
- ss << boost::format("Is Quadrature: %s") % (subdev[usrp::SUBDEV_PROP_QUADRATURE].as<bool>()? "Yes" : "No") << std::endl;
- ss << boost::format("Is IQ Swapped: %s") % (subdev[usrp::SUBDEV_PROP_IQ_SWAPPED].as<bool>()? "Yes" : "No") << std::endl;
- ss << boost::format("Is Spectrum Inverted: %s") % (subdev[usrp::SUBDEV_PROP_SPECTRUM_INVERTED].as<bool>()? "Yes" : "No") << std::endl;
+ ss << boost::format("Connection Type: %c") % char(subdev[usrp::SUBDEV_PROP_CONNECTION].as<usrp::subdev_conn_t>()) << std::endl;
ss << boost::format("Uses LO offset: %s") % (subdev[usrp::SUBDEV_PROP_USE_LO_OFFSET].as<bool>()? "Yes" : "No") << std::endl;
return ss.str();
}
+static std::string get_codec_pp_string(const std::string &type, wax::obj codec){
+ std::stringstream ss;
+ ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl;
+ //ss << std::endl;
+ prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>());
+ if (gain_names.size() == 0) ss << "Gain Elements: None" << std::endl;
+ BOOST_FOREACH(const std::string &gain_name, gain_names){
+ gain_range_t gain_range(codec[named_prop_t(usrp::CODEC_PROP_GAIN_RANGE, gain_name)].as<gain_range_t>());
+ ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % gain_name % gain_range.min % gain_range.max % gain_range.step << std::endl;
+ }
+ return ss.str();
+}
+
static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){
std::stringstream ss;
ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl;
@@ -103,6 +115,7 @@ static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard
BOOST_FOREACH(const std::string &subdev_name, dboard[usrp::DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){
ss << make_border(get_subdev_pp_string(type, dboard[named_prop_t(usrp::DBOARD_PROP_SUBDEV, subdev_name)]));
}
+ ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC]));
return ss.str();
}
diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py
index d47a4f5f4..1db5e59ce 100755
--- a/host/utils/usrp2_card_burner.py
+++ b/host/utils/usrp2_card_burner.py
@@ -21,6 +21,7 @@ import tempfile
import subprocess
import urllib
import optparse
+import math
import os
import re
@@ -59,6 +60,14 @@ def get_dd_path():
return dd_path
return 'dd'
+def int_ceil_div(num, den):
+ return int(math.ceil(float(num)/float(den)))
+
+def get_tmp_file():
+ tmp = tempfile.mkstemp()
+ os.close(tmp[0])
+ return tmp[1]
+
########################################################################
# list possible devices
########################################################################
@@ -136,10 +145,12 @@ def get_raw_device_hints():
# write and verify with dd
########################################################################
def verify_image(image_file, device_file, offset):
- #create a temporary file to store the readback
- tmp = tempfile.mkstemp()
- os.close(tmp[0])
- tmp_file = tmp[1]
+ #create a temporary file to store the readback image
+ tmp_file = get_tmp_file()
+
+ #read the image data
+ img_data = open(image_file, 'rb').read()
+ count = int_ceil_div(len(img_data), SECTOR_SIZE)
#execute a dd subprocess
verbose = command(
@@ -148,24 +159,33 @@ def verify_image(image_file, device_file, offset):
"if=%s"%device_file,
"skip=%d"%(offset/SECTOR_SIZE),
"bs=%d"%SECTOR_SIZE,
- "count=%d"%(MAX_FILE_SIZE/SECTOR_SIZE),
+ "count=%d"%count,
)
- #read in the image and readback
- img_data = open(image_file, 'rb').read()
- tmp_data = open(tmp_file, 'rb').read(len(img_data))
-
#verfy the data
+ tmp_data = open(tmp_file, 'rb').read(len(img_data))
if img_data != tmp_data: return 'Verification Failed:\n%s'%verbose
return 'Verification Passed:\n%s'%verbose
def write_image(image_file, device_file, offset):
+ #create a temporary file to store the padded image
+ tmp_file = get_tmp_file()
+
+ #write the padded image data
+ img_data = open(image_file, 'rb').read()
+ count = int_ceil_div(len(img_data), SECTOR_SIZE)
+ pad_len = SECTOR_SIZE*count - len(img_data)
+ pad_str = ''.join([chr(0)]*pad_len) #zero-padding
+ open(tmp_file, 'wb').write(img_data + pad_str)
+
+ #execute a dd subprocess
verbose = command(
get_dd_path(),
- "if=%s"%image_file,
+ "if=%s"%tmp_file,
"of=%s"%device_file,
"seek=%d"%(offset/SECTOR_SIZE),
"bs=%d"%SECTOR_SIZE,
+ "count=%d"%count,
)
try: #exec the sync command (only works on linux)
diff --git a/host/utils/usrp2_card_burner_gui.py b/host/utils/usrp2_card_burner_gui.py
index 61fbadbe3..58b7a514a 100755
--- a/host/utils/usrp2_card_burner_gui.py
+++ b/host/utils/usrp2_card_burner_gui.py
@@ -17,7 +17,7 @@
#
import usrp2_card_burner #import implementation
-import Tkinter, Tkconstants, tkFileDialog, tkFont, tkMessageBox
+import Tkinter, tkFileDialog, tkFont, tkMessageBox
import os
class BinFileEntry(Tkinter.Frame):
@@ -53,7 +53,7 @@ class BinFileEntry(Tkinter.Frame):
class DeviceEntryWidget(Tkinter.Frame):
"""
- Simple entry widget for getting the raw device name.
+ Simple entry widget for getting the raw device name.
Combines a label, entry, and helpful text box with hints.
"""