aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/.gitignore1
-rw-r--r--host/AUTHORS1
-rw-r--r--host/CMakeLists.txt144
-rw-r--r--host/LICENSE12
-rw-r--r--host/README29
-rw-r--r--host/cmake_uninstall.cmake.in23
-rw-r--r--host/docs/CMakeLists.txt101
-rw-r--r--host/docs/Doxyfile.in1514
-rw-r--r--host/docs/build.rst130
-rw-r--r--host/docs/coding.rst63
-rw-r--r--host/docs/dboards.rst64
-rw-r--r--host/docs/index.rst31
-rw-r--r--host/docs/style.css102
-rw-r--r--host/docs/usrp2.rst185
-rw-r--r--host/examples/CMakeLists.txt24
-rw-r--r--host/examples/rx_timed_samples.cpp101
-rw-r--r--host/examples/tx_timed_samples.cpp92
-rw-r--r--host/include/CMakeLists.txt19
-rw-r--r--host/include/uhd/CMakeLists.txt29
-rw-r--r--host/include/uhd/config.hpp88
-rw-r--r--host/include/uhd/device.hpp181
-rw-r--r--host/include/uhd/transport/CMakeLists.txt27
-rw-r--r--host/include/uhd/transport/convert_types.hpp59
-rw-r--r--host/include/uhd/transport/if_addrs.hpp47
-rw-r--r--host/include/uhd/transport/udp_simple.hpp80
-rw-r--r--host/include/uhd/transport/udp_zero_copy.hpp66
-rw-r--r--host/include/uhd/transport/vrt.hpp75
-rw-r--r--host/include/uhd/transport/zero_copy.hpp133
-rw-r--r--host/include/uhd/types/CMakeLists.txt33
-rw-r--r--host/include/uhd/types/clock_config.hpp51
-rw-r--r--host/include/uhd/types/device_addr.hpp72
-rw-r--r--host/include/uhd/types/dict.hpp155
-rw-r--r--host/include/uhd/types/io_type.hpp70
-rw-r--r--host/include/uhd/types/mac_addr.hpp66
-rw-r--r--host/include/uhd/types/metadata.hpp118
-rw-r--r--host/include/uhd/types/otw_type.hpp69
-rw-r--r--host/include/uhd/types/ranges.hpp46
-rw-r--r--host/include/uhd/types/serial.hpp122
-rw-r--r--host/include/uhd/types/stream_cmd.hpp64
-rw-r--r--host/include/uhd/types/time_spec.hpp76
-rw-r--r--host/include/uhd/types/tune_result.hpp44
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt42
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp117
-rw-r--r--host/include/uhd/usrp/dboard_eeprom.hpp60
-rw-r--r--host/include/uhd/usrp/dboard_id.hpp90
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp162
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp79
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp39
-rw-r--r--host/include/uhd/usrp/device_props.hpp55
-rw-r--r--host/include/uhd/usrp/dsp_props.hpp49
-rw-r--r--host/include/uhd/usrp/mboard_props.hpp50
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp151
-rw-r--r--host/include/uhd/usrp/subdev_props.hpp49
-rw-r--r--host/include/uhd/usrp/tune_helper.hpp79
-rw-r--r--host/include/uhd/usrp/usrp2.hpp62
-rw-r--r--host/include/uhd/utils/CMakeLists.txt27
-rw-r--r--host/include/uhd/utils/algorithm.hpp51
-rw-r--r--host/include/uhd/utils/assert.hpp76
-rw-r--r--host/include/uhd/utils/exception.hpp38
-rw-r--r--host/include/uhd/utils/gain_handler.hpp90
-rw-r--r--host/include/uhd/utils/props.hpp77
-rw-r--r--host/include/uhd/utils/safe_main.hpp44
-rw-r--r--host/include/uhd/utils/static.hpp37
-rw-r--r--host/include/uhd/wax.hpp167
-rw-r--r--host/lib/CMakeLists.txt120
-rw-r--r--host/lib/device.cpp146
-rw-r--r--host/lib/gain_handler.cpp177
-rw-r--r--host/lib/ic_reg_maps/.gitignore1
-rw-r--r--host/lib/ic_reg_maps/CMakeLists.txt65
-rw-r--r--host/lib/ic_reg_maps/common.py147
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad5624_regs.py48
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad7922_regs.py54
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9510_regs.py139
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9522_regs.py183
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9777_regs.py118
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9862_regs.py246
-rwxr-xr-xhost/lib/ic_reg_maps/gen_adf4350_regs.py121
-rwxr-xr-xhost/lib/ic_reg_maps/gen_adf4360_regs.py89
-rwxr-xr-xhost/lib/ic_reg_maps/gen_max2829_regs.py133
-rw-r--r--host/lib/load_modules.cpp146
-rw-r--r--host/lib/transport/CMakeLists.txt53
-rw-r--r--host/lib/transport/convert_types.cpp151
-rwxr-xr-xhost/lib/transport/gen_vrt.py210
-rw-r--r--host/lib/transport/if_addrs.cpp109
-rw-r--r--host/lib/transport/udp_simple.cpp159
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp210
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp363
-rw-r--r--host/lib/types.cpp307
-rw-r--r--host/lib/usrp/CMakeLists.txt27
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt26
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp284
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp532
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp613
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp626
-rw-r--r--host/lib/usrp/dboard_base.cpp123
-rw-r--r--host/lib/usrp/dboard_ctor_args.hpp32
-rw-r--r--host/lib/usrp/dboard_eeprom.cpp103
-rw-r--r--host/lib/usrp/dboard_id.cpp68
-rw-r--r--host/lib/usrp/dboard_manager.cpp304
-rw-r--r--host/lib/usrp/simple_usrp.cpp227
-rw-r--r--host/lib/usrp/tune_helper.cpp127
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt31
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp163
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp60
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp91
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp38
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp263
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp193
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp243
-rw-r--r--host/lib/usrp/usrp2/fw_common.h119
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp100
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp247
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.cpp46
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.hpp40
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp219
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp119
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp219
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp222
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp247
-rw-r--r--host/lib/utils.cpp53
-rw-r--r--host/lib/wax.cpp150
-rw-r--r--host/test/CMakeLists.txt36
-rw-r--r--host/test/addr_test.cpp80
-rw-r--r--host/test/dict_test.cpp72
-rw-r--r--host/test/error_test.cpp48
-rw-r--r--host/test/gain_handler_test.cpp121
-rw-r--r--host/test/main_test.cpp3
-rw-r--r--host/test/module_test.cpp26
-rw-r--r--host/test/vrt_test.cpp102
-rw-r--r--host/test/wax_test.cpp104
-rw-r--r--host/uhd.pc.in11
-rw-r--r--host/utils/CMakeLists.txt34
-rw-r--r--host/utils/uhd_burn_db_eeprom.cpp103
-rw-r--r--host/utils/uhd_find_devices.cpp60
-rw-r--r--host/utils/usrp2_addr_burner.cpp90
-rwxr-xr-xhost/utils/usrp2_card_burner.py344
-rwxr-xr-xhost/utils/usrp2_recovery.py68
137 files changed, 16850 insertions, 0 deletions
diff --git a/host/.gitignore b/host/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/host/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/host/AUTHORS b/host/AUTHORS
new file mode 100644
index 000000000..d0fe52768
--- /dev/null
+++ b/host/AUTHORS
@@ -0,0 +1 @@
+Josh Blum - josh@ettus.com
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
new file mode 100644
index 000000000..0b2d3f012
--- /dev/null
+++ b/host/CMakeLists.txt
@@ -0,0 +1,144 @@
+#
+# 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/>.
+#
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(UHD)
+ENABLE_TESTING()
+
+########################################################################
+# Setup CPack
+########################################################################
+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
+
+########################################################################
+# Install Dirs
+########################################################################
+SET(RUNTIME_DIR bin)
+SET(LIBRARY_DIR lib)
+SET(INCLUDE_DIR include)
+SET(PKG_DATA_DIR share/uhd)
+SET(PKG_DOC_DIR share/doc/uhd)
+MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
+
+########################################################################
+# Local Include Dir
+########################################################################
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+########################################################################
+# Optional Compiler Flags
+########################################################################
+INCLUDE(CheckCXXCompilerFlag)
+MACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have)
+ CHECK_CXX_COMPILER_FLAG(${flag} ${have})
+ IF(${have})
+ ADD_DEFINITIONS(${flag})
+ ENDIF(${have})
+ENDMACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG)
+
+IF(UNIX)
+ 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)
+ #only export symbols that are declared to be part of the uhd api:
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
+ UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations
+ENDIF(UNIX)
+
+IF(WIN32)
+ ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp
+ ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max
+ ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split
+ ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
+ENDIF(WIN32)
+
+########################################################################
+# Setup Boost
+########################################################################
+SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42")
+FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS
+ date_time
+ filesystem
+ program_options
+ regex
+ system
+ thread
+ unit_test_framework
+)
+
+INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
+LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
+
+########################################################################
+# Setup Endianess
+########################################################################
+INCLUDE(TestBigEndian)
+TEST_BIG_ENDIAN(HAVE_BIG_ENDIAN)
+IF(HAVE_BIG_ENDIAN)
+ ADD_DEFINITIONS(-DHAVE_BIG_ENDIAN)
+ENDIF(HAVE_BIG_ENDIAN)
+
+########################################################################
+# Create Uninstall Target
+########################################################################
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
+@ONLY)
+
+ADD_CUSTOM_TARGET(uninstall
+ ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
+)
+
+########################################################################
+# Create Pkg Config File
+########################################################################
+CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/uhd.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/uhd.pc
+@ONLY)
+
+INSTALL(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/uhd.pc
+ DESTINATION ${LIBRARY_DIR}/pkgconfig
+)
+
+########################################################################
+# Install Package Docs
+########################################################################
+INSTALL(FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/README
+ ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
+ ${CMAKE_CURRENT_SOURCE_DIR}/AUTHORS
+ DESTINATION ${PKG_DOC_DIR}
+)
+
+########################################################################
+# Add the subdirectories
+########################################################################
+ADD_SUBDIRECTORY(docs)
+ADD_SUBDIRECTORY(examples)
+ADD_SUBDIRECTORY(include)
+ADD_SUBDIRECTORY(lib)
+ADD_SUBDIRECTORY(test)
+ADD_SUBDIRECTORY(utils)
diff --git a/host/LICENSE b/host/LICENSE
new file mode 100644
index 000000000..9aa03b39b
--- /dev/null
+++ b/host/LICENSE
@@ -0,0 +1,12 @@
+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/>.
diff --git a/host/README b/host/README
new file mode 100644
index 000000000..e67bb25f8
--- /dev/null
+++ b/host/README
@@ -0,0 +1,29 @@
+########################################################################
+# Ettus Research - Universal Hardware Driver
+########################################################################
+The hardware driver for Ettus Research products.
+
+########################################################################
+# Supported USRP Motherboards
+########################################################################
+USRP2 - udp over gigabit ethernet
+
+########################################################################
+# Supported USRP Daughterboards
+########################################################################
+Basic RX
+Basic TX
+LF RX
+LF TX
+RFX Series
+XCVR 2450
+
+########################################################################
+# Documentation
+########################################################################
+Online documentation available at:
+http://ettus-apps.sourcerepo.com/redmine/ettus/projects/uhd/wiki/
+
+The build system can generate the html for the manual and Doxygen.
+Docutils and Doxygen are required to build the html docs.
+See the docs directory for the manual source (reStructuredText).
diff --git a/host/cmake_uninstall.cmake.in b/host/cmake_uninstall.cmake.in
new file mode 100644
index 000000000..6031a6ca9
--- /dev/null
+++ b/host/cmake_uninstall.cmake.in
@@ -0,0 +1,23 @@
+# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
+
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt
new file mode 100644
index 000000000..61eede8b7
--- /dev/null
+++ b/host/docs/CMakeLists.txt
@@ -0,0 +1,101 @@
+#
+# 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/>.
+#
+
+########################################################################
+# List of manual sources
+########################################################################
+SET(manual_sources
+ index.rst
+ build.rst
+ coding.rst
+ dboards.rst
+ usrp2.rst
+)
+
+########################################################################
+# Setup Manual
+########################################################################
+MESSAGE(STATUS "Checking for rst2html (docutils)")
+FIND_PROGRAM(RST2HTML rst2html)
+IF(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND")
+ MESSAGE(STATUS "Checking for rst2html (docutils) - not found")
+ MESSAGE(STATUS " Disabled generation of HTML manual.")
+ELSE(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND")
+ MESSAGE(STATUS "Checking for rst2html (docutils) - found")
+ MESSAGE(STATUS " Enabled generation of HTML manual.")
+
+ #setup rst2html options
+ SET(stylesheet ${CMAKE_CURRENT_SOURCE_DIR}/style.css)
+ SET(rst2html_options
+ --stylesheet=${stylesheet}
+ --no-toc-backlinks --date --time
+ )
+
+ #create generation rule for each source
+ FOREACH(rstfile ${manual_sources})
+ #set input and output file names
+ SET(rstfile ${CMAKE_CURRENT_SOURCE_DIR}/${rstfile})
+ GET_FILENAME_COMPONENT(rstfile_we ${rstfile} NAME_WE)
+ SET(htmlfile ${CMAKE_CURRENT_BINARY_DIR}/${rstfile_we}.html)
+
+ #make the html file depend on the rst file
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${htmlfile} DEPENDS ${rstfile} ${stylesheet}
+ COMMAND ${RST2HTML} ${rstfile} ${htmlfile} ${rst2html_options}
+ COMMENT "Generating ${htmlfile}"
+ )
+
+ #make the manual target depend on the html file
+ LIST(APPEND manual_html_files ${htmlfile})
+ INSTALL(FILES ${htmlfile} DESTINATION ${PKG_DOC_DIR}/manual/html)
+ ENDFOREACH(rstfile ${manual_sources})
+
+ #make the html manual a build-time dependency
+ ADD_CUSTOM_TARGET(manual_html ALL DEPENDS ${manual_html_files})
+ENDIF(${RST2HTML} STREQUAL "RST2HTML-NOTFOUND")
+
+INSTALL(FILES ${manual_sources} DESTINATION ${PKG_DOC_DIR}/manual/rst)
+
+########################################################################
+# Setup Doxygen
+########################################################################
+INCLUDE(FindDoxygen)
+
+IF(DOXYGEN_FOUND)
+ MESSAGE(STATUS " Enabled generation of Doxygen documentation.")
+
+ #generate the doxygen configuration file
+ SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
+ CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ @ONLY)
+
+ #make doxygen directory depend on the header files
+ FILE(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DEPENDS ${header_files}
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ COMMENT "Generating documentation with doxygen"
+ )
+
+ #make the doxygen generation a built-time dependency
+ ADD_CUSTOM_TARGET(doxygen_docs ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN})
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DESTINATION ${PKG_DOC_DIR})
+ELSE(DOXYGEN_FOUND)
+ MESSAGE(STATUS " Disabled generation of Doxygen documentation.")
+ENDIF(DOXYGEN_FOUND)
diff --git a/host/docs/Doxyfile.in b/host/docs/Doxyfile.in
new file mode 100644
index 000000000..7395516b5
--- /dev/null
+++ b/host/docs/Doxyfile.in
@@ -0,0 +1,1514 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = @CPACK_PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @CPACK_PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR_DOXYGEN@
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @CMAKE_SOURCE_DIR@/include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.hpp
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/host/docs/build.rst b/host/docs/build.rst
new file mode 100644
index 000000000..d28682764
--- /dev/null
+++ b/host/docs/build.rst
@@ -0,0 +1,130 @@
+========================================================================
+UHD - Build Guide
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Build Dependencies
+------------------------------------------------------------------------
+
+**Unix Notes:**
+The dependencies can be acquired through the package manager.
+
+**Windows Notes:**
+The dependencies can be acquired through installable exe files.
+Usually, the windows installer can be found on the project's website.
+Some projects do not host windows installers, and if this is the case,
+follow the auxiliary download url for the windows installer (below).
+
+^^^^^^^^^^^^^^^^
+Git
+^^^^^^^^^^^^^^^^
+Required to check out the repository.
+On windows, install cygwin with git support to checkout the repository,
+or install msysgit from http://code.google.com/p/msysgit/downloads/list
+
+^^^^^^^^^^^^^^^^
+C++
+^^^^^^^^^^^^^^^^
+On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008.
+Other compilers have not been tested yet or confirmed working.
+
+^^^^^^^^^^^^^^^^
+CMake
+^^^^^^^^^^^^^^^^
+* **Version:** at least 2.8
+* **Required for:** build time
+* **Download URL:** http://www.cmake.org/cmake/resources/software.html
+
+^^^^^^^^^^^^^^^^
+Boost
+^^^^^^^^^^^^^^^^
+* **Version:** at least 3.6 unix, at least 4.0 windows
+* **Required for:** build time + run time
+* **Download URL:** http://www.boost.org/users/download/
+* **Download URL (windows installer):** http://www.boostpro.com/download
+
+^^^^^^^^^^^^^^^^
+Python
+^^^^^^^^^^^^^^^^
+* **Version:** at least 2.6
+* **Required for:** build time
+* **Download URL:** http://www.python.org/download/
+
+^^^^^^^^^^^^^^^^
+Cheetah
+^^^^^^^^^^^^^^^^
+* **Version:** at least 2.0
+* **Required for:** build time
+* **Download URL:** http://www.cheetahtemplate.org/download.html
+* **Download URL (windows installer):** http://feisley.com/python/cheetah/
+
+^^^^^^^^^^^^^^^^
+Doxygen
+^^^^^^^^^^^^^^^^
+* **Required for:** build time (optional)
+* **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc
+
+------------------------------------------------------------------------
+Build Instructions (Unix)
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Generate Makefiles with cmake
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ cd <uhd-repo-path>/host
+ mkdir build
+ cd build
+ cmake ../
+
+For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Build and install
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ make
+ make test
+ sudo make install
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup the library path
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Make sure that libuhd.so is in your LD_LIBRARY_PATH
+or add it to /etc/ld.so.conf and make sure to run sudo ldconfig
+
+
+------------------------------------------------------------------------
+Build Instructions (Windows)
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Generate the project with cmake
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Open the cmake gui program.
+* Set the path to the source code: <uhd-repo-path>/host
+* Set the path to the build directory: <uhd-repo-path>/host/build
+* Make sure that the paths do not contain spaces.
+* Click configure and select the MSVC compiler.
+* Set the build variables and click configure again.
+* Click generate and a project file will be created in the build directory.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Build the project in MSVC
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Open the generated project file in MSVC.
+* Select the build all target, right click, and choose build.
+* Select the install target, right click, and choose build.
+
+**Note:** you may not have permission to build the install target.
+You need to be an administrator or to run MSVC as administrator.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup the PATH environment variable
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Add the boost library path to %PATH% (usually c:\\program files\\boost\\<version>\\lib)
+* Add the uhd library path to %PATH% (usually c:\\program files\\uhd\\lib)
diff --git a/host/docs/coding.rst b/host/docs/coding.rst
new file mode 100644
index 000000000..689667f30
--- /dev/null
+++ b/host/docs/coding.rst
@@ -0,0 +1,63 @@
+========================================================================
+UHD - Coding to the API
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Low-Level: The device API
+------------------------------------------------------------------------
+A device is an abstraction for hardware that is connected to the host system.
+For a USRP, this means that the motherboard and everything on it would be considered to be a "device".
+The device API provides ways to:
+
+* Discover devices that are physical connected to the host system.
+* Create a device object for a particular physical device identified by address.
+* Register a device driver into the discovery and factory sub-system.
+* Streaming samples with metadata into and out of the device.
+* Set and get properties on the device object.
+
+See the documentation in device.hpp for reference.
+
+------------------------------------------------------------------------
+High-Level: The simple usrp
+------------------------------------------------------------------------
+The goal of the simple usrp is to wrap high level functions around the device properties.
+The simple usrp provides a fat interface to access the most common properties.
+The simple usrp provides ways to:
+
+* Set and get daughterboard gains.
+* Set and get daughterboard antennas.
+* Set and get the streaming rates.
+* Tune the DSPs and daughterboards.
+* Issue stream commands.
+* Set the clock configuration.
+* Set the usrp time registers.
+* Get the underlying device (as discussed above).
+
+It is recommended that users code to the simple_usrp api when possible.
+See the documentation in usrp/simple_usrp.hpp for reference.
+
+------------------------------------------------------------------------
+Integrating custom hardware
+------------------------------------------------------------------------
+Creators of custom hardware can create drivers that use the UHD API.
+These drivers can be built as dynamically lodable modules that the UHD will load at runtime.
+For a module to be loaded at runtime, it must be found in the UHD_MODULE_PATH environment variable.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Custom motherboard
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Create a new device driver when the driver in lib/usrp/
+cannot support your custom FPGA or hardware modifications.
+Make a copy of the relevant driver code in lib/usrp/, make mods, and rename the class.
+The new device code should register itself into the discovery and factory system.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Custom daughterboard
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use code from an existing daughterboard in lib/usrp/dboard/* as an example.
+Your daughterboard code should subclass an rx dboard, rx dboard, or xcvr dboard;
+and it should respond to calls to get and set properties.
+The new daughterboard code should register itself into the dboard manager
+with a unique rx and/or tx 16 bit identification number.
diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst
new file mode 100644
index 000000000..d08b752a6
--- /dev/null
+++ b/host/docs/dboards.rst
@@ -0,0 +1,64 @@
+========================================================================
+UHD - Daughterboard Application Notes
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Daughterboard Properties
+------------------------------------------------------------------------
+
+The following contains interesting notes about each daughterboard.
+Eventually, this page will be expanded to list out the full
+properties of each board as well.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Basic RX and and LFRX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The Basic RX and LFRX boards have 3 subdevices:
+
+* **Subdevice A:** real signal on antenna RXA
+* **Subdevice B:** real signal on antenna RXB
+* **Subdevice AB:** quadrature subdevice using both antennas
+
+The boards have no tunable elements or programmable gains.
+Though the magic of aliasing, you can down-convert signals
+greater than the nyquist rate of the ADC.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Basic TX and and LFTX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+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.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+RFX Series
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Transmit Antennas: **TX/RX**
+
+Receive Antennas: **TX/RX** or **RX2**
+
+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.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+XCVR 2450
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The XCVR2450 has a non-contiguous tuning range consiting of a high band and a low band.
+The high band consists of frequencies between...TODO
+
+Transmit Antennas: **J1** or **J2**
+
+Receive Antennas: **J1** or **J2**
+
+When using the XCVR2450 in full-duplex mode,
+the user must set the receive antenna and the transmit antenna to be different;
+not doing so will yeild undefined results.
+
+The XCVR2450 uses a common LO for both receive and transmit.
+Even though the API allows the RX and TX LOs to be individually set,
+a change of one LO setting will be reflected in the other LO setting.
diff --git a/host/docs/index.rst b/host/docs/index.rst
new file mode 100644
index 000000000..3dc7a2d98
--- /dev/null
+++ b/host/docs/index.rst
@@ -0,0 +1,31 @@
+========================================================================
+UHD - Universal Hardware Driver
+========================================================================
+
+The UHD is the universal hardware driver for Ettus Research products.
+The goal of the UHD is to provide a host driver and api for current and future Ettus Research products.
+Users will be able to use the UHD driver standalone/without gnuradio.
+Also, a dual license option will be available for those who build against the UHD
+but cannot release their software products under the GPL.
+
+------------------------------------------------------------------------
+Contents
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^
+Building the UHD
+^^^^^^^^^^^^^^^^^^^^^
+* `Build Guide <./build.html>`_
+
+^^^^^^^^^^^^^^^^^^^^^
+Supported Devices
+^^^^^^^^^^^^^^^^^^^^^
+* `USRP2 App Notes <./usrp2.html>`_
+* `Daughterboard App Notes <./dboards.html>`_
+
+^^^^^^^^^^^^^^^^^^^^^
+API Documentation
+^^^^^^^^^^^^^^^^^^^^^
+* `Doxygen <./../../doxygen/html/index.html>`_
+* `Using the API <./coding.html>`_
+
diff --git a/host/docs/style.css b/host/docs/style.css
new file mode 100644
index 000000000..bf97bf007
--- /dev/null
+++ b/host/docs/style.css
@@ -0,0 +1,102 @@
+body{
+font-family:Arial, Helvetica, sans-serif;
+font-size:11pt;
+color:black;
+background-color:white;
+width:90%;
+margin:0 auto 0 auto;
+}
+
+div.document div.contents{
+border:1px solid #333333;
+padding:10px 30px 10px 10px;
+margin-left:50px;
+color:inherit;
+background-color:#FCFCFC;
+display:inline-block;
+}
+
+div.document p.topic-title{
+font-weight:bold;
+}
+
+div.document a:link, div.document a:visited{
+color:#236B8E;
+background-color:inherit;
+text-decoration:none;
+}
+
+div.document a:hover{
+color:#4985D6;
+background-color:inherit;
+text-decoration:none;
+}
+
+div.document h1.title{
+font-size:150%;
+border-left:1px solid #333333;
+border-bottom:1px solid #333333;
+text-align:left;
+padding:10px 0px 10px 10px;
+margin:10px 5px 20px 5px;
+color:#333333;
+background-color:inherit;
+}
+
+div.document h2.subtitle, div.section h1{
+margin-top:50px;
+border-bottom:1px solid #333333;
+font-size:140%;
+text-align:center;
+padding:20px 0px 10px 0px;
+color:#333333;
+background-color:inherit;
+}
+
+div.section h2{
+font-size:110%;
+text-align:left;
+padding:15px 0px 5px 0px;
+text-decoration:underline;
+color:#333333;
+background-color:inherit;
+}
+
+div.document pre.literal-block{
+border:1px inset #333333;
+padding:5px;
+margin:10px 5px 10px 5px;
+color:inherit;
+background-color:#FCFCFC;
+font-size:90%;
+}
+
+div.document table{
+padding:5px;
+font-size:95%;
+}
+
+div.document th{
+padding:3px 7px 3px 7px;
+border:1px solid #333333;
+text-align:center;
+color:inherit;
+background-color:#ECECEC;
+}
+
+div.document tr{
+}
+
+div.document td{
+padding:3px 7px 3px 7px;
+border:1px solid #333333;
+text-align:center;
+color:inherit;
+background-color:#FCFCFC;
+}
+
+div.footer{
+margin:50px auto 30px auto;
+text-align:center;
+font-size:85%;
+}
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
new file mode 100644
index 000000000..4731b73cf
--- /dev/null
+++ b/host/docs/usrp2.rst
@@ -0,0 +1,185 @@
+========================================================================
+UHD - USRP2 Application Notes
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Building firmware and FPGA images
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^
+FPGA Image
+^^^^^^^^^^^^^^^^^^
+Xilinx ISE 10.1 is required to build the FPGA image for the USRP2
+(newer version of ISE are known to build buggy images).
+The build requires that you have a unix-like environment with make.
+Make sure that xtclsh from the Xilinx ISE bin directory is in your $PATH.
+
+Run the following commands:
+::
+
+ cd <uhd-repo-path>/fpga/usrp2/top/u2_rev3
+ make bin
+
+*The image file will be ./build/u2_rev3.bin*
+
+^^^^^^^^^^^^^^^^^^
+Firmware Image
+^^^^^^^^^^^^^^^^^^
+The Microblaze GCC compiler from the Xilinx EDK is required to build the firmware.
+The build requires that you have a unix-like environment with autotools and make.
+Make sure that mb-gcc from the Xilinx EDK/microblaze directory is in your $PATH.
+
+Run the following commands:
+::
+
+ cd <uhd-repo-path>/firmware/microblaze
+ ./boostrap
+ ./configure --host=mb
+ make
+
+*The image file will be ./apps/txrx_uhd.bin*
+
+------------------------------------------------------------------------
+Load the images onto the SD card
+------------------------------------------------------------------------
+**Warning!**
+Use the usrp2_card_burner.py with caution. If you specify the wrong device node,
+you could overwrite your hard drive. Make sure that --dev= specifies the SD card.
+
+Use the *--list* option to get a list of possible raw devices.
+The list result will filter out disk partitions and devices too large to be the sd card.
+The list option has not yet been implemented on macosx.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (unix)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ sudo <prefix>/share/uhd/utils/usrp2_card_burner.py --gui
+
+ -- OR --
+
+ cd <prefix>/share/uhd/utils
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fpga=<path_to_fpga_image>
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fw=<path_to_firmware_image>
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (windows)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ <path_to_python.exe> <prefix>/share/uhd/utils/usrp2_card_burner.py --gui
+
+
+------------------------------------------------------------------------
+Setup networking
+------------------------------------------------------------------------
+The USRP2 only supports gigabit ethernet, and
+will not work with a 10/100 Mbps interface.
+Because the USRP2 uses gigabit ethernet pause frames for flow control,
+you cannot use multiple USRP2s with a switch or a hub.
+It is recommended that each USRP2 be plugged directly into its own
+dedicated gigabit ethernet interface on the host computer.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup the host interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The USRP2 communicates at the IP/UDP layer over the gigabit ethernet.
+The default IP address of the USRP2 is **192.168.10.2**
+You will need to configure the host's ethernet interface with a static IP address to enable communication.
+An address of **192.168.10.1** is recommended.
+
+**Note:**
+When using the UHD, if an IP address for the USRP2 is not specified,
+the software will use UDP broadcast packets to locate the USRP2.
+On some systems, the firewall will block UDP broadcast packets.
+It is recommended that you change or disable your firewall settings.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Change the USRP2's IP address
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+You may need to change the USRP2's IP address for several reasons:
+
+* to satisfy your particular network configuration
+* to use multiple USRP2s on the same host computer
+* to set a known IP address into USRP2 (in case you forgot)
+
+**Method 1:**
+To change the USRP2's IP address
+you must know the current address of the USRP2,
+and the network must be setup properly as described above.
+Run the following commands:
+::
+
+ cd <prefix>/share/uhd/utils
+ ./usrp_addr_burner --addr=192.168.10.2 --new-ip=192.168.10.3
+
+**Method 2 (Linux Only):**
+This method assumes that you do not know the IP address of your USRP2.
+It uses raw ethernet packets to bypass the IP/UDP layer to communicate with the USRP2.
+Run the following commands:
+::
+
+ cd <prefix>/share/uhd/utils
+ ./usrp2_recovery.py --ifc=eth0 --new-ip=192.168.10.3
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Debugging networking problems
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Disable the firewall:**
+If uhd_find_devices gives you nothing
+but uhd_find_devices --args addr=192.168.10.2 yeilds a discovered device,
+then your firewall may be blocking replies to UDP broadcast packets.
+
+**Ping the USRP2:**
+The USRP2 will reply to icmp echo requests.
+::
+
+ ping 192.168.10.2
+
+**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.
+The microcontroller prints useful information about IP addresses,
+MAC addresses, control packets, and fast-path settings.
+
+**Monitor the host network traffic:**
+Use wireshark to monitor packets sent to and received from the USRP2.
+
+------------------------------------------------------------------------
+Resize the send and receive buffers
+------------------------------------------------------------------------
+It may be useful increase the size of the socket buffers to
+move the burden of buffering samples into the kernel, or to
+buffer incoming samples faster than they can be processed.
+However, if you application cannot process samples fast enough,
+no amount of buffering can save you.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device address params
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To set the size of the buffers,
+the usrp2 will accept two optional parameters in the device address.
+Each parameter will accept a numeric value for the number of bytes.
+
+* recv_buff_size
+* send_buff_size
+
+Example, set the args string to the following:
+::
+
+ addr=192.168.10.2, recv_buff_size=100e6
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+OS specific notes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+On linux, the maximum buffer sizes are capped by the sysctl values
+**net.core.rmem_max** and **net.core.wmem_max**.
+To change the maximum values, run the following commands:
+::
+
+ sudo sysctl -w net.core.rmem_max=<new value>
+ sudo sysctl -w net.core.wmem_max=<new value>
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
new file mode 100644
index 000000000..a537c0901
--- /dev/null
+++ b/host/examples/CMakeLists.txt
@@ -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/>.
+#
+
+ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)
+TARGET_LINK_LIBRARIES(rx_timed_samples uhd)
+INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+
+ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
+TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
+INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
new file mode 100644
index 000000000..d2306c7c4
--- /dev/null
+++ b/host/examples/rx_timed_samples.cpp
@@ -0,0 +1,101 @@
+//
+// 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/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //variables to be set by po
+ std::string args;
+ int seconds_in_future;
+ size_t total_num_samps;
+ double rx_rate, freq;
+
+ //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")
+ ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
+ ("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
+ ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
+ ;
+ 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 RX Timed Samples %s") % desc << std::endl;
+ return ~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_name() << std::endl;
+
+ //set properties on the device
+ std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl;
+ sdev->set_rx_rate(rx_rate);
+ std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_rx_freq(freq);
+ sdev->set_time_now(uhd::time_spec_t(0));
+
+ //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;
+ 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;
+ stream_cmd.time_spec = uhd::time_spec_t(seconds_in_future);
+ sdev->issue_stream_cmd(stream_cmd);
+
+ //loop until total number of samples reached
+ size_t num_acc_samps = 0; //number of accumulated samples
+ while(num_acc_samps < total_num_samps){
+ uhd::rx_metadata_t md;
+ std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
+ size_t num_rx_samps = dev->recv(
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
+ );
+ if (num_rx_samps == 0) continue; //wait for packets with contents
+
+ std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs")
+ % num_rx_samps % md.time_spec.secs % md.time_spec.nsecs << std::endl;
+
+ num_acc_samps += num_rx_samps;
+ }
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
new file mode 100644
index 000000000..e9e0c785e
--- /dev/null
+++ b/host/examples/tx_timed_samples.cpp
@@ -0,0 +1,92 @@
+//
+// 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/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //variables to be set by po
+ std::string args;
+ int seconds_in_future;
+ size_t total_num_samps;
+ 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")
+ ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
+ ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
+ ("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")
+ ;
+ 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 Timed Samples %s") % desc << std::endl;
+ return ~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_name() << 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;
+ std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
+ sdev->set_tx_freq(freq);
+ sdev->set_time_now(uhd::time_spec_t(0));
+
+ //data to send
+ std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl));
+ uhd::tx_metadata_t md;
+ md.start_of_burst = true;
+ md.end_of_burst = true;
+ md.has_time_spec = true;
+ md.time_spec = uhd::time_spec_t(seconds_in_future);
+
+ //send the entire buffer, let the driver handle fragmentation
+ size_t num_tx_samps = dev->send(
+ boost::asio::buffer(buff),
+ md, uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::SEND_MODE_FULL_BUFF
+ );
+ std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl;
+
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/include/CMakeLists.txt b/host/include/CMakeLists.txt
new file mode 100644
index 000000000..3f7ca2cb7
--- /dev/null
+++ b/host/include/CMakeLists.txt
@@ -0,0 +1,19 @@
+#
+# 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/>.
+#
+
+
+ADD_SUBDIRECTORY(uhd)
diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt
new file mode 100644
index 000000000..d63062032
--- /dev/null
+++ b/host/include/uhd/CMakeLists.txt
@@ -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/>.
+#
+
+
+ADD_SUBDIRECTORY(transport)
+ADD_SUBDIRECTORY(types)
+ADD_SUBDIRECTORY(usrp)
+ADD_SUBDIRECTORY(utils)
+
+INSTALL(FILES
+ config.hpp
+ device.hpp
+ wax.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd
+)
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
new file mode 100644
index 000000000..fea95145c
--- /dev/null
+++ b/host/include/uhd/config.hpp
@@ -0,0 +1,88 @@
+//
+// 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_CONFIG_HPP
+#define INCLUDED_UHD_CONFIG_HPP
+
+// suppress warnings
+#include <boost/config.hpp>
+#ifdef BOOST_MSVC
+//# pragma warning(push)
+//# pragma warning(disable: 4511) // copy constructor can't not be generated
+//# pragma warning(disable: 4512) // assignment operator can't not be generated
+//# pragma warning(disable: 4100) // unreferenced formal parameter
+//# pragma warning(disable: 4996) // <symbol> was declared deprecated
+//# pragma warning(disable: 4355) // 'this' : used in base member initializer list
+//# pragma warning(disable: 4706) // assignment within conditional expression
+# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B'
+//# pragma warning(disable: 4127) // conditional expression is constant
+//# pragma warning(disable: 4290) // C++ exception specification ignored except to ...
+//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
+# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ...
+//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
+//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated
+#endif
+
+//define logical operators
+#ifdef BOOST_MSVC
+ #include <ciso646>
+#endif
+
+// http://gcc.gnu.org/wiki/Visibility
+// Generic helper definitions for shared library support
+#if defined(BOOST_HAS_DECLSPEC)
+ #define UHD_HELPER_DLL_IMPORT __declspec(dllimport)
+ #define UHD_HELPER_DLL_EXPORT __declspec(dllexport)
+ #define UHD_HELPER_DLL_LOCAL
+#elif defined(__GNUG__) && __GNUG__ >= 4
+ #define UHD_HELPER_DLL_IMPORT __attribute__ ((visibility("default")))
+ #define UHD_HELPER_DLL_EXPORT __attribute__ ((visibility("default")))
+ #define UHD_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden")))
+#else
+ #define UHD_HELPER_DLL_IMPORT
+ #define UHD_HELPER_DLL_EXPORT
+ #define UHD_HELPER_DLL_LOCAL
+#endif
+
+// Now we use the generic helper definitions above to define UHD_API and UHD_LOCAL.
+// UHD_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
+// UHD_LOCAL is used for non-api symbols.
+
+#define UHD_DLL // defined here, put into configuration if we need to make static libs
+
+#ifdef UHD_DLL // defined if UHD is compiled as a DLL
+ #ifdef UHD_DLL_EXPORTS // defined if we are building the UHD DLL (instead of using it)
+ #define UHD_API UHD_HELPER_DLL_EXPORT
+ #else
+ #define UHD_API UHD_HELPER_DLL_IMPORT
+ #endif // UHD_DLL_EXPORTS
+ #define UHD_LOCAL UHD_HELPER_DLL_LOCAL
+#else // UHD_DLL is not defined: this means UHD is a static lib.
+ #define UHD_API
+ #define UHD_LOCAL
+#endif // UHD_DLL
+
+// Define force inline macro
+#ifdef BOOST_MSVC
+ #define UHD_INLINE __forceinline
+#elif defined(__GNUG__) && __GNUG__ >= 4
+ #define UHD_INLINE inline __attribute__((always_inline))
+#else
+ #define UHD_INLINE inline
+#endif
+
+#endif /* INCLUDED_UHD_CONFIG_HPP */
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
new file mode 100644
index 000000000..27b461184
--- /dev/null
+++ b/host/include/uhd/device.hpp
@@ -0,0 +1,181 @@
+//
+// 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_DEVICE_HPP
+#define INCLUDED_UHD_DEVICE_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/wax.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/asio/buffer.hpp>
+
+namespace uhd{
+
+/*!
+ * The usrp device interface represents the usrp hardware.
+ * The api allows for discovery, configuration, and streaming.
+ */
+class UHD_API device : boost::noncopyable, public wax::obj{
+
+public:
+ typedef boost::shared_ptr<device> sptr;
+ typedef boost::function<device_addrs_t(const device_addr_t &)> find_t;
+ typedef boost::function<sptr(const device_addr_t &)> make_t;
+
+ /*!
+ * Register a device into the discovery and factory system.
+ *
+ * \param find a function that discovers devices
+ * \param make a factory function that makes a device
+ */
+ static void register_device(
+ const find_t &find,
+ const make_t &make
+ );
+
+ /*!
+ * \brief Find usrp devices attached to the host.
+ *
+ * The hint device address should be used to narrow down the search
+ * to particular transport types and/or transport arguments.
+ *
+ * \param hint a partially (or fully) filled in device address
+ * \return a vector of device addresses for all usrps on the system
+ */
+ static device_addrs_t find(const device_addr_t &hint);
+
+ /*!
+ * \brief Create a new usrp device from the device address hint.
+ *
+ * The make routine will call find and pick one of the results.
+ * By default, the first result will be used to create a new device.
+ * Use the which parameter as an index into the list of results.
+ *
+ * \param hint a partially (or fully) filled in device address
+ * \param which which address to use when multiple are found
+ * \return a shared pointer to a new device instance
+ */
+ static sptr make(const device_addr_t &hint, size_t which = 0);
+
+ /*!
+ * Send modes for the device send routine.
+ */
+ enum send_mode_t{
+ //! Tells the send routine to send the entire buffer
+ SEND_MODE_FULL_BUFF = 0,
+ //! Tells the send routine to return after one packet
+ SEND_MODE_ONE_PACKET = 1
+ };
+
+ /*!
+ * Recv modes for the device recv routine.
+ */
+ enum recv_mode_t{
+ //! Tells the recv routine to recv the entire buffer
+ RECV_MODE_FULL_BUFF = 0,
+ //! Tells the recv routine to return after one packet
+ RECV_MODE_ONE_PACKET = 1
+ };
+
+ /*!
+ * Send a buffer containing IF data with its metadata.
+ *
+ * Send handles fragmentation as follows:
+ * If the buffer has more samples than the maximum per packet,
+ * the send method will fragment the samples across several packets.
+ * Send will respect the burst flags when fragmenting to ensure
+ * that start of burst can only be set on the first fragment and
+ * that end of burst can only be set on the final fragment.
+ * Fragmentation only applies in the full buffer send mode.
+ *
+ * This is a blocking call and will not return until the number
+ * of samples returned have been read out of the buffer.
+ *
+ * \param buff a buffer pointing to some read-only memory
+ * \param metadata data describing the buffer's contents
+ * \param io_type the type of data loaded in the buffer
+ * \param send_mode tells send how to unload the buffer
+ * \return the number of samples sent
+ */
+ virtual size_t send(
+ const boost::asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
+ const io_type_t &io_type,
+ send_mode_t send_mode = SEND_MODE_ONE_PACKET
+ ) = 0;
+
+ /*!
+ * Receive a buffer containing IF data and its metadata.
+ *
+ * Receive handles fragmentation as follows:
+ * If the buffer has insufficient space to hold all samples
+ * that were received in a single packet over-the-wire,
+ * then the buffer will be completely filled and the implementation
+ * will hold a pointer into the remaining portion of the packet.
+ * Subsequent calls will load from the remainder of the packet,
+ * and will flag the metadata to show that this is a fragment.
+ * The next call to receive, after the remainder becomes exahausted,
+ * will perform an over-the-wire receive as usual.
+ * 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 the 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.
+ *
+ * When using the full buffer recv mode, the metadata only applies
+ * to the first packet received and written into the recv buffer.
+ * Use the one packet recv mode to get per packet metadata.
+ *
+ * \param buff the buffer to fill with IF data
+ * \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
+ * \return the number of samples received
+ */
+ virtual size_t recv(
+ const boost::asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
+ const io_type_t &io_type,
+ recv_mode_t recv_mode = RECV_MODE_ONE_PACKET
+ ) = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on send.
+ * \return the number of samples
+ */
+ virtual size_t get_max_send_samps_per_packet(void) const = 0;
+
+ /*!
+ * Get the maximum number of samples per packet on recv.
+ * \return the number of samples
+ */
+ virtual size_t get_max_recv_samps_per_packet(void) const = 0;
+
+};
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_DEVICE_HPP */
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
new file mode 100644
index 000000000..4cefffa24
--- /dev/null
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# 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/>.
+#
+
+
+INSTALL(FILES
+ convert_types.hpp
+ if_addrs.hpp
+ udp_simple.hpp
+ udp_zero_copy.hpp
+ vrt.hpp
+ zero_copy.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd/transport
+)
diff --git a/host/include/uhd/transport/convert_types.hpp b/host/include/uhd/transport/convert_types.hpp
new file mode 100644
index 000000000..a4d999240
--- /dev/null
+++ b/host/include/uhd/transport/convert_types.hpp
@@ -0,0 +1,59 @@
+//
+// 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_TRANSPORT_CONVERT_TYPES_HPP
+#define INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * Convert IO samples to OWT samples.
+ *
+ * \param io_buff memory containing samples
+ * \param io_type the type of these samples
+ * \param otw_buff memory to write converted samples
+ * \param otw_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+);
+
+/*!
+ * Convert OTW samples to IO samples.
+ *
+ * \param otw_buff memory containing samples
+ * \param otw_type the type of these samples
+ * \param io_buff memory to write converted samples
+ * \param io_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+);
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP */
diff --git a/host/include/uhd/transport/if_addrs.hpp b/host/include/uhd/transport/if_addrs.hpp
new file mode 100644
index 000000000..fbbb35e1d
--- /dev/null
+++ b/host/include/uhd/transport/if_addrs.hpp
@@ -0,0 +1,47 @@
+//
+// 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_IFADDRS_HPP
+#define INCLUDED_UHD_IFADDRS_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+#include <vector>
+
+namespace uhd{ namespace transport{
+
+ /*!
+ * The address for a network interface.
+ */
+ struct UHD_API if_addrs_t{
+ std::string inet;
+ std::string mask;
+ std::string bcast;
+ if_addrs_t(void);
+ };
+
+ /*!
+ * Get a list of network interface addresses.
+ * The internal implementation is system-dependent.
+ * \return a vector of if addrs
+ */
+ UHD_API std::vector<if_addrs_t> get_if_addrs(void);
+
+}} //namespace
+
+
+#endif /* INCLUDED_UHD_IFADDRS_HPP */
diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp
new file mode 100644
index 000000000..793ec4fd7
--- /dev/null
+++ b/host/include/uhd/transport/udp_simple.hpp
@@ -0,0 +1,80 @@
+//
+// 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_TRANSPORT_UDP_SIMPLE_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP
+
+#include <uhd/config.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+class UHD_API udp_simple : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<udp_simple> sptr;
+
+ /*!
+ * Make a new connected udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be control transactions.
+ * The underlying implementation is simple and portable (not fast).
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make_connected(const std::string &addr, const std::string &port);
+
+ /*!
+ * Make a new broadcasting udp transport:
+ * This transport can send udp broadcast datagrams
+ * and receive datagrams from multiple sources.
+ * The primary usage for this transport will be to discover devices.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ */
+ static sptr make_broadcast(const std::string &addr, const std::string &port);
+
+ /*!
+ * Send a single buffer.
+ * Blocks until the data is sent.
+ * \param buff single asio buffer
+ * \return the number of bytes sent
+ */
+ virtual size_t send(const boost::asio::const_buffer &buff) = 0;
+
+ /*!
+ * Receive into the provided buffer.
+ * Blocks until data is received or a timeout occurs.
+ * \param buff a mutable buffer to receive into
+ * \return the number of bytes received or zero on timeout
+ */
+ virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP */
diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp
new file mode 100644
index 000000000..525606a9f
--- /dev/null
+++ b/host/include/uhd/transport/udp_zero_copy.hpp
@@ -0,0 +1,66 @@
+//
+// 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_TRANSPORT_UDP_ZERO_COPY_HPP
+#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A zero copy udp transport provides an efficient way to handle data.
+ * by avoiding the extra copy when recv() or send() is called on the socket.
+ * Rather, the zero copy transport gives the caller memory references.
+ * The caller informs the transport when it is finished with the reference.
+ *
+ * On linux systems, the zero copy transport can use a kernel packet ring.
+ * If no platform specific solution is available, make returns a boost asio
+ * implementation that wraps the functionality around a standard send/recv calls.
+ */
+class UHD_API udp_zero_copy : public zero_copy_if{
+public:
+ typedef boost::shared_ptr<udp_zero_copy> sptr;
+
+ /*!
+ * Make a new zero copy udp transport:
+ * This transport is for sending and receiving
+ * between this host and a single endpoint.
+ * The primary usage for this transport will be data transactions.
+ * The underlying implementation is fast and platform specific.
+ *
+ * The address will be resolved, it can be a host name or ipv4.
+ * The port will be resolved, it can be a port type or number.
+ *
+ * \param addr a string representing the destination address
+ * \param port a string representing the destination port
+ * \param recv_buff_size size in bytes for the recv buffer, 0 for automatic
+ * \param send_buff_size size in bytes for the send buffer, 0 for automatic
+ */
+ static sptr make(
+ const std::string &addr,
+ const std::string &port,
+ size_t recv_buff_size = 0,
+ size_t send_buff_size = 0
+ );
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP */
diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp
new file mode 100644
index 000000000..f2f42f9eb
--- /dev/null
+++ b/host/include/uhd/transport/vrt.hpp
@@ -0,0 +1,75 @@
+//
+// 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_TRANSPORT_VRT_HPP
+#define INCLUDED_UHD_TRANSPORT_VRT_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/metadata.hpp>
+#include <cstddef>
+
+namespace uhd{ namespace transport{
+
+namespace vrt{
+
+ static const size_t max_header_words32 = 5; //hdr+sid+tsi+tsf (no class id supported)
+
+ /*!
+ * Pack a vrt header from metadata.
+ * \param metadata the tx metadata with flags and timestamps
+ * \param header_buff memory to write the packed vrt header
+ * \param num_header_words32 number of words in the vrt header
+ * \param num_payload_words32 the length of the payload
+ * \param num_packet_words32 the length of the packet
+ * \param packet_count the packet count sequence number
+ * \param tick_rate ticks per second used in time conversion
+ */
+ UHD_API void pack(
+ const tx_metadata_t &metadata, //input
+ boost::uint32_t *header_buff, //output
+ size_t &num_header_words32, //output
+ size_t num_payload_words32, //input
+ size_t &num_packet_words32, //output
+ size_t packet_count, //input
+ double tick_rate //input
+ );
+
+ /*!
+ * Unpack a vrt header to metadata.
+ * \param metadata the rx metadata with flags and timestamps
+ * \param header_buff memory to read the packed vrt header
+ * \param num_header_words32 number of words in the vrt header
+ * \param num_payload_words32 the length of the payload
+ * \param num_packet_words32 the length of the packet
+ * \param packet_count the packet count sequence number
+ * \param tick_rate ticks per second used in time conversion
+ */
+ UHD_API void unpack(
+ rx_metadata_t &metadata, //output
+ const boost::uint32_t *header_buff, //input
+ size_t &num_header_words32, //output
+ size_t &num_payload_words32, //output
+ size_t num_packet_words32, //input
+ size_t &packet_count, //output
+ double tick_rate //input
+ );
+
+} //namespace vrt
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
new file mode 100644
index 000000000..fdc5b141c
--- /dev/null
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -0,0 +1,133 @@
+//
+// 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_TRANSPORT_ZERO_COPY_HPP
+#define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP
+
+#include <uhd/config.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A managed receive buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after reading.
+ */
+class UHD_API managed_recv_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<managed_recv_buffer> sptr;
+
+ /*!
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to release the buffer to the transport.
+ * After calling, the referenced memory should be considered invalid.
+ */
+ virtual void done(void) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void) const{
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void) const{
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+private:
+ /*!
+ * Get a reference to the internal const buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio const buffer
+ */
+ virtual const boost::asio::const_buffer &get(void) const = 0;
+};
+
+/*!
+ * A managed send buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after writing.
+ */
+class UHD_API managed_send_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<managed_send_buffer> sptr;
+
+ /*!
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to commit the write to the transport object.
+ * After calling, the referenced memory should be considered invalid.
+ * \param num_bytes the number of bytes written into the buffer
+ */
+ virtual void done(size_t num_bytes) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void) const{
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void) const{
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+private:
+ /*!
+ * Get a reference to the internal mutable buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio mutable buffer
+ */
+ virtual const boost::asio::mutable_buffer &get(void) const = 0;
+};
+
+/*!
+ * A zero-copy interface for transport objects.
+ * Provides a way to get send and receive buffers
+ * with memory managed by the transport object.
+ */
+class UHD_API zero_copy_if : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<zero_copy_if> sptr;
+
+ /*!
+ * Get a new receive buffer from this transport object.
+ */
+ virtual managed_recv_buffer::sptr get_recv_buff(void) = 0;
+
+ /*!
+ * Get a new send buffer from this transport object.
+ */
+ virtual managed_send_buffer::sptr get_send_buff(void) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP */
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
new file mode 100644
index 000000000..dbce21c98
--- /dev/null
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -0,0 +1,33 @@
+#
+# 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/>.
+#
+
+
+INSTALL(FILES
+ clock_config.hpp
+ device_addr.hpp
+ dict.hpp
+ io_type.hpp
+ mac_addr.hpp
+ metadata.hpp
+ otw_type.hpp
+ ranges.hpp
+ serial.hpp
+ stream_cmd.hpp
+ time_spec.hpp
+ tune_result.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd/types
+)
diff --git a/host/include/uhd/types/clock_config.hpp b/host/include/uhd/types/clock_config.hpp
new file mode 100644
index 000000000..9342fbb7b
--- /dev/null
+++ b/host/include/uhd/types/clock_config.hpp
@@ -0,0 +1,51 @@
+//
+// 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_TYPES_CLOCK_CONFIG_HPP
+#define INCLUDED_UHD_TYPES_CLOCK_CONFIG_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * Clock configuration settings:
+ * The source for the 10MHz reference clock.
+ * The source and polarity for the PPS clock.
+ */
+ struct UHD_API clock_config_t{
+ enum ref_source_t {
+ REF_AUTO = 'a', //automatic (device specific)
+ REF_INT = 'i', //internal reference
+ REF_SMA = 's', //external sma port
+ REF_MIMO = 'm' //mimo cable (usrp2 only)
+ } ref_source;
+ enum pps_source_t {
+ PPS_INT = 'i', //there is no internal
+ PPS_SMA = 's', //external sma port
+ PPS_MIMO = 'm' //mimo cable (usrp2 only)
+ } pps_source;
+ enum pps_polarity_t {
+ PPS_NEG = 'n', //negative edge
+ PPS_POS = 'p' //positive edge
+ } pps_polarity;
+ clock_config_t(void);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_CLOCK_CONFIG_HPP */
diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp
new file mode 100644
index 000000000..e359d9467
--- /dev/null
+++ b/host/include/uhd/types/device_addr.hpp
@@ -0,0 +1,72 @@
+//
+// 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_TYPES_DEVICE_ADDR_HPP
+#define INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/dict.hpp>
+#include <vector>
+#include <string>
+
+namespace uhd{
+
+ /*!
+ * Mapping of key/value pairs for locating devices on the system.
+ * When left empty, the device discovery routines will search
+ * all available transports on the system (ethernet, usb...).
+ *
+ * To narrow down the discovery process to a particular device,
+ * specify a transport key/value pair specific to your device.
+ * - Ex, to find a usrp2: my_dev_addr["addr"] = [resolvable_hostname_or_ip]
+ *
+ * The device address can also be used to pass arguments into
+ * the transport layer control to set (for example) buffer sizes.
+ *
+ * An arguments string, is a way to represent a device address
+ * using a single string with delimiter characters.
+ * - Ex: addr=192.168.10.2
+ * - Ex: addr=192.168.10.2, recv_buff_size=1e6
+ */
+ class UHD_API device_addr_t : public dict<std::string, std::string>{
+ public:
+ /*!
+ * Create a device address from an args string.
+ * \param args the arguments string
+ */
+ device_addr_t(const std::string &args = "");
+
+ /*!
+ * Convert a device address into a pretty print string.
+ * \return a printable string representing the device address
+ */
+ std::string to_pp_string(void) const;
+
+ /*!
+ * Convert the device address into an args string.
+ * The args string contains delimiter symbols.
+ * \return a string with delimiter markup
+ */
+ std::string to_string(void) const;
+ };
+
+ //handy typedef for a vector of device addresses
+ typedef std::vector<device_addr_t> device_addrs_t;
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_DEVICE_ADDR_HPP */
diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp
new file mode 100644
index 000000000..b5fb11120
--- /dev/null
+++ b/host/include/uhd/types/dict.hpp
@@ -0,0 +1,155 @@
+//
+// 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_TYPES_DICT_HPP
+#define INCLUDED_UHD_TYPES_DICT_HPP
+
+#include <uhd/config.hpp>
+#include <boost/foreach.hpp>
+#include <stdexcept>
+#include <vector>
+#include <list>
+
+namespace uhd{
+
+ /*!
+ * A templated dictionary class with a python-like interface.
+ */
+ template <typename Key, typename Val> class dict{
+ public:
+ typedef std::pair<Key, Val> pair_t;
+
+ /*!
+ * Create a new empty dictionary.
+ */
+ dict(void){
+ /* NOP */
+ }
+
+ /*!
+ * Input iterator constructor:
+ * Makes boost::assign::map_list_of work.
+ * \param first the begin iterator
+ * \param last the end iterator
+ */
+ template <class InputIterator>
+ dict(InputIterator first, InputIterator last){
+ for(InputIterator it = first; it != last; it++){
+ _map.push_back(*it);
+ }
+ }
+
+ /*!
+ * Destroy this dict.
+ */
+ ~dict(void){
+ /* NOP */
+ }
+
+ /*!
+ * Get the number of elements in this dict.
+ * \return the number of elements
+ */
+ std::size_t size(void) const{
+ return _map.size();
+ }
+
+ /*!
+ * Get a list of the keys in this dict.
+ * Key order depends on insertion precedence.
+ * \return vector of keys
+ */
+ const std::vector<Key> keys(void) const{
+ std::vector<Key> keys;
+ BOOST_FOREACH(const pair_t &p, _map){
+ keys.push_back(p.first);
+ }
+ return keys;
+ }
+
+ /*!
+ * Get a list of the values in this dict.
+ * Value order depends on insertion precedence.
+ * \return vector of values
+ */
+ const std::vector<Val> vals(void) const{
+ std::vector<Val> vals;
+ BOOST_FOREACH(const pair_t &p, _map){
+ vals.push_back(p.second);
+ }
+ return vals;
+ }
+
+ /*!
+ * Does the dictionary contain this key?
+ * \param key the key to look for
+ * \return true if found
+ */
+ bool has_key(const Key &key) const{
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return true;
+ }
+ return false;
+ }
+
+ /*!
+ * Get a value for the given key if it exists.
+ * If the key is not found throw an error.
+ * \param key the key to look for
+ * \return the value at the key
+ * \throw an exception when not found
+ */
+ const Val &operator[](const Key &key) const{
+ BOOST_FOREACH(const pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ throw std::invalid_argument("key not found in dict");
+ }
+
+ /*!
+ * Set a value for the given key, however, in reality
+ * it really returns a reference which can be assigned to.
+ * \param key the key to set to
+ * \return a reference to the value
+ */
+ Val &operator[](const Key &key){
+ BOOST_FOREACH(pair_t &p, _map){
+ if (p.first == key) return p.second;
+ }
+ _map.push_back(std::make_pair(key, Val()));
+ return _map.back().second;
+ }
+
+ /*!
+ * Pop an item out of the dictionary.
+ * \param key the item key
+ * \return the value of the item
+ * \throw an exception when not found
+ */
+ Val pop(const Key &key){
+ Val val = (*this)[key];
+ _map.remove(pair_t(key, val));
+ return val;
+ }
+
+ private:
+ std::list<pair_t> _map; //private container
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_DICT_HPP */
diff --git a/host/include/uhd/types/io_type.hpp b/host/include/uhd/types/io_type.hpp
new file mode 100644
index 000000000..5176374d6
--- /dev/null
+++ b/host/include/uhd/types/io_type.hpp
@@ -0,0 +1,70 @@
+//
+// 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_TYPES_IO_TYPE_HPP
+#define INCLUDED_UHD_TYPES_IO_TYPE_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * The Input/Output configuration struct:
+ * Used to specify the IO type with device send/recv.
+ */
+ class UHD_API io_type_t{
+ public:
+
+ /*!
+ * Built in IO types known to the system.
+ */
+ enum tid_t{
+ CUSTOM_TYPE = '?',
+ COMPLEX_FLOAT32 = 'f',
+ COMPLEX_INT16 = 's',
+ COMPLEX_INT8 = 'b'
+ };
+
+ /*!
+ * The size of this io type in bytes.
+ */
+ const size_t size;
+
+ /*!
+ * The type id of this io type.
+ * Good for using with switch statements.
+ */
+ const tid_t tid;
+
+ /*!
+ * Create an io type from a built-in type id.
+ * \param tid a type id known to the system
+ */
+ io_type_t(tid_t tid);
+
+ /*!
+ * Create an io type from attributes.
+ * The tid will be set to custom.
+ * \param size the size in bytes
+ */
+ io_type_t(size_t size);
+
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_IO_TYPE_HPP */
diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp
new file mode 100644
index 000000000..0ced2e734
--- /dev/null
+++ b/host/include/uhd/types/mac_addr.hpp
@@ -0,0 +1,66 @@
+//
+// 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_TYPES_MAC_ADDR_HPP
+#define INCLUDED_UHD_TYPES_MAC_ADDR_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <string>
+
+namespace uhd{
+
+ /*!
+ * Wrapper for an ethernet mac address.
+ * Provides conversion between string and binary formats.
+ */
+ class UHD_API mac_addr_t{
+ public:
+ /*!
+ * Create a mac address a byte array.
+ * \param bytes a vector of bytes
+ * \return a new mac address
+ */
+ static mac_addr_t from_bytes(const byte_vector_t &bytes);
+
+ /*!
+ * Create a mac address from a string.
+ * \param mac_addr_str the string with delimiters
+ * \return a new mac address
+ */
+ static mac_addr_t from_string(const std::string &mac_addr_str);
+
+ /*!
+ * Get the byte representation of the mac address.
+ * \return a vector of bytes
+ */
+ byte_vector_t to_bytes(void) const;
+
+ /*!
+ * Get the string representation of this mac address.
+ * \return a string with delimiters
+ */
+ std::string to_string(void) const;
+
+ private:
+ mac_addr_t(const byte_vector_t &bytes); //private constructor
+ const byte_vector_t _bytes; //internal representation
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_MAC_ADDR_HPP */
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
new file mode 100644
index 000000000..55add71cc
--- /dev/null
+++ b/host/include/uhd/types/metadata.hpp
@@ -0,0 +1,118 @@
+//
+// 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_TYPES_METADATA_HPP
+#define INCLUDED_UHD_TYPES_METADATA_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <uhd/types/time_spec.hpp>
+
+namespace uhd{
+
+ /*!
+ * RX metadata structure for describing sent IF data.
+ * Includes stream ID, time specification, and fragmentation flags.
+ * The receive routines will convert IF data headers into metadata.
+ */
+ struct UHD_API rx_metadata_t{
+ /*!
+ * Stream IDs may be used to identify source DSP units.
+ * --Not currently used in any known device implementation.--
+ */
+ bool has_stream_id;
+ boost::uint32_t stream_id;
+
+ /*!
+ * Time specification:
+ * Set from timestamps on incoming data when provided.
+ */
+ bool has_time_spec;
+ time_spec_t time_spec;
+
+ /*!
+ * Fragmentation flag and offset:
+ * Similar to IPv4 fragmentation: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly
+ * More fragments is true when the input buffer has insufficient size to fit
+ * an entire received packet. More fragments will be false for the last fragment.
+ * The fragment offset is the sample number at the start of the receive buffer.
+ * For non-fragmented receives, the fragment offset should always be zero.
+ */
+ bool more_fragments;
+ size_t fragment_offset;
+
+ /*!
+ * Burst flags:
+ * Start of burst will be true for the first packet in the chain.
+ * End of burst will be true for the last packet in the chain.
+ * --Not currently used in any known device implementation.--
+ */
+ //bool start_of_burst;
+ //bool end_of_burst;
+
+ /*!
+ * Error conditions (TODO):
+ * Previous packets dropped?
+ * Timed-out on receive?
+ */
+
+ /*!
+ * 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.
+ * The send routines will convert the metadata to IF data headers.
+ */
+ struct UHD_API tx_metadata_t{
+ /*!
+ * Stream IDs may be used to identify destination DSP units.
+ * --Not currently used in any known device implementation.--
+ */
+ bool has_stream_id;
+ boost::uint32_t stream_id;
+
+ /*!
+ * Time specification:
+ * Set has time spec to false to perform a send "now".
+ * Or, set to true, and fill in time spec for a send "at".
+ */
+ bool has_time_spec;
+ time_spec_t time_spec;
+
+ /*!
+ * Burst flags:
+ * Set start of burst to true for the first packet in the chain.
+ * Set end of burst to true for the last packet in the chain.
+ */
+ bool start_of_burst;
+ bool end_of_burst;
+
+ /*!
+ * The default constructor:
+ * Sets the fields to default values (flags set to false).
+ */
+ tx_metadata_t(void);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_METADATA_HPP */
diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp
new file mode 100644
index 000000000..8e3e65d78
--- /dev/null
+++ b/host/include/uhd/types/otw_type.hpp
@@ -0,0 +1,69 @@
+//
+// 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_TYPES_OTW_TYPE_HPP
+#define INCLUDED_UHD_TYPES_OTW_TYPE_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * Description for over-the-wire integers:
+ * The DSP units in the FPGA deal with signed 16-bit integers.
+ * The width and shift define the translation between OTW and DSP,
+ * defined by the following relation: otw_int = dsp_int >> shift
+ *
+ * Note: possible combinations of width, shift, and byteorder
+ * depend on the internals of the FPGA. Not all are supported!
+ */
+ struct UHD_API otw_type_t{
+
+ /*!
+ * Width of an over-the-wire integer in bits.
+ */
+ size_t width; //in bits
+
+ /*!
+ * Shift of an over-the-wire integer in bits.
+ * otw_int = dsp_int >> shift
+ * dsp_int = otw_int << shift
+ */
+ size_t shift; //in bits
+
+ /*!
+ * Constants for byte order (borrowed from numpy's dtype)
+ */
+ enum /*bo_t*/ {
+ BO_NATIVE = '=',
+ BO_LITTLE_ENDIAN = '<',
+ BO_BIG_ENDIAN = '>',
+ BO_NOT_APPLICABLE = '|'
+ } byteorder;
+
+ /*!
+ * Get the sample size of this otw type.
+ * \return the size of a sample in bytes
+ */
+ size_t get_sample_size(void) const;
+
+ otw_type_t(void);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_OTW_TYPE_HPP */
diff --git a/host/include/uhd/types/ranges.hpp b/host/include/uhd/types/ranges.hpp
new file mode 100644
index 000000000..a2057d1c8
--- /dev/null
+++ b/host/include/uhd/types/ranges.hpp
@@ -0,0 +1,46 @@
+//
+// 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_TYPES_RANGES_HPP
+#define INCLUDED_UHD_TYPES_RANGES_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * The gain range struct describes possible gain settings.
+ * The mimumum gain, maximum gain, and step size are in dB.
+ */
+ struct UHD_API gain_range_t{
+ float min, max, step;
+ gain_range_t(float min = 0.0, float max = 0.0, float step = 0.0);
+ };
+
+ /*!
+ * The frequency range struct describes possible frequency settings.
+ * Because tuning is very granular (sub-Hz), step size is not listed.
+ * The mimumum frequency and maximum frequency are in Hz.
+ */
+ struct UHD_API freq_range_t{
+ double min, max;
+ freq_range_t(double min = 0.0, double max = 0.0);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_RANGES_HPP */
diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp
new file mode 100644
index 000000000..c134725f5
--- /dev/null
+++ b/host/include/uhd/types/serial.hpp
@@ -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/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_SERIAL_HPP
+#define INCLUDED_UHD_TYPES_SERIAL_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <vector>
+
+namespace uhd{
+
+ /*!
+ * Byte vector typedef for passing data in and out of I2C interfaces.
+ */
+ typedef std::vector<boost::uint8_t> byte_vector_t;
+
+ /*!
+ * The i2c interface class:
+ * Provides i2c and eeprom functionality.
+ * A subclass should only have to implement the i2c routines.
+ * An eeprom implementation comes for free with the interface.
+ *
+ * The eeprom routines are implemented on top of i2c.
+ * The built in eeprom implementation only does single
+ * byte reads and byte writes over the i2c interface,
+ * so it should be portable across multiple eeproms.
+ * Override the eeprom routines if this is not acceptable.
+ */
+ class UHD_API i2c_iface{
+ public:
+ /*!
+ * Write bytes over the i2c.
+ * \param addr the address
+ * \param buf the vector of bytes
+ */
+ virtual void write_i2c(
+ boost::uint8_t addr,
+ const byte_vector_t &buf
+ ) = 0;
+
+ /*!
+ * Read bytes over the i2c.
+ * \param addr the address
+ * \param num_bytes number of bytes to read
+ * \return a vector of bytes
+ */
+ virtual byte_vector_t read_i2c(
+ boost::uint8_t addr,
+ size_t num_bytes
+ ) = 0;
+
+ /*!
+ * Write bytes to an eeprom.
+ * \param addr the address
+ * \param offset byte offset
+ * \param buf the vector of bytes
+ */
+ virtual void write_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ const byte_vector_t &buf
+ );
+
+ /*!
+ * Read bytes from an eeprom.
+ * \param addr the address
+ * \param offset byte offset
+ * \param num_bytes number of bytes to read
+ * \return a vector of bytes
+ */
+ virtual byte_vector_t read_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ size_t num_bytes
+ );
+ };
+
+ /*!
+ * The SPI configuration struct:
+ * Used to configure a SPI transaction interface.
+ */
+ struct UHD_API spi_config_t{
+ /*!
+ * The edge type specifies when data is valid
+ * relative to the edge of the serial clock.
+ */
+ enum edge_t{
+ EDGE_RISE = 'r',
+ EDGE_FALL = 'f'
+ };
+
+ //! on what edge is the mosi data valid?
+ edge_t mosi_edge;
+
+ //! on what edge is the miso data valid?
+ edge_t miso_edge;
+
+ /*!
+ * Create a new spi config.
+ * \param edge the default edge for mosi and miso
+ */
+ spi_config_t(edge_t edge = EDGE_RISE);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_SERIAL_HPP */
diff --git a/host/include/uhd/types/stream_cmd.hpp b/host/include/uhd/types/stream_cmd.hpp
new file mode 100644
index 000000000..41708e2e2
--- /dev/null
+++ b/host/include/uhd/types/stream_cmd.hpp
@@ -0,0 +1,64 @@
+//
+// 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_TYPES_STREAM_CMD_HPP
+#define INCLUDED_UHD_TYPES_STREAM_CMD_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/time_spec.hpp>
+
+namespace uhd{
+
+ /*!
+ * Command struct for configuration and control of streaming:
+ *
+ * A stream command defines how the device sends samples to the host.
+ * Streaming is controlled by submitting a stream command to the rx dsp.
+ * Granular control over what the device streams to the host can be
+ * achieved through submission of multiple (carefully-crafted) commands.
+ *
+ * The mode parameter controls how streaming is issued to the device:
+ * - "Start continuous" tells the device to stream samples indefinitely.
+ * - "Stop continuous" tells the device to end continuous streaming.
+ * - "Num samps and done" tells the device to stream num samps and
+ * to not expect a future stream command for contiguous samples.
+ * - "Num samps and more" tells the device to stream num samps and
+ * to expect a future stream command for contiguous samples.
+ *
+ * The stream now parameter controls when the stream begins.
+ * When true, the device will begin streaming ASAP. When false,
+ * the device will begin streaming at a time specified by time_spec.
+ */
+ struct UHD_API stream_cmd_t{
+
+ enum stream_mode_t {
+ STREAM_MODE_START_CONTINUOUS = 'a',
+ STREAM_MODE_STOP_CONTINUOUS = 'o',
+ STREAM_MODE_NUM_SAMPS_AND_DONE = 'd',
+ STREAM_MODE_NUM_SAMPS_AND_MORE = 'm'
+ } stream_mode;
+ size_t num_samps;
+
+ bool stream_now;
+ time_spec_t time_spec;
+
+ stream_cmd_t(const stream_mode_t &stream_mode);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_STREAM_CMD_HPP */
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
new file mode 100644
index 000000000..25d9e41d0
--- /dev/null
+++ b/host/include/uhd/types/time_spec.hpp
@@ -0,0 +1,76 @@
+//
+// 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_TYPES_TIME_SPEC_HPP
+#define INCLUDED_UHD_TYPES_TIME_SPEC_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+
+namespace uhd{
+
+ /*!
+ * A time_spec_t holds a seconds and fractional seconds time value.
+ * The time_spec_t can be used when setting the time on devices,
+ * and for dealing with time stamped samples though the metadata.
+ * and for controlling the start of streaming for applicable dsps.
+ *
+ * The fractional seconds are represented in units of nanoseconds,
+ * which provide a clock-domain independent unit of time storage.
+ * The methods "get_ticks" and "set_ticks" can be used to convert
+ * the fractional seconds to and from clock-domain specific units.
+ *
+ * The nanoseconds count is stored as double precision floating point.
+ * This gives the fractional seconds enough precision to unambiguously
+ * specify a clock-tick/sample-count up to rates of several petahertz.
+ */
+ struct UHD_API time_spec_t{
+
+ //! whole/integer seconds count in seconds
+ boost::uint32_t secs;
+
+ //! fractional seconds count in nano-seconds
+ double nsecs;
+
+ /*!
+ * Convert the fractional nsecs to clock ticks.
+ * Translation into clock-domain specific units.
+ * \param tick_rate the number of ticks per second
+ * \return the fractional seconds tick count
+ */
+ boost::uint32_t get_ticks(double tick_rate) const;
+
+ /*!
+ * Set the fractional nsecs from clock ticks.
+ * Translation from clock-domain specific units.
+ * \param ticks the fractional seconds tick count
+ * \param tick_rate the number of ticks per second
+ */
+ void set_ticks(boost::uint32_t ticks, double tick_rate);
+
+ /*!
+ * Create a time_spec_t from whole and fractional seconds.
+ * \param secs the whole/integer seconds count in seconds (default = 0)
+ * \param nsecs the fractional seconds count in nanoseconds (default = 0)
+ */
+ time_spec_t(boost::uint32_t secs = 0, double nsecs = 0);
+
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */
diff --git a/host/include/uhd/types/tune_result.hpp b/host/include/uhd/types/tune_result.hpp
new file mode 100644
index 000000000..c428a7692
--- /dev/null
+++ b/host/include/uhd/types/tune_result.hpp
@@ -0,0 +1,44 @@
+//
+// 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_TYPES_TUNE_RESULT_HPP
+#define INCLUDED_UHD_TYPES_TUNE_RESULT_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ /*!
+ * The tune result struct holds result of a 2-phase tuning:
+ * The struct hold the result of tuning the dboard as
+ * 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);
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_TUNE_RESULT_HPP */
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
new file mode 100644
index 000000000..bbd124ed8
--- /dev/null
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -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/>.
+#
+
+
+INSTALL(FILES
+ #### props headers ###
+ dboard_props.hpp
+ device_props.hpp
+ dsp_props.hpp
+ mboard_props.hpp
+ subdev_props.hpp
+
+ #### dboard headers ###
+ dboard_base.hpp
+ dboard_eeprom.hpp
+ dboard_id.hpp
+ dboard_iface.hpp
+ dboard_manager.hpp
+
+ ### usrp headers ###
+ usrp2.hpp
+
+ ### utilities ###
+ tune_helper.hpp
+ simple_usrp.hpp
+
+ DESTINATION ${INCLUDE_DIR}/uhd/usrp
+)
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
new file mode 100644
index 000000000..28bf2ae66
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -0,0 +1,117 @@
+//
+// 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_DBOARD_BASE_HPP
+#define INCLUDED_UHD_USRP_DBOARD_BASE_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/dboard_iface.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * A daughter board dboard_base class for all dboards.
+ * Only other dboard dboard_base classes should inherit this.
+ */
+class UHD_API dboard_base : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<dboard_base> sptr;
+ /*!
+ * An opaque type for the dboard constructor args.
+ * 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;
+
+ //structors
+ dboard_base(ctor_args_t);
+ virtual ~dboard_base(void);
+
+ //interface
+ virtual void rx_get(const wax::obj &key, wax::obj &val) = 0;
+ virtual void rx_set(const wax::obj &key, const wax::obj &val) = 0;
+ virtual void tx_get(const wax::obj &key, wax::obj &val) = 0;
+ virtual void tx_set(const wax::obj &key, const wax::obj &val) = 0;
+
+protected:
+ std::string get_subdev_name(void);
+ dboard_iface::sptr get_iface(void);
+ dboard_id_t get_rx_id(void);
+ dboard_id_t get_tx_id(void);
+
+private:
+ struct dboard_base_impl;
+ dboard_base_impl *_impl;
+};
+
+/*!
+ * A xcvr daughter board implements rx and tx methods
+ * Sub classes for xcvr boards should inherit this.
+ */
+class UHD_API xcvr_dboard_base : public dboard_base{
+public:
+ /*!
+ * Create a new xcvr dboard object, override in subclasses.
+ */
+ xcvr_dboard_base(ctor_args_t);
+
+ virtual ~xcvr_dboard_base(void);
+};
+
+/*!
+ * A rx daughter board only implements rx methods.
+ * Sub classes for rx-only boards should inherit this.
+ */
+class UHD_API rx_dboard_base : public dboard_base{
+public:
+ /*!
+ * Create a new rx dboard object, override in subclasses.
+ */
+ rx_dboard_base(ctor_args_t);
+
+ virtual ~rx_dboard_base(void);
+
+ //override here so the derived classes cannot
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+};
+
+/*!
+ * A tx daughter board only implements tx methods.
+ * Sub classes for rx-only boards should inherit this.
+ */
+class UHD_API tx_dboard_base : public dboard_base{
+public:
+ /*!
+ * Create a new rx dboard object, override in subclasses.
+ */
+ tx_dboard_base(ctor_args_t);
+
+ virtual ~tx_dboard_base(void);
+
+ //override here so the derived classes cannot
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_BASE_HPP */
diff --git a/host/include/uhd/usrp/dboard_eeprom.hpp b/host/include/uhd/usrp/dboard_eeprom.hpp
new file mode 100644
index 000000000..108027b46
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_eeprom.hpp
@@ -0,0 +1,60 @@
+//
+// 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_DBOARD_EEPROM_HPP
+#define INCLUDED_UHD_USRP_DBOARD_EEPROM_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/types/serial.hpp>
+#include <string>
+
+namespace uhd{ namespace usrp{
+
+struct UHD_API dboard_eeprom_t{
+ /*!
+ * The dboard id that was read from eeprom or will be set to eeprom.
+ */
+ dboard_id_t id;
+
+ /*!
+ * Create a dboard eeprom struct from the bytes read out of eeprom.
+ * The constructor will parse out the dboard id from a vector of bytes.
+ * To be valid, the bytes vector should be at least num_bytes() long.
+ * If the parsing fails due to bad checksum or incomplete length,
+ * the dboard id in this struct will be set to dboard_id::NONE.
+ * \param bytes the vector of bytes
+ */
+ dboard_eeprom_t(const uhd::byte_vector_t &bytes = uhd::byte_vector_t(0));
+
+ /*!
+ * Get the bytes that would be written to dboard eeprom.
+ * \return a vector of bytes
+ */
+ uhd::byte_vector_t get_eeprom_bytes(void);
+
+ /*!
+ * Get the number of bytes in the dboard eeprom segment.
+ * Use this value when reading out of the dboard eeprom.
+ * \return the number of bytes used by dboard eeprom
+ */
+ static size_t num_bytes(void);
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_EEPROM_HPP */
diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp
new file mode 100644
index 000000000..8b6eaf6bd
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_id.hpp
@@ -0,0 +1,90 @@
+//
+// 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_DBOARD_ID_HPP
+#define INCLUDED_UHD_USRP_DBOARD_ID_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/operators.hpp>
+#include <string>
+
+namespace uhd{ namespace usrp{
+
+ class UHD_API dboard_id_t : boost::equality_comparable1<dboard_id_t>{
+ public:
+ /*!
+ * Create a dboard id from an integer.
+ * \param id the integer representation
+ */
+ dboard_id_t(boost::uint16_t id = 0xffff);
+
+ /*!
+ * Obtain a dboard id that represents no dboard.
+ * \return the dboard id with the 0xffff id.
+ */
+ static dboard_id_t none(void);
+
+ /*!
+ * Create a new dboard id from an integer representation.
+ * \param uint16 an unsigned 16 bit integer
+ * \return a new dboard id containing the integer
+ */
+ static dboard_id_t from_uint16(boost::uint16_t uint16);
+
+ /*!
+ * Get the dboard id represented as an integer.
+ * \return an unsigned 16 bit integer representation
+ */
+ boost::uint16_t to_uint16(void) const;
+
+ /*!
+ * Create a new dboard id from a string representation.
+ * If the string has a 0x prefix, it will be parsed as hex.
+ * \param string a numeric string, possibly hex
+ * \return a new dboard id containing the integer
+ */
+ static dboard_id_t from_string(const std::string &string);
+
+ /*!
+ * Get the dboard id represented as an integer.
+ * \return a hex string representation with 0x prefix
+ */
+ std::string to_string(void) const;
+
+ /*!
+ * Get the pretty print representation of this dboard id.
+ * \return a string with the dboard name and id number
+ */
+ std::string to_pp_string(void) const;
+
+ private:
+ boost::uint16_t _id; //internal representation
+ };
+
+ /*!
+ * Comparator operator overloaded for dboard ids.
+ * The boost::equality_comparable provides the !=.
+ * \param lhs the dboard id to the left of the operator
+ * \param rhs the dboard id to the right of the operator
+ * \return true when the dboard ids are equal
+ */
+ UHD_API bool operator==(const dboard_id_t &lhs, const dboard_id_t &rhs);
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_ID_HPP */
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
new file mode 100644
index 000000000..1214a1a2f
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -0,0 +1,162 @@
+//
+// 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_DBOARD_IFACE_HPP
+#define INCLUDED_UHD_USRP_DBOARD_IFACE_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The daughter board dboard interface to be subclassed.
+ * A dboard instance interfaces with the mboard though this api.
+ * This interface provides i2c, spi, gpio, atr, aux dac/adc access.
+ * Each mboard should have a specially tailored iface for its dboard.
+ */
+class UHD_API dboard_iface{
+public:
+ typedef boost::shared_ptr<dboard_iface> sptr;
+
+ //tells the host which unit to use
+ enum unit_t{
+ UNIT_RX = 'r',
+ UNIT_TX = 't'
+ };
+
+ //possible atr registers
+ enum atr_reg_t{
+ ATR_REG_IDLE = 'i',
+ ATR_REG_TX_ONLY = 't',
+ ATR_REG_RX_ONLY = 'r',
+ ATR_REG_FULL_DUPLEX = 'f'
+ };
+
+ /*!
+ * Write to an aux dac.
+ *
+ * \param unit which unit rx or tx
+ * \param which_dac the dac index 0, 1, 2, 3...
+ * \param value the value in volts
+ */
+ virtual void write_aux_dac(unit_t unit, int which_dac, float value) = 0;
+
+ /*!
+ * Read from an aux adc.
+ *
+ * \param unit which unit rx or tx
+ * \param which_adc the adc index 0, 1, 2, 3...
+ * \return the value in volts
+ */
+ virtual float read_aux_adc(unit_t unit, int which_adc) = 0;
+
+ /*!
+ * Set a daughterboard ATR register.
+ *
+ * \param unit which unit rx or tx
+ * \param reg which ATR register to set
+ * \param value 16-bits, 0=FPGA output low, 1=FPGA output high
+ */
+ virtual void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0;
+
+ /*!
+ * Set daughterboard GPIO data direction register.
+ *
+ * \param unit which unit rx or tx
+ * \param value 16-bits, 0=FPGA input, 1=FPGA output
+ */
+ virtual void set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0;
+
+ /*!
+ * Read daughterboard GPIO pin values.
+ *
+ * \param unit which unit rx or tx
+ * \return the value of the gpio unit
+ */
+ virtual boost::uint16_t read_gpio(unit_t unit) = 0;
+
+ /*!
+ * Write to an I2C peripheral.
+ *
+ * \param addr I2C bus address (7-bits)
+ * \param bytes the data to write
+ */
+ virtual void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) = 0;
+
+ /*!
+ * Read from an I2C peripheral.
+ *
+ * \param addr I2C bus address (7-bits)
+ * \param num_bytes number of bytes to read
+ * \return the data read if successful, else a zero length string.
+ */
+ virtual byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) = 0;
+
+ /*!
+ * Write data to SPI bus peripheral.
+ *
+ * \param unit which unit, rx or tx
+ * \param config configuration settings
+ * \param data the bits to write LSB first
+ * \param num_bits the number of bits in data
+ */
+ virtual void write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ ) = 0;
+
+ /*!
+ * Read and write data to SPI bus peripheral.
+ *
+ * \param unit which unit, rx or tx
+ * \param config configuration settings
+ * \param data the bits to write LSB first
+ * \param num_bits the number of bits in data
+ * \return the data that was read
+ */
+ virtual boost::uint32_t read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ ) = 0;
+
+ /*!
+ * Get the rate of a dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \return the clock rate in Hz
+ */
+ virtual double get_clock_rate(unit_t unit) = 0;
+
+ /*!
+ * Enable or disable a dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \param enb true for enabled
+ */
+ virtual void set_clock_enabled(unit_t unit, bool enb) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_IFACE_HPP */
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
new file mode 100644
index 000000000..b84fee4e7
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -0,0 +1,79 @@
+//
+// 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_DBOARD_MANAGER_HPP
+#define INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/utils/props.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * A daughter board subdev dboard_manager class.
+ * Create subdev instances for each subdev on a dboard.
+ * Provide wax::obj access to the subdevs inside.
+ */
+class UHD_API dboard_manager : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<dboard_manager> sptr;
+
+ //dboard constructor (each dboard should have a ::make with this signature)
+ typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t);
+
+ /*!
+ * Register a dboard into the system.
+ * For single subdevice boards, omit subdev_names.
+ * \param dboard_id the dboard id (rx or tx)
+ * \param dboard_ctor the dboard constructor function pointer
+ * \param name the canonical name for the dboard represented
+ * \param subdev_names the names of the subdevs on this dboard
+ */
+ static void register_dboard(
+ dboard_id_t dboard_id,
+ dboard_ctor_t dboard_ctor,
+ const std::string &name,
+ const prop_names_t &subdev_names = prop_names_t(1, "")
+ );
+
+ /*!
+ * Make a new dboard manager.
+ * \param rx_dboard_id the id of the rx dboard
+ * \param tx_dboard_id the id of the tx dboard
+ * \param iface the custom dboard interface
+ * \return an sptr to the new dboard manager
+ */
+ static sptr make(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_iface::sptr iface
+ );
+
+ //dboard manager interface
+ virtual prop_names_t get_rx_subdev_names(void) = 0;
+ virtual prop_names_t get_tx_subdev_names(void) = 0;
+ virtual wax::obj get_rx_subdev(const std::string &subdev_name) = 0;
+ virtual wax::obj get_tx_subdev(const std::string &subdev_name) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP */
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
new file mode 100644
index 000000000..0208a6c2c
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_props.hpp
@@ -0,0 +1,39 @@
+//
+// 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_DBOARD_PROPS_HPP
+#define INCLUDED_UHD_USRP_DBOARD_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device dboard properties
+ */
+ 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_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_PROPS_HPP */
diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp
new file mode 100644
index 000000000..983bcb672
--- /dev/null
+++ b/host/include/uhd/usrp/device_props.hpp
@@ -0,0 +1,55 @@
+//
+// 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_DEVICE_PROPS_HPP
+#define INCLUDED_UHD_USRP_DEVICE_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device properties:
+ * In general, a device will have a single mboard.
+ * In certain mimo applications, multiple boards
+ * will be present in the interface for configuration.
+ */
+ enum device_prop_t{
+ DEVICE_PROP_NAME = 'n', //ro, std::string
+ DEVICE_PROP_MBOARD = 'm', //ro, wax::obj
+ 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/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp
new file mode 100644
index 000000000..75d8c0a60
--- /dev/null
+++ b/host/include/uhd/usrp/dsp_props.hpp
@@ -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/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_DSP_PROPS_HPP
+#define INCLUDED_UHD_USRP_DSP_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device dsp properties:
+ * A dsp is a black box fpga component found between
+ * the over-the-wire data and the codec pins.
+ *
+ * The host rate can be modified to control resampling.
+ * Resampling can take the form of decimation, interpolation,
+ * or more complex fractional resampling techniques.
+ * As usual, read back the host rate after setting it
+ * to get the actual rate that was set (implementation dependent).
+ *
+ * A dsp can also shift the digital stream in frequency.
+ * Set the shift property and read it back to get actual shift.
+ */
+ enum dsp_prop_t{
+ DSP_PROP_NAME = 'n', //ro, std::string
+ DSP_PROP_OTHERS = 'o', //ro, prop_names_t
+ DSP_PROP_FREQ_SHIFT = 'f', //rw, double Hz
+ DSP_PROP_CODEC_RATE = 'c', //ro, double Sps
+ DSP_PROP_HOST_RATE = 'h' //rw, double Sps
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DSP_PROPS_HPP */
diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp
new file mode 100644
index 000000000..7ff454472
--- /dev/null
+++ b/host/include/uhd/usrp/mboard_props.hpp
@@ -0,0 +1,50 @@
+//
+// 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_MBOARD_PROPS_HPP
+#define INCLUDED_UHD_USRP_MBOARD_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device mboard properties:
+ * The general mboard properties are listed below.
+ * Custom properties can be identified with a string
+ * and discovered though the others property.
+ */
+ enum mboard_prop_t{
+ MBOARD_PROP_NAME = 'n', //ro, std::string
+ MBOARD_PROP_OTHERS = 'o', //ro, prop_names_t
+ MBOARD_PROP_RX_DSP = 'd', //ro, wax::obj
+ MBOARD_PROP_RX_DSP_NAMES = 'D', //ro, prop_names_t
+ MBOARD_PROP_TX_DSP = 'u', //ro, wax::obj
+ MBOARD_PROP_TX_DSP_NAMES = 'U', //ro, prop_names_t
+ MBOARD_PROP_RX_DBOARD = 'e', //ro, wax::obj
+ 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_CLOCK_CONFIG = 'C', //rw, clock_config_t
+ MBOARD_PROP_TIME_NOW = 't', //wo, time_spec_t
+ MBOARD_PROP_TIME_NEXT_PPS = 'T', //wo, time_spec_t
+ MBOARD_PROP_STREAM_CMD = 's' //wo, stream_cmd_t
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_MBOARD_PROPS_HPP */
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
new file mode 100644
index 000000000..6ba1b90dd
--- /dev/null
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -0,0 +1,151 @@
+//
+// 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_SIMPLE_USRP_HPP
+#define INCLUDED_UHD_USRP_SIMPLE_USRP_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/clock_config.hpp>
+#include <uhd/types/tune_result.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <vector>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The simple USRP device class:
+ * A simple usrp facilitates ease-of-use for most use-case scenarios.
+ * The wrapper provides convenience functions to tune the devices
+ * as well as to set the dboard gains, antennas, and other properties.
+ */
+class UHD_API simple_usrp : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<simple_usrp> sptr;
+
+ /*!
+ * Make a new simple usrp from the device address.
+ * \param dev_addr the device address
+ * \return a new simple usrp object
+ */
+ static sptr make(const device_addr_t &dev_addr);
+
+ /*!
+ * Get the underlying device object.
+ * This is needed to get access to the streaming API and properties.
+ * \return the device object within this simple usrp
+ */
+ virtual device::sptr get_device(void) = 0;
+
+ /*!
+ * Get a printable name for this simple usrp.
+ * \return a printable string
+ */
+ virtual std::string get_name(void) = 0;
+
+ /*******************************************************************
+ * Misc
+ ******************************************************************/
+ /*!
+ * Sets the time registers on the usrp immediately.
+ * \param time_spec the time to latch into the usrp device
+ */
+ virtual void set_time_now(const time_spec_t &time_spec) = 0;
+
+ /*!
+ * Set the time registers on the usrp at the next pps tick.
+ * The values will not be latched in until the pulse occurs.
+ * It is recommended that the user sleep(1) after calling to ensure
+ * that the time registers will be in a known state prior to use.
+ *
+ * Note: Because this call sets the time on the "next" pps,
+ * the seconds in the time spec should be current seconds + 1.
+ *
+ * \param time_spec the time to latch into the usrp device
+ */
+ virtual void set_time_next_pps(const time_spec_t &time_spec) = 0;
+
+ /*!
+ * Issue a stream command to the usrp device.
+ * This tells the usrp to send samples into the host.
+ * See the documentation for stream_cmd_t for more info.
+ * \param stream_cmd the stream command to issue
+ */
+ virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0;
+
+ /*!
+ * Set the clock configuration for the usrp device.
+ * This tells the usrp how to get a 10Mhz reference and PPS clock.
+ * See the documentation for clock_config_t for more info.
+ * \param clock_config the clock configuration to set
+ */
+ virtual void set_clock_config(const clock_config_t &clock_config) = 0;
+
+ /*!
+ * Read the RSSI value from a usrp device.
+ * Or throw if the dboard does not support an RSSI readback.
+ * \return the rssi in dB
+ */
+ virtual float read_rssi(void) = 0;
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ 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 freq_range_t get_rx_freq_range(void) = 0;
+
+ virtual void set_rx_gain(float gain) = 0;
+ virtual float get_rx_gain(void) = 0;
+ virtual gain_range_t get_rx_gain_range(void) = 0;
+
+ virtual void set_rx_antenna(const std::string &ant) = 0;
+ virtual std::string get_rx_antenna(void) = 0;
+ virtual std::vector<std::string> get_rx_antennas(void) = 0;
+
+ virtual bool get_rx_lo_locked(void) = 0;
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ 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 freq_range_t get_tx_freq_range(void) = 0;
+
+ virtual void set_tx_gain(float gain) = 0;
+ virtual float get_tx_gain(void) = 0;
+ virtual gain_range_t get_tx_gain_range(void) = 0;
+
+ virtual void set_tx_antenna(const std::string &ant) = 0;
+ virtual std::string get_tx_antenna(void) = 0;
+ virtual std::vector<std::string> get_tx_antennas(void) = 0;
+
+ virtual bool get_tx_lo_locked(void) = 0;
+};
+
+}}
+
+#endif /* INCLUDED_UHD_USRP_SIMPLE_USRP_HPP */
diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp
new file mode 100644
index 000000000..1f8e91d68
--- /dev/null
+++ b/host/include/uhd/usrp/subdev_props.hpp
@@ -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/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP
+#define INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP
+
+#include <uhd/utils/props.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Possible device subdev properties
+ */
+ enum subdev_prop_t{
+ SUBDEV_PROP_NAME = 'n', //ro, std::string
+ SUBDEV_PROP_OTHERS = 'o', //ro, prop_names_t
+ SUBDEV_PROP_GAIN = 'g', //rw, float
+ SUBDEV_PROP_GAIN_RANGE = 'r', //ro, gain_range_t
+ SUBDEV_PROP_GAIN_NAMES = 'G', //ro, prop_names_t
+ SUBDEV_PROP_FREQ = 'f', //rw, double
+ SUBDEV_PROP_FREQ_RANGE = 'F', //ro, freq_range_t
+ 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_USE_LO_OFFSET = 'l', //ro, bool
+ SUBDEV_PROP_RSSI = 'R', //ro, float
+ SUBDEV_PROP_BANDWIDTH = 'B' //rw, double
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP */
diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp
new file mode 100644
index 000000000..f1e276d4f
--- /dev/null
+++ b/host/include/uhd/usrp/tune_helper.hpp
@@ -0,0 +1,79 @@
+//
+// 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_TUNE_HELPER_HPP
+#define INCLUDED_UHD_USRP_TUNE_HELPER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <uhd/types/tune_result.hpp>
+
+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:
+ * 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 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
+);
+
+/*!
+ * 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
+);
+
+}}
+
+#endif /* INCLUDED_UHD_USRP_TUNE_HELPER_HPP */
diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp
new file mode 100644
index 000000000..7387e5dd4
--- /dev/null
+++ b/host/include/uhd/usrp/usrp2.hpp
@@ -0,0 +1,62 @@
+//
+// 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_USRP2_HPP
+#define INCLUDED_UHD_USRP_USRP2_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The usrp2 device class.
+ */
+class UHD_API usrp2 : public device{
+public:
+ /*!
+ * Find usrp2 devices over the ethernet.
+ *
+ * Recommended key/value pairs for the device hint address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which may or may not be a broadcast address.
+ *
+ * Other optional device address keys:
+ * recv_buff_size: resizes the recv buffer on the data socket
+ * send_buff_size: resizes the send buffer on the data socket
+ *
+ * \param hint a device addr with the usrp2 address filled in
+ * \return a vector of device addresses for all usrp2s found
+ */
+ static device_addrs_t find(const device_addr_t &hint);
+
+ /*!
+ * Make a usrp2 from a device address.
+ *
+ * Required key/value pairs for the device address:
+ * hint["addr"] = address, where address is a resolvable address
+ * or ip address, which must be the specific address of a usrp2.
+ *
+ * \param addr the device address
+ * \return a device sptr to a new usrp2
+ */
+ static device::sptr make(const device_addr_t &addr);
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_USRP2_HPP */
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
new file mode 100644
index 000000000..f588c6310
--- /dev/null
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# 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/>.
+#
+
+INSTALL(FILES
+ algorithm.hpp
+ assert.hpp
+ exception.hpp
+ gain_handler.hpp
+ props.hpp
+ safe_main.hpp
+ static.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd/utils
+)
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
new file mode 100644
index 000000000..146b56c63
--- /dev/null
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -0,0 +1,51 @@
+//
+// 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_ALGORITHM_HPP
+#define INCLUDED_UHD_UTILS_ALGORITHM_HPP
+
+#include <algorithm>
+#include <boost/range/functions.hpp>
+
+/*!
+ * Useful templated functions and classes that I like to pretend are part of stl
+ */
+namespace std{
+
+ template<typename RangeSrc, typename RangeDst> inline
+ void copy(const RangeSrc &src, RangeDst &dst){
+ std::copy(boost::begin(src), boost::end(src), boost::begin(dst));
+ }
+
+ template<typename Range, typename T> inline
+ bool has(const Range &range, const T &value){
+ return boost::end(range) != std::find(boost::begin(range), boost::end(range), value);
+ }
+
+ template<typename T> inline T signum(T n){
+ if (n < 0) return -1;
+ if (n > 0) return 1;
+ return 0;
+ }
+
+ template<typename T> inline T clip(T val, T minVal, T maxVal){
+ return std::min(std::max(val, minVal), maxVal);
+ }
+
+}//namespace std
+
+#endif /* INCLUDED_UHD_UTILS_ALGORITHM_HPP */
diff --git a/host/include/uhd/utils/assert.hpp b/host/include/uhd/utils/assert.hpp
new file mode 100644
index 000000000..2f0ed4ff1
--- /dev/null
+++ b/host/include/uhd/utils/assert.hpp
@@ -0,0 +1,76 @@
+//
+// 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_ASSERT_HPP
+#define INCLUDED_UHD_UTILS_ASSERT_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/utils/exception.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <stdexcept>
+#include <string>
+
+namespace uhd{
+
+ //! The exception to throw when assertions fail
+ struct UHD_API assert_error : std::runtime_error{
+ assert_error(const std::string &what);
+ };
+
+ //! Throw an assert error with throw-site information
+ #define UHD_ASSERT_THROW(_x) if (not (_x)) \
+ throw uhd::assert_error(UHD_THROW_SITE_INFO("assertion failed: " + std::string(#_x)))
+
+ /*!
+ * Check that an element is found in a container.
+ * If not, throw a meaningful assertion error.
+ * The "what" in the error will show what is
+ * being set and a list of known good values.
+ *
+ * \param range a list of possible settings
+ * \param value an element that may be in the list
+ * \param what a description of what is being set
+ * \throw assertion_error when elem not in list
+ */
+ template<typename T, typename Range> void assert_has(
+ const Range &range,
+ const T &value,
+ const std::string &what = "unknown"
+ ){
+ if (std::has(range, value)) return;
+ std::string possible_values = "";
+ size_t i = 0;
+ BOOST_FOREACH(const T &v, range){
+ if (i++ > 0) possible_values += ", ";
+ possible_values += boost::lexical_cast<std::string>(v);
+ }
+ throw uhd::assert_error(str(boost::format(
+ "assertion failed:\n"
+ " %s is not a valid %s.\n"
+ " possible values are: [%s].\n"
+ )
+ % boost::lexical_cast<std::string>(value)
+ % what % possible_values
+ ));
+ }
+
+}//namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_ASSERT_HPP */
diff --git a/host/include/uhd/utils/exception.hpp b/host/include/uhd/utils/exception.hpp
new file mode 100644
index 000000000..40e81fae0
--- /dev/null
+++ b/host/include/uhd/utils/exception.hpp
@@ -0,0 +1,38 @@
+//
+// 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_EXCEPTION_HPP
+#define INCLUDED_UHD_UTILS_EXCEPTION_HPP
+
+#include <uhd/config.hpp>
+#include <boost/current_function.hpp>
+#include <stdexcept>
+#include <string>
+
+/*!
+ * Create a formated string with throw-site information.
+ * Fills in the function name, file name, and line number.
+ * \param what the std::exeption message
+ * \return the formatted exception message
+ */
+#define UHD_THROW_SITE_INFO(what) std::string( \
+ std::string(what) + "\n" + \
+ " in " + std::string(BOOST_CURRENT_FUNCTION) + "\n" + \
+ " at " + std::string(__FILE__) + ":" + BOOST_STRINGIZE(__LINE__) + "\n" \
+)
+
+#endif /* INCLUDED_UHD_UTILS_EXCEPTION_HPP */
diff --git a/host/include/uhd/utils/gain_handler.hpp b/host/include/uhd/utils/gain_handler.hpp
new file mode 100644
index 000000000..f4629e6a7
--- /dev/null
+++ b/host/include/uhd/utils/gain_handler.hpp
@@ -0,0 +1,90 @@
+//
+// 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/props.hpp b/host/include/uhd/utils/props.hpp
new file mode 100644
index 000000000..f376d2612
--- /dev/null
+++ b/host/include/uhd/utils/props.hpp
@@ -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/>.
+//
+
+#ifndef INCLUDED_UHD_UTILS_PROPS_HPP
+#define INCLUDED_UHD_UTILS_PROPS_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <uhd/utils/exception.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <stdexcept>
+#include <vector>
+#include <string>
+
+namespace uhd{
+
+ //! The type for a vector of property names
+ typedef std::vector<std::string> prop_names_t;
+
+ /*!
+ * A named prop struct holds a key and a name.
+ * Allows properties to be sub-sectioned by name.
+ */
+ struct UHD_API named_prop_t{
+ wax::obj key;
+ std::string name;
+
+ /*!
+ * Create a new named prop from key and name.
+ * \param key the property key
+ * \param name the string name
+ */
+ named_prop_t(const wax::obj &key, const std::string &name);
+ };
+
+ /*!
+ * Utility function to separate a named property into its components.
+ * \param key a reference to the prop object
+ * \param name a reference to the name object
+ * \return a tuple that can be used with boost::tie
+ */
+ UHD_API boost::tuple<wax::obj, std::string> extract_named_prop(
+ const wax::obj &key,
+ const std::string &name = ""
+ );
+
+ /*!
+ * Throw when getting a not-implemented or write-only property.
+ * Throw-site information will be included with this error.
+ */
+ #define UHD_THROW_PROP_GET_ERROR() \
+ throw std::runtime_error(UHD_THROW_SITE_INFO("cannot get this property"))
+
+ /*!
+ * Throw when setting a not-implemented or read-only property.
+ * Throw-site information will be included with this error.
+ */
+ #define UHD_THROW_PROP_SET_ERROR() \
+ throw std::runtime_error(UHD_THROW_SITE_INFO("cannot set this property"))
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_PROPS_HPP */
diff --git a/host/include/uhd/utils/safe_main.hpp b/host/include/uhd/utils/safe_main.hpp
new file mode 100644
index 000000000..b682aa540
--- /dev/null
+++ b/host/include/uhd/utils/safe_main.hpp
@@ -0,0 +1,44 @@
+//
+// 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_SAFE_MAIN_HPP
+#define INCLUDED_UHD_UTILS_SAFE_MAIN_HPP
+
+#include <uhd/config.hpp>
+#include <iostream>
+#include <stdexcept>
+
+/*!
+ * Defines a safe wrapper that places a catch-all around main.
+ * If an exception is thrown, it prints to stderr and returns.
+ * Usage: int UHD_SAFE_MAIN(int argc, char *argv[]){ main code here }
+ * \param _argc the declaration for argc
+ * \param _argv the declaration for argv
+ */
+#define UHD_SAFE_MAIN(_argc, _argv) _main(int, char*[]); \
+int main(int argc, char *argv[]){ \
+ try { \
+ return _main(argc, argv); \
+ } catch(const std::exception &e) { \
+ std::cerr << "Error: " << e.what() << std::endl; \
+ } catch(...) { \
+ std::cerr << "Error: unknown exception" << std::endl; \
+ } \
+ return ~0; \
+} int _main(_argc, _argv)
+
+#endif /* INCLUDED_UHD_UTILS_SAFE_MAIN_HPP */
diff --git a/host/include/uhd/utils/static.hpp b/host/include/uhd/utils/static.hpp
new file mode 100644
index 000000000..c61f10884
--- /dev/null
+++ b/host/include/uhd/utils/static.hpp
@@ -0,0 +1,37 @@
+//
+// 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_STATIC_HPP
+#define INCLUDED_UHD_UTILS_STATIC_HPP
+
+#include <uhd/config.hpp>
+
+/*!
+ * Defines a function that implements the "construct on first use" idiom
+ * \param _t the type definition for the instance
+ * \param _x the name of the defined function
+ * \return a reference to the lazy instance
+ */
+#define UHD_SINGLETON_FCN(_t, _x) static _t &_x(){static _t _x; return _x;}
+
+/*!
+ * Defines a static code block that will be called before main()
+ * \param _x the name of the defined struct (must be unique in file)
+ */
+#define UHD_STATIC_BLOCK(_x) static struct _x{_x();}_x;_x::_x()
+
+#endif /* INCLUDED_UHD_UTILS_STATIC_HPP */
diff --git a/host/include/uhd/wax.hpp b/host/include/uhd/wax.hpp
new file mode 100644
index 000000000..14e6734a5
--- /dev/null
+++ b/host/include/uhd/wax.hpp
@@ -0,0 +1,167 @@
+//
+// 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_WAX_HPP
+#define INCLUDED_WAX_HPP
+
+#include <uhd/config.hpp>
+#include <boost/any.hpp>
+
+/*!
+ * WAX - it's a metaphor!
+ *
+ * The WAX framework allows an object to have generic/anyobj properties.
+ * These properties can be addressed through generic/anyobj identifiers.
+ *
+ * The WAX object itself is an anytype container much like boost::any.
+ * To retrieve the value of the appropriate type, use my_obj.as<type>().
+ *
+ * Proprties may be referenced though the [] overloaded operator.
+ * The [] operator returns a special proxy that allows for assigment.
+ * Also, the [] operators may be chained as in the folowing examples:
+ * my_obj[prop1][prop2][prop3] = value;
+ * value = my_obj[prop1][prop2][prop3].as<type>();
+ *
+ * Property nesting occurs when a WAX object gets another object's link.
+ * This special link is obtained through a call to my_obj.get_link().
+ *
+ * Note: Do not put a class derived from wax::obj into an stl container.
+ * MSVC will compile the code, but the binaries will crash at runtime.
+ * Rather, use pointers or smart pointers to instances of the derived class.
+ */
+
+namespace wax{
+
+ /*!
+ * The wax::bad cast will be thrown when
+ * cast is called with the wrong typeid.
+ */
+ typedef boost::bad_any_cast bad_cast;
+
+ /*!
+ * WAX object base class:
+ *
+ * A wax obj has two major purposes:
+ * 1) to act as a polymorphic container, just like boost any
+ * 2) to provide a nested set/get properties interface
+ *
+ * Internally, the polymorphic container is handled by a boost any.
+ * For properties, a subclass should override the set and get methods.
+ * For property nesting, wax obj subclasses return special links
+ * to other wax obj subclasses, and the api handles the magic.
+ */
+ class UHD_API obj{
+ public:
+
+ /*!
+ * Default constructor:
+ * The contents will be empty.
+ */
+ obj(void);
+
+ /*!
+ * Copy constructor:
+ * The contents will be cloned.
+ * \param o another wax::obj
+ */
+ obj(const obj &o);
+
+ /*!
+ * Templated any type constructor:
+ * The contents can be anything.
+ * Uses the boost::any to handle the magic.
+ * \param o an object of any type
+ */
+ template<class T> obj(const T &o){
+ _contents = o;
+ }
+
+ /*!
+ * Destructor.
+ */
+ virtual ~obj(void);
+
+ /*!
+ * The chaining operator:
+ * This operator allows access objs with properties.
+ * A call to the [] operator will return a new proxy obj.
+ * The proxy object is an obj with special proxy contents.
+ * Assignment and casting can be used on this special object
+ * to access the property referenced by the obj key.
+ * \param key a key to identify a property within this obj
+ * \return a special wax obj that proxies the obj and key
+ */
+ obj operator[](const obj &key);
+
+ /*!
+ * The assignment operator:
+ * This operator allows for assignment of new contents.
+ * In the special case where this obj contains a proxy,
+ * the value will be set to the proxy's property reference.
+ * \param val the new value to assign to the wax obj
+ * \return a reference to this obj (*this)
+ */
+ obj & operator=(const obj &val);
+
+ /*!
+ * Get a link in the chain:
+ * When a wax obj returns another wax obj as part of a get call,
+ * the return value should be set to the result of this method.
+ * Doing so will ensure chain-ability of the returned object.
+ * \return an obj containing a valid link to a wax obj
+ */
+ obj get_link(void) const;
+
+ /*!
+ * Get the type of the contents of this obj.
+ * \return a reference to the type_info
+ */
+ const std::type_info & type(void) const;
+
+ /*!
+ * Cast this obj into the desired type.
+ * Usage: myobj.as<type>()
+ *
+ * \return an object of the desired type
+ * \throw wax::bad_cast when the cast fails
+ */
+ template<class T> T as(void) const{
+ return boost::any_cast<T>(resolve());
+ }
+
+ private:
+ //private interface (override in subclasses)
+ virtual void get(const obj &, obj &);
+ virtual void set(const obj &, const obj &);
+
+ /*!
+ * Resolve the contents of this obj.
+ * In the case where this obj is a proxy,
+ * the referenced property will be resolved.
+ * Otherwise, just get the private contents.
+ * \return a boost any type with contents
+ */
+ boost::any resolve(void) const;
+
+ //private contents of this obj
+ boost::any _contents;
+
+ };
+
+} //namespace wax
+
+#endif /* INCLUDED_WAX_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
new file mode 100644
index 000000000..7b765b0d3
--- /dev/null
+++ b/host/lib/CMakeLists.txt
@@ -0,0 +1,120 @@
+#
+# 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)
+
+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_PYTHON_GEN_SOURCE pyfile outfile)
+ #ensure that the directory exists for outfile
+ GET_FILENAME_COMPONENT(outfile_dir ${outfile} PATH)
+ FILE(MAKE_DIRECTORY ${outfile_dir})
+
+ #make the outfile depend on the python script
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${outfile} DEPENDS ${pyfile}
+ COMMAND ${PYTHON_EXECUTABLE} ${pyfile} ${outfile}
+ COMMENT "Generating ${outfile}"
+ )
+
+ #make libuhd depend on the outfile
+ LIBUHD_APPEND_SOURCES(${outfile})
+ENDMACRO(LIBUHD_PYTHON_GEN_SOURCE)
+
+########################################################################
+# Include CMakeLists.txt from subdirectories
+########################################################################
+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)
+
+########################################################################
+# 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)
+
+########################################################################
+# Append to the list of sources for lib uhd
+########################################################################
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp
+)
+
+########################################################################
+# Setup libuhd library
+########################################################################
+ADD_LIBRARY(uhd SHARED ${libuhd_sources})
+
+TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
+
+SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")
+
+INSTALL(TARGETS uhd
+ LIBRARY DESTINATION ${LIBRARY_DIR} # .so file
+ ARCHIVE DESTINATION ${LIBRARY_DIR} # .lib file
+ RUNTIME DESTINATION ${LIBRARY_DIR} # .dll file
+)
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
new file mode 100644
index 000000000..f139ecb20
--- /dev/null
+++ b/host/lib/device.cpp
@@ -0,0 +1,146 @@
+//
+// 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
+// asize_t with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/device.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <stdexcept>
+#include <algorithm>
+
+using namespace uhd;
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+/*!
+ * Make a device hash that maps 1 to 1 with a device address.
+ * The hash will be used to identify created devices.
+ * \param dev_addr the device address
+ * \return the hash number
+ */
+static size_t hash_device_addr(
+ const device_addr_t &dev_addr
+){
+ //sort the keys of the device address
+ std::vector<std::string> keys = dev_addr.keys();
+ std::sort(keys.begin(), keys.end());
+
+ //combine the hashes of sorted keys/value pairs
+ size_t hash = 0;
+ BOOST_FOREACH(const std::string &key, keys){
+ boost::hash_combine(hash, key);
+ boost::hash_combine(hash, dev_addr[key]);
+ }
+ return hash;
+}
+
+/***********************************************************************
+ * Registration
+ **********************************************************************/
+typedef boost::tuple<device::find_t, device::make_t> dev_fcn_reg_t;
+
+// instantiate the device function registry container
+UHD_SINGLETON_FCN(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs)
+
+void device::register_device(
+ const find_t &find,
+ const make_t &make
+){
+ //std::cout << "registering device" << std::endl;
+ get_dev_fcn_regs().push_back(dev_fcn_reg_t(find, make));
+}
+
+/***********************************************************************
+ * Discover
+ **********************************************************************/
+device_addrs_t device::find(const device_addr_t &hint){
+ device_addrs_t device_addrs;
+
+ BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){
+ device_addrs_t discovered_addrs = fcn.get<0>()(hint);
+ device_addrs.insert(
+ device_addrs.begin(),
+ discovered_addrs.begin(),
+ discovered_addrs.end()
+ );
+ }
+
+ return device_addrs;
+}
+
+/***********************************************************************
+ * Make
+ **********************************************************************/
+device::sptr device::make(const device_addr_t &hint, size_t which){
+ typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t;
+ std::vector<dev_addr_make_t> dev_addr_makers;
+
+ BOOST_FOREACH(const dev_fcn_reg_t &fcn, get_dev_fcn_regs()){
+ BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){
+ //append the discovered address and its factory function
+ dev_addr_makers.push_back(dev_addr_make_t(dev_addr, fcn.get<1>()));
+ }
+ }
+
+ //check that we found any devices
+ if (dev_addr_makers.size() == 0){
+ throw std::runtime_error(str(
+ boost::format("No devices found for ----->\n%s") % hint.to_pp_string()
+ ));
+ }
+
+ //check that the which index is valid
+ if (dev_addr_makers.size() <= which){
+ throw std::runtime_error(str(
+ boost::format("No device at index %d for ----->\n%s") % which % hint.to_pp_string()
+ ));
+ }
+
+ //create a unique hash for the device address
+ device_addr_t dev_addr; make_t maker;
+ boost::tie(dev_addr, maker) = dev_addr_makers.at(which);
+ size_t dev_hash = hash_device_addr(dev_addr);
+ //std::cout << boost::format("Hash: %u") % dev_hash << std::endl;
+
+ //copy keys that were in hint but not in dev_addr
+ //this way, we can pass additional transport arguments
+ BOOST_FOREACH(const std::string &key, hint.keys()){
+ if (not dev_addr.has_key(key)) dev_addr[key] = hint[key];
+ }
+
+ //map device address hash to created devices
+ static uhd::dict<size_t, boost::weak_ptr<device> > hash_to_device;
+
+ //try to find an existing device
+ try{
+ UHD_ASSERT_THROW(hash_to_device.has_key(dev_hash));
+ UHD_ASSERT_THROW(not hash_to_device[dev_hash].expired());
+ return hash_to_device[dev_hash].lock();
+ }
+ //create and register a new device
+ catch(const uhd::assert_error &){
+ device::sptr dev = maker(dev_addr);
+ hash_to_device[dev_hash] = dev;
+ return dev;
+ }
+}
diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp
new file mode 100644
index 000000000..36e2e8ed3
--- /dev/null
+++ b/host/lib/gain_handler.cpp
@@ -0,0 +1,177 @@
+//
+// 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/.gitignore b/host/lib/ic_reg_maps/.gitignore
new file mode 100644
index 000000000..a74b07aee
--- /dev/null
+++ b/host/lib/ic_reg_maps/.gitignore
@@ -0,0 +1 @@
+/*.pyc
diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt
new file mode 100644
index 000000000..63378eb89
--- /dev/null
+++ b/host/lib/ic_reg_maps/CMakeLists.txt
@@ -0,0 +1,65 @@
+#
+# 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!
+
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/lib/ic_reg_maps)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_adf4350_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/adf4350_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_adf4360_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/adf4360_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9510_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9510_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9777_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9777_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad5624_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad5624_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad7922_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad7922_regs.hpp
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_max2829_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/max2829_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
+)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9522_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9522_regs.hpp
+)
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
new file mode 100644
index 000000000..e27c2816d
--- /dev/null
+++ b/host/lib/ic_reg_maps/common.py
@@ -0,0 +1,147 @@
+#
+# 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/>.
+#
+
+import re
+import sys
+import math
+from Cheetah.Template import Template
+
+COMMON_TMPL = """\
+#import time
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_$(name.upper())_HPP
+\#define INCLUDED_$(name.upper())_HPP
+
+\#include <uhd/config.hpp>
+\#include <boost/cstdint.hpp>
+\#include <stdexcept>
+\#include <set>
+
+class $(name)_t{
+public:
+ #for $reg in $regs
+ #if $reg.get_enums()
+ enum $reg.get_type(){
+ #for $i, $enum in enumerate($reg.get_enums())
+ #set $end_comma = ',' if $i < len($reg.get_enums())-1 else ''
+ $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma
+ #end for
+ };
+ #end if
+ $reg.get_type() $reg.get_name();
+ #end for
+
+ $(name)_t(void){
+ _state = NULL;
+ #for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+ #end for
+ }
+
+ ~$(name)_t(void){
+ delete _state;
+ }
+
+$body
+
+ void save_state(void){
+ if (_state == NULL) _state = new $(name)_t();
+ #for $reg in $regs
+ _state->$reg.get_name() = this->$reg.get_name();
+ #end for
+ }
+
+ template<typename T> std::set<T> get_changed_addrs(void){
+ if (_state == NULL) throw std::runtime_error("no saved state");
+ //check each register for changes
+ std::set<T> addrs;
+ #for $reg in $regs
+ if(_state->$reg.get_name() != this->$reg.get_name()){
+ addrs.insert($reg.get_addr());
+ }
+ #end for
+ return addrs;
+ }
+
+private:
+ $(name)_t *_state;
+};
+
+\#endif /* INCLUDED_$(name.upper())_HPP */
+"""
+
+def parse_tmpl(_tmpl_text, **kwargs):
+ return str(Template(_tmpl_text, kwargs))
+
+def to_num(arg): return eval(arg)
+
+class reg:
+ def __init__(self, reg_des):
+ try: self.parse(reg_des)
+ except Exception, e:
+ raise Exception, 'Error parsing register description: "%s"\nWhat: %s'%(reg_des, e)
+
+ def parse(self, reg_des):
+ x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des)
+ name, addr, bit_range, default, enums = x.groups()
+
+ #store variables
+ self._name = name
+ self._addr = to_num(addr)
+ if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':')))
+ else: self._addr_spec = int(bit_range), int(bit_range)
+ self._default = to_num(default)
+
+ #extract enum
+ self._enums = list()
+ if enums:
+ enum_val = 0
+ for enum_str in map(str.strip, enums.split(',')):
+ if '=' in enum_str:
+ enum_name, enum_val = enum_str.split('=')
+ enum_val = to_num(enum_val)
+ else: enum_name = enum_str
+ self._enums.append((enum_name, enum_val))
+ enum_val += 1
+
+ def get_addr(self): return self._addr
+ def get_enums(self): return self._enums
+ def get_name(self): return self._name
+ def get_default(self):
+ for key, val in self.get_enums():
+ if val == self._default: return str.upper('%s_%s'%(self.get_name(), key))
+ return self._default
+ def get_type(self):
+ if self.get_enums(): return '%s_t'%self.get_name()
+ return 'boost::uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8)
+ def get_shift(self): return self._addr_spec[0]
+ def get_mask(self): return hex(int('1'*self.get_bit_width(), 2))
+ def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1
+
+def generate(name, regs_tmpl, body_tmpl='', file=__file__):
+ regs = map(reg, parse_tmpl(regs_tmpl).splitlines())
+ body = parse_tmpl(body_tmpl, regs=regs).replace('\n', '\n ').strip()
+ code = parse_tmpl(COMMON_TMPL,
+ name=name,
+ regs=regs,
+ body=body,
+ file=file,
+ )
+ open(sys.argv[1], 'w').write(code)
diff --git a/host/lib/ic_reg_maps/gen_ad5624_regs.py b/host/lib/ic_reg_maps/gen_ad5624_regs.py
new file mode 100755
index 000000000..24401b878
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad5624_regs.py
@@ -0,0 +1,48 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+data 0[4:15] 0
+addr 0[16:18] 0 DAC_A=0, DAC_B=1, DAC_C=2, DAC_D=3, ALL=7
+cmd 0[19:21] 0 wr_input_n, up_dac_n, wr_input_n_up_all, wr_up_dac_chan_n, power_down, reset, load_ldac
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint32_t get_reg(void){
+ boost::uint32_t reg = 0;
+ #for $reg in filter(lambda r: r.get_addr() == 0, $regs)
+ reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ return reg;
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad5624_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_ad7922_regs.py b/host/lib/ic_reg_maps/gen_ad7922_regs.py
new file mode 100755
index 000000000..5cec1924a
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad7922_regs.py
@@ -0,0 +1,54 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+result 0[0:11] 0
+mod 0[12] 0
+chn 0[13] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint16_t get_reg(void){
+ boost::uint16_t reg = 0;
+ #for $reg in filter(lambda r: r.get_addr() == 0, $regs)
+ reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ return reg;
+}
+
+void set_reg(boost::uint16_t reg){
+ #for $reg in filter(lambda r: r.get_addr() == 0, $regs)
+ $reg.get_name() = $(reg.get_type())((reg >> $reg.get_shift()) & $reg.get_mask());
+ #end for
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad7922_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py
new file mode 100755
index 000000000..83236c921
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py
@@ -0,0 +1,139 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## serial control port config
+########################################################################
+long_instruction 0[4] 1 8bits, 16bits
+soft_reset 0[5] 0
+lsb_first 0[6] 0 msb, lsb
+sdo_inactive 0[7] 0 active, inactive
+########################################################################
+## pll settings
+########################################################################
+acounter 4[0:5] 0
+bcounter_msb 5[0:4] 0
+bcounter_lsb 6[0:7] 0
+lor_enable 7[2] 0 enb, dis
+lor_ildd 7[5:6] 0 3cyc, 6cyc, 12cyc, 24cyc
+charge_pump_mode 8[0:1] 0 3state, pump_up, pump_down, normal
+pll_mux_control 8[2:5] 0 off, dld_high, ndiv, dld_low, rdiv, ald_nchan, acounter, prescaler, pfd_up, pfd_down, lor_high, 3state, ald_pchan, lor_lol_high, lor_lol_low, lor_low
+pfd_polarity 8[6] 0 neg, pos
+reset_all_counters 9[0] 0
+ncounter_reset 9[1] 0
+rcounter_reset 9[2] 0
+cp_current_setting 9[4:6] 0 0_60ma, 1_2ma, 1_8ma, 2_4ma, 3_0ma, 3_6ma, 4_2ma, 4_8ma
+pll_power_down 0xA[0:1] 0 normal=0, async_pd=1, sync_pd=3
+prescaler_value 0xA[2:4] 0 div1, div2, 2_3, 4_5, 8_9, 16_17, 32_33, div3
+b_counter_bypass 0xA[6] 0
+ref_counter_msb 0xB[0:5] 0
+ref_counter_lsb 0xC[0:7] 0
+antibacklash_pw 0xD[0:1] 0 1_3ns, 2_9ns, 6_0ns
+dld_window 0xD[5] 0 9_5ns, 3_5ns
+lock_detect_disable 0xD[6] 0 enb, dis
+########################################################################
+## fine delay adjust
+########################################################################
+#for $i, $o in ((5, 0), (6, 4))
+delay_control_out$i $hex(0x34+$o)[0] 0
+ramp_current_out$i $hex(0x35+$o)[0:2] 0 200ua, 400ua, 600ua, 800ua, 1000ua, 1200ua, 1400ua, 1600ua
+ramp_capacitor_out$i $hex(0x35+$o)[3:5] 0 4caps=0, 3caps=1, 2caps=3, 1cap=7
+delay_fine_adjust_out$i $hex(0x36+$o)[1:5] 0
+#end for
+########################################################################
+## outputs
+########################################################################
+#for $i, $o in ((0, 0), (1, 1), (2, 2), (3, 3))
+power_down_lvpecl_out$i $hex(0x3C+$o)[0:1] 0 normal, test, safe_pd, total_pd
+output_level_lvpecl_out$i $hex(0x3C+$o)[2:3] 2 500mv, 340mv, 810mv, 660mv
+#end for
+#for $i, $o in ((4, 0), (5, 1), (6, 2), (7, 3))
+power_down_lvds_cmos_out$i $hex(0x40+$o)[0] 0
+output_level_lvds_out$i $hex(0x40+$o)[1:2] 1 1_75ma, 3_5ma, 5_25ma, 7ma
+lvds_cmos_select_out$i $hex(0x40+$o)[3] 1 lvds, cmos
+inverted_cmos_driver_out$i $hex(0x40+$o)[4] 0 dis, enb
+#end for
+clock_select 45[0] 1 clk2_drives, clk1_drives
+clk1_power_down 45[1] 0
+clk2_power_down 45[2] 0
+prescaler_clock_pd 45[3] 0
+refin_power_down 45[4] 0
+all_clock_inputs_pd 45[5] 0
+########################################################################
+## dividers
+########################################################################
+#for $i, $o in ((0, 0), (1, 2), (2, 4), (3, 6), (4, 8), (5, 10), (6, 12), (7, 14))
+divider_high_cycles_out$i $hex(0x48+$o)[0:3] 0
+divider_low_cycles_out$i $hex(0x48+$o)[4:7] 0
+phase_offset_out$i $hex(0x49+$o)[0:3] 0
+start_out$i $hex(0x49+$o)[4] 0
+force_out$i $hex(0x49+$o)[5] 0
+nosync_out$i $hex(0x49+$o)[6] 0
+bypass_divider_out$i $hex(0x49+$o)[7] 0
+#end for
+########################################################################
+## function
+########################################################################
+sync_detect_enable 58[0] 0 dis, enb
+sync_select 58[1] 0 1_to_0_5, 0_5_to_1
+soft_sync 58[2] 0
+dist_power_down 58[3] 0
+sync_power_down 58[4] 0
+function_pin_select 58[5:6] 0 resetb, syncb, test, pdb
+update_registers 0x5A[0] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint8_t get_reg(boost::uint16_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::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+}
+
+boost::uint32_t get_write_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | get_reg(addr);
+}
+
+boost::uint32_t get_read_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | (1 << 23);
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad9510_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py
new file mode 100755
index 000000000..9da51205b
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py
@@ -0,0 +1,183 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+sdo_active 0x000[7] 0 sdio, sdo_sdio
+lsb_first_addr_incr 0x000[6] 0 msb, lsb
+soft_reset 0x000[5] 0
+mirror 0x000[3:0] 0
+readback_active_registers 0x004[0] 0 buffer, active
+pfd_polarity 0x010[7] 0 pos, neg
+cp_current 0x010[6:4] 7 0_6ma, 1_2ma, 1_8ma, 2_4ma, 3_0ma, 3_6ma, 4_2ma, 4_8ma
+cp_mode 0x010[3:2] 3 high_imp, force_source, force_sink, normal
+pll_power_down 0x010[1:0] 1 normal=0, async=1, sync=3
+r_counter_lsb 0x011[7:0] 1
+r_counter_msb 0x012[5:0] 0
+a_counter 0x013[5:0] 0
+b_counter_lsb 0x014[7:0] 3
+b_counter_msb 0x015[4:0] 0
+set_cp_pin_to_vcp_2 0x016[7] 0 normal, vcp_2
+reset_r_counter 0x016[6] 0
+reset_a_and_b_counters 0x016[5] 0
+reset_all_counters 0x016[4] 0
+b_counter_bypass 0x016[3] 0 normal, div1
+prescaler_p 0x016[2:0] 6 div1, div2, div2_3, div4_5, div8_9, div16_17, div32_33, div3
+status_pin_control 0x017[7:2] 0
+antibacklash_pulse_width 0x017[1:0] 0 2_9ns, 1_3ns, 6_0ns
+enb_cmos_ref_input_dc_off 0x018[7] 0
+lock_detect_counter 0x018[6:5] 0 5cyc, 16cyc, 64cyc, 255cyc
+digital_lock_detect_window 0x018[4] 0 high_range, low_range
+disable_digital_lock_detect 0x018[3] 0 normal, disabled
+vco_calibration_divider 0x018[2:1] 3 div2, div4, div8, div16
+vco_calibration_now 0x018[0] 0
+r_a_b_counters_sync_pin_rst 0x019[7:6] 0 nothing, async, sync
+r_path_delay 0x019[5:3] 0
+n_path_delay 0x019[2:0] 0
+enable_status_pin_divider 0x01A[7] 0
+ref_freq_monitor_threshold 0x01A[6] 0 1_02mhz, 6khz
+ld_pin_control 0x01A[5:0] 0
+enable_vco_freq_monitor 0x01B[7] 0
+enable_ref2_freq_monitor 0x01B[6] 0
+enable_ref1_freq_monitor 0x01B[5] 0
+refmon_pin_control 0x01B[4:0] 0
+disable_switchover_deglitch 0x01C[7] 0
+select_ref 0x01C[6] 0 ref1, ref2
+use_ref_sel_pin 0x01C[5] 0 register, ref_sel
+enb_auto_ref_switchover 0x01C[4] 0 manual, auto
+stay_on_ref2 0x01C[3] 0 return_ref1, stay_ref2
+enable_ref2 0x01C[2] 0
+enable_ref1 0x01C[1] 0
+enable_differential_ref 0x01C[0] 0
+enb_stat_eeprom_at_stat_pin 0x01D[7] 1
+enable_xtal_osc 0x01D[6] 0
+enable_clock_doubler 0x01D[5] 0
+disable_pll_status_reg 0x01D[4] 0
+enable_ld_pin_comparator 0x01D[3] 0
+enable_external_holdover 0x01D[1] 0
+enable_holdover 0x01D[0] 0
+external_zero_delay_fcds 0x01E[4:3] 0
+enable_external_zero_delay 0x01E[2] 0
+enable_zero_delay 0x01E[1] 0
+########################################################################
+#for $i in range(12)
+#set $addr = ($i + 0x0F0)
+out$(i)_format $(addr)[7] 0 lvds, cmos
+out$(i)_cmos_configuration $(addr)[6:5] 3 off, a_on, b_on, ab_on
+out$(i)_polarity $(addr)[4:3] 0 lvds_a_non_b_inv=0, lvds_a_inv_b_non=1, cmos_ab_non=0, cmos_ab_inv=1, cmos_a_non_b_inv=2, cmos_a_inv_b_non=3
+out$(i)_lvds_diff_voltage $(addr)[2:1] 1 1_75ma, 3_5ma, 5_25ma, 7_0ma
+out$(i)_lvds_power_down $(addr)[0] 0
+#end for
+########################################################################
+#for $i in reversed(range(8))
+csdld_en_out_$i 0x0FC[$i] 0 ignore, async
+#end for
+########################################################################
+#for $i in reversed(range(4))
+csdld_en_out_$(8 + $i) 0x0FD[$i] 0 ignore, async
+#end for
+########################################################################
+#set $default_val = 0x7
+#for $i in range(4)
+#set $addr0 = hex($i*3 + 0x190)
+#set $addr1 = hex($i*3 + 0x191)
+#set $addr2 = hex($i*3 + 0x192)
+divider$(i)_low_cycles $(addr0)[7:4] $default_val
+divider$(i)_high_cycles $(addr0)[3:0] $default_val
+divider$(i)_bypass $(addr1)[7] 0
+divider$(i)_ignore_sync $(addr1)[6] 0
+divider$(i)_force_high $(addr1)[5] 0
+divider$(i)_start_high $(addr1)[4] 0
+divider$(i)_phase_offset $(addr1)[3:0] 0
+channel$(i)_power_down $(addr2)[2] 0
+disable_divider$(i)_ddc $(addr2)[0] 0
+#set $default_val /= 2
+#end for
+########################################################################
+vco_divider 0x1E0[2:0] 2 div2, div3, div4, div5, div6, static, div1
+power_down_clock_input_sel 0x1E1[4] 0
+power_down_vco_clock_ifc 0x1E1[3] 0
+power_down_vco_and_clock 0x1E1[2] 0
+select_vco_or_clock 0x1E1[1] 0 external, vco
+bypass_vco_divider 0x1E1[0] 0
+disable_power_on_sync 0x230[3] 0
+power_down_sync 0x230[2] 0
+power_down_dist_ref 0x230[1] 0
+soft_sync 0x230[0] 0
+io_update 0x232[0] 0
+soft_eeprom 0xB02[1] 0
+enable_eeprom_write 0xB02[0] 0
+reg2eeprom 0xB03[0] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint8_t get_reg(boost::uint16_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
+ }
+ if (addr == 0){ //mirror 4 bits in register 0
+ reg |= ((reg >> 7) & 0x1) << 0;
+ reg |= ((reg >> 6) & 0x1) << 1;
+ reg |= ((reg >> 5) & 0x1) << 2;
+ reg |= ((reg >> 4) & 0x1) << 3;
+ }
+ return reg;
+}
+
+void set_reg(boost::uint8_t addr, boost::uint32_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
+ }
+}
+
+boost::uint32_t get_write_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | get_reg(addr);
+}
+
+boost::uint32_t get_read_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | (1 << 23);
+}
+
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad9522_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py
new file mode 100755
index 000000000..690b15e24
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py
@@ -0,0 +1,118 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+sdio_bidirectional 0[7] 0 input, io
+lsb_msb_first 0[6] 0 msb, lsb
+soft_reset 0[5] 0
+sleep_mode 0[4] 0
+power_down_mode 0[3] 0
+x_1r_2r_mode 0[2] 0 2r, 1r
+pll_lock_indicator 0[1] 0
+########################################################################
+## address 1
+########################################################################
+filter_interp_rate 1[6:7] 0 1x, 2x, 4x, 8x
+modulation_mode 1[4:5] 0 none, fs_2, fs_4, fs_8
+zero_stuff_mode 1[3] 0
+mix_mode 1[2] 1 complex, real
+modulation_form 1[1] 0 e_minus_jwt, e_plus_jwt
+data_clk_pll_lock_sel 1[0] 0 pll_lock, data_clk
+########################################################################
+## address 2
+########################################################################
+signed_input_data 2[7] 0 signed, unsigned
+two_port_mode 2[6] 0 two_port, one_port
+dataclk_driver_strength 2[5] 0 weak, strong
+dataclk_invert 2[4] 0
+oneportclk_invert 2[2] 0
+iqsel_invert 2[1] 0
+iq_first 2[0] 0 i_first, q_first
+########################################################################
+## address 3
+########################################################################
+data_rate_clock_output 3[7] 0 pll_lock, spi_sdo
+pll_divide_ratio 3[0:1] 0 div1, div2, div4, div8
+########################################################################
+## address 4
+########################################################################
+pll_state 4[7] 0 off, on
+auto_cp_control 4[6] 0 auto, manual
+pll_cp_control 4[0:2] 0 50ua=0, 100ua=1, 200ua=2, 400ua=3, 800ua=7
+########################################################################
+## address 5 and 9
+########################################################################
+idac_fine_gain_adjust 5[0:7] 0
+qdac_fine_gain_adjust 9[0:7] 0
+########################################################################
+## address 6 and A
+########################################################################
+idac_coarse_gain_adjust 6[0:3] 0
+qdac_coarse_gain_adjust 0xA[0:3] 0
+########################################################################
+## address 7, 8 and B, C
+########################################################################
+idac_offset_adjust_msb 7[0:7] 0
+idac_offset_adjust_lsb 8[0:1] 0
+idac_ioffset_direction 8[7] 0 out_a, out_b
+qdac_offset_adjust_msb 0xB[0:7] 0
+qdac_offset_adjust_lsb 0xC[0:1] 0
+qdac_ioffset_direction 0xC[7] 0 out_a, out_b
+"""
+
+########################################################################
+# 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 reg;
+}
+
+boost::uint16_t get_write_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | get_reg(addr);
+}
+
+boost::uint16_t get_read_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | (1 << 7);
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad9777_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py
new file mode 100755
index 000000000..fdbea5828
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py
@@ -0,0 +1,246 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## General
+########################################################################
+sdio_bidir 0[7] 0 sdio_sdo, sdio
+lsb_first 0[6] 0 msb, lsb
+soft_reset 0[5] 0
+########################################################################
+## Rx Power Down
+########################################################################
+pd_vref_diff 1[7] 0
+pd_vref 1[6] 0
+pd_rx_digital 1[5] 0
+pd_rx_channel_b 1[4] 0
+pd_rx_channel_a 1[3] 0
+pd_buffer_b 1[2] 0
+pd_buffer_a 1[1] 0
+pd_all_rx 1[0] 0
+########################################################################
+## Rx A and B
+########################################################################
+#for $x, $i in (('a', 2), ('b', 3))
+byp_buffer_$x $(i)[7] 0
+rx_pga_$x $(i)[0:4] 0
+#end for
+########################################################################
+## Rx Misc
+########################################################################
+hs_duty_cycle 4[2] 0
+shared_ref 4[1] 0
+clk_duty 4[0] 0
+########################################################################
+## RX I/F (INTERFACE)
+########################################################################
+three_state 5[4] 0
+rx_retime 5[3] 0 clkout1, clkout2
+rx_twos_comp 5[2] 0
+inv_rxsync 5[1] 0
+mux_out 5[0] 0 rx_mux_mode=1, dual_port_mode=0
+########################################################################
+## RX Digital
+########################################################################
+two_channel 6[3] 1 rx_b_dis, both_enb
+rx_keep_ve 6[2] 0 pass_pos, pass_neg
+rx_hilbert 6[1] 0 dis, enb
+decimate 6[0] 0 dis, enb
+########################################################################
+## TX Power Down
+########################################################################
+alt_timing_mode 8[5] 0
+txoff_enable 8[4] 0
+tx_digital_pd 8[3] 0
+tx_analog_pd 8[0:2] 0 none=0, txb=4, txa=2, both=7
+########################################################################
+## Tx Offset and Gain
+########################################################################
+#for $x, $i, $j, $k in (('a', 10, 11, 14), ('b', 12, 13, 15))
+dac_$(x)_offset_1_0 $(i)[6:7] 0
+dac_$(x)_offset_dir $(i)[0] 0 neg_diff, pos_dif
+dac_$(x)_offset_9_2 $(j)[0:7] 0
+dac_$(x)_coarse_gain $(k)[6:7] 0
+dac_$(x)_fine_gain $(k)[0:5] 0
+#end for
+tx_pga_gain 16[0:7] 0
+########################################################################
+## Tx Misc
+########################################################################
+tx_slave_enable 17[1] 0
+tx_pga_mode 17[0] 0 normal, fast
+########################################################################
+## Tx IF (INTERFACE)
+########################################################################
+tx_retime 18[6] 1 clkout1=1, clkout2=0
+qi_order 18[5] 0 iq, qi
+inv_txsync 18[4] 0
+tx_twos_comp 18[3] 0
+inverse_samp 18[2] 0 rise, fall
+edges 18[1] 0 normal, both
+interleaved 18[0] 0 single, interleaved
+########################################################################
+## TX Digital
+########################################################################
+two_data_paths 19[4] 0 single, both
+tx_keep_ve 19[3] 0 pass_pos, pass_neg
+tx_hilbert 19[2] 0 dis, enb
+interp 19[0:1] 0 1, 2, 4
+########################################################################
+## TX Modulator
+########################################################################
+neg_fine_tune 20[5] 0 pos_shift, neg_shift
+fine_mode 20[4] 0 bypass, nco
+real_mix_mode 20[3] 0 complex, real
+neg_coarse_tune 20[2] 0 pos_shift, neg_shift
+coarse_mod 20[0:1] 0 bypass, fdac_4, fdac_8
+########################################################################
+## NCO Tuning Word
+########################################################################
+ftw_7_0 21[0:7] 0
+ftw_15_8 22[0:7] 0
+ftw_23_16 23[0:7] 0
+########################################################################
+## DLL
+########################################################################
+input_clk_ctrl 24[6] 0 external, internal
+adc_div2 24[5] 0 normal, div2
+dll_mult 24[3:4] 0 1, 2, 4
+dll_pd 24[2] 0
+dll_mode 24[0] 0 slow, fast
+########################################################################
+## Clock Out
+########################################################################
+clkout2_div_factor 25[6:7] 0 1, 2, 4, 8
+inv2 25[5] 0 normal, inverted
+inv1 25[1] 0 normal, inverted
+dis2 25[4] 0 enb, dis
+dis1 25[0] 0 enb, dis
+########################################################################
+## Aux ADC
+########################################################################
+#for $x, $i in (('a2', 26), ('a1', 28), ('b2', 30), ('b1', 32))
+aux_adc_$(x)_1_0 $(i)[6:7] 0
+aux_adc_$(x)_9_2 $int(1+$i)[0:7] 0
+#end for
+########################################################################
+## Aux ADC Control
+########################################################################
+aux_spi 34[7] 0 dis, enb
+sel_bnota 34[6] 0 adc_a, adc_b
+#for $x, $i in (('b', 5), ('a', 2))
+refsel_$(x) 34[$i] 0 external, internal
+select_$(x) 34[$int($i-1)] 0 aux_adc2, aux_adc1
+start_$(x) 34[$int($i-2)] 0
+#end for
+########################################################################
+## Aux ADC Clock
+########################################################################
+clk_4 35[0] 0 1_2, 1_4
+########################################################################
+## Aux DAC
+########################################################################
+#for $x, $i in (('a', 36), ('b', 37), ('c', 38))
+aux_dac_$x $(i)[0:7] 0
+#end for
+########################################################################
+## Aux DAC Update
+########################################################################
+aux_dac_slave_enable 39[7] 0
+aux_dacupdate_c 39[2] 0
+aux_dacupdate_b 39[1] 0
+aux_dacupdate_a 39[0] 0
+########################################################################
+## AUX DAC Power Down
+########################################################################
+aux_dac_pd_a 40[2] 0
+aux_dac_pd_b 40[1] 0
+aux_dac_pd_c 40[0] 0
+########################################################################
+## AUX DAC Control
+########################################################################
+aux_dac_invert_a 41[2] 0
+aux_dac_invert_b 41[1] 0
+aux_dac_invert_c 41[0] 0
+########################################################################
+## Sig Delt
+########################################################################
+sig_delt_3_0 42[4:7] 0
+sig_delt_11_4 43[0:7] 0
+########################################################################
+## ADC Low Power
+########################################################################
+rx_low_power_mode_r49 49[0:7] 0
+rx_low_power_mode_r50 50[0:7] 0
+########################################################################
+## Chip ID
+########################################################################
+chip_id 63[0:7] 0
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+BODY_TMPL="""
+boost::uint8_t get_reg(boost::uint8_t addr){
+ boost::uint8_t reg = 0;
+ switch(addr){
+ #for $addr in range(0, 63+1)
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+}
+
+void set_reg(boost::uint8_t addr, boost::uint16_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
+ }
+}
+
+boost::uint16_t get_write_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | get_reg(addr);
+}
+
+boost::uint16_t get_read_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | (1 << 7);
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ad9862_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_adf4350_regs.py b/host/lib/ic_reg_maps/gen_adf4350_regs.py
new file mode 100755
index 000000000..e97772843
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_adf4350_regs.py
@@ -0,0 +1,121 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+frac_12_bit 0[3:14] 0
+int_16_bit 0[15:30] 0x23
+##reserved 0[31] 0
+########################################################################
+## address 1
+########################################################################
+mod_12_bit 1[3:14] 0xfff
+phase_12_bit 1[15:26] 0
+prescaler 1[27] 0 4_5, 8_9
+##reserved 1[28:31] 0
+########################################################################
+## address 2
+########################################################################
+counter_reset 2[3] 0 disabled, enabled
+cp_three_state 2[4] 0 disabled, enabled
+power_down 2[5] 0 disabled, enabled
+pd_polarity 2[6] 1 negative, positive
+ldp 2[7] 0 10ns, 6ns
+ldf 2[8] 0 frac_n, int_n
+#set $current_setting_enums = ', '.join(map(lambda x: '_'.join(("%0.2fma"%(round(x*31.27 + 31.27)/100)).split('.')), range(0,16)))
+charge_pump_current 2[9:12] 5 $current_setting_enums
+double_buffer 2[13] 0 disabled, enabled
+r_counter_10_bit 2[14:23] 0
+reference_divide_by_2 2[24] 1 disabled, enabled
+reference_doubler 2[25] 0 disabled, enabled
+muxout 2[26:28] 1 3state, dvdd, dgnd, rdiv, ndiv, analog_ld, dld, reserved
+low_noise_and_spur 2[29:30] 3 low_noise, reserved0, reserved1, low_spur
+########################################################################
+## address 3
+########################################################################
+clock_divider_12_bit 3[3:14] 0
+clock_div_mode 3[15:16] 0 clock_divider_off, fast_lock, resync_enable, reserved
+##reserved 3[17] 0
+cycle_slip_reduction 3[18] 0 disabled, enabled
+##reserved 3[19:20] 0
+##reserved 3[21:31] 0
+########################################################################
+## address 4
+########################################################################
+output_power 4[3:4] 3 m4dbm, m1dbm, 2dbm, 5dbm
+rf_output_enable 4[5] 1 disabled, enabled
+aux_output_power 4[6:7] 0 m4dbm, m1dbm, 2dbm, 5dbm
+aux_output_enable 4[8] 0 disabled, enabled
+aux_output_select 4[9] 1 divided, fundamental
+mute_till_lock_detect 4[10] 0 mute_disabled, mute_enabled
+vco_power_down 4[11] 0 vco_powered_up, vco_powered_down
+band_select_clock_div 4[12:19] 0
+rf_divider_select 4[20:22] 0 div1, div2, div4, div8, div16
+feedback_select 4[23] 1 divided, fundamental
+##reserved 4[24:31] 0
+########################################################################
+## address 5
+########################################################################
+##reserved 5[3:18] 0
+##reserved 5[19:20] 0
+##reserved 5[21] 0
+ld_pin_mode 5[22:23] 1 low0, dld, low, high
+##reserved 5[24:31] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+enum addr_t{
+ ADDR_R0 = 0,
+ ADDR_R1 = 1,
+ ADDR_R2 = 2,
+ ADDR_R3 = 3,
+ ADDR_R4 = 4,
+ ADDR_R5 = 5
+};
+
+boost::uint32_t get_reg(boost::uint8_t addr){
+ boost::uint32_t reg = addr & 0x7;
+ switch(addr){
+ #for $addr in range(5+1)
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='adf4350_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py
new file mode 100755
index 000000000..3fd8707a7
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py
@@ -0,0 +1,89 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+core_power_level 0[2:3] 0 5ma, 10ma, 15ma, 20ma
+counter_operation 0[4] 0 normal, reset
+muxout_control 0[5:7] 0 3state, dld, ndiv, dvdd, rdiv, nchan_od_ld, sdo, dgnd
+phase_detector_polarity 0[8] 0 neg, pos
+charge_pump_output 0[9] 0 normal, 3state
+cp_gain_0 0[10] 0 set1, set2
+mute_till_ld 0[11] 0 dis, enb
+output_power_level 0[12:13] 0 3_5ma, 5_0ma, 7_5ma, 11_0ma
+#set $current_setting_enums = ', '.join(map(lambda x: x+"ma", "0_31 0_62 0_93 1_25 1_56 1_87 2_18 2_50".split()))
+current_setting1 0[14:16] 0 $current_setting_enums
+current_setting2 0[17:19] 0 $current_setting_enums
+power_down 0[20:21] 0 normal_op=0, async_pd=1, sync_pd=3
+prescaler_value 0[22:23] 0 8_9, 16_17, 32_33
+########################################################################
+## address 2
+########################################################################
+a_counter 2[2:6] 0
+b_counter 2[8:20] 0
+cp_gain_1 2[21] 0 set1, set2
+divide_by_2_output 2[22] 0 fund, div2
+divide_by_2_prescaler 2[23] 0 fund, div2
+########################################################################
+## address 1
+########################################################################
+r_counter 1[2:15] 0
+ablpw 1[16:17] 0 3_0ns, 1_3ns, 6_0ns
+lock_detect_precision 1[18] 0 3cycles, 5cycles
+test_mode_bit 1[19] 0
+band_select_clock_div 1[20:21] 0 1, 2, 4, 8
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+enum addr_t{
+ ADDR_CONTROL = 0,
+ ADDR_NCOUNTER = 2,
+ ADDR_RCOUNTER = 1
+};
+
+boost::uint32_t get_reg(addr_t addr){
+ boost::uint32_t reg = addr & 0x3;
+ 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::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='adf4360_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/ic_reg_maps/gen_max2829_regs.py b/host/lib/ic_reg_maps/gen_max2829_regs.py
new file mode 100755
index 000000000..383131c18
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_max2829_regs.py
@@ -0,0 +1,133 @@
+#!/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 registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## Note: offsets given from perspective of data bits (excludes address)
+########################################################################
+##
+########################################################################
+## Standby (2)
+########################################################################
+_set_to_1_2_0 2[0] 1
+_set_to_1_2_1 2[1] 1
+_set_to_1_2_2 2[2] 1
+pa_bias_dac 2[10] 0
+voltage_ref 2[11] 0
+_set_to_1_2_12 2[12] 1
+mimo_select 2[13] 0 normal, mimo
+########################################################################
+## Integer Divider Ratio (3)
+########################################################################
+int_div_ratio_word 3[0:7] 0xa2
+frac_div_ratio_lsb 3[12:13] 0
+########################################################################
+## Fractional Divider Ratio (4)
+########################################################################
+frac_div_ratio_msb 4[0:13] 0
+########################################################################
+## Band Select and PLL (5)
+########################################################################
+band_select 5[0] 0 2_4ghz, 5ghz
+ref_divider 5[1:3] 1
+pll_cp_select 5[5] 1 2ma, 4ma
+band_select_802_11a 5[6] 0 4_9ghz_to_5_35ghz, 5_47ghz_to_5_875ghz
+vco_bandswitch 5[7] 0 disable, automatic
+vco_spi_bandswitch 5[8] 0 fsm, spi
+vco_sub_band 5[9:10] 0
+_set_to_1_5_11 5[11] 1
+_set_to_1_5_12 5[12] 1
+band_sel_mimo 5[13] 0 normal, mimo
+########################################################################
+## Calibration (6)
+########################################################################
+rx_cal_mode 6[0] 0 dis, enb
+tx_cal_mode 6[1] 0 dis, enb
+_set_to_1_6_10 6[10] 1
+iq_cal_gain 6[11:12] 3 8db, 18db, 24db, 34db
+########################################################################
+## Lowpass Filter (7)
+########################################################################
+rx_lpf_fine_adj 7[0:2] 2 90, 95, 100, 105, 110
+rx_lpf_coarse_adj 7[3:4] 1 7_5mhz, 9_5mhz, 14mhz, 18mhz
+tx_lpf_coarse_adj 7[5:6] 1 12mhz=1, 18mhz=2, 24mhz=3
+rssi_high_bw 7[11] 0 2mhz, 6mhz
+########################################################################
+## Rx Control/RSSI (8)
+########################################################################
+_set_to_1_8_0 8[0] 1
+rx_highpass 8[2] 1 100hz, 30khz
+_set_to_1_8_5 8[5] 1
+rssi_pin_fcn 8[8] 0 rssi, temp
+rssi_op_mode 8[10] 0 rssi_rxhp, enabled
+rssi_output_range 8[11] 0 low, high
+rx_vga_gain_spi 8[12] 0 io, spi
+########################################################################
+## Tx Linearity/Baseband Gain (9)
+########################################################################
+tx_baseband_gain 9[0:1] 0 0db, 2db, 3_5db, 5db
+tx_upconv_linearity 9[2:3] 0 50, 63, 78, 100
+tx_vga_linearity 9[6:7] 0 50, 63, 78, 100
+pa_driver_linearity 9[8:9] 2 50, 63, 78, 100
+tx_vga_gain_spi 9[10] 0 io, spi
+########################################################################
+## PA Bias DAC (10)
+########################################################################
+pa_bias_dac_out_curr 10[0:5] 0
+pa_bias_dac_delay 10[6:9] 0xf
+########################################################################
+## Rx Gain (11)
+########################################################################
+rx_vga_gain 11[0:4] 0x1f
+rx_lna_gain 11[5:6] 3
+########################################################################
+## Tx VGA Gain (12)
+########################################################################
+tx_vga_gain 12[0:5] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint32_t get_reg(boost::uint8_t addr){
+ boost::uint16_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::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return (boost::uint32_t(reg) << 4) | (addr & 0xf);
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='max2829_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp
new file mode 100644
index 000000000..d6bfe1369
--- /dev/null
+++ b/host/lib/load_modules.cpp
@@ -0,0 +1,146 @@
+//
+// 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/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>
+
+namespace po = boost::program_options;
+namespace fs = boost::filesystem;
+
+/***********************************************************************
+ * Module Load Function
+ **********************************************************************/
+#ifdef 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){
+ throw std::runtime_error(str(
+ boost::format("dlopen failed to load \"%s\"") % file_name
+ ));
+ }
+}
+
+#elif 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){
+ throw std::runtime_error(str(
+ boost::format("LoadLibrary failed to load \"%s\"") % file_name
+ ));
+ }
+}
+
+#else
+static const std::string env_path_sep = ":";
+
+static void load_module(const std::string &file_name){
+ throw std::runtime_error(str(
+ boost::format("Module loading not supported: Cannot load \"%s\"") % file_name
+ ));
+}
+
+#endif
+
+/***********************************************************************
+ * Load Modules
+ **********************************************************************/
+/*!
+ * Load all modules in a given path.
+ * This will recurse into sub-directories.
+ * Does not throw, prints to std error.
+ * \param path the filesystem path
+ */
+static void load_path(const fs::path &path){
+ if (not fs::exists(path)){
+ std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl;
+ return;
+ }
+
+ //try to load the files in this path
+ if (fs::is_directory(path)){
+ for(
+ fs::directory_iterator dir_itr(path);
+ dir_itr != fs::directory_iterator();
+ ++dir_itr
+ ){
+ load_path(dir_itr->path());
+ }
+ return;
+ }
+
+ //its not a directory, try to load it
+ try{
+ load_module(path.file_string());
+ }
+ catch(const std::exception &err){
+ std::cerr << boost::format("Error: %s") % err.what() << std::endl;
+ }
+}
+
+//! The string constant for the module path environment variable
+static const std::string MODULE_PATH_KEY = "UHD_MODULE_PATH";
+
+/*!
+ * 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.
+ */
+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)));
+ }
+}
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
new file mode 100644
index 000000000..ed8c35225
--- /dev/null
+++ b/host/lib/transport/CMakeLists.txt
@@ -0,0 +1,53 @@
+#
+# 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 interface address discovery
+########################################################################
+MESSAGE(STATUS "Configuring interface address discovery...")
+
+INCLUDE(CheckIncludeFileCXX)
+CHECK_INCLUDE_FILE_CXX(ifaddrs.h HAVE_IFADDRS_H)
+CHECK_INCLUDE_FILE_CXX(winsock2.h HAVE_WINSOCK2_H)
+
+IF(HAVE_IFADDRS_H)
+ MESSAGE(STATUS " Interface address discovery supported through getifaddrs.")
+ ADD_DEFINITIONS(-DHAVE_IFADDRS_H)
+ELSEIF(HAVE_WINSOCK2_H)
+ MESSAGE(STATUS " Interface address discovery supported through SIO_GET_INTERFACE_LIST.")
+ ADD_DEFINITIONS(-DHAVE_WINSOCK2_H)
+ELSE(HAVE_IFADDRS_H)
+ MESSAGE(STATUS " Interface address discovery not supported.")
+ENDIF(HAVE_IFADDRS_H)
+
+########################################################################
+# Append to the list of sources for lib uhd
+########################################################################
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/transport/gen_vrt.py
+ ${CMAKE_BINARY_DIR}/lib/transport/vrt.cpp
+)
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/transport/convert_types.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp
+)
diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp
new file mode 100644
index 000000000..510d39454
--- /dev/null
+++ b/host/lib/transport/convert_types.cpp
@@ -0,0 +1,151 @@
+//
+// 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/transport/convert_types.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/asio.hpp> //endianness conversion
+#include <boost/cstdint.hpp>
+#include <complex>
+
+using namespace uhd;
+
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+typedef std::complex<float> fc32_t;
+
+static const float shorts_per_float = float(1 << 15);
+static const float floats_per_short = float(1.0/shorts_per_float);
+
+#define unrolled_loop(__inst, __len){ \
+ size_t __i = 0; \
+ for(; __i < (__len & ~0x3); __i+= 4){ \
+ __inst(__i+0); __inst(__i+1); \
+ __inst(__i+2); __inst(__i+3); \
+ } \
+ for(; __i < __len; __i++){ \
+ __inst(__i); \
+ } \
+}
+
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
+static inline void host_floats_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const fc32_t *host_floats,
+ size_t num_samps
+){
+ #define host_floats_to_usrp2_items_i(i){ \
+ boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
+ boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
+ usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
+ }
+ unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
+}
+
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_floats_i(i){ \
+ boost::uint32_t item = ntohl(usrp2_items[i]); \
+ boost::int16_t real = boost::uint16_t(item >> 16); \
+ boost::int16_t imag = boost::uint16_t(item >> 0); \
+ host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
+ }
+ unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
+}
+
+static inline void host_items_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const boost::uint32_t *host_items,
+ size_t num_samps
+){
+ #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(host_items_to_usrp2_items_i, num_samps);
+ }
+}
+
+static inline void usrp2_items_to_host_items(
+ boost::uint32_t *host_items,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(usrp2_items_to_host_items_i, num_samps);
+ }
+}
+
+void transport::convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ UHD_ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps);
+ return;
+ case io_type_t::COMPLEX_INT16:
+ host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps);
+ return;
+ case io_type_t::CUSTOM_TYPE:
+ std::memcpy(otw_buff, io_buff, num_samps*io_type.size);
+ return;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
+
+void transport::convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ UHD_ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ return;
+ case io_type_t::COMPLEX_INT16:
+ usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ return;
+ case io_type_t::CUSTOM_TYPE:
+ std::memcpy(io_buff, otw_buff, num_samps*io_type.size);
+ return;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py
new file mode 100755
index 000000000..9a57c83c3
--- /dev/null
+++ b/host/lib/transport/gen_vrt.py
@@ -0,0 +1,210 @@
+#!/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/>.
+#
+
+"""
+The vrt packer/unpacker code generator:
+
+This script will generate the pack and unpack routines that convert
+metatdata into vrt headers and vrt headers into metadata.
+
+The generated code infers jump tables to speed-up the parsing time.
+"""
+
+TMPL_TEXT = """
+#import time
+
+########################################################################
+## setup predicates
+########################################################################
+#set $sid_p = 0b00001
+#set $cid_p = 0b00010
+#set $tsi_p = 0b00100
+#set $tsf_p = 0b01000
+#set $tlr_p = 0b10000
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#include <uhd/transport/vrt.hpp>
+\#include <boost/asio.hpp> //endianness conversion
+\#include <stdexcept>
+
+using namespace uhd;
+using namespace uhd::transport;
+
+void vrt::pack(
+ const tx_metadata_t &metadata, //input
+ boost::uint32_t *header_buff, //output
+ size_t &num_header_words32, //output
+ size_t num_payload_words32, //input
+ size_t &num_packet_words32, //output
+ size_t packet_count, //input
+ double tick_rate //input
+){
+ boost::uint32_t vrt_hdr_flags;
+
+ boost::uint8_t pred = 0;
+ if (metadata.has_stream_id) pred |= $hex($sid_p);
+ if (metadata.has_time_spec) pred |= $hex($tsi_p | $tsf_p);
+
+ switch(pred){
+ #for $pred in range(2**5)
+ case $pred:
+ #set $num_header_words = 1
+ #set $flags = 0
+ ########## Stream ID ##########
+ #if $pred & $sid_p
+ header_buff[$num_header_words] = htonl(metadata.stream_id);
+ #set $num_header_words += 1
+ #set $flags |= (0x1 << 28);
+ #end if
+ ########## Class ID ##########
+ #if $pred & $cid_p
+ header_buff[$num_header_words] = htonl(0);
+ #set $num_header_words += 1
+ header_buff[$num_header_words] = htonl(0);
+ #set $num_header_words += 1
+ #set $flags |= (0x1 << 27);
+ #end if
+ ########## Integer Time ##########
+ #if $pred & $tsi_p
+ header_buff[$num_header_words] = htonl(metadata.time_spec.secs);
+ #set $num_header_words += 1
+ #set $flags |= (0x3 << 22);
+ #end if
+ ########## Fractional Time ##########
+ #if $pred & $tsf_p
+ header_buff[$num_header_words] = htonl(0);
+ #set $num_header_words += 1
+ header_buff[$num_header_words] = htonl(metadata.time_spec.get_ticks(tick_rate));
+ #set $num_header_words += 1
+ #set $flags |= (0x1 << 20);
+ #end if
+ ########## Trailer ##########
+ #if $pred & $tlr_p
+ #set $flags |= (0x1 << 26);
+ #set $num_trailer_words = 1;
+ #else
+ #set $num_trailer_words = 0;
+ #end if
+ ########## Variables ##########
+ num_header_words32 = $num_header_words;
+ num_packet_words32 = $($num_header_words + $num_trailer_words) + num_payload_words32;
+ vrt_hdr_flags = $hex($flags);
+ break;
+ #end for
+ }
+
+ //set the burst flags
+ if (metadata.start_of_burst) vrt_hdr_flags |= $hex(0x1 << 25);
+ if (metadata.end_of_burst) vrt_hdr_flags |= $hex(0x1 << 24);
+
+ //fill in complete header word
+ header_buff[0] = htonl(vrt_hdr_flags |
+ ((packet_count & 0xf) << 16) |
+ (num_packet_words32 & 0xffff)
+ );
+}
+
+void vrt::unpack(
+ rx_metadata_t &metadata, //output
+ const boost::uint32_t *header_buff, //input
+ size_t &num_header_words32, //output
+ size_t &num_payload_words32, //output
+ size_t num_packet_words32, //input
+ size_t &packet_count, //output
+ double tick_rate //input
+){
+ //clear the metadata
+ metadata = rx_metadata_t();
+
+ //extract vrt header
+ boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]);
+ size_t packet_words32 = vrt_hdr_word & 0xffff;
+ packet_count = (vrt_hdr_word >> 16) & 0xf;
+
+ //failure cases
+ if (packet_words32 == 0 or num_packet_words32 < packet_words32)
+ throw std::runtime_error("bad vrt header or packet fragment");
+ if (vrt_hdr_word & (0x7 << 29))
+ throw std::runtime_error("unsupported vrt packet type");
+
+ boost::uint8_t pred = 0;
+ if(vrt_hdr_word & $hex(0x1 << 28)) pred |= $hex($sid_p);
+ if(vrt_hdr_word & $hex(0x1 << 27)) pred |= $hex($cid_p);
+ if(vrt_hdr_word & $hex(0x3 << 22)) pred |= $hex($tsi_p);
+ if(vrt_hdr_word & $hex(0x3 << 20)) pred |= $hex($tsf_p);
+ if(vrt_hdr_word & $hex(0x1 << 26)) pred |= $hex($tlr_p);
+
+ switch(pred){
+ #for $pred in range(2**5)
+ case $pred:
+ #set $set_has_time_spec = False
+ #set $num_header_words = 1
+ ########## Stream ID ##########
+ #if $pred & $sid_p
+ metadata.has_stream_id = true;
+ metadata.stream_id = ntohl(header_buff[$num_header_words]);
+ #set $num_header_words += 1
+ #end if
+ ########## Class ID ##########
+ #if $pred & $cid_p
+ #set $num_header_words += 1
+ #set $num_header_words += 1
+ #end if
+ ########## Integer Time ##########
+ #if $pred & $tsi_p
+ metadata.has_time_spec = true;
+ #set $set_has_time_spec = True
+ metadata.time_spec.secs = ntohl(header_buff[$num_header_words]);
+ #set $num_header_words += 1
+ #end if
+ ########## Fractional Time ##########
+ #if $pred & $tsf_p
+ #if not $set_has_time_spec
+ metadata.has_time_spec = true;
+ #set $set_has_time_spec = True
+ #end if
+ #set $num_header_words += 1
+ metadata.time_spec.set_ticks(ntohl(header_buff[$num_header_words]), tick_rate);
+ #set $num_header_words += 1
+ #end if
+ ########## Trailer ##########
+ #if $pred & $tlr_p
+ #set $num_trailer_words = 1;
+ #else
+ #set $num_trailer_words = 0;
+ #end if
+ ########## Variables ##########
+ num_header_words32 = $num_header_words;
+ num_payload_words32 = packet_words32 - $($num_header_words + $num_trailer_words);
+ break;
+ #end for
+ }
+}
+"""
+
+import sys
+
+from Cheetah.Template import Template
+def parse_tmpl(_tmpl_text, **kwargs):
+ return str(Template(_tmpl_text, kwargs))
+
+if __name__ == '__main__':
+ open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__))
diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp
new file mode 100644
index 000000000..5c8c8a176
--- /dev/null
+++ b/host/lib/transport/if_addrs.cpp
@@ -0,0 +1,109 @@
+//
+// 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/transport/if_addrs.hpp>
+#include <boost/asio/ip/address_v4.hpp>
+#include <boost/cstdint.hpp>
+#include <iostream>
+
+uhd::transport::if_addrs_t::if_addrs_t(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Interface address discovery through ifaddrs api
+ **********************************************************************/
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+
+static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){
+ return boost::asio::ip::address_v4(ntohl(
+ reinterpret_cast<sockaddr_in*>(addr)->sin_addr.s_addr
+ ));
+}
+
+std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
+ std::vector<if_addrs_t> if_addrs;
+ struct ifaddrs *ifap;
+ if (getifaddrs(&ifap) == 0){
+ for (struct ifaddrs *iter = ifap; iter != NULL; iter = iter->ifa_next){
+ //ensure that the entries are valid
+ if (iter->ifa_addr->sa_family != AF_INET) continue;
+ if (iter->ifa_netmask->sa_family != AF_INET) continue;
+ if (iter->ifa_broadaddr->sa_family != AF_INET) continue;
+
+ //append a new set of interface addresses
+ if_addrs_t if_addr;
+ if_addr.inet = sockaddr_to_ip_addr(iter->ifa_addr).to_string();
+ if_addr.mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_string();
+ if_addr.bcast = sockaddr_to_ip_addr(iter->ifa_broadaddr).to_string();
+ if_addrs.push_back(if_addr);
+ }
+ freeifaddrs(ifap);
+ }
+ return if_addrs;
+}
+
+/***********************************************************************
+ * Interface address discovery through windows api (TODO)
+ **********************************************************************/
+#elif HAVE_WINSOCK2_H
+#include <winsock2.h>
+
+std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
+ std::vector<if_addrs_t> if_addrs;
+ SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
+ if (sd == SOCKET_ERROR) {
+ std::cerr << "Failed to get a socket. Error " << WSAGetLastError() <<
+ std::endl; return if_addrs;
+ }
+
+ INTERFACE_INFO InterfaceList[20];
+ unsigned long nBytesReturned;
+ if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList,
+ sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) {
+ std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() <<
+ std::endl;
+ return if_addrs;
+ }
+
+ int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
+ for (int i = 0; i < nNumInterfaces; ++i) {
+ boost::uint32_t iiAddress = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiAddress).sin_addr.s_addr);
+ boost::uint32_t iiNetmask = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiNetmask).sin_addr.s_addr);
+ boost::uint32_t iiBroadcastAddress = (iiAddress & iiNetmask) | ~iiNetmask;
+
+ if_addrs_t if_addr;
+ if_addr.inet = boost::asio::ip::address_v4(iiAddress).to_string();
+ if_addr.mask = boost::asio::ip::address_v4(iiNetmask).to_string();
+ if_addr.bcast = boost::asio::ip::address_v4(iiBroadcastAddress).to_string();
+ if_addrs.push_back(if_addr);
+ }
+
+ return if_addrs;
+}
+
+/***********************************************************************
+ * Interface address discovery not included
+ **********************************************************************/
+#else /* HAVE_IFADDRS_H */
+
+std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
+ return std::vector<if_addrs_t>();
+}
+
+#endif /* HAVE_IFADDRS_H */
diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp
new file mode 100644
index 000000000..f339127ad
--- /dev/null
+++ b/host/lib/transport/udp_simple.cpp
@@ -0,0 +1,159 @@
+//
+// 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/transport/udp_simple.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+/*!
+ * A receive timeout for a socket:
+ *
+ * It seems that asio cannot have timeouts with synchronous io.
+ * However, we can implement a polling loop that will timeout.
+ * This is okay bacause this is the slow-path implementation.
+ *
+ * \param socket the asio socket
+ */
+static void reasonable_recv_timeout(
+ boost::asio::ip::udp::socket &socket
+){
+ boost::asio::deadline_timer timer(socket.get_io_service());
+ timer.expires_from_now(boost::posix_time::milliseconds(100));
+ while (not (socket.available() or timer.expires_from_now().is_negative())){
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+}
+
+/***********************************************************************
+ * UDP connected implementation class
+ **********************************************************************/
+class udp_connected_impl : public udp_simple{
+public:
+ //structors
+ udp_connected_impl(const std::string &addr, const std::string &port);
+ ~udp_connected_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+};
+
+udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ // Create, open, and connect the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+}
+
+udp_connected_impl::~udp_connected_impl(void){
+ delete _socket;
+}
+
+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);
+ if (not _socket->available()) return 0;
+ return _socket->receive(boost::asio::buffer(buff));
+}
+
+/***********************************************************************
+ * UDP broadcast implementation class
+ **********************************************************************/
+class udp_broadcast_impl : public udp_simple{
+public:
+ //structors
+ udp_broadcast_impl(const std::string &addr, const std::string &port);
+ ~udp_broadcast_impl(void);
+
+ //send/recv
+ size_t send(const boost::asio::const_buffer &buff);
+ size_t recv(const boost::asio::mutable_buffer &buff);
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::ip::udp::endpoint _receiver_endpoint;
+ boost::asio::io_service _io_service;
+};
+
+udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ _receiver_endpoint = *resolver.resolve(query);
+
+ // Create and open the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+
+ // Allow broadcasting
+ boost::asio::socket_base::broadcast option(true);
+ _socket->set_option(option);
+
+}
+
+udp_broadcast_impl::~udp_broadcast_impl(void){
+ delete _socket;
+}
+
+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);
+ if (not _socket->available()) return 0;
+ boost::asio::ip::udp::endpoint sender_endpoint;
+ return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint);
+}
+
+/***********************************************************************
+ * UDP public make functions
+ **********************************************************************/
+udp_simple::sptr udp_simple::make_connected(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_connected_impl(addr, port));
+}
+
+udp_simple::sptr udp_simple::make_broadcast(
+ const std::string &addr, const std::string &port
+){
+ return sptr(new udp_broadcast_impl(addr, port));
+}
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
new file mode 100644
index 000000000..56ba391d3
--- /dev/null
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -0,0 +1,210 @@
+//
+// 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/transport/udp_zero_copy.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/asio.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd::transport;
+
+/***********************************************************************
+ * Managed receive buffer implementation for udp zero-copy asio:
+ **********************************************************************/
+class managed_recv_buffer_impl : public managed_recv_buffer{
+public:
+ managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){
+ /* NOP */
+ }
+
+ ~managed_recv_buffer_impl(void){
+ /* NOP */
+ }
+
+ void done(void){
+ /* NOP */
+ }
+
+private:
+ const boost::asio::const_buffer &get(void) const{
+ return _buff;
+ }
+
+ const boost::asio::const_buffer _buff;
+};
+
+/***********************************************************************
+ * Managed send buffer implementation for udp zero-copy asio:
+ **********************************************************************/
+class managed_send_buffer_impl : public managed_send_buffer{
+public:
+ managed_send_buffer_impl(
+ const boost::asio::mutable_buffer &buff,
+ boost::asio::ip::udp::socket *socket
+ ) : _buff(buff), _socket(socket){
+ /* NOP */
+ }
+
+ ~managed_send_buffer_impl(void){
+ /* NOP */
+ }
+
+ void done(size_t num_bytes){
+ _socket->send(boost::asio::buffer(_buff, num_bytes));
+ }
+
+private:
+ const boost::asio::mutable_buffer &get(void) const{
+ return _buff;
+ }
+
+ const boost::asio::mutable_buffer _buff;
+ boost::asio::ip::udp::socket *_socket;
+};
+
+/***********************************************************************
+ * Zero Copy UDP implementation with ASIO:
+ * This is the portable zero copy implementation for systems
+ * where a faster, platform specific solution is not available.
+ * However, it is not a true zero copy implementation as each
+ * send and recv requires a copy operation to/from userspace.
+ **********************************************************************/
+static const size_t max_buff_size = 2000; //assume max size on send and recv
+
+class udp_zero_copy_impl : public udp_zero_copy{
+public:
+ typedef boost::shared_ptr<udp_zero_copy_impl> sptr;
+
+ //structors
+ udp_zero_copy_impl(const std::string &addr, const std::string &port);
+ ~udp_zero_copy_impl(void);
+
+ //send/recv
+ managed_recv_buffer::sptr get_recv_buff(void);
+ managed_send_buffer::sptr get_send_buff(void);
+
+ //manage buffer
+ template <typename Opt> size_t get_buff_size(void){
+ Opt option;
+ _socket->get_option(option);
+ return option.value();
+ }
+
+ template <typename Opt> size_t resize_buff(size_t num_bytes){
+ Opt option(num_bytes);
+ _socket->set_option(option);
+ return get_buff_size<Opt>();
+ }
+
+private:
+ boost::asio::ip::udp::socket *_socket;
+ boost::asio::io_service _io_service;
+
+ //send and recv buffer memory (allocated once)
+ boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size];
+
+ managed_send_buffer::sptr _send_buff;
+};
+
+udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){
+ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
+
+ // resolve the address
+ boost::asio::ip::udp::resolver resolver(_io_service);
+ boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);
+ boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+
+ // create, open, and connect the socket
+ _socket = new boost::asio::ip::udp::socket(_io_service);
+ _socket->open(boost::asio::ip::udp::v4());
+ _socket->connect(receiver_endpoint);
+
+ // create the managed send buff (just once)
+ _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl(
+ boost::asio::buffer(_send_mem, max_buff_size), _socket
+ ));
+
+ // set recv timeout
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100*1000; //100 ms
+ UHD_ASSERT_THROW(setsockopt(
+ _socket->native(),
+ SOL_SOCKET, SO_RCVTIMEO,
+ (const char *)&tv, sizeof(timeval)
+ ) == 0);
+}
+
+udp_zero_copy_impl::~udp_zero_copy_impl(void){
+ delete _socket;
+}
+
+managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
+ //call recv() with timeout option
+ size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size));
+
+ //create a new managed buffer to house the data
+ return managed_recv_buffer::sptr(
+ new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes))
+ );
+}
+
+managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){
+ return _send_buff;
+}
+
+/***********************************************************************
+ * UDP zero copy make function
+ **********************************************************************/
+template<typename Opt> static inline void resize_buff_helper(
+ udp_zero_copy_impl::sptr udp_trans,
+ size_t target_size,
+ const std::string &name
+){
+ static const size_t min_buff_size = size_t(100e3);
+
+ //resize the buffer if size was provided
+ if (target_size > 0){
+ size_t actual_size = udp_trans->resize_buff<Opt>(target_size);
+ if (target_size != actual_size) std::cout << boost::format(
+ "Target %s buffer size: %d\n"
+ "Actual %s byffer size: %d"
+ ) % name % target_size % name % actual_size << std::endl;
+ }
+
+ //otherwise, ensure that the buffer is at least the minimum size
+ else if (udp_trans->get_buff_size<Opt>() < min_buff_size){
+ resize_buff_helper<Opt>(udp_trans, min_buff_size, name);
+ }
+}
+
+udp_zero_copy::sptr udp_zero_copy::make(
+ const std::string &addr,
+ const std::string &port,
+ size_t recv_buff_size,
+ size_t send_buff_size
+){
+ udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port));
+
+ //call the helper to resize send and recv buffers
+ resize_buff_helper<boost::asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv");
+ resize_buff_helper<boost::asio::socket_base::send_buffer_size> (udp_trans, send_buff_size, "send");
+
+ return udp_trans;
+}
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
new file mode 100644
index 000000000..5b73c82bf
--- /dev/null
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -0,0 +1,363 @@
+//
+// 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_TRANSPORT_VRT_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/convert_types.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/function.hpp>
+#include <stdexcept>
+#include <iostream>
+
+namespace vrt_packet_handler{
+
+/***********************************************************************
+ * vrt packet handler for recv
+ **********************************************************************/
+ struct recv_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ //state variables to handle fragments
+ uhd::transport::managed_recv_buffer::sptr managed_buff;
+ boost::asio::const_buffer copy_buff;
+ size_t fragment_offset_in_samps;
+
+ recv_state(void){
+ //first expected seq is zero
+ next_packet_seq = 0;
+
+ //initially empty copy buffer
+ copy_buff = boost::asio::buffer("", 0);
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t;
+
+ static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Unpack a received vrt header and set the copy buffer.
+ * - helper function for vrt_packet_handler::_recv1
+ ******************************************************************/
+ static UHD_INLINE void _recv1_helper(
+ recv_state &state,
+ uhd::rx_metadata_t &metadata,
+ double tick_rate,
+ size_t vrt_header_offset_words32
+ ){
+ size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t);
+ if (num_packet_words32 <= vrt_header_offset_words32){
+ state.copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
+ const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32;
+ size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
+ uhd::transport::vrt::unpack(
+ metadata, //output
+ vrt_hdr, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out, //output
+ tick_rate
+ );
+
+ //handle the packet count / sequence number
+ if (packet_count_out != state.next_packet_seq){
+ std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16;
+ }
+ state.next_packet_seq = (packet_count_out+1)%16;
+
+ //setup the buffer to point to the data
+ state.copy_buff = boost::asio::buffer(
+ vrt_hdr + num_header_words32_out,
+ num_payload_words32_out*sizeof(boost::uint32_t)
+ );
+ }
+
+ /*******************************************************************
+ * Recv data, unpack a vrt header, and copy-convert the data.
+ * - helper function for vrt_packet_handler::recv
+ ******************************************************************/
+ static UHD_INLINE size_t _recv1(
+ recv_state &state,
+ void *recv_mem,
+ size_t total_samps,
+ uhd::rx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32,
+ const recv_cb_t& recv_cb
+ ){
+ //perform a receive if no rx data is waiting to be copied
+ if (boost::asio::buffer_size(state.copy_buff) == 0){
+ state.fragment_offset_in_samps = 0;
+ state.managed_buff = zc_iface->get_recv_buff();
+ recv_cb(state.managed_buff); //callback before vrt unpack
+ _recv1_helper(
+ state, metadata, tick_rate, vrt_header_offset_words32
+ );
+ }
+
+ //extract the number of samples available to copy
+ size_t bytes_per_item = otw_type.get_sample_size();
+ size_t bytes_available = boost::asio::buffer_size(state.copy_buff);
+ size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item);
+
+ //setup the fragment flags and offset
+ metadata.more_fragments = total_samps < num_samps;
+ metadata.fragment_offset = state.fragment_offset_in_samps;
+ state.fragment_offset_in_samps += num_samps; //set for next call
+
+ //copy-convert the samples from the recv buffer
+ uhd::transport::convert_otw_type_to_io_type(
+ boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type,
+ recv_mem, io_type, num_samps
+ );
+
+ //update the rx copy buffer to reflect the bytes copied
+ size_t bytes_copied = num_samps*bytes_per_item;
+ state.copy_buff = boost::asio::buffer(
+ boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied,
+ bytes_available - bytes_copied
+ );
+
+ return num_samps;
+ }
+
+ /*******************************************************************
+ * Recv vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t recv(
+ recv_state &state,
+ const boost::asio::mutable_buffer &buff,
+ uhd::rx_metadata_t &metadata,
+ uhd::device::recv_mode_t recv_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const recv_cb_t& recv_cb = &recv_cb_nop
+ ){
+ metadata = uhd::rx_metadata_t(); //init the metadata
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+
+ switch(recv_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ return _recv1(
+ state,
+ boost::asio::buffer_cast<void *>(buff),
+ total_num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::RECV_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ size_t num_samps = 0;
+ uhd::rx_metadata_t tmp_md;
+ while(num_samps < total_num_samps){
+ num_samps += _recv1(
+ state,
+ boost::asio::buffer_cast<boost::uint8_t *>(buff) + (num_samps*io_type.size),
+ total_num_samps - num_samps,
+ (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ recv_cb
+ );
+ }
+ return total_num_samps;
+ }
+
+ default: throw std::runtime_error("unknown recv mode");
+ }//switch(recv_mode)
+ }
+
+/***********************************************************************
+ * vrt packet handler for send
+ **********************************************************************/
+ struct send_state{
+ //init the expected seq number
+ size_t next_packet_seq;
+
+ send_state(void){
+ next_packet_seq = 0;
+ }
+ };
+
+ typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t;
+
+ static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){
+ /* NOP */
+ }
+
+ /*******************************************************************
+ * Pack a vrt header, copy-convert the data, and send it.
+ * - helper function for vrt_packet_handler::send
+ ******************************************************************/
+ static UHD_INLINE void _send1(
+ send_state &state,
+ const void *send_mem,
+ size_t num_samps,
+ const uhd::tx_metadata_t &metadata,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t vrt_header_offset_words32,
+ const send_cb_t& send_cb
+ ){
+ //get a new managed send buffer
+ uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff();
+ boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32;
+
+ size_t num_header_words32, num_packet_words32;
+ size_t packet_count = state.next_packet_seq++;
+
+ //pack metadata into a vrt header
+ uhd::transport::vrt::pack(
+ metadata, //input
+ tx_mem, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count, //input
+ tick_rate
+ );
+
+ //copy-convert the samples into the send buffer
+ uhd::transport::convert_io_type_to_otw_type(
+ send_mem, io_type,
+ tx_mem + num_header_words32, otw_type,
+ num_samps
+ );
+
+ send_cb(send_buff); //callback after memory filled
+
+ //commit the samples to the zero-copy interface
+ send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
+ }
+
+ /*******************************************************************
+ * Send vrt packets and copy convert the samples into the buffer.
+ ******************************************************************/
+ static UHD_INLINE size_t send(
+ send_state &state,
+ const boost::asio::const_buffer &buff,
+ const uhd::tx_metadata_t &metadata,
+ uhd::device::send_mode_t send_mode,
+ const uhd::io_type_t &io_type,
+ const uhd::otw_type_t &otw_type,
+ double tick_rate,
+ uhd::transport::zero_copy_if::sptr zc_iface,
+ size_t max_samples_per_packet,
+ //use these two params to handle a layer above vrt
+ size_t vrt_header_offset_words32 = 0,
+ const send_cb_t& send_cb = &send_cb_nop
+ ){
+ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size;
+ switch(send_mode){
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_ONE_PACKET:{
+ ////////////////////////////////////////////////////////////////
+ size_t num_samps = std::min(total_num_samps, max_samples_per_packet);
+ _send1(
+ state,
+ boost::asio::buffer_cast<const void *>(buff),
+ num_samps,
+ metadata,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ return num_samps;
+ }
+
+ ////////////////////////////////////////////////////////////////
+ case uhd::device::SEND_MODE_FULL_BUFF:{
+ ////////////////////////////////////////////////////////////////
+ //calculate constants for fragmentation
+ const size_t final_packet_samps = total_num_samps%max_samples_per_packet;
+ const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet;
+ static const size_t first_fragment_index = 0;
+ const size_t final_fragment_index = num_fragments-1;
+
+ //make a rw copy of the metadata to re-flag below
+ uhd::tx_metadata_t md(metadata);
+
+ //loop through the following fragment indexes
+ for (size_t n = first_fragment_index; n <= final_fragment_index; n++){
+
+ //calculate new flags for the fragments
+ md.has_time_spec = md.has_time_spec and (n == first_fragment_index);
+ md.start_of_burst = md.start_of_burst and (n == first_fragment_index);
+ md.end_of_burst = md.end_of_burst and (n == final_fragment_index);
+
+ //send the fragment with the helper function
+ _send1(
+ state,
+ boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size),
+ (n == final_fragment_index)?final_packet_samps:max_samples_per_packet,
+ md,
+ io_type, otw_type,
+ tick_rate,
+ zc_iface,
+ vrt_header_offset_words32,
+ send_cb
+ );
+ }
+ return total_num_samps;
+ }
+
+ default: throw std::runtime_error("unknown send mode");
+ }//switch(send_mode)
+ }
+
+} //namespace vrt_packet_handler
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
new file mode 100644
index 000000000..daf3be7f7
--- /dev/null
+++ b/host/lib/types.cpp
@@ -0,0 +1,307 @@
+//
+// 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>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/tune_result.hpp>
+#include <uhd/types/clock_config.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/types/mac_addr.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/thread.hpp>
+#include <stdexcept>
+#include <complex>
+
+using namespace uhd;
+
+/***********************************************************************
+ * ranges
+ **********************************************************************/
+gain_range_t::gain_range_t(float min, float max, float step):
+ min(min),
+ max(max),
+ step(step)
+{
+ /* NOP */
+}
+
+freq_range_t::freq_range_t(double min, double max):
+ min(min),
+ max(max)
+{
+ /* NOP */
+}
+
+/***********************************************************************
+ * 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 */
+}
+
+/***********************************************************************
+ * clock config
+ **********************************************************************/
+clock_config_t::clock_config_t(void):
+ ref_source(REF_INT),
+ pps_source(PPS_INT),
+ pps_polarity(PPS_NEG)
+{
+ /* NOP */
+}
+
+/***********************************************************************
+ * stream command
+ **********************************************************************/
+stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode):
+ stream_mode(stream_mode),
+ num_samps(0),
+ stream_now(true)
+{
+ /* NOP */
+}
+
+/***********************************************************************
+ * metadata
+ **********************************************************************/
+rx_metadata_t::rx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ more_fragments(false),
+ fragment_offset(0)
+{
+ /* NOP */
+}
+
+tx_metadata_t::tx_metadata_t(void):
+ has_stream_id(false),
+ stream_id(0),
+ has_time_spec(false),
+ time_spec(time_spec_t()),
+ start_of_burst(false),
+ end_of_burst(false)
+{
+ /* NOP */
+}
+
+/***********************************************************************
+ * time spec
+ **********************************************************************/
+time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs):
+ secs(secs),
+ nsecs(nsecs)
+{
+ /* NOP */
+}
+
+boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
+ return boost::math::iround(nsecs*tick_rate*1e-9);
+}
+
+void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){
+ nsecs = double(ticks)*1e9/tick_rate;
+}
+
+/***********************************************************************
+ * device addr
+ **********************************************************************/
+static const std::string arg_delim = ",";
+static const std::string pair_delim = "=";
+
+static std::string trim(const std::string &in){
+ return boost::algorithm::trim_copy(in);
+}
+
+device_addr_t::device_addr_t(const std::string &args){
+ //split the args at the semi-colons
+ std::vector<std::string> pairs;
+ boost::split(pairs, args, boost::is_any_of(arg_delim));
+ BOOST_FOREACH(const std::string &pair, pairs){
+ if (trim(pair) == "") continue;
+
+ //split the key value pairs at the equals
+ 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]);
+ }
+}
+
+std::string device_addr_t::to_pp_string(void) const{
+ if (this->size() == 0) return "Empty Device Address";
+
+ std::stringstream ss;
+ BOOST_FOREACH(std::string key, this->keys()){
+ 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;
+ BOOST_FOREACH(const std::string &key, this->keys()){
+ args_str += key + pair_delim + (*this)[key] + arg_delim;
+ }
+ return args_str;
+}
+
+/***********************************************************************
+ * mac addr
+ **********************************************************************/
+mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){
+ UHD_ASSERT_THROW(_bytes.size() == 6);
+}
+
+mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){
+ return mac_addr_t(bytes);
+}
+
+mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){
+
+ byte_vector_t bytes = boost::assign::list_of
+ (0x00)(0x50)(0xC2)(0x85)(0x30)(0x00); // Matt's IAB
+
+ try{
+ //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx
+ //the IAB above will fill in for the shorter pattern
+ if (mac_addr_str.size() != 5 and mac_addr_str.size() != 17)
+ throw std::runtime_error("expected exactly 5 or 17 characters");
+
+ //split the mac addr hex string at the colons
+ std::vector<std::string> hex_strs;
+ boost::split(hex_strs, mac_addr_str, boost::is_any_of(":"));
+ for (size_t i = 0; i < hex_strs.size(); i++){
+ int hex_num;
+ std::istringstream iss(hex_strs[i]);
+ iss >> std::hex >> hex_num;
+ bytes[i] = boost::uint8_t(hex_num);
+ }
+
+ }
+ catch(std::exception const& e){
+ throw std::runtime_error(str(
+ boost::format("Invalid mac address: %s\n\t%s") % mac_addr_str % e.what()
+ ));
+ }
+
+ return mac_addr_t::from_bytes(bytes);
+}
+
+byte_vector_t mac_addr_t::to_bytes(void) const{
+ return _bytes;
+}
+
+std::string mac_addr_t::to_string(void) const{
+ std::string addr = "";
+ BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){
+ addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte));
+ }
+ return addr;
+}
+
+/***********************************************************************
+ * otw type
+ **********************************************************************/
+size_t otw_type_t::get_sample_size(void) const{
+ return (this->width * 2) / 8;
+}
+
+otw_type_t::otw_type_t(void):
+ width(0),
+ shift(0),
+ byteorder(BO_NATIVE)
+{
+ /* NOP */
+}
+
+/***********************************************************************
+ * io type
+ **********************************************************************/
+static size_t tid_to_size(io_type_t::tid_t tid){
+ switch(tid){
+ case io_type_t::COMPLEX_FLOAT32: return sizeof(std::complex<float>);
+ case io_type_t::COMPLEX_INT16: return sizeof(std::complex<boost::int16_t>);
+ case io_type_t::COMPLEX_INT8: return sizeof(std::complex<boost::int8_t>);
+ default: throw std::runtime_error("unknown io type tid");
+ }
+}
+
+io_type_t::io_type_t(tid_t tid)
+: size(tid_to_size(tid)), tid(tid){
+ /* NOP */
+}
+
+io_type_t::io_type_t(size_t size)
+: size(size), tid(CUSTOM_TYPE){
+ /* NOP */
+}
+
+/***********************************************************************
+ * serial
+ **********************************************************************/
+spi_config_t::spi_config_t(edge_t edge):
+ mosi_edge(edge),
+ miso_edge(edge)
+{
+ /* NOP */
+}
+
+void i2c_iface::write_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ const byte_vector_t &bytes
+){
+ for (size_t i = 0; i < bytes.size(); i++){
+ //write a byte at a time, its easy that way
+ byte_vector_t cmd = boost::assign::list_of(offset+i)(bytes[i]);
+ this->write_i2c(addr, cmd);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10)); //worst case write
+ }
+}
+
+byte_vector_t i2c_iface::read_eeprom(
+ boost::uint8_t addr,
+ boost::uint8_t offset,
+ size_t num_bytes
+){
+ byte_vector_t bytes;
+ for (size_t i = 0; i < num_bytes; i++){
+ //do a zero byte write to start read cycle
+ this->write_i2c(addr, byte_vector_t(1, offset+i));
+ bytes.push_back(this->read_i2c(addr, 1).at(0));
+ }
+ return bytes;
+}
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
new file mode 100644
index 000000000..39a72ab37
--- /dev/null
+++ b/host/lib/usrp/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# 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!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_base.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_eeprom.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_id.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp
+)
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
new file mode 100644
index 000000000..3a6c2d84a
--- /dev/null
+++ b/host/lib/usrp/dboard/CMakeLists.txt
@@ -0,0 +1,26 @@
+#
+# 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!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_basic_and_lf.cpp
+ ${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
+)
+
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
new file mode 100644
index 000000000..23ac98872
--- /dev/null
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -0,0 +1,284 @@
+//
+// 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_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The basic and lf boards:
+ * They share a common class because only the frequency bounds differ.
+ **********************************************************************/
+class basic_rx : public rx_dboard_base{
+public:
+ basic_rx(ctor_args_t args, double max_freq);
+ ~basic_rx(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ double _max_freq;
+};
+
+class basic_tx : public tx_dboard_base{
+public:
+ basic_tx(ctor_args_t args, double max_freq);
+ ~basic_tx(void);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ double _max_freq;
+};
+
+/***********************************************************************
+ * Register the basic and LF dboards
+ **********************************************************************/
+static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new basic_rx(args, 90e9));
+}
+
+static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new basic_tx(args, 90e9));
+}
+
+static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new basic_rx(args, 32e6));
+}
+
+static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new basic_tx(args, 32e6));
+}
+
+UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){
+ dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX");
+ dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("AB")("A")("B"));
+ dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX");
+ dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("AB")("A")("B"));
+}
+
+/***********************************************************************
+ * Basic and LF RX dboard
+ **********************************************************************/
+basic_rx::basic_rx(ctor_args_t args, double max_freq) : rx_dboard_base(args){
+ _max_freq = max_freq;
+}
+
+basic_rx::~basic_rx(void){
+ /* NOP */
+}
+
+void basic_rx::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 = std::string(str(boost::format("%s - %s")
+ % get_rx_id().to_pp_string()
+ % get_subdev_name()
+ ));
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = double(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ 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_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = true; //there is no LO, so it must be true!
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void basic_rx::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_GAIN:
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * Basic and LF TX dboard
+ **********************************************************************/
+basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args){
+ _max_freq = max_freq;
+}
+
+basic_tx::~basic_tx(void){
+ /* NOP */
+}
+
+void basic_tx::tx_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_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = double(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(+_max_freq, -_max_freq);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ 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;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = true; //there is no LO, so it must be true!
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void basic_tx::tx_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_GAIN:
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
new file mode 100644
index 000000000..bbc9716b1
--- /dev/null
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -0,0 +1,532 @@
+//
+// 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/>.
+//
+
+static const bool rfx_debug = false;
+
+// IO Pin functions
+#define POWER_IO (1 << 7) // Low enables power supply
+#define ANTSW_IO (1 << 6) // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2
+#define MIXER_IO (1 << 5) // Enable appropriate mixer
+#define LOCKDET_MASK (1 << 2) // Input pin
+
+// Mixer constants
+#define MIXER_ENB MIXER_IO
+#define MIXER_DIS 0
+
+// Power constants
+#define POWER_UP 0
+#define POWER_DOWN POWER_IO
+
+// Antenna constants
+#define ANT_TX 0 //the tx line is transmitting
+#define ANT_RX ANTSW_IO //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 ANTSW_IO //the rx line in on rx2
+#define ANT_XX 0 //dont care how the antenna is set
+
+#include "adf4360_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/algorithm.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/math/special_functions/round.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The RFX series of dboards
+ **********************************************************************/
+static const float _max_rx_pga0_gain = 45;
+
+class rfx_xcvr : public xcvr_dboard_base{
+public:
+ rfx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range,
+ bool rx_div2, bool tx_div2
+ );
+ ~rfx_xcvr(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_range_t _freq_range;
+ uhd::dict<dboard_iface::unit_t, bool> _div2;
+ double _rx_lo_freq, _tx_lo_freq;
+ std::string _rx_ant;
+ float _rx_pga0_gain;
+
+ void set_rx_lo_freq(double freq);
+ void set_tx_lo_freq(double freq);
+ void set_rx_ant(const std::string &ant);
+ void set_rx_pga0_gain(float gain);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+
+ /*!
+ * Get the lock detect status of the LO.
+ * \param unit which unit rx or tx
+ * \return true for locked
+ */
+ bool get_locked(dboard_iface::unit_t unit){
+ return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+ }
+};
+
+/***********************************************************************
+ * Register the RFX dboards (min freq, max freq, rx div2, tx div2)
+ **********************************************************************/
+static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true));
+}
+
+static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6), true, true));
+}
+
+static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6), false, false));
+}
+
+static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6), true, true));
+}
+
+static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6), false, false));
+}
+
+UHD_STATIC_BLOCK(reg_rfx_dboards){
+ dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B");
+ dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B");
+ dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B");
+ dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B");
+ dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B");
+ dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+rfx_xcvr::rfx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range,
+ bool rx_div2, bool tx_div2
+) : xcvr_dboard_base(args){
+ _freq_range = freq_range;
+ _div2[dboard_iface::UNIT_RX] = rx_div2;
+ _div2[dboard_iface::UNIT_TX] = tx_div2;
+
+ //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);
+
+ //set the gpio directions
+ boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO;
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);
+
+ //setup the tx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP | ANT_RX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_TX | MIXER_ENB);
+
+ //setup the rx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_RX2| MIXER_ENB);
+
+ //set some default values
+ set_rx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_rx_ant("RX2");
+ set_rx_pga0_gain(0);
+}
+
+rfx_xcvr::~rfx_xcvr(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void rfx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void rfx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
+}
+
+void rfx_xcvr::set_rx_ant(const std::string &ant){
+ //validate input
+ UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+
+ //set the rx atr regs that change with antenna setting
+ this->get_iface()->set_atr_reg(
+ dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
+ POWER_UP | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
+ );
+
+ //shadow the setting
+ _rx_ant = ant;
+}
+
+void rfx_xcvr::set_rx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_rx_pga0_gain);
+
+ //voltage level constants
+ static const float max_volts = float(.2), min_volts = float(1.2);
+ static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain;
+
+ //calculate the voltage for the aux dac
+ float dac_volts = gain*slope + min_volts;
+
+ //write the new voltage to the aux dac
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 1, dac_volts);
+
+ //shadow the setting (does not account for precision loss)
+ _rx_pga0_gain = gain;
+}
+
+double rfx_xcvr::set_lo_freq(
+ dboard_iface::unit_t unit,
+ double target_freq
+){
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: target frequency %f Mhz"
+ ) % (target_freq/1e6) << std::endl;
+
+ //clip the input
+ target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max);
+ if (_div2[unit]) target_freq *= 2;
+
+ //map prescalers to the register enums
+ static const uhd::dict<int, adf4360_regs_t::prescaler_value_t> prescaler_to_enum = map_list_of
+ (8, adf4360_regs_t::PRESCALER_VALUE_8_9)
+ (16, adf4360_regs_t::PRESCALER_VALUE_16_17)
+ (32, adf4360_regs_t::PRESCALER_VALUE_32_33)
+ ;
+
+ //map band select clock dividers to enums
+ static const uhd::dict<int, adf4360_regs_t::band_select_clock_div_t> bandsel_to_enum = map_list_of
+ (1, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_1)
+ (2, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_2)
+ (4, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_4)
+ (8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8)
+ ;
+
+ double actual_freq, ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R, BS, P, B, A;
+
+ /*
+ * The goal here to to loop though possible R dividers,
+ * band select clock dividers, and prescaler values.
+ * Calculate the A and B counters for each set of values.
+ * The loop exists when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * fvco = [P*B + A] * fref/R
+ * fvco*R/fref = P*B + A = N
+ */
+ for(R = 2; R <= 32; R+=2){
+ BOOST_FOREACH(BS, bandsel_to_enum.keys()){
+ if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock
+ BOOST_FOREACH(P, prescaler_to_enum.keys()){
+ //calculate B and A from N
+ double N = target_freq*R/ref_freq;
+ B = int(std::floor(N/P));
+ A = boost::math::iround(N - P*B);
+ if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B
+ //calculate the actual frequency
+ actual_freq = double(P*B + A)*ref_freq/R;
+ if (actual_freq/P > 300e6) continue; //constraint on prescaler output
+ //constraints met: exit loop
+ goto done_loop;
+ }
+ }
+ } done_loop:
+
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d"
+ ) % R % BS % P % B % A << std::endl;
+
+ //load the register values
+ adf4360_regs_t regs;
+ regs.core_power_level = adf4360_regs_t::CORE_POWER_LEVEL_10MA;
+ regs.counter_operation = adf4360_regs_t::COUNTER_OPERATION_NORMAL;
+ regs.muxout_control = adf4360_regs_t::MUXOUT_CONTROL_DLD;
+ regs.phase_detector_polarity = adf4360_regs_t::PHASE_DETECTOR_POLARITY_POS;
+ regs.charge_pump_output = adf4360_regs_t::CHARGE_PUMP_OUTPUT_NORMAL;
+ regs.cp_gain_0 = adf4360_regs_t::CP_GAIN_0_SET1;
+ regs.mute_till_ld = adf4360_regs_t::MUTE_TILL_LD_ENB;
+ regs.output_power_level = adf4360_regs_t::OUTPUT_POWER_LEVEL_3_5MA;
+ regs.current_setting1 = adf4360_regs_t::CURRENT_SETTING1_0_31MA;
+ regs.current_setting2 = adf4360_regs_t::CURRENT_SETTING2_0_31MA;
+ regs.power_down = adf4360_regs_t::POWER_DOWN_NORMAL_OP;
+ regs.prescaler_value = prescaler_to_enum[P];
+ regs.a_counter = A;
+ regs.b_counter = B;
+ regs.cp_gain_1 = adf4360_regs_t::CP_GAIN_1_SET1;
+ regs.divide_by_2_output = (_div2[unit])?
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
+ regs.divide_by_2_prescaler = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
+ regs.r_counter = R;
+ regs.ablpw = adf4360_regs_t::ABLPW_3_0NS;
+ regs.lock_detect_precision = adf4360_regs_t::LOCK_DETECT_PRECISION_5CYCLES;
+ regs.test_mode_bit = 0;
+ regs.band_select_clock_div = bandsel_to_enum[BS];
+
+ //write the registers
+ std::vector<adf4360_regs_t::addr_t> addrs = list_of //correct power-up sequence to write registers (R, C, N)
+ (adf4360_regs_t::ADDR_RCOUNTER)
+ (adf4360_regs_t::ADDR_CONTROL)
+ (adf4360_regs_t::ADDR_NCOUNTER)
+ ;
+ BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){
+ this->get_iface()->write_spi(
+ unit, spi_config_t::EDGE_RISE,
+ regs.get_reg(addr), 24
+ );
+ }
+
+ //return the actual frequency
+ if (_div2[unit]) actual_freq /= 2;
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: actual frequency %f Mhz"
+ ) % (actual_freq/1e6) << std::endl;
+ return actual_freq;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void rfx_xcvr::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:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = _rx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_rx_pga0_gain, float(0.022));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:{
+ prop_names_t ants = list_of("TX/RX")("RX2");
+ val = ants;
+ }
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_RX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void rfx_xcvr::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:
+ set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ set_rx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ set_rx_ant(val.as<std::string>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void rfx_xcvr::tx_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_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, "TX/RX");
+ 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_USE_LO_OFFSET:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_TX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void rfx_xcvr::tx_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:
+ set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ //no gains to set!
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ //its always set to tx/rx, so we only allow this value
+ UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
new file mode 100644
index 000000000..2a8a3a9f2
--- /dev/null
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -0,0 +1,613 @@
+//
+// 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/>.
+//
+
+static const bool wbx_debug = false;
+
+// Common IO Pins
+#define ANTSW_IO ((1 << 5)|(1 << 15)) // on UNIT_TX, 0 = TX, 1 = RX, on UNIT_RX 0 = main ant, 1 = RX2
+#define ADF4350_CE (1 << 3)
+#define ADF4350_PDBRF (1 << 2)
+#define ADF4350_MUXOUT (1 << 1) // INPUT!!!
+#define LOCKDET_MASK (1 << 0) // INPUT!!!
+
+// TX IO Pins
+#define TX_PUP_5V (1 << 7) // enables 5.0V power supply
+#define TX_PUP_3V (1 << 6) // enables 3.3V supply
+#define TXMOD_EN (1 << 4) // on UNIT_TX, 1 enables TX Modulator
+
+// RX IO Pins
+#define RX_PUP_5V (1 << 7) // enables 5.0V power supply
+#define RX_PUP_3V (1 << 6) // enables 3.3V supply
+#define RXBB_PDB (1 << 4) // on UNIT_RX, 1 powers up RX baseband
+
+// RX Attenuator Pins
+#define RX_ATTN_SHIFT 8 // lsb of RX Attenuator Control
+#define RX_ATTN_MASK (63 << RX_ATTN_SHIFT) // valid bits of RX Attenuator Control
+
+// Mixer functions
+#define TX_MIXER_ENB (TXMOD_EN|ADF4350_PDBRF)
+#define TX_MIXER_DIS 0
+
+#define RX_MIXER_ENB (RXBB_PDB|ADF4350_PDBRF)
+#define RX_MIXER_DIS 0
+
+// Pin functions
+#define TX_POWER_IO (TX_PUP_5V|TX_PUP_3V) // high enables power supply
+#define TXIO_MASK (TX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|TXMOD_EN)
+
+#define RX_POWER_IO (RX_PUP_5V|RX_PUP_3V) // high enables power supply
+#define RXIO_MASK (RX_POWER_IO|ANTSW_IO|ADF4350_CE|ADF4350_PDBRF|RXBB_PDB|RX_ATTN_MASK)
+
+// Power functions
+#define TX_POWER_UP (TX_POWER_IO|ADF4350_CE)
+#define TX_POWER_DOWN 0
+
+#define RX_POWER_UP (RX_POWER_IO|ADF4350_CE)
+#define RX_POWER_DOWN 0
+
+// Antenna constants
+#define ANT_TX 0 //the tx line is transmitting
+#define ANT_RX ANTSW_IO //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 ANTSW_IO //the rx line in on rx2
+#define ANT_XX 0 //dont care how the antenna is set
+
+#include "adf4350_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/algorithm.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/math/special_functions/round.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The WBX dboard
+ **********************************************************************/
+static const float _max_rx_pga0_gain = 31.5;
+static const float _max_tx_pga0_gain = 25;
+
+class wbx_xcvr : public xcvr_dboard_base{
+public:
+ wbx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range
+ );
+ ~wbx_xcvr(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_range_t _freq_range;
+ uhd::dict<dboard_iface::unit_t, bool> _div2;
+ double _rx_lo_freq, _tx_lo_freq;
+ std::string _rx_ant;
+ int _rx_pga0_attn_iobits;
+ float _rx_pga0_gain;
+ float _tx_pga0_gain;
+
+ void set_rx_lo_freq(double freq);
+ void set_tx_lo_freq(double freq);
+ void set_rx_ant(const std::string &ant);
+ void set_rx_pga0_gain(float gain);
+ void set_rx_pga0_attn(float attn);
+ void set_tx_pga0_gain(float gain);
+
+ void update_atr(void);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+
+ /*!
+ * Get the lock detect status of the LO.
+ * \param unit which unit rx or tx
+ * \return true for locked
+ */
+ bool get_locked(dboard_iface::unit_t unit){
+ return (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0;
+ }
+};
+
+/***********************************************************************
+ * Register the WBX dboard (min freq, max freq, rx div2, tx div2)
+ **********************************************************************/
+static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new wbx_xcvr(args, freq_range_t(50e6, 2220e6)));
+}
+
+UHD_STATIC_BLOCK(reg_wbx_dboards){
+ dboard_manager::register_dboard(0x0052, &make_wbx, "WBX RX");
+ dboard_manager::register_dboard(0x0053, &make_wbx, "WBX TX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+wbx_xcvr::wbx_xcvr(
+ ctor_args_t args,
+ const freq_range_t &freq_range
+) : xcvr_dboard_base(args){
+ _freq_range = freq_range;
+
+ //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);
+
+ //set the gpio directions
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
+ ) % RXIO_MASK % TXIO_MASK << std::endl;
+
+ //set some default values
+ set_rx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_rx_ant("RX2");
+ set_rx_pga0_gain(0);
+ set_tx_pga0_gain(0);
+}
+
+wbx_xcvr::~wbx_xcvr(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void wbx_xcvr::update_atr(void){
+ //calculate atr pins
+
+ //setup the tx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_POWER_UP | ANT_XX | TX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, TX_POWER_UP | ANT_RX | TX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
+
+ //setup the rx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX,
+ _rx_pga0_attn_iobits | RX_POWER_UP | ANT_RX2| RX_MIXER_ENB);
+
+ //set the rx atr regs that change with antenna setting
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
+ _rx_pga0_attn_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2));
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX RXONLY ATR REG: 0x%08x"
+ ) % (_rx_pga0_attn_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2)) << std::endl;
+}
+
+void wbx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void wbx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
+}
+
+void wbx_xcvr::set_rx_ant(const std::string &ant){
+ //validate input
+ UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+
+ //shadow the setting
+ _rx_ant = ant;
+
+ //write the new antenna setting to atr regs
+ update_atr();
+}
+
+void wbx_xcvr::set_rx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_rx_pga0_gain);
+
+ //shadow the setting (does not account for precision loss)
+ _rx_pga0_gain = gain;
+
+ //convert to attenuation and update iobits for atr
+ set_rx_pga0_attn(_max_rx_pga0_gain - gain);
+
+ //write the new gain to atr regs
+ update_atr();
+}
+
+void wbx_xcvr::set_rx_pga0_attn(float attn)
+{
+ int attn_code = int(floor(attn*2));
+ _rx_pga0_attn_iobits = ((~attn_code) << RX_ATTN_SHIFT) & RX_ATTN_MASK;
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x"
+ ) % attn % attn_code % (_rx_pga0_attn_iobits & RX_ATTN_MASK) % RX_ATTN_MASK << std::endl;
+}
+
+void wbx_xcvr::set_tx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_tx_pga0_gain);
+
+ //voltage level constants
+ static const float max_volts = float(0.5), min_volts = float(1.4);
+ static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain;
+
+ //calculate the voltage for the aux dac
+ float dac_volts = gain*slope + min_volts;
+
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX TX Gain: %f dB, dac_volts: %f V"
+ ) % gain % dac_volts << std::endl;
+
+ //write the new voltage to the aux dac
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, 0, dac_volts);
+
+ //shadow the setting (does not account for precision loss)
+ _tx_pga0_gain = gain;
+}
+
+double wbx_xcvr::set_lo_freq(
+ dboard_iface::unit_t unit,
+ double target_freq
+){
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX tune: target frequency %f Mhz"
+ ) % (target_freq/1e6) << std::endl;
+
+ //clip the input
+ target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max);
+
+ //map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
+ static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
+ (0,23) //adf4350_regs_t::PRESCALER_4_5
+ (1,75) //adf4350_regs_t::PRESCALER_8_9
+ ;
+
+ //map rf divider select output dividers to enums
+ static const uhd::dict<int, adf4350_regs_t::rf_divider_select_t> rfdivsel_to_enum = map_list_of
+ (1, adf4350_regs_t::RF_DIVIDER_SELECT_DIV1)
+ (2, adf4350_regs_t::RF_DIVIDER_SELECT_DIV2)
+ (4, adf4350_regs_t::RF_DIVIDER_SELECT_DIV4)
+ (8, adf4350_regs_t::RF_DIVIDER_SELECT_DIV8)
+ (16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
+ ;
+
+ double actual_freq, pfd_freq;
+ double ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R, BS, N, FRAC, MOD;
+ int RFdiv = 1;
+ adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
+
+ //Reference doubler for 50% duty cycle
+ // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
+ if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
+
+ //increase RF divider until acceptable VCO frequency
+ //start with target_freq*2 because mixer has divide by 2
+ double vco_freq = target_freq*2;
+ while (vco_freq < 2.2e9) {
+ vco_freq *= 2;
+ RFdiv *= 2;
+ }
+
+ //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
+ adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+
+ /*
+ * The goal here is to loop though possible R dividers,
+ * band select clock dividers, N (int) dividers, and FRAC
+ * (frac) dividers.
+ *
+ * Calculate the N and F dividers for each set of values.
+ * The loop exists when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * from pg.21
+ *
+ * f_pfd = f_ref*(1+D)/(R*(1+T))
+ * f_vco = (N + (FRAC/MOD))*f_pfd
+ * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
+ * f_rf = f_vco/RFdiv)
+ * f_actual = f_rf/2
+ */
+ for(R = 1; R <= 1023; R+=1){
+ //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
+ pfd_freq = ref_freq*(1+D)/(R*(1+T));
+
+ //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
+ if (pfd_freq > 25e6) continue;
+
+ //ignore fractional part of tuning
+ N = int(std::floor(vco_freq/pfd_freq));
+
+ //keep N > minimum int divider requirement
+ if (N < prescaler_to_min_int_div[prescaler]) continue;
+
+ for(BS=1; BS <= 255; BS+=1){
+ //keep the band select frequency at or below 100KHz
+ //constraint on band select clock
+ if (pfd_freq/BS > 100e3) continue;
+ goto done_loop;
+ }
+ } done_loop:
+
+ //Fractional-N calculation
+ MOD = 4095; //max fractional accuracy
+ FRAC = int((vco_freq/pfd_freq - N)*MOD);
+
+ //Reference divide-by-2 for 50% duty cycle
+ // if R even, move one divide by 2 to to regs.reference_divide_by_2
+ if(R % 2 == 0){
+ T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
+ R /= 2;
+ }
+
+ //actual frequency calculation
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);
+
+
+ if (wbx_debug) {
+ std::cerr << boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl;
+
+ std::cerr << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv % get_locked(unit)<< std::endl
+ << boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
+ ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
+ }
+
+ //load the register values
+ adf4350_regs_t regs;
+
+ regs.frac_12_bit = FRAC;
+ regs.int_16_bit = N;
+ regs.mod_12_bit = MOD;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = R;
+ regs.reference_divide_by_2 = T;
+ regs.reference_doubler = D;
+ regs.band_select_clock_div = BS;
+ regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+
+ //write the registers
+ //correct power-up sequence to write registers (5, 4, 3, 2, 1, 0)
+ int addr;
+
+ for(addr=5; addr>=0; addr--){
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX SPI Reg (0x%02x): 0x%08x"
+ ) % addr % regs.get_reg(addr) << std::endl;
+ this->get_iface()->write_spi(
+ unit, spi_config_t::EDGE_RISE,
+ regs.get_reg(addr), 32
+ );
+ }
+
+ //return the actual frequency
+ if (wbx_debug) std::cerr << boost::format(
+ "WBX tune: actual frequency %f Mhz"
+ ) % (actual_freq/1e6) << std::endl;
+ return actual_freq;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void wbx_xcvr::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:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = _rx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_rx_pga0_gain, float(0.5));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:{
+ prop_names_t ants = list_of("TX/RX")("RX2");
+ val = ants;
+ }
+ 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_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_RX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void wbx_xcvr::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:
+ set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ set_rx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ set_rx_ant(val.as<std::string>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void wbx_xcvr::tx_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_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = _tx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ UHD_ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_tx_pga0_gain, float(0.05));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, "TX/RX");
+ 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_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked(dboard_iface::UNIT_TX);
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void wbx_xcvr::tx_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:
+ set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(name == "PGA0");
+ set_tx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ //its always set to tx/rx, so we only allow this value
+ UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
new file mode 100644
index 000000000..3472229f4
--- /dev/null
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -0,0 +1,626 @@
+//
+// 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/>.
+//
+
+// TX IO Pins
+#define HB_PA_OFF_TXIO (1 << 15) // 5GHz PA, 1 = off, 0 = on
+#define LB_PA_OFF_TXIO (1 << 14) // 2.4GHz PA, 1 = off, 0 = on
+#define ANTSEL_TX1_RX2_TXIO (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX
+#define ANTSEL_TX2_RX1_TXIO (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX
+#define TX_EN_TXIO (1 << 11) // 1 = TX on, 0 = TX off
+#define AD9515DIV_TXIO (1 << 4) // 1 = Div by 3, 0 = Div by 2
+
+#define TXIO_MASK (HB_PA_OFF_TXIO | LB_PA_OFF_TXIO | ANTSEL_TX1_RX2_TXIO | ANTSEL_TX2_RX1_TXIO | TX_EN_TXIO | AD9515DIV_TXIO)
+
+// TX IO Functions
+#define HB_PA_TXIO LB_PA_OFF_TXIO
+#define LB_PA_TXIO HB_PA_OFF_TXIO
+#define TX_ENB_TXIO TX_EN_TXIO
+#define TX_DIS_TXIO 0
+#define AD9515DIV_3_TXIO AD9515DIV_TXIO
+#define AD9515DIV_2_TXIO 0
+
+// RX IO Pins
+#define LOCKDET_RXIO (1 << 15) // This is an INPUT!!!
+#define POWER_RXIO (1 << 14) // 1 = power on, 0 = shutdown
+#define RX_EN_RXIO (1 << 13) // 1 = RX on, 0 = RX off
+#define RX_HP_RXIO (1 << 12) // 0 = Fc set by rx_hpf, 1 = 600 KHz
+
+#define RXIO_MASK (POWER_RXIO | RX_EN_RXIO | RX_HP_RXIO)
+
+// RX IO Functions
+#define POWER_UP_RXIO POWER_RXIO
+#define POWER_DOWN_RXIO 0
+#define RX_ENB_RXIO RX_EN_RXIO
+#define RX_DIS_RXIO 0
+
+#include "max2829_regs.hpp"
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.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>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The XCVR 2450 constants
+ **********************************************************************/
+static const bool xcvr2450_debug = false;
+
+static const freq_range_t xcvr_freq_range(2.4e9, 6.0e9);
+
+static const prop_names_t xcvr_antennas = list_of("J1")("J2");
+
+static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list_of
+ ("VGA", gain_range_t(0, 30, 0.5))
+ ("BB", gain_range_t(0, 5, 1.5))
+;
+static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of
+ ("LNA", gain_range_t(0, 30.5, 15))
+ ("VGA", gain_range_t(0, 62, 2.0))
+;
+
+/***********************************************************************
+ * The XCVR 2450 dboard class
+ **********************************************************************/
+class xcvr2450 : public xcvr_dboard_base{
+public:
+ xcvr2450(ctor_args_t args);
+ ~xcvr2450(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ double _lo_freq;
+ uhd::dict<std::string, float> _tx_gains, _rx_gains;
+ std::string _tx_ant, _rx_ant;
+ int _ad9515div;
+ max2829_regs_t _max2829_regs;
+
+ void set_lo_freq(double target_freq);
+ void set_tx_ant(const std::string &ant);
+ void set_rx_ant(const std::string &ant);
+ void set_tx_gain(float gain, const std::string &name);
+ void set_rx_gain(float gain, const std::string &name);
+
+ void update_atr(void);
+ void spi_reset(void);
+ void send_reg(boost::uint8_t addr){
+ boost::uint32_t value = _max2829_regs.get_reg(addr);
+ if(xcvr2450_debug) std::cerr << boost::format(
+ "XCVR2450: send reg 0x%02x, value 0x%05x"
+ ) % int(addr) % value << std::endl;
+ this->get_iface()->write_spi(
+ dboard_iface::UNIT_RX,
+ spi_config_t::EDGE_RISE,
+ value, 24
+ );
+ }
+
+ static bool is_highband(double freq){return freq > 3e9;}
+
+ /*!
+ * Is the LO locked?
+ * \return true for locked
+ */
+ bool get_locked(void){
+ return (this->get_iface()->read_gpio(dboard_iface::UNIT_RX) & LOCKDET_RXIO) != 0;
+ }
+
+ /*!
+ * Read the RSSI from the aux adc
+ * \return the rssi in dB
+ */
+ float get_rssi(void){
+ //constants for the rssi calculation
+ static const float min_v = float(0.5), max_v = float(2.5);
+ static const float rssi_dyn_range = 60;
+ //calculate the rssi from the voltage
+ float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, 1);
+ return rssi_dyn_range*(voltage - min_v)/(max_v - min_v);
+ }
+};
+
+/***********************************************************************
+ * Register the XCVR 2450 dboard
+ **********************************************************************/
+static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new xcvr2450(args));
+}
+
+UHD_STATIC_BLOCK(reg_xcvr2450_dboard){
+ //register the factory function for the rx and tx dbids
+ dboard_manager::register_dboard(0x0060, &make_xcvr2450, "XCVR2450 TX");
+ dboard_manager::register_dboard(0x0061, &make_xcvr2450, "XCVR2450 RX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){
+ //enable only the clocks we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
+
+ //set the gpio directions
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
+
+ spi_reset(); //prepare the spi
+
+ //setup the misc max2829 registers
+ _max2829_regs.mimo_select = max2829_regs_t::MIMO_SELECT_MIMO;
+ _max2829_regs.band_sel_mimo = max2829_regs_t::BAND_SEL_MIMO_MIMO;
+ _max2829_regs.pll_cp_select = max2829_regs_t::PLL_CP_SELECT_4MA;
+ _max2829_regs.rssi_high_bw = max2829_regs_t::RSSI_HIGH_BW_6MHZ;
+ _max2829_regs.tx_lpf_coarse_adj = max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ;
+ _max2829_regs.rx_lpf_coarse_adj = max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ;
+ _max2829_regs.rx_lpf_fine_adj = max2829_regs_t::RX_LPF_FINE_ADJ_95;
+ _max2829_regs.rx_vga_gain_spi = max2829_regs_t::RX_VGA_GAIN_SPI_SPI;
+ _max2829_regs.rssi_output_range = max2829_regs_t::RSSI_OUTPUT_RANGE_HIGH;
+ _max2829_regs.rssi_op_mode = max2829_regs_t::RSSI_OP_MODE_ENABLED;
+ _max2829_regs.rssi_pin_fcn = max2829_regs_t::RSSI_PIN_FCN_RSSI;
+ _max2829_regs.rx_highpass = max2829_regs_t::RX_HIGHPASS_100HZ;
+ _max2829_regs.tx_vga_gain_spi = max2829_regs_t::TX_VGA_GAIN_SPI_SPI;
+ _max2829_regs.pa_driver_linearity = max2829_regs_t::PA_DRIVER_LINEARITY_78;
+ _max2829_regs.tx_vga_linearity = max2829_regs_t::TX_VGA_LINEARITY_78;
+ _max2829_regs.tx_upconv_linearity = max2829_regs_t::TX_UPCONV_LINEARITY_78;
+
+ //send initial register settings
+ for(boost::uint8_t reg = 0x2; reg <= 0xC; reg++){
+ this->send_reg(reg);
+ }
+
+ //set defaults for LO, gains, antennas
+ set_lo_freq(2.45e9);
+ set_rx_ant(xcvr_antennas.at(0));
+ set_tx_ant(xcvr_antennas.at(1));
+ BOOST_FOREACH(const std::string &name, xcvr_tx_gain_ranges.keys()){
+ set_tx_gain(xcvr_tx_gain_ranges[name].min, name);
+ }
+ BOOST_FOREACH(const std::string &name, xcvr_rx_gain_ranges.keys()){
+ set_rx_gain(xcvr_rx_gain_ranges[name].min, name);
+ }
+}
+
+xcvr2450::~xcvr2450(void){
+ spi_reset();
+}
+
+void xcvr2450::spi_reset(void){
+ //spi reset mode: global enable = off, tx and rx enable = on
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_ENB_TXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_ENB_RXIO | POWER_DOWN_RXIO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ //take it back out of spi reset mode and wait a bit
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_DIS_RXIO | POWER_UP_RXIO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+}
+
+void xcvr2450::update_atr(void){
+ //calculate tx atr pins
+ int band_sel = (xcvr2450::is_highband(_lo_freq))? HB_PA_TXIO : LB_PA_TXIO;
+ int tx_ant_sel = (_tx_ant == "J1")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;
+ int rx_ant_sel = (_rx_ant == "J2")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;
+ int xx_ant_sel = tx_ant_sel; //prefer the tx antenna selection for full duplex (rx will get the other antenna)
+ int ad9515div = (_ad9515div == 3)? AD9515DIV_3_TXIO : AD9515DIV_2_TXIO;
+
+ //set the tx registers
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, band_sel | ad9515div | TX_DIS_TXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, band_sel | ad9515div | TX_DIS_TXIO | rx_ant_sel);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, band_sel | ad9515div | TX_ENB_TXIO | tx_ant_sel);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, band_sel | ad9515div | TX_ENB_TXIO | xx_ant_sel);
+
+ //set the rx registers
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP_RXIO | RX_DIS_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP_RXIO | RX_ENB_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP_RXIO | RX_DIS_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_ENB_RXIO);
+}
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void xcvr2450::set_lo_freq(double target_freq){
+ target_freq = std::clip(target_freq, xcvr_freq_range.min, xcvr_freq_range.max);
+ //TODO: clip for highband and lowband
+
+ //variables used in the calculation below
+ double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0);
+ double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_TX);
+ int R, intdiv, fracdiv;
+
+ //loop through values until we get a match
+ for(_ad9515div = 2; _ad9515div <= 3; _ad9515div++){
+ for(R = 1; R <= 7; R++){
+ double N = (target_freq*scaler*R*_ad9515div)/ref_freq;
+ intdiv = int(std::floor(N));
+ fracdiv = boost::math::iround((N - intdiv)*double(1 << 16));
+ //actual minimum is 128, but most chips seems to require higher to lock
+ if (intdiv < 131 or intdiv > 255) continue;
+ //constraints met: exit loop
+ goto done_loop;
+ }
+ } done_loop:
+
+ //calculate the actual freq from the values above
+ double N = double(intdiv) + double(fracdiv)/double(1 << 16);
+ _lo_freq = (N*ref_freq)/(scaler*R*_ad9515div);
+
+ if (xcvr2450_debug) std::cerr
+ << boost::format("XCVR2450 tune:\n")
+ << boost::format(" R=%d, N=%f, ad9515=%d, scaler=%f\n") % R % N % _ad9515div % scaler
+ << boost::format(" Ref Freq=%fMHz\n") % (ref_freq/1e6)
+ << boost::format(" Target Freq=%fMHz\n") % (target_freq/1e6)
+ << boost::format(" Actual Freq=%fMHz\n") % (_lo_freq/1e6)
+ << std::endl;
+
+ //high-high band or low-high band?
+ if(_lo_freq > (5.35e9 + 5.47e9)/2.0){
+ if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using high-high band" << std::endl;
+ _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_5_47GHZ_TO_5_875GHZ;
+ }else{
+ if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using low-high band" << std::endl;
+ _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_4_9GHZ_TO_5_35GHZ;
+ }
+
+ //new band select settings and ad9515 divider
+ this->update_atr();
+
+ //load new counters into registers
+ _max2829_regs.int_div_ratio_word = intdiv;
+ _max2829_regs.frac_div_ratio_lsb = fracdiv & 0x3;
+ _max2829_regs.frac_div_ratio_msb = fracdiv >> 2;
+ this->send_reg(0x3); //integer
+ this->send_reg(0x4); //fractional
+
+ //load the reference divider and band select into registers
+ //toggle the bandswitch from off to automatic (which really means start)
+ _max2829_regs.ref_divider = R;
+ _max2829_regs.band_select = (xcvr2450::is_highband(_lo_freq))?
+ max2829_regs_t::BAND_SELECT_5GHZ :
+ max2829_regs_t::BAND_SELECT_2_4GHZ ;
+ _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_DISABLE;
+ this->send_reg(0x5);
+ _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_AUTOMATIC;;
+ this->send_reg(0x5);
+}
+
+/***********************************************************************
+ * Antenna Handling
+ **********************************************************************/
+void xcvr2450::set_tx_ant(const std::string &ant){
+ assert_has(xcvr_antennas, ant, "xcvr antenna name");
+ _tx_ant = ant;
+ this->update_atr(); //sets the atr to the new antenna setting
+}
+
+void xcvr2450::set_rx_ant(const std::string &ant){
+ assert_has(xcvr_antennas, ant, "xcvr antenna name");
+ _rx_ant = ant;
+ this->update_atr(); //sets the atr to the new antenna setting
+}
+
+/***********************************************************************
+ * Gain Handling
+ **********************************************************************/
+/*!
+ * Convert a requested gain for the tx 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 6 bit the register value
+ */
+static int gain_to_tx_vga_reg(float &gain){
+ //calculate the register value
+ int reg = std::clip(boost::math::iround(gain*60/30.0) + 3, 0, 63);
+
+ //calculate the actual gain value
+ if (reg < 4) gain = 0;
+ else if (reg < 48) gain = float(reg/2 - 1);
+ else gain = float(reg/2.0 - 1.5);
+
+ //return register value
+ return reg;
+}
+
+/*!
+ * Convert a requested gain for the tx bb 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 gain enum value
+ */
+static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3);
+ switch(reg){
+ case 0:
+ gain = 0;
+ return max2829_regs_t::TX_BASEBAND_GAIN_0DB;
+ case 1:
+ gain = 2;
+ return max2829_regs_t::TX_BASEBAND_GAIN_2DB;
+ case 2:
+ gain = 3.5;
+ return max2829_regs_t::TX_BASEBAND_GAIN_3_5DB;
+ case 3:
+ gain = 5;
+ return max2829_regs_t::TX_BASEBAND_GAIN_5DB;
+ }
+ UHD_ASSERT_THROW(false);
+}
+
+/*!
+ * Convert a requested gain for the rx 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_rx_vga_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain/2.0), 0, 31);
+ gain = float(reg*2);
+ return reg;
+}
+
+/*!
+ * Convert a requested gain for the rx lna 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 2 bit the register value
+ */
+static int gain_to_rx_lna_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3);
+ switch(reg){
+ case 0:
+ case 1: gain = 0; break;
+ case 2: gain = 15; break;
+ case 3: gain = 30.5; break;
+ }
+ return reg;
+}
+
+void xcvr2450::set_tx_gain(float gain, const std::string &name){
+ assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");
+ if (name == "VGA"){
+ _max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain);
+ send_reg(0xC);
+ }
+ else if(name == "BB"){
+ _max2829_regs.tx_baseband_gain = gain_to_tx_bb_reg(gain);
+ send_reg(0x9);
+ }
+ else UHD_ASSERT_THROW(false);
+ _tx_gains[name] = gain;
+}
+
+void xcvr2450::set_rx_gain(float gain, const std::string &name){
+ assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");
+ if (name == "VGA"){
+ _max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain);
+ send_reg(0xB);
+ }
+ else if(name == "LNA"){
+ _max2829_regs.rx_lna_gain = gain_to_rx_lna_reg(gain);
+ send_reg(0xB);
+ }
+ else UHD_ASSERT_THROW(false);
+ _rx_gains[name] = gain;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void xcvr2450::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(_rx_gains.keys(), name, "xcvr rx gain name");
+ val = _rx_gains[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");
+ val = xcvr_rx_gain_ranges[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(xcvr_rx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = xcvr_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ 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;
+ 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;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void xcvr2450::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_rx_gain(val.as<float>(), name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_rx_ant(val.as<std::string>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void xcvr2450::tx_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_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_tx_gains.keys(), name, "xcvr tx gain name");
+ val = _tx_gains[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");
+ val = xcvr_tx_gain_ranges[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(xcvr_tx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = xcvr_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _tx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ 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;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = this->get_locked();
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void xcvr2450::tx_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:
+ set_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_tx_gain(val.as<float>(), name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_tx_ant(val.as<std::string>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp
new file mode 100644
index 000000000..bd4b37ef3
--- /dev/null
+++ b/host/lib/usrp/dboard_base.cpp
@@ -0,0 +1,123 @@
+//
+// 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 "dboard_ctor_args.hpp"
+#include <uhd/usrp/dboard_base.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * dboard_base dboard dboard_base class
+ **********************************************************************/
+struct dboard_base::dboard_base_impl{
+ ctor_args_impl args;
+ dboard_base_impl(ctor_args_t args) : args(*args){}
+};
+
+dboard_base::dboard_base(ctor_args_t args){
+ _impl = new dboard_base_impl(args);
+}
+
+dboard_base::~dboard_base(void){
+ delete _impl;
+}
+
+std::string dboard_base::get_subdev_name(void){
+ return _impl->args.sd_name;
+}
+
+dboard_iface::sptr dboard_base::get_iface(void){
+ return _impl->args.db_iface;
+}
+
+dboard_id_t dboard_base::get_rx_id(void){
+ return _impl->args.rx_id;
+}
+
+dboard_id_t dboard_base::get_tx_id(void){
+ return _impl->args.tx_id;
+}
+
+/***********************************************************************
+ * xcvr dboard dboard_base class
+ **********************************************************************/
+xcvr_dboard_base::xcvr_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_rx_id() == dboard_id_t::none()){
+ throw std::runtime_error(str(boost::format(
+ "cannot create xcvr board when the rx id is \"%s\""
+ ) % dboard_id_t::none().to_pp_string()));
+ }
+ if (get_tx_id() == dboard_id_t::none()){
+ throw std::runtime_error(str(boost::format(
+ "cannot create xcvr board when the tx id is \"%s\""
+ ) % dboard_id_t::none().to_pp_string()));
+ }
+}
+
+xcvr_dboard_base::~xcvr_dboard_base(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * rx dboard dboard_base class
+ **********************************************************************/
+rx_dboard_base::rx_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_tx_id() != dboard_id_t::none()){
+ throw std::runtime_error(str(boost::format(
+ "cannot create rx board when the tx id is \"%s\""
+ " -> expected a tx id of \"%s\""
+ ) % get_tx_id().to_pp_string() % dboard_id_t::none().to_pp_string()));
+ }
+}
+
+rx_dboard_base::~rx_dboard_base(void){
+ /* NOP */
+}
+
+void rx_dboard_base::tx_get(const wax::obj &, wax::obj &){
+ throw std::runtime_error("cannot call tx_get on a rx dboard");
+}
+
+void rx_dboard_base::tx_set(const wax::obj &, const wax::obj &){
+ throw std::runtime_error("cannot call tx_set on a rx dboard");
+}
+
+/***********************************************************************
+ * tx dboard dboard_base class
+ **********************************************************************/
+tx_dboard_base::tx_dboard_base(ctor_args_t args) : dboard_base(args){
+ if (get_rx_id() != dboard_id_t::none()){
+ throw std::runtime_error(str(boost::format(
+ "cannot create tx board when the rx id is \"%s\""
+ " -> expected a rx id of \"%s\""
+ ) % get_rx_id().to_pp_string() % dboard_id_t::none().to_pp_string()));
+ }
+}
+
+tx_dboard_base::~tx_dboard_base(void){
+ /* NOP */
+}
+
+void tx_dboard_base::rx_get(const wax::obj &, wax::obj &){
+ throw std::runtime_error("cannot call rx_get on a tx dboard");
+}
+
+void tx_dboard_base::rx_set(const wax::obj &, const wax::obj &){
+ throw std::runtime_error("cannot call rx_set on a tx dboard");
+}
diff --git a/host/lib/usrp/dboard_ctor_args.hpp b/host/lib/usrp/dboard_ctor_args.hpp
new file mode 100644
index 000000000..13abe79e8
--- /dev/null
+++ b/host/lib/usrp/dboard_ctor_args.hpp
@@ -0,0 +1,32 @@
+//
+// 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_DBOARD_CTOR_ARGS_HPP
+#define INCLUDED_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;
+};
+
+#endif /* INCLUDED_DBOARD_CTOR_ARGS_HPP */
diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp
new file mode 100644
index 000000000..fa3631948
--- /dev/null
+++ b/host/lib/usrp/dboard_eeprom.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 <uhd/usrp/dboard_eeprom.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+static const bool _dboard_eeprom_debug = false;
+
+////////////////////////////////////////////////////////////////////////
+// format of daughterboard EEPROM
+// 00: 0xDB code for ``I'm a daughterboard''
+// 01: .. Daughterboard ID (LSB)
+// 02: .. Daughterboard ID (MSB)
+// 03: .. io bits 7-0 direction (bit set if it's an output from m'board)
+// 04: .. io bits 15-8 direction (bit set if it's an output from m'board)
+// 05: .. ADC0 DC offset correction (LSB)
+// 06: .. ADC0 DC offset correction (MSB)
+// 07: .. ADC1 DC offset correction (LSB)
+// 08: .. ADC1 DC offset correction (MSB)
+// ...
+// 1f: .. negative of the sum of bytes [0x00, 0x1e]
+
+#define DB_EEPROM_MAGIC 0x00
+#define DB_EEPROM_MAGIC_VALUE 0xDB
+#define DB_EEPROM_ID_LSB 0x01
+#define DB_EEPROM_ID_MSB 0x02
+#define DB_EEPROM_OE_LSB 0x03
+#define DB_EEPROM_OE_MSB 0x04
+#define DB_EEPROM_OFFSET_0_LSB 0x05 // offset correction for ADC or DAC 0
+#define DB_EEPROM_OFFSET_0_MSB 0x06
+#define DB_EEPROM_OFFSET_1_LSB 0x07 // offset correction for ADC or DAC 1
+#define DB_EEPROM_OFFSET_1_MSB 0x08
+#define DB_EEPROM_CHKSUM 0x1f
+
+#define DB_EEPROM_CLEN 0x20 // length of common portion of eeprom
+
+#define DB_EEPROM_CUSTOM_BASE DB_EEPROM_CLEN // first avail offset for
+ // daughterboard specific use
+////////////////////////////////////////////////////////////////////////
+
+//negative sum of bytes excluding checksum byte
+static boost::uint8_t checksum(const byte_vector_t &bytes){
+ int sum = 0;
+ for (size_t i = 0; i < std::min(bytes.size(), size_t(DB_EEPROM_CHKSUM)); i++){
+ sum -= int(bytes.at(i));
+ }
+ if (_dboard_eeprom_debug)
+ std::cout << boost::format("sum: 0x%02x") % sum << std::endl;
+ return boost::uint8_t(sum);
+}
+
+dboard_eeprom_t::dboard_eeprom_t(const byte_vector_t &bytes){
+ if (_dboard_eeprom_debug){
+ for (size_t i = 0; i < bytes.size(); i++){
+ std::cout << boost::format(
+ "eeprom byte[0x%02x] = 0x%02x") % i % int(bytes.at(i)
+ ) << std::endl;
+ }
+ }
+ try{
+ UHD_ASSERT_THROW(bytes.size() >= DB_EEPROM_CLEN);
+ UHD_ASSERT_THROW(bytes[DB_EEPROM_MAGIC] == DB_EEPROM_MAGIC_VALUE);
+ UHD_ASSERT_THROW(bytes[DB_EEPROM_CHKSUM] == checksum(bytes));
+ id = dboard_id_t::from_uint16(0
+ | (boost::uint16_t(bytes[DB_EEPROM_ID_LSB]) << 0)
+ | (boost::uint16_t(bytes[DB_EEPROM_ID_MSB]) << 8)
+ );
+ }catch(const uhd::assert_error &){
+ id = dboard_id_t::none();
+ }
+}
+
+byte_vector_t dboard_eeprom_t::get_eeprom_bytes(void){
+ byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros
+ bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE;
+ bytes[DB_EEPROM_ID_LSB] = boost::uint8_t(id.to_uint16() >> 0);
+ bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id.to_uint16() >> 8);
+ bytes[DB_EEPROM_CHKSUM] = checksum(bytes);
+ return bytes;
+}
+
+size_t dboard_eeprom_t::num_bytes(void){
+ return DB_EEPROM_CLEN;
+}
diff --git a/host/lib/usrp/dboard_id.cpp b/host/lib/usrp/dboard_id.cpp
new file mode 100644
index 000000000..3028d2a3b
--- /dev/null
+++ b/host/lib/usrp/dboard_id.cpp
@@ -0,0 +1,68 @@
+//
+// 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/dboard_id.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
+#include <sstream>
+#include <iostream>
+
+using namespace uhd::usrp;
+
+dboard_id_t::dboard_id_t(boost::uint16_t id){
+ _id = id;
+}
+
+dboard_id_t dboard_id_t::none(void){
+ return dboard_id_t();
+}
+
+dboard_id_t dboard_id_t::from_uint16(boost::uint16_t uint16){
+ return dboard_id_t(uint16);
+}
+
+boost::uint16_t dboard_id_t::to_uint16(void) const{
+ return _id;
+}
+
+//used with lexical cast to parse a hex string
+template <class T> struct to_hex{
+ T value;
+ operator T() const {return value;}
+ friend std::istream& operator>>(std::istream& in, to_hex& out){
+ in >> std::hex >> out.value;
+ return in;
+ }
+};
+
+dboard_id_t dboard_id_t::from_string(const std::string &string){
+ if (string.substr(0, 2) == "0x"){
+ return dboard_id_t::from_uint16(boost::lexical_cast<to_hex<boost::uint16_t> >(string));
+ }
+ return dboard_id_t::from_uint16(boost::lexical_cast<boost::uint16_t>(string));
+}
+
+std::string dboard_id_t::to_string(void) const{
+ return str(boost::format("0x%04x") % this->to_uint16());
+}
+
+//Note: to_pp_string is implemented in the dboard manager
+//because it needs access to the dboard registration table
+
+bool uhd::usrp::operator==(const dboard_id_t &lhs, const dboard_id_t &rhs){
+ return lhs.to_uint16() == rhs.to_uint16();
+}
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
new file mode 100644
index 000000000..8161727e5
--- /dev/null
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -0,0 +1,304 @@
+//
+// 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 "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>
+#include <boost/tuple/tuple.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * storage and registering for dboards
+ **********************************************************************/
+//dboard registry tuple: dboard constructor, canonical name, subdev names
+typedef boost::tuple<dboard_manager::dboard_ctor_t, std::string, prop_names_t> args_t;
+
+//map a dboard id to a dboard constructor
+typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t;
+UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map)
+
+void dboard_manager::register_dboard(
+ dboard_id_t dboard_id,
+ dboard_ctor_t dboard_ctor,
+ const std::string &name,
+ const prop_names_t &subdev_names
+){
+ //std::cout << "registering: " << name << std::endl;
+ if (get_id_to_args_map().has_key(dboard_id)){
+ throw std::runtime_error(str(boost::format(
+ "The dboard id %s is already registered to %s."
+ ) % dboard_id.to_string() % dboard_id.to_pp_string()));
+ }
+ get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
+}
+
+std::string dboard_id_t::to_pp_string(void) const{
+ std::string name = "unknown";
+ if (get_id_to_args_map().has_key(*this)){
+ name = get_id_to_args_map()[*this].get<1>();
+ }
+ return str(boost::format("%s (%s)") % name % this->to_string());
+}
+
+/***********************************************************************
+ * internal helper classe
+ **********************************************************************/
+/*!
+ * A special wax proxy object that forwards calls to a subdev.
+ * A sptr to an instance will be used in the properties structure.
+ */
+class subdev_proxy : boost::noncopyable, public wax::obj{
+public:
+ typedef boost::shared_ptr<subdev_proxy> sptr;
+ 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){
+ /* 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);
+ }
+ }
+
+ //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);
+ }
+ }
+};
+
+/***********************************************************************
+ * dboard manager implementation class
+ **********************************************************************/
+class dboard_manager_impl : public dboard_manager{
+
+public:
+ dboard_manager_impl(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_iface::sptr iface
+ );
+ ~dboard_manager_impl(void);
+
+ //dboard_iface
+ prop_names_t get_rx_subdev_names(void);
+ prop_names_t get_tx_subdev_names(void);
+ wax::obj get_rx_subdev(const std::string &subdev_name);
+ wax::obj get_tx_subdev(const std::string &subdev_name);
+
+private:
+ //list of rx and tx dboards in this dboard_manager
+ //each dboard here is actually a subdevice proxy
+ //the subdevice proxy is internal to the cpp file
+ uhd::dict<std::string, subdev_proxy::sptr> _rx_dboards;
+ uhd::dict<std::string, subdev_proxy::sptr> _tx_dboards;
+ dboard_iface::sptr _iface;
+ void set_nice_dboard_if(void);
+};
+
+/***********************************************************************
+ * make routine for dboard manager
+ **********************************************************************/
+dboard_manager::sptr dboard_manager::make(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_iface::sptr iface
+){
+ return dboard_manager::sptr(
+ new dboard_manager_impl(rx_dboard_id, tx_dboard_id, iface)
+ );
+}
+
+/***********************************************************************
+ * implementation class methods
+ **********************************************************************/
+static args_t get_dboard_args(
+ dboard_iface::unit_t unit,
+ dboard_id_t dboard_id
+){
+ //special case, the none id was provided, use the following ids
+ if (dboard_id == dboard_id_t::none()){
+ std::cerr << boost::format(
+ "Warning: unregistered dboard id: %s"
+ " -> defaulting to a basic board"
+ ) % dboard_id.to_pp_string() << std::endl;
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0x0001));
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0x0000));
+ switch(unit){
+ case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0x0001);
+ case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0x0000);
+ default: UHD_ASSERT_THROW(false);
+ }
+ }
+
+ //verify that there is a registered constructor for this id
+ if (not get_id_to_args_map().has_key(dboard_id)){
+ return get_dboard_args(unit, dboard_id_t::none());
+ }
+
+ //return the dboard args for this id
+ return get_id_to_args_map()[dboard_id];
+}
+
+dboard_manager_impl::dboard_manager_impl(
+ dboard_id_t rx_dboard_id,
+ dboard_id_t tx_dboard_id,
+ dboard_iface::sptr iface
+){
+ _iface = iface;
+
+ dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id);
+
+ dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id);
+
+ //initialize the gpio pins before creating subdevs
+ set_nice_dboard_if();
+
+ //dboard constructor args
+ dboard_base::ctor_args_impl db_ctor_args;
+ db_ctor_args.db_iface = iface;
+
+ //make xcvr subdevs (make one subdev for both rx and tx dboards)
+ if (rx_dboard_ctor == tx_dboard_ctor){
+ UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
+ BOOST_FOREACH(const std::string &subdev, rx_subdevs){
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = rx_dboard_id;
+ db_ctor_args.tx_id = tx_dboard_id;
+ dboard_base::sptr xcvr_dboard = rx_dboard_ctor(&db_ctor_args);
+ //create a rx proxy for this xcvr board
+ _rx_dboards[subdev] = subdev_proxy::sptr(
+ new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
+ );
+ //create a tx proxy for this xcvr board
+ _tx_dboards[subdev] = subdev_proxy::sptr(
+ new subdev_proxy(xcvr_dboard, subdev_proxy::TX_TYPE)
+ );
+ }
+ }
+
+ //make tx and rx subdevs (separate subdevs for rx and tx dboards)
+ else{
+ //make the rx subdevs
+ BOOST_FOREACH(const std::string &subdev, rx_subdevs){
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = rx_dboard_id;
+ db_ctor_args.tx_id = dboard_id_t::none();
+ dboard_base::sptr rx_dboard = rx_dboard_ctor(&db_ctor_args);
+ //create a rx proxy for this rx board
+ _rx_dboards[subdev] = subdev_proxy::sptr(
+ new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
+ );
+ }
+ //make the tx subdevs
+ BOOST_FOREACH(const std::string &subdev, tx_subdevs){
+ db_ctor_args.sd_name = subdev;
+ db_ctor_args.rx_id = dboard_id_t::none();
+ db_ctor_args.tx_id = tx_dboard_id;
+ dboard_base::sptr tx_dboard = tx_dboard_ctor(&db_ctor_args);
+ //create a tx proxy for this tx board
+ _tx_dboards[subdev] = subdev_proxy::sptr(
+ new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE)
+ );
+ }
+ }
+}
+
+dboard_manager_impl::~dboard_manager_impl(void){
+ set_nice_dboard_if();
+}
+
+prop_names_t dboard_manager_impl::get_rx_subdev_names(void){
+ return _rx_dboards.keys();
+}
+
+prop_names_t dboard_manager_impl::get_tx_subdev_names(void){
+ return _tx_dboards.keys();
+}
+
+wax::obj dboard_manager_impl::get_rx_subdev(const std::string &subdev_name){
+ if (not _rx_dboards.has_key(subdev_name)) throw std::invalid_argument(
+ str(boost::format("Unknown rx subdev name %s") % subdev_name)
+ );
+ //get a link to the rx subdev proxy
+ return _rx_dboards[subdev_name]->get_link();
+}
+
+wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
+ if (not _tx_dboards.has_key(subdev_name)) throw std::invalid_argument(
+ str(boost::format("Unknown tx subdev name %s") % subdev_name)
+ );
+ //get a link to the tx subdev proxy
+ return _tx_dboards[subdev_name]->get_link();
+}
+
+void dboard_manager_impl::set_nice_dboard_if(void){
+ //make a list of possible unit types
+ std::vector<dboard_iface::unit_t> units = boost::assign::list_of
+ (dboard_iface::UNIT_RX)
+ (dboard_iface::UNIT_TX)
+ ;
+
+ //set nice settings on each unit
+ BOOST_FOREACH(dboard_iface::unit_t unit, units){
+ _iface->set_gpio_ddr(unit, 0x0000); //all inputs
+ _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low
+ _iface->set_clock_enabled(unit, false); //clock off
+ }
+}
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
new file mode 100644
index 000000000..f4aa82669
--- /dev/null
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -0,0 +1,227 @@
+//
+// 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/simple_usrp.hpp>
+#include <uhd/usrp/tune_helper.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <uhd/usrp/dsp_props.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Simple Device Implementation
+ **********************************************************************/
+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){
+ /* NOP */
+ }
+
+ device::sptr get_device(void){
+ return _dev;
+ }
+
+ std::string get_name(void){
+ return str(boost::format(
+ "Simple USRP:\n"
+ " Device: %s\n"
+ " Mboard: %s\n"
+ " RX DSP: %s\n"
+ " RX Dboard: %s\n"
+ " RX Subdev: %s\n"
+ " TX DSP: %s\n"
+ " TX Dboard: %s\n"
+ " 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>()
+ );
+ }
+
+ /*******************************************************************
+ * Misc
+ ******************************************************************/
+ void set_time_now(const time_spec_t &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;
+ }
+
+ void issue_stream_cmd(const stream_cmd_t &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;
+ }
+
+ float read_rssi(void){
+ return _rx_subdev[SUBDEV_PROP_RSSI].as<float>();
+ }
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ void set_rx_rate(double rate){
+ _rx_dsp[DSP_PROP_HOST_RATE] = rate;
+ }
+
+ double get_rx_rate(void){
+ 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);
+ }
+
+ 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);
+ }
+
+ freq_range_t get_rx_freq_range(void){
+ return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ }
+
+ void set_rx_gain(float gain){
+ _rx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_rx_gain(void){
+ return _rx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ }
+
+ gain_range_t get_rx_gain_range(void){
+ return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ }
+
+ void set_rx_antenna(const std::string &ant){
+ _rx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_rx_antenna(void){
+ 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>();
+ }
+
+ bool get_rx_lo_locked(void){
+ return _rx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ }
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ void set_tx_rate(double rate){
+ _tx_dsp[DSP_PROP_HOST_RATE] = rate;
+ }
+
+ double get_tx_rate(void){
+ 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);
+ }
+
+ 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);
+ }
+
+ freq_range_t get_tx_freq_range(void){
+ return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>();
+ }
+
+ void set_tx_gain(float gain){
+ _tx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_tx_gain(void){
+ return _tx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ }
+
+ gain_range_t get_tx_gain_range(void){
+ return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ }
+
+ void set_tx_antenna(const std::string &ant){
+ _tx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_tx_antenna(void){
+ 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>();
+ }
+
+ bool get_tx_lo_locked(void){
+ 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;
+};
+
+/***********************************************************************
+ * The Make Function
+ **********************************************************************/
+simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){
+ return sptr(new simple_usrp_impl(dev_addr));
+}
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
new file mode 100644
index 000000000..a7d695b4e
--- /dev/null
+++ b/host/lib/usrp/tune_helper.cpp
@@ -0,0 +1,127 @@
+//
+// 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/tune_helper.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dsp_props.hpp>
+#include <cmath>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Tune Helper Function
+ **********************************************************************/
+static tune_result_t tune_xx_subdev_and_dxc(
+ bool is_tx,
+ 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>();
+
+ // Ask the d'board to tune as closely as it can to target_freq+lo_offset
+ double target_inter_freq = target_freq + lo_offset;
+ 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;
+ double 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;
+
+ dxc_freq_proxy = target_dxc_freq;
+ double actual_dxc_freq = dxc_freq_proxy.as<double>();
+
+ //return some kind of tune result tuple/struct
+ 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;
+}
+
+/***********************************************************************
+ * RX Tune
+ **********************************************************************/
+tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(
+ 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);
+}
+
+tune_result_t uhd::usrp::tune_rx_subdev_and_ddc(
+ wax::obj subdev, wax::obj ddc,
+ double target_freq
+){
+ double lo_offset = 0.0;
+ //if the local oscillator will be in the passband, use an offset
+ 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);
+}
+
+/***********************************************************************
+ * TX Tune
+ **********************************************************************/
+tune_result_t uhd::usrp::tune_tx_subdev_and_duc(
+ 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);
+}
+
+tune_result_t uhd::usrp::tune_tx_subdev_and_duc(
+ wax::obj subdev, wax::obj duc,
+ double target_freq
+){
+ double lo_offset = 0.0;
+ //if the local oscillator will be in the passband, use an offset
+ 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);
+}
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
new file mode 100644
index 000000000..fee67dff9
--- /dev/null
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+# 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!
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.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
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp
+)
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
new file mode 100644
index 000000000..4c5207203
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -0,0 +1,163 @@
+//
+// 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 "clock_ctrl.hpp"
+#include "ad9510_regs.hpp"
+#include "usrp2_regs.hpp" //spi slave constants
+#include <boost/cstdint.hpp>
+
+using namespace uhd;
+
+/*!
+ * A usrp2 clock control specific to the ad9510 ic.
+ */
+class clock_ctrl_impl : public clock_ctrl{
+public:
+ clock_ctrl_impl(usrp2_iface::sptr iface){
+ _iface = iface;
+
+ _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
+ this->write_reg(0x09);
+
+ // Setup the clock registers to 100MHz:
+ // This was already done by the firmware (or the host couldnt communicate).
+ // We could remove this part, and just leave it to the firmware.
+ // But why not leave it in for those who want to mess with clock settings?
+ // 100mhz = 10mhz/R * (P*B + A)
+
+ _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL;
+ _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2;
+ this->write_reg(0x0A);
+
+ _ad9510_regs.acounter = 0;
+ this->write_reg(0x04);
+
+ _ad9510_regs.bcounter_msb = 0;
+ _ad9510_regs.bcounter_lsb = 5;
+ this->write_reg(0x05);
+ this->write_reg(0x06);
+
+ _ad9510_regs.ref_counter_msb = 0;
+ _ad9510_regs.ref_counter_lsb = 1; // r divider = 1
+ this->write_reg(0x0B);
+ this->write_reg(0x0C);
+
+ /* regs will be updated in commands below */
+
+ this->enable_external_ref(false);
+ this->enable_rx_dboard_clock(false);
+ this->enable_tx_dboard_clock(false);
+
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(true);
+ this->enable_adc_clock(true);
+
+ }
+
+ ~clock_ctrl_impl(void){
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(false);
+ this->enable_adc_clock(false);
+ }
+
+ //uses output clock 7 (cmos)
+ void enable_rx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
+ _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
+ _ad9510_regs.bypass_divider_out7 = 1;
+ this->write_reg(0x43);
+ this->write_reg(0x57);
+ this->update_regs();
+ }
+
+ //uses output clock 6 (cmos)
+ void enable_tx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ _ad9510_regs.bypass_divider_out6 = 1;
+ this->write_reg(0x42);
+ this->write_reg(0x55);
+ this->update_regs();
+ }
+
+ /*!
+ * If we are to use an external reference, enable the charge pump.
+ * \param enb true to enable the CP
+ */
+ void enable_external_ref(bool enb){
+ _ad9510_regs.charge_pump_mode = (enb)?
+ ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL :
+ ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ;
+ _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH;
+ _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS;
+ this->write_reg(0x08);
+ this->update_regs();
+ }
+
+private:
+ /*!
+ * Write a single register to the spi regs.
+ * \param addr the address to write
+ */
+ void write_reg(boost::uint8_t addr){
+ boost::uint32_t data = _ad9510_regs.get_write_reg(addr);
+ _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/);
+ }
+
+ /*!
+ * Tells the ad9510 to latch the settings into the operational registers.
+ */
+ void update_regs(void){
+ _ad9510_regs.update_registers = 1;
+ this->write_reg(0x5a);
+ }
+
+ //uses output clock 3 (pecl)
+ void enable_dac_clock(bool enb){
+ _ad9510_regs.power_down_lvpecl_out3 = (enb)?
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
+ _ad9510_regs.bypass_divider_out3 = 1;
+ this->write_reg(0x3F);
+ this->write_reg(0x4F);
+ this->update_regs();
+ }
+
+ //uses output clock 4 (lvds)
+ void enable_adc_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
+ _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ _ad9510_regs.bypass_divider_out4 = 1;
+ this->write_reg(0x40);
+ this->write_reg(0x51);
+ this->update_regs();
+ }
+
+ usrp2_iface::sptr _iface;
+ ad9510_regs_t _ad9510_regs;
+};
+
+/***********************************************************************
+ * Public make function for the ad9510 clock control
+ **********************************************************************/
+clock_ctrl::sptr clock_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new clock_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp
new file mode 100644
index 000000000..706bf4246
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_ctrl.hpp
@@ -0,0 +1,60 @@
+//
+// 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_CLOCK_CTRL_HPP
+#define INCLUDED_CLOCK_CTRL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class clock_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<clock_ctrl> sptr;
+
+ /*!
+ * Make a clock config for the ad9510 ic.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new clock control object
+ */
+ static sptr make(usrp2_iface::sptr iface);
+
+ /*!
+ * Enable/disable the rx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_rx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable the tx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_tx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable external reference.
+ * \param enb true to enable
+ */
+ virtual void enable_external_ref(bool enb) = 0;
+
+ /*!
+ * TODO other clock control api here....
+ */
+
+};
+
+#endif /* INCLUDED_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
new file mode 100644
index 000000000..d698216ba
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_ctrl.cpp
@@ -0,0 +1,91 @@
+//
+// 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 "codec_ctrl.hpp"
+#include "ad9777_regs.hpp"
+#include "usrp2_regs.hpp"
+#include <boost/cstdint.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+static const bool codec_ctrl_debug = false;
+
+using namespace uhd;
+
+/*!
+ * A usrp2 codec control specific to the ad9777 ic.
+ */
+class codec_ctrl_impl : public codec_ctrl{
+public:
+ codec_ctrl_impl(usrp2_iface::sptr iface){
+ _iface = iface;
+
+ //setup the ad9777 dac
+ _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
+ _ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X;
+ _ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL;
+ _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
+ _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_ON;
+ _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_AUTO;
+ //I dac values
+ _ad9777_regs.idac_fine_gain_adjust = 0;
+ _ad9777_regs.idac_coarse_gain_adjust = 0xf;
+ _ad9777_regs.idac_offset_adjust_lsb = 0;
+ _ad9777_regs.idac_offset_adjust_msb = 0;
+ //Q dac values
+ _ad9777_regs.qdac_fine_gain_adjust = 0;
+ _ad9777_regs.qdac_coarse_gain_adjust = 0xf;
+ _ad9777_regs.qdac_offset_adjust_lsb = 0;
+ _ad9777_regs.qdac_offset_adjust_msb = 0;
+ //write all regs
+ for(boost::uint8_t addr = 0; addr <= 0xC; addr++){
+ this->send_ad9777_reg(addr);
+ }
+
+ //power-up adc
+ _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON);
+ }
+
+ ~codec_ctrl_impl(void){
+ //power-down dac
+ _ad9777_regs.power_down_mode = 1;
+ this->send_ad9777_reg(0);
+
+ //power-down adc
+ _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF);
+ }
+
+private:
+ ad9777_regs_t _ad9777_regs;
+ usrp2_iface::sptr _iface;
+
+ void send_ad9777_reg(boost::uint8_t addr){
+ boost::uint16_t reg = _ad9777_regs.get_write_reg(addr);
+ if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl;
+ _iface->transact_spi(
+ SPI_SS_AD9777, spi_config_t::EDGE_RISE,
+ reg, 16, false /*no rb*/
+ );
+ }
+};
+
+/***********************************************************************
+ * Public make function for the usrp2 codec control
+ **********************************************************************/
+codec_ctrl::sptr codec_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new codec_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
new file mode 100644
index 000000000..0ee52f476
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_ctrl.hpp
@@ -0,0 +1,38 @@
+//
+// 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_CODEC_CTRL_HPP
+#define INCLUDED_CODEC_CTRL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class codec_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<codec_ctrl> sptr;
+
+ /*!
+ * Make a codec control for the DAC and ADC.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new codec control object
+ */
+ static sptr make(usrp2_iface::sptr iface);
+
+};
+
+#endif /* INCLUDED_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
new file mode 100644
index 000000000..d33a11fd6
--- /dev/null
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -0,0 +1,263 @@
+//
+// 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_iface.hpp"
+#include "clock_ctrl.hpp"
+#include "usrp2_regs.hpp" //wishbone address constants
+#include <uhd/usrp/dboard_iface.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <boost/math/special_functions/round.hpp>
+#include "ad7922_regs.hpp" //aux adc
+#include "ad5624_regs.hpp" //aux dac
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+class usrp2_dboard_iface : public dboard_iface{
+public:
+ usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl);
+ ~usrp2_dboard_iface(void);
+
+ void write_aux_dac(unit_t, int, float);
+ float read_aux_adc(unit_t, int);
+
+ void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
+ void set_gpio_ddr(unit_t, boost::uint16_t);
+ boost::uint16_t read_gpio(unit_t);
+
+ void write_i2c(boost::uint8_t, const byte_vector_t &);
+ byte_vector_t read_i2c(boost::uint8_t, size_t);
+
+ double get_clock_rate(unit_t);
+ void set_clock_enabled(unit_t, bool);
+ bool get_clock_enabled(unit_t);
+
+ void write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+ boost::uint32_t read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+private:
+ usrp2_iface::sptr _iface;
+ clock_ctrl::sptr _clock_ctrl;
+ boost::uint32_t _ddr_shadow;
+
+ uhd::dict<unit_t, ad5624_regs_t> _dac_regs;
+ void _write_aux_dac(unit_t);
+};
+
+/***********************************************************************
+ * Make Function
+ **********************************************************************/
+dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_ctrl::sptr clock_ctrl
+){
+ return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl){
+ _iface = iface;
+ _clock_ctrl = clock_ctrl;
+ _ddr_shadow = 0;
+
+ //set the selection mux to use atr
+ boost::uint32_t new_sels = 0x0;
+ for(size_t i = 0; i < 16; i++){
+ new_sels |= FRF_GPIO_SEL_ATR << (i*2);
+ }
+ _iface->poke32(FR_GPIO_TX_SEL, new_sels);
+ _iface->poke32(FR_GPIO_RX_SEL, new_sels);
+
+ //reset the aux dacs
+ _dac_regs[UNIT_RX] = ad5624_regs_t();
+ _dac_regs[UNIT_TX] = ad5624_regs_t();
+ BOOST_FOREACH(unit_t unit, _dac_regs.keys()){
+ _dac_regs[unit].data = 1;
+ _dac_regs[unit].addr = ad5624_regs_t::ADDR_ALL;
+ _dac_regs[unit].cmd = ad5624_regs_t::CMD_RESET;
+ this->_write_aux_dac(unit);
+ }
+}
+
+usrp2_dboard_iface::~usrp2_dboard_iface(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Clocks
+ **********************************************************************/
+double usrp2_dboard_iface::get_clock_rate(unit_t){
+ return _iface->get_master_clock_freq();
+}
+
+void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
+ switch(unit){
+ case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return;
+ case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return;
+ }
+}
+
+/***********************************************************************
+ * GPIO
+ **********************************************************************/
+static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
+ (dboard_iface::UNIT_RX, 0)
+ (dboard_iface::UNIT_TX, 16)
+;
+
+void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
+ _ddr_shadow = \
+ (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
+ (boost::uint32_t(value) << unit_to_shift[unit]);
+ _iface->poke32(FR_GPIO_DDR, _ddr_shadow);
+}
+
+boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
+ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift[unit]);
+}
+
+void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
+ //define mapping of unit to atr regs to register address
+ static const uhd::dict<
+ unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
+ > unit_to_atr_to_addr = map_list_of
+ (UNIT_RX, map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
+ )
+ (UNIT_TX, map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE)
+ )
+ ;
+ _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+}
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of
+ (dboard_iface::UNIT_TX, SPI_SS_TX_DB)
+ (dboard_iface::UNIT_RX, SPI_SS_RX_DB)
+;
+
+void usrp2_dboard_iface::write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, false /*no rb*/);
+}
+
+boost::uint32_t usrp2_dboard_iface::read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ return _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, true /*rb*/);
+}
+
+/***********************************************************************
+ * I2C
+ **********************************************************************/
+void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
+ return _iface->write_i2c(addr, bytes);
+}
+
+byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
+ return _iface->read_i2c(addr, num_bytes);
+}
+
+/***********************************************************************
+ * Aux DAX/ADC
+ **********************************************************************/
+void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
+ static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of
+ (UNIT_RX, SPI_SS_RX_DAC)
+ (UNIT_TX, SPI_SS_TX_DAC)
+ ;
+ _iface->transact_spi(
+ unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,
+ _dac_regs[unit].get_reg(), 24, false /*no rb*/
+ );
+}
+
+void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){
+ _dac_regs[unit].data = boost::math::iround(4095*value/3.3);
+ _dac_regs[unit].cmd = ad5624_regs_t::CMD_WR_UP_DAC_CHAN_N;
+ switch(which){
+ case 0: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_A; break;
+ case 1: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_B; break;
+ case 2: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_C; break;
+ case 3: _dac_regs[unit].addr = ad5624_regs_t::ADDR_DAC_D; break;
+ default: throw std::runtime_error("not a possible aux dac, must be 0, 1, 2, or 3");
+ }
+ this->_write_aux_dac(unit);
+}
+
+float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
+ static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
+ (UNIT_RX, SPI_SS_RX_ADC)
+ (UNIT_TX, SPI_SS_TX_ADC)
+ ;
+
+ //setup spi config args
+ spi_config_t config;
+ config.mosi_edge = spi_config_t::EDGE_FALL;
+ config.miso_edge = spi_config_t::EDGE_RISE;
+
+ //setup the spi registers
+ ad7922_regs_t ad7922_regs;
+ ad7922_regs.mod = which; //normal mode: mod == chn
+ ad7922_regs.chn = which;
+
+ //write and read spi
+ _iface->transact_spi(
+ unit_to_spi_adc[unit], config,
+ ad7922_regs.get_reg(), 16, false /*no rb*/
+ );
+ ad7922_regs.set_reg(boost::uint16_t(_iface->transact_spi(
+ unit_to_spi_adc[unit], config,
+ ad7922_regs.get_reg(), 16, true /*rb*/
+ )));
+
+ //convert to voltage and return
+ return float(3.3*ad7922_regs.result/4095);
+}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
new file mode 100644
index 000000000..0f8a739f2
--- /dev/null
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -0,0 +1,193 @@
+//
+// 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 "usrp2_regs.hpp"
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void usrp2_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()));
+
+ //create a new dboard interface and manager
+ dboard_iface::sptr _dboard_iface(
+ make_usrp2_dboard_iface(_iface, _clock_ctrl)
+ );
+ _dboard_manager = dboard_manager::make(
+ _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface
+ );
+
+ //load dboards
+ _rx_dboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2),
+ boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2)
+ );
+ _tx_dboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2),
+ boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2)
+ );
+
+ //init the subdevs in use (use the first subdevice)
+ _rx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_rx_subdev_names().at(0));
+ update_rx_mux_config();
+
+ _tx_subdevs_in_use = prop_names_t(1, _dboard_manager->get_tx_subdev_names().at(0));
+ update_tx_mux_config();
+}
+
+void usrp2_impl::update_rx_mux_config(void){
+ //calculate the rx mux
+ boost::uint32_t rx_mux = 0;
+ 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;
+ if (rx_subdev[SUBDEV_PROP_QUADRATURE].as<bool>()){
+ rx_mux = (0x01 << 2) | (0x00 << 0); //Q=ADC1, I=ADC0
+ }else{
+ rx_mux = 0x00; //ADC0
+ }
+ if (rx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){
+ rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0);
+ }
+
+ _iface->poke32(FR_DSP_RX_MUX, rx_mux);
+}
+
+void usrp2_impl::update_tx_mux_config(void){
+ //calculate the tx mux
+ boost::uint32_t tx_mux = 0x10;
+ 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;
+ if (tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){
+ tx_mux = (((tx_mux >> 0) & 0xf) << 4) | (((tx_mux >> 4) & 0xf) << 0);
+ }
+
+ _iface->poke32(FR_DSP_TX_MUX, tx_mux);
+}
+
+/***********************************************************************
+ * RX DBoard Properties
+ **********************************************************************/
+void usrp2_impl::rx_dboard_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<dboard_prop_t>()){
+ case DBOARD_PROP_NAME:
+ val = std::string("usrp2 dboard (rx unit)");
+ return;
+
+ case DBOARD_PROP_SUBDEV:
+ val = _dboard_manager->get_rx_subdev(name);
+ return;
+
+ case DBOARD_PROP_SUBDEV_NAMES:
+ 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;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_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>();
+ update_rx_mux_config(); //if the val is bad, this will throw
+ 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());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * TX DBoard Properties
+ **********************************************************************/
+void usrp2_impl::tx_dboard_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<dboard_prop_t>()){
+ case DBOARD_PROP_NAME:
+ val = std::string("usrp2 dboard (tx unit)");
+ return;
+
+ case DBOARD_PROP_SUBDEV:
+ val = _dboard_manager->get_tx_subdev(name);
+ return;
+
+ case DBOARD_PROP_SUBDEV_NAMES:
+ 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;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_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>();
+ update_tx_mux_config(); //if the val is bad, this will throw
+ 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());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
new file mode 100644
index 000000000..195a9bc53
--- /dev/null
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -0,0 +1,243 @@
+//
+// 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 "usrp2_regs.hpp"
+#include <uhd/usrp/dsp_props.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+static const size_t default_decim = 16;
+static const size_t default_interp = 16;
+
+#define rint boost::math::iround
+
+template <class T> T log2(T num){
+ return std::log(num)/std::log(T(2));
+}
+
+/***********************************************************************
+ * DDC Helper Methods
+ **********************************************************************/
+static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){
+ UHD_ASSERT_THROW(std::abs(freq) < clock_freq/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+
+ //calculate the freq register word
+ boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
+
+ //update the actual frequency
+ freq = (double(freq_word) / scale_factor) * clock_freq;
+
+ return freq_word;
+}
+
+// Check if requested decim/interp rate is:
+// multiple of 4, enable two halfband filters
+// multiple of 2, enable one halfband filter
+// handle remainder in CIC
+static boost::uint32_t calculate_cic_word(size_t rate){
+ int hb0 = 0, hb1 = 0;
+ if (not (rate & 0x1)){
+ hb0 = 1;
+ rate /= 2;
+ }
+ if (not (rate & 0x1)){
+ hb1 = 1;
+ rate /= 2;
+ }
+ return (hb1 << 9) | (hb0 << 8) | (rate & 0xff);
+}
+
+static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){
+ return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0);
+}
+
+template <class rate_t> static rate_t
+pick_closest_rate(double exact_rate, const std::vector<rate_t> &rates){
+ rate_t closest_match = rates.at(0);
+ BOOST_FOREACH(rate_t possible_rate, rates){
+ if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match))
+ closest_match = possible_rate;
+ }
+ return closest_match;
+}
+
+void usrp2_impl::init_ddc_config(void){
+ //create the ddc in the rx dsp dict
+ _rx_dsp_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_impl::ddc_get, this, _1, _2),
+ boost::bind(&usrp2_impl::ddc_set, this, _1, _2)
+ );
+
+ //initial config and update
+ _ddc_decim = default_decim;
+ _ddc_freq = 0;
+ update_ddc_config();
+}
+
+void usrp2_impl::update_ddc_config(void){
+ //set the decimation
+ _iface->poke32(FR_DSP_RX_DECIM_RATE, calculate_cic_word(_ddc_decim));
+
+ //set the scaling
+ static const boost::int16_t default_rx_scale_iq = 1024;
+ _iface->poke32(FR_DSP_RX_SCALE_IQ,
+ calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
+ );
+}
+
+/***********************************************************************
+ * DDC Properties
+ **********************************************************************/
+void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+ case DSP_PROP_NAME:
+ val = std::string("usrp2 ddc0");
+ return;
+
+ case DSP_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case DSP_PROP_FREQ_SHIFT:
+ val = _ddc_freq;
+ return;
+
+ case DSP_PROP_CODEC_RATE:
+ val = get_master_clock_freq();
+ return;
+
+ case DSP_PROP_HOST_RATE:
+ val = get_master_clock_freq()/_ddc_decim;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+
+ case DSP_PROP_FREQ_SHIFT:{
+ double new_freq = val.as<double>();
+ _iface->poke32(FR_DSP_RX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
+ );
+ _ddc_freq = new_freq; //shadow
+ }
+ return;
+
+ case DSP_PROP_HOST_RATE:{
+ double extact_rate = get_master_clock_freq()/val.as<double>();
+ _ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
+ update_ddc_config();
+ }
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * DUC Helper Methods
+ **********************************************************************/
+void usrp2_impl::init_duc_config(void){
+ //create the duc in the tx dsp dict
+ _tx_dsp_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_impl::duc_get, this, _1, _2),
+ boost::bind(&usrp2_impl::duc_set, this, _1, _2)
+ );
+
+ //initial config and update
+ _duc_interp = default_interp;
+ _duc_freq = 0;
+ update_duc_config();
+}
+
+void usrp2_impl::update_duc_config(void){
+ // Calculate CIC interpolation (i.e., without halfband interpolators)
+ size_t tmp_interp = calculate_cic_word(_duc_interp) & 0xff;
+
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ double interp_cubed = std::pow(double(tmp_interp), 3);
+ boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
+
+ //set the interpolation
+ _iface->poke32(FR_DSP_TX_INTERP_RATE, calculate_cic_word(_duc_interp));
+
+ //set the scaling
+ _iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
+}
+
+/***********************************************************************
+ * DUC Properties
+ **********************************************************************/
+void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+ case DSP_PROP_NAME:
+ val = std::string("usrp2 duc0");
+ return;
+
+ case DSP_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case DSP_PROP_FREQ_SHIFT:
+ val = _duc_freq;
+ return;
+
+ case DSP_PROP_CODEC_RATE:
+ val = get_master_clock_freq();
+ return;
+
+ case DSP_PROP_HOST_RATE:
+ val = get_master_clock_freq()/_duc_interp;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
+ switch(key.as<dsp_prop_t>()){
+
+ case DSP_PROP_FREQ_SHIFT:{
+ double new_freq = val.as<double>();
+ _iface->poke32(FR_DSP_TX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
+ );
+ _duc_freq = new_freq; //shadow
+ }
+ return;
+
+ case DSP_PROP_HOST_RATE:{
+ double extact_rate = get_master_clock_freq()/val.as<double>();
+ _duc_interp = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
+ update_duc_config();
+ }
+ 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
new file mode 100644
index 000000000..75f5b1779
--- /dev/null
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -0,0 +1,119 @@
+//
+// 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_USRP2_FW_COMMON_H
+#define INCLUDED_USRP2_FW_COMMON_H
+
+/*!
+ * Structs and constants for usrp2 communication.
+ * This header is shared by the firmware and host code.
+ * Therefore, this header may only contain valid C code.
+ */
+#ifdef __cplusplus
+#include <boost/cstdint.hpp>
+#define _SINS_ boost:://stdint namespace when in c++
+extern "C" {
+#else
+#include <stdint.h>
+#define _SINS_
+#endif
+
+//defines the protocol version in this shared header
+//increment this value when the protocol is changed
+#define USRP2_PROTO_VERSION 3
+
+//used to differentiate control packets over data port
+#define USRP2_INVALID_VRT_HEADER 0
+
+// size of the vrt header and trailer to the host
+#define USRP2_HOST_RX_VRT_HEADER_WORDS32 5
+#define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present
+
+// udp ports for the usrp2 communication
+// Dynamic and/or private ports: 49152-65535
+#define USRP2_UDP_CTRL_PORT 49152
+#define USRP2_UDP_DATA_PORT 49153
+
+typedef enum{
+ USRP2_CTRL_ID_HUH_WHAT = ' ',
+ //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
+ //USRP2_CTRL_ID_SUX_MAN,
+
+ USRP2_CTRL_ID_WAZZUP_BRO = 'a',
+ USRP2_CTRL_ID_WAZZUP_DUDE = 'A',
+
+ USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's',
+ USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S',
+
+ USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO = 'i',
+ USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE = 'I',
+
+ USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',
+ USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H',
+
+ USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO = 'p',
+ USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE = 'P',
+
+ USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO = 'r',
+ USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE = 'R',
+
+ USRP2_CTRL_ID_PEACE_OUT = '~'
+
+} usrp2_ctrl_id_t;
+
+typedef enum{
+ USRP2_DIR_RX = 'r',
+ USRP2_DIR_TX = 't'
+} usrp2_dir_which_t;
+
+typedef enum{
+ USRP2_CLK_EDGE_RISE = 'r',
+ USRP2_CLK_EDGE_FALL = 'f'
+} usrp2_clk_edge_t;
+
+typedef struct{
+ _SINS_ uint32_t proto_ver;
+ _SINS_ uint32_t id;
+ _SINS_ uint32_t seq;
+ union{
+ _SINS_ uint32_t ip_addr;
+ struct {
+ _SINS_ uint8_t dev;
+ _SINS_ uint8_t miso_edge;
+ _SINS_ uint8_t mosi_edge;
+ _SINS_ uint8_t readback;
+ _SINS_ uint32_t data;
+ _SINS_ uint8_t num_bits;
+ } spi_args;
+ struct {
+ _SINS_ uint8_t addr;
+ _SINS_ uint8_t bytes;
+ _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
+ } i2c_args;
+ struct {
+ _SINS_ uint32_t addr;
+ _SINS_ uint32_t data;
+ _SINS_ uint8_t num_bytes; //1, 2, 4
+ } poke_args;
+ } data;
+} usrp2_ctrl_data_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INCLUDED_USRP2_FW_COMMON_H */
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
new file mode 100644
index 000000000..b6ab919e7
--- /dev/null
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -0,0 +1,100 @@
+//
+// 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 "usrp2_regs.hpp"
+#include <uhd/transport/convert_types.hpp>
+#include <boost/format.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+void usrp2_impl::io_init(void){
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+
+ //send a small data packet so the usrp2 knows the udp source port
+ managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
+ boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
+ memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ send_buff->done(sizeof(data));
+
+ //setup RX DSP regs
+ std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl;
+ _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
+ _iface->poke32(FR_RX_CTRL_NCHANNELS, 1);
+ _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset
+ _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0
+ | (0x1 << 28) //if data with stream id
+ | (0x1 << 26) //has trailer
+ | (0x3 << 22) //integer time other
+ | (0x1 << 20) //fractional time sample count
+ );
+ _iface->poke32(FR_RX_CTRL_VRT_STREAM_ID, 0);
+ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0);
+}
+
+/***********************************************************************
+ * Send Data
+ **********************************************************************/
+size_t usrp2_impl::send(
+ const asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
+ const io_type_t &io_type,
+ send_mode_t send_mode
+){
+ return vrt_packet_handler::send(
+ _packet_handler_send_state, //last state of the send handler
+ buff, metadata, send_mode, //buffer to empty and samples metadata
+ io_type, _tx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport, //zero copy interface
+ get_max_send_samps_per_packet()
+ );
+}
+
+/***********************************************************************
+ * Receive Data
+ **********************************************************************/
+size_t usrp2_impl::recv(
+ const asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
+ const io_type_t &io_type,
+ recv_mode_t recv_mode
+){
+ return vrt_packet_handler::recv(
+ _packet_handler_recv_state, //last state of the recv handler
+ buff, metadata, recv_mode, //buffer to fill and samples metadata
+ io_type, _rx_otw_type, //input and output types to convert
+ get_master_clock_freq(), //master clock tick rate
+ _data_transport //zero copy interface
+ );
+}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
new file mode 100644
index 000000000..f17efd88e
--- /dev/null
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -0,0 +1,247 @@
+//
+// 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 "usrp2_regs.hpp"
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/types/mac_addr.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio/ip/address_v4.hpp>
+#include <boost/assign/list_of.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void usrp2_impl::mboard_init(void){
+ _mboard_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_impl::mboard_get, this, _1, _2),
+ boost::bind(&usrp2_impl::mboard_set, this, _1, _2)
+ );
+}
+
+void usrp2_impl::init_clock_config(void){
+ //setup the clock configuration settings
+ _clock_config.ref_source = clock_config_t::REF_INT;
+ _clock_config.pps_source = clock_config_t::PPS_SMA;
+ _clock_config.pps_polarity = clock_config_t::PPS_NEG;
+
+ //update the clock config (sends a control packet)
+ update_clock_config();
+}
+
+void usrp2_impl::update_clock_config(void){
+ boost::uint32_t pps_flags = 0;
+
+ //translate pps source enums
+ switch(_clock_config.pps_source){
+ case clock_config_t::PPS_SMA: pps_flags |= FRF_TIME64_PPS_SMA; break;
+ case clock_config_t::PPS_MIMO: pps_flags |= FRF_TIME64_PPS_MIMO; break;
+ default: throw std::runtime_error("usrp2: unhandled clock configuration pps source");
+ }
+
+ //translate pps polarity enums
+ switch(_clock_config.pps_polarity){
+ case clock_config_t::PPS_POS: pps_flags |= FRF_TIME64_PPS_POSEDGE; break;
+ case clock_config_t::PPS_NEG: pps_flags |= FRF_TIME64_PPS_NEGEDGE; break;
+ default: throw std::runtime_error("usrp2: unhandled clock configuration pps polarity");
+ }
+
+ //set the pps flags
+ _iface->poke32(FR_TIME64_FLAGS, pps_flags);
+
+ //clock source ref 10mhz
+ switch(_clock_config.ref_source){
+ case clock_config_t::REF_INT : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x10); break;
+ case clock_config_t::REF_SMA : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x1C); break;
+ case clock_config_t::REF_MIMO: _iface->poke32(FR_MISC_CTRL_CLOCK, 0x15); break;
+ default: throw std::runtime_error("usrp2: unhandled clock configuration reference source");
+ }
+
+ //clock source ref 10mhz
+ bool use_external = _clock_config.ref_source != clock_config_t::REF_INT;
+ _clock_ctrl->enable_external_ref(use_external);
+}
+
+void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
+ //set ticks and seconds
+ _iface->poke32(FR_TIME64_SECS, time_spec.secs);
+ _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
+
+ //set the register to latch it all in
+ boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS;
+ _iface->poke32(FR_TIME64_IMM, imm_flags);
+}
+
+void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= FR_RX_CTRL_MAX_SAMPS_PER_CMD);
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps;
+ boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode];
+
+ //issue the stream command
+ _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD(
+ (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1),
+ (stream_cmd.stream_now)? 1 : 0,
+ (inst_chain)? 1 : 0,
+ (inst_reload)? 1 : 0
+ ));
+ _iface->poke32(FR_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs);
+ _iface->poke32(FR_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
+}
+
+/***********************************************************************
+ * MBoard Get Properties
+ **********************************************************************/
+void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //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);
+ 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);
+ val = boost::asio::ip::address_v4(bytes).to_string();
+ return;
+ }
+ }
+
+ //handle the get request conditioned on the key
+ switch(key.as<mboard_prop_t>()){
+ case MBOARD_PROP_NAME:
+ val = std::string("usrp2 mboard");
+ return;
+
+ case MBOARD_PROP_OTHERS:{
+ prop_names_t others = boost::assign::list_of
+ ("mac-addr")
+ ("ip-addr")
+ ;
+ val = others;
+ }
+ return;
+
+ case MBOARD_PROP_RX_DBOARD:
+ UHD_ASSERT_THROW(name == "");
+ val = _rx_dboard_proxy->get_link();
+ return;
+
+ case MBOARD_PROP_RX_DBOARD_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
+ case MBOARD_PROP_TX_DBOARD:
+ UHD_ASSERT_THROW(name == "");
+ val = _tx_dboard_proxy->get_link();
+ return;
+
+ case MBOARD_PROP_TX_DBOARD_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
+ case MBOARD_PROP_RX_DSP:
+ UHD_ASSERT_THROW(name == "");
+ val = _rx_dsp_proxy->get_link();
+ return;
+
+ case MBOARD_PROP_RX_DSP_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
+ case MBOARD_PROP_TX_DSP:
+ UHD_ASSERT_THROW(name == "");
+ val = _tx_dsp_proxy->get_link();
+ return;
+
+ case MBOARD_PROP_TX_DSP_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
+ case MBOARD_PROP_CLOCK_CONFIG:
+ val = _clock_config;
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * MBoard Set Properties
+ **********************************************************************/
+void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
+ //handle the other props
+ 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);
+ 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);
+ return;
+ }
+ }
+
+ //handle the get request conditioned on the key
+ switch(key.as<mboard_prop_t>()){
+
+ case MBOARD_PROP_CLOCK_CONFIG:
+ _clock_config = val.as<clock_config_t>();
+ update_clock_config();
+ return;
+
+ case MBOARD_PROP_TIME_NOW:
+ set_time_spec(val.as<time_spec_t>(), true);
+ return;
+
+ case MBOARD_PROP_TIME_NEXT_PPS:
+ set_time_spec(val.as<time_spec_t>(), false);
+ return;
+
+ case MBOARD_PROP_STREAM_CMD:
+ issue_ddc_stream_cmd(val.as<stream_cmd_t>());
+ return;
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp
new file mode 100644
index 000000000..dde22b499
--- /dev/null
+++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp
@@ -0,0 +1,46 @@
+//
+// 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 "serdes_ctrl.hpp"
+#include "usrp2_regs.hpp"
+
+using namespace uhd;
+
+/*!
+ * A usrp2 serdes control implementation
+ */
+class serdes_ctrl_impl : public serdes_ctrl{
+public:
+ serdes_ctrl_impl(usrp2_iface::sptr iface){
+ _iface = iface;
+ _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN);
+ }
+
+ ~serdes_ctrl_impl(void){
+ _iface->poke32(FR_MISC_CTRL_SERDES, 0); //power-down
+ }
+
+private:
+ usrp2_iface::sptr _iface;
+};
+
+/***********************************************************************
+ * Public make function for the usrp2 serdes control
+ **********************************************************************/
+serdes_ctrl::sptr serdes_ctrl::make(usrp2_iface::sptr iface){
+ return sptr(new serdes_ctrl_impl(iface));
+}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp
new file mode 100644
index 000000000..586238739
--- /dev/null
+++ b/host/lib/usrp/usrp2/serdes_ctrl.hpp
@@ -0,0 +1,40 @@
+//
+// 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_SERDES_CTRL_HPP
+#define INCLUDED_SERDES_CTRL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class serdes_ctrl : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<serdes_ctrl> sptr;
+
+ /*!
+ * Make a serdes control object for the usrp2 serdes port.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new serdes control object
+ */
+ static sptr make(usrp2_iface::sptr iface);
+
+ //TODO fill me in with virtual methods
+
+};
+
+#endif /* INCLUDED_SERDES_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
new file mode 100644
index 000000000..e43b9678e
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -0,0 +1,219 @@
+//
+// 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_iface.hpp"
+#include <uhd/utils/assert.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/thread.hpp>
+#include <boost/foreach.hpp>
+#include <boost/asio.hpp> //used for htonl and ntohl
+#include <boost/assign/list_of.hpp>
+#include <stdexcept>
+#include <algorithm>
+
+using namespace uhd;
+
+class usrp2_iface_impl : public usrp2_iface{
+public:
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+ usrp2_iface_impl(transport::udp_simple::sptr ctrl_transport){
+ _ctrl_transport = ctrl_transport;
+ }
+
+ ~usrp2_iface_impl(void){
+ /* NOP */
+ }
+
+/***********************************************************************
+ * Peek and Poke
+ **********************************************************************/
+ void poke32(boost::uint32_t addr, boost::uint32_t data){
+ return this->poke<boost::uint32_t>(addr, data);
+ }
+
+ boost::uint32_t peek32(boost::uint32_t addr){
+ return this->peek<boost::uint32_t>(addr);
+ }
+
+ void poke16(boost::uint32_t addr, boost::uint16_t data){
+ return this->poke<boost::uint16_t>(addr, data);
+ }
+
+ boost::uint16_t peek16(boost::uint32_t addr){
+ return this->peek<boost::uint16_t>(addr);
+ }
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ static const uhd::dict<spi_config_t::edge_t, int> spi_edge_to_otw = boost::assign::map_list_of
+ (spi_config_t::EDGE_RISE, USRP2_CLK_EDGE_RISE)
+ (spi_config_t::EDGE_FALL, USRP2_CLK_EDGE_FALL)
+ ;
+
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
+ out_data.data.spi_args.dev = which_slave;
+ out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge];
+ out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge];
+ out_data.data.spi_args.readback = (readback)? 1 : 0;
+ out_data.data.spi_args.num_bits = num_bits;
+ out_data.data.spi_args.data = htonl(data);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
+
+ return ntohl(in_data.data.spi_args.data);
+ }
+
+/***********************************************************************
+ * I2C
+ **********************************************************************/
+ void write_i2c(boost::uint8_t addr, const byte_vector_t &buf){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO);
+ out_data.data.i2c_args.addr = addr;
+ out_data.data.i2c_args.bytes = buf.size();
+
+ //limitation of i2c transaction size
+ UHD_ASSERT_THROW(buf.size() <= sizeof(out_data.data.i2c_args.data));
+
+ //copy in the data
+ std::copy(buf.begin(), buf.end(), out_data.data.i2c_args.data);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
+ }
+
+ byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO);
+ out_data.data.i2c_args.addr = addr;
+ out_data.data.i2c_args.bytes = num_bytes;
+
+ //limitation of i2c transaction size
+ UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data));
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
+ UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes);
+
+ //copy out the data
+ byte_vector_t result(num_bytes);
+ std::copy(in_data.data.i2c_args.data, in_data.data.i2c_args.data + num_bytes, result.begin());
+ return result;
+ }
+
+/***********************************************************************
+ * Send/Recv over control
+ **********************************************************************/
+ usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ //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.seq = htonl(++_ctrl_seq_num);
+ _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
+
+ //loop until we get the packet or timeout
+ while(true){
+ usrp2_ctrl_data_t in_data;
+ size_t len = _ctrl_transport->recv(boost::asio::buffer(&in_data, sizeof(in_data)));
+ if(len >= sizeof(boost::uint32_t) and ntohl(in_data.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(in_data.proto_ver)
+ ));
+ }
+ if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
+ return in_data;
+ }
+ if (len == 0) break; //timeout
+ //didnt get seq or bad packet, continue looking...
+ }
+ throw std::runtime_error("usrp2 no control response");
+ }
+
+/***********************************************************************
+ * Master Clock! Ahhhhh
+ **********************************************************************/
+ double get_master_clock_freq(void){
+ return 100e6;
+ }
+
+private:
+ //this lovely lady makes it all possible
+ transport::udp_simple::sptr _ctrl_transport;
+
+ //used in send/recv
+ boost::mutex _ctrl_mutex;
+ boost::uint32_t _ctrl_seq_num;
+
+/***********************************************************************
+ * Private Templated Peek and Poke
+ **********************************************************************/
+ template <class T> void poke(boost::uint32_t addr, T data){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.data = htonl(boost::uint32_t(data));
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
+ }
+
+ template <class T> T peek(boost::uint32_t addr){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
+ return T(ntohl(out_data.data.poke_args.data));
+ }
+
+};
+
+/***********************************************************************
+ * Public make function for usrp2 interface
+ **********************************************************************/
+usrp2_iface::sptr usrp2_iface::make(transport::udp_simple::sptr ctrl_transport){
+ return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport));
+}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
new file mode 100644
index 000000000..caf6623e2
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -0,0 +1,119 @@
+//
+// 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_USRP2_IFACE_HPP
+#define INCLUDED_USRP2_IFACE_HPP
+
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/cstdint.hpp>
+#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.
+ * Including spi, peek, poke, control...
+ */
+class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{
+public:
+ typedef boost::shared_ptr<usrp2_iface> sptr;
+
+ /*!
+ * Make a new usrp2 interface with the control transport.
+ * \param ctrl_transport the udp transport object
+ * \return a new usrp2 interface object
+ */
+ static sptr make(uhd::transport::udp_simple::sptr ctrl_transport);
+
+ /*!
+ * Perform a control transaction.
+ * \param data a control data struct
+ * \return the result control data
+ */
+ virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0;
+
+ /*!
+ * Write a register (32 bits)
+ * \param addr the address
+ * \param data the 32bit data
+ */
+ virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0;
+
+ /*!
+ * Read a register (32 bits)
+ * \param addr the address
+ * \return the 32bit data
+ */
+ virtual boost::uint32_t peek32(boost::uint32_t addr) = 0;
+
+ /*!
+ * Write a register (16 bits)
+ * \param addr the address
+ * \param data the 16bit data
+ */
+ virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0;
+
+ /*!
+ * Read a register (16 bits)
+ * \param addr the address
+ * \return the 16bit data
+ */
+ virtual boost::uint16_t peek16(boost::uint32_t addr) = 0;
+
+ /*!
+ * Perform an spi transaction.
+ * \param which_slave the slave device number
+ * \param config spi config args
+ * \param data the bits to write
+ * \param num_bits how many bits in data
+ * \param readback true to readback a value
+ * \return spi data if readback set
+ */
+ virtual boost::uint32_t transact_spi(
+ int which_slave,
+ const uhd::spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ) = 0;
+
+ /*!
+ * Get the master clock frequency.
+ * \return the frequency in Hz
+ */
+ virtual double get_master_clock_freq(void) = 0;
+};
+
+#endif /* INCLUDED_USRP2_IFACE_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
new file mode 100644
index 000000000..af3ec216a
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -0,0 +1,219 @@
+//
+// 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/transport/if_addrs.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
+
+UHD_STATIC_BLOCK(register_usrp2_device){
+ device::register_device(&usrp2::find, &usrp2::make);
+}
+
+/***********************************************************************
+ * Discovery over the udp transport
+ **********************************************************************/
+uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
+ device_addrs_t usrp2_addrs;
+
+ //if no address was specified, send a broadcast on each interface
+ if (not hint.has_key("addr")){
+ BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
+ //avoid the loopback device
+ if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue;
+
+ //create a new hint with this broadcast address
+ device_addr_t new_hint;
+ new_hint["addr"] = if_addrs.bcast;
+
+ //call discover with the new hint and append results
+ device_addrs_t new_usrp2_addrs = usrp2::find(new_hint);
+ usrp2_addrs.insert(usrp2_addrs.begin(),
+ new_usrp2_addrs.begin(), new_usrp2_addrs.end()
+ );
+ }
+ return usrp2_addrs;
+ }
+
+ //create a udp transport to communicate
+ std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
+ udp_simple::sptr udp_transport = udp_simple::make_broadcast(
+ hint["addr"], ctrl_port
+ );
+
+ //send a hello control packet
+ usrp2_ctrl_data_t ctrl_data_out;
+ ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);
+ ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
+ udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
+
+ //loop and recieve until the timeout
+ while(true){
+ usrp2_ctrl_data_t ctrl_data_in;
+ size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)));
+ //std::cout << len << "\n";
+ if (len >= sizeof(usrp2_ctrl_data_t)){
+ //handle the received data
+ switch(ntohl(ctrl_data_in.id)){
+ case USRP2_CTRL_ID_WAZZUP_DUDE:
+ //make a boost asio ipv4 with the raw addr in host byte order
+ boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr));
+ device_addr_t new_addr;
+ new_addr["name"] = "USRP2";
+ new_addr["addr"] = ip_addr.to_string();
+ usrp2_addrs.push_back(new_addr);
+ //dont break here, it will exit the while loop
+ //just continue on to the next loop iteration
+ }
+ }
+ if (len == 0) break; //timeout
+ }
+
+ return usrp2_addrs;
+}
+
+/***********************************************************************
+ * Make
+ **********************************************************************/
+template <class T> std::string num2str(T num){
+ return boost::lexical_cast<std::string>(num);
+}
+
+device::sptr usrp2::make(const device_addr_t &device_addr){
+ //create a control transport
+ udp_simple::sptr ctrl_transport = udp_simple::make_connected(
+ device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
+ );
+
+ //extract the receive and send buffer sizes
+ size_t recv_buff_size = 0, send_buff_size= 0 ;
+ if (device_addr.has_key("recv_buff_size")){
+ recv_buff_size = size_t(boost::lexical_cast<double>(device_addr["recv_buff_size"]));
+ }
+ if (device_addr.has_key("send_buff_size")){
+ send_buff_size = size_t(boost::lexical_cast<double>(device_addr["send_buff_size"]));
+ }
+
+ //create a data transport
+ udp_zero_copy::sptr data_transport = udp_zero_copy::make(
+ device_addr["addr"],
+ num2str(USRP2_UDP_DATA_PORT),
+ recv_buff_size,
+ send_buff_size
+ );
+
+ //create the usrp2 implementation guts
+ return device::sptr(
+ new usrp2_impl(ctrl_transport, data_transport)
+ );
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp2_impl::usrp2_impl(
+ udp_simple::sptr ctrl_transport,
+ udp_zero_copy::sptr data_transport
+){
+ _data_transport = data_transport;
+
+ //make a new interface for usrp2 stuff
+ _iface = usrp2_iface::make(ctrl_transport);
+ _clock_ctrl = clock_ctrl::make(_iface);
+ _codec_ctrl = codec_ctrl::make(_iface);
+ _serdes_ctrl = serdes_ctrl::make(_iface);
+
+ //load the allowed decim/interp rates
+ //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
+ _allowed_decim_and_interp_rates.clear();
+ for (size_t i = 4; i <= 128; i+=1){
+ _allowed_decim_and_interp_rates.push_back(i);
+ }
+ for (size_t i = 130; i <= 256; i+=2){
+ _allowed_decim_and_interp_rates.push_back(i);
+ }
+ for (size_t i = 260; i <= 512; i+=4){
+ _allowed_decim_and_interp_rates.push_back(i);
+ }
+
+ //init the mboard
+ mboard_init();
+
+ //init the ddc
+ init_ddc_config();
+
+ //init the duc
+ init_duc_config();
+
+ //initialize the clock configuration
+ init_clock_config();
+
+ //init the tx and rx dboards (do last)
+ dboard_init();
+
+ //init the send and recv io
+ io_init();
+
+}
+
+usrp2_impl::~usrp2_impl(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Device Properties
+ **********************************************************************/
+void usrp2_impl::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<device_prop_t>()){
+ case DEVICE_PROP_NAME:
+ val = std::string("usrp2 device");
+ return;
+
+ case DEVICE_PROP_MBOARD:
+ UHD_ASSERT_THROW(name == "");
+ val = _mboard_proxy->get_link();
+ return;
+
+ case DEVICE_PROP_MBOARD_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_impl::set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
new file mode 100644
index 000000000..afea9683c
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -0,0 +1,222 @@
+//
+// 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_USRP2_IMPL_HPP
+#define INCLUDED_USRP2_IMPL_HPP
+
+#include "usrp2_iface.hpp"
+#include "clock_ctrl.hpp"
+#include "codec_ctrl.hpp"
+#include "serdes_ctrl.hpp"
+#include <uhd/usrp/usrp2.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/clock_config.hpp>
+#include <uhd/usrp/dboard_eeprom.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <uhd/transport/vrt.hpp>
+#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include "../../transport/vrt_packet_handler.hpp"
+
+/*!
+ * Make a usrp2 dboard interface.
+ * \param iface the usrp2 interface object
+ * \param clk_ctrl the clock control object
+ * \return a sptr to a new dboard interface
+ */
+uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_ctrl::sptr clk_ctrl
+);
+
+/*!
+ * Simple wax obj proxy class:
+ * Provides a wax obj interface for a set and a get function.
+ * This allows us to create nested properties structures
+ * while maintaining flattened code within the implementation.
+ */
+class wax_obj_proxy : public wax::obj{
+public:
+ typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
+ typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
+ typedef boost::shared_ptr<wax_obj_proxy> sptr;
+
+ static sptr make(const get_t &get, const set_t &set){
+ return sptr(new wax_obj_proxy(get, set));
+ }
+
+ ~wax_obj_proxy(void){
+ /* NOP */
+ }
+
+private:
+ get_t _get;
+ set_t _set;
+
+ wax_obj_proxy(const get_t &get, const set_t &set){
+ _get = get;
+ _set = set;
+ };
+
+ void get(const wax::obj &key, wax::obj &val){
+ return _get(key, val);
+ }
+
+ void set(const wax::obj &key, const wax::obj &val){
+ return _set(key, val);
+ }
+};
+
+/*!
+ * USRP2 implementation guts:
+ * The implementation details are encapsulated here.
+ * Handles properties on the mboard, dboard, dsps...
+ */
+class usrp2_impl : public uhd::device{
+public:
+ /*!
+ * Create a new usrp2 impl base.
+ * \param ctrl_transport the udp transport for control
+ * \param data_transport the udp transport for data
+ */
+ usrp2_impl(
+ uhd::transport::udp_simple::sptr ctrl_transport,
+ uhd::transport::udp_zero_copy::sptr data_transport
+ );
+
+ ~usrp2_impl(void);
+
+ //the io interface
+ size_t get_max_send_samps_per_packet(void) const{
+ return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size();
+ }
+ size_t send(
+ const boost::asio::const_buffer &,
+ 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{
+ return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size();
+ }
+ size_t recv(
+ const boost::asio::mutable_buffer &,
+ uhd::rx_metadata_t &,
+ const uhd::io_type_t &,
+ uhd::device::recv_mode_t
+ );
+
+private:
+ double get_master_clock_freq(void){
+ return _iface->get_master_clock_freq();
+ }
+
+ //device properties interface
+ void get(const wax::obj &, wax::obj &);
+ void set(const wax::obj &, const wax::obj &);
+
+ //interfaces
+ usrp2_iface::sptr _iface;
+ clock_ctrl::sptr _clock_ctrl;
+ codec_ctrl::sptr _codec_ctrl;
+ serdes_ctrl::sptr _serdes_ctrl;
+
+ /*******************************************************************
+ * Deal with the rx and tx packet sizes
+ ******************************************************************/
+ static const size_t _mtu = 1500; //FIXME we have no idea
+ static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)
+ static const size_t _max_rx_bytes_per_packet =
+ _mtu - _hdrs -
+ USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) -
+ USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)
+ ;
+ static const size_t _max_tx_bytes_per_packet =
+ _mtu - _hdrs -
+ uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)
+ ;
+
+ vrt_packet_handler::recv_state _packet_handler_recv_state;
+ vrt_packet_handler::send_state _packet_handler_send_state;
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
+ void io_init(void);
+
+ //udp transports for control and data
+ uhd::transport::udp_zero_copy::sptr _data_transport;
+
+ //methods and shadows for clock configuration
+ uhd::clock_config_t _clock_config;
+ void init_clock_config(void);
+ void update_clock_config(void);
+ void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
+
+ //rx and tx dboard methods and objects
+ uhd::usrp::dboard_manager::sptr _dboard_manager;
+ void dboard_init(void);
+
+ //properties for the mboard
+ void mboard_init(void);
+ void mboard_get(const wax::obj &, wax::obj &);
+ void mboard_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _mboard_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;
+ void update_rx_mux_config(void);
+ void update_tx_mux_config(void);
+
+ //methods and shadows for the ddc dsp
+ std::vector<size_t> _allowed_decim_and_interp_rates;
+ size_t _ddc_decim;
+ double _ddc_freq;
+ void init_ddc_config(void);
+ void update_ddc_config(void);
+ void issue_ddc_stream_cmd(const uhd::stream_cmd_t &stream_cmd);
+
+ //methods and shadows for the duc dsp
+ size_t _duc_interp;
+ double _duc_freq;
+ void init_duc_config(void);
+ void update_duc_config(void);
+
+ //properties interface for ddc
+ void ddc_get(const wax::obj &, wax::obj &);
+ void ddc_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_dsp_proxy;
+
+ //properties interface for duc
+ void duc_get(const wax::obj &, wax::obj &);
+ void duc_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _tx_dsp_proxy;
+
+};
+
+#endif /* INCLUDED_USRP2_IMPL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
new file mode 100644
index 000000000..feeccaa34
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -0,0 +1,247 @@
+//
+// 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_USRP2_REGS_HPP
+#define INCLUDED_USRP2_REGS_HPP
+
+#include <boost/cstdint.hpp>
+
+////////////////////////////////////////////////////
+// Settings Bus, Slave #7, Not Byte Addressable!
+//
+// Output-only from processor point-of-view.
+// 1KB of address space (== 256 32-bit write-only regs)
+
+
+#define MISC_OUTPUT_BASE 0xD400
+//#define TX_PROTOCOL_ENGINE_BASE 0xD480
+//#define RX_PROTOCOL_ENGINE_BASE 0xD4C0
+//#define BUFFER_POOL_CTRL_BASE 0xD500
+//#define LAST_SETTING_REG 0xD7FC // last valid setting register
+
+#define SR_MISC 0
+#define SR_TX_PROT_ENG 32
+#define SR_RX_PROT_ENG 48
+#define SR_BUFFER_POOL_CTRL 64
+#define SR_UDP_SM 96
+#define SR_TX_DSP 208
+#define SR_TX_CTRL 224
+#define SR_RX_DSP 160
+#define SR_RX_CTRL 176
+#define SR_TIME64 192
+#define SR_SIMTIMER 198
+#define SR_LAST 255
+
+#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(boost::uint32_t))
+
+/////////////////////////////////////////////////
+// SPI Slave Constants
+////////////////////////////////////////////////
+// Masks for controlling different peripherals
+#define SPI_SS_AD9510 1
+#define SPI_SS_AD9777 2
+#define SPI_SS_RX_DAC 4
+#define SPI_SS_RX_ADC 8
+#define SPI_SS_RX_DB 16
+#define SPI_SS_TX_DAC 32
+#define SPI_SS_TX_ADC 64
+#define SPI_SS_TX_DB 128
+
+/////////////////////////////////////////////////
+// Misc Control
+////////////////////////////////////////////////
+#define FR_MISC_CTRL_CLOCK _SR_ADDR(0)
+#define FR_MISC_CTRL_SERDES _SR_ADDR(1)
+#define FR_MISC_CTRL_ADC _SR_ADDR(2)
+#define FR_MISC_CTRL_LEDS _SR_ADDR(3)
+#define FR_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy
+#define FR_MISC_CTRL_DBG_MUX _SR_ADDR(5)
+#define FR_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else...
+#define FR_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache
+#define FR_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs
+
+#define FRF_MISC_CTRL_SERDES_ENABLE 8
+#define FRF_MISC_CTRL_SERDES_PRBSEN 4
+#define FRF_MISC_CTRL_SERDES_LOOPEN 2
+#define FRF_MISC_CTRL_SERDES_RXEN 1
+
+#define FRF_MISC_CTRL_ADC_ON 0x0F
+#define FRF_MISC_CTRL_ADC_OFF 0x00
+
+/////////////////////////////////////////////////
+// VITA49 64 bit time (write only)
+////////////////////////////////////////////////
+ /*!
+ * \brief Time 64 flags
+ *
+ * <pre>
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------------------+-+-+
+ * | |S|P|
+ * +-----------------------------------------------------------+-+-+
+ *
+ * P - PPS edge selection (0=negedge, 1=posedge, default=0)
+ * S - Source (0=sma, 1=mimo, 0=default)
+ *
+ * </pre>
+ */
+#define FR_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS
+#define FR_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS
+#define FR_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above
+#define FR_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
+
+//pps flags (see above)
+#define FRF_TIME64_PPS_NEGEDGE (0 << 0)
+#define FRF_TIME64_PPS_POSEDGE (1 << 0)
+#define FRF_TIME64_PPS_SMA (0 << 1)
+#define FRF_TIME64_PPS_MIMO (1 << 1)
+
+#define FRF_TIME64_LATCH_NOW 1
+#define FRF_TIME64_LATCH_NEXT_PPS 0
+
+/////////////////////////////////////////////////
+// DSP TX Regs
+////////////////////////////////////////////////
+#define FR_DSP_TX_FREQ _SR_ADDR(SR_TX_DSP + 0)
+#define FR_DSP_TX_SCALE_IQ _SR_ADDR(SR_TX_DSP + 1) // {scale_i,scale_q}
+#define FR_DSP_TX_INTERP_RATE _SR_ADDR(SR_TX_DSP + 2)
+
+ /*!
+ * \brief output mux configuration.
+ *
+ * <pre>
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------------------------------+-------+-------+-------+-------+
+ * | | DAC1 | DAC0 |
+ * +-------------------------------+-------+-------+-------+-------+
+ *
+ * There are N DUCs (1 now) with complex inputs and outputs.
+ * There are two DACs.
+ *
+ * Each 4-bit DACx field specifies the source for the DAC
+ * Each subfield is coded like this:
+ *
+ * 3 2 1 0
+ * +-------+
+ * | N |
+ * +-------+
+ *
+ * N specifies which DUC output is connected to this DAC.
+ *
+ * N which interp output
+ * --- -------------------
+ * 0 DUC 0 I
+ * 1 DUC 0 Q
+ * 2 DUC 1 I
+ * 3 DUC 1 Q
+ * F All Zeros
+ *
+ * The default value is 0x10
+ * </pre>
+ */
+#define FR_DSP_TX_MUX _SR_ADDR(SR_TX_DSP + 4)
+
+/////////////////////////////////////////////////
+// DSP RX Regs
+////////////////////////////////////////////////
+#define FR_DSP_RX_FREQ _SR_ADDR(SR_RX_DSP + 0)
+#define FR_DSP_RX_SCALE_IQ _SR_ADDR(SR_RX_DSP + 1) // {scale_i,scale_q}
+#define FR_DSP_RX_DECIM_RATE _SR_ADDR(SR_RX_DSP + 2)
+#define FR_DSP_RX_DCOFFSET_I _SR_ADDR(SR_RX_DSP + 3) // Bit 31 high sets fixed offset mode, using lower 14 bits,
+ // otherwise it is automatic
+#define FR_DSP_RX_DCOFFSET_Q _SR_ADDR(SR_RX_DSP + 4) // Bit 31 high sets fixed offset mode, using lower 14 bits
+ /*!
+ * \brief input mux configuration.
+ *
+ * This determines which ADC (or constant zero) is connected to
+ * each DDC input. There are N DDCs (1 now). Each has two inputs.
+ *
+ * <pre>
+ * Mux value:
+ *
+ * 3 2 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | |Q0 |I0 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
+ * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
+ *
+ * The default value is 0x4
+ * </pre>
+ */
+#define FR_DSP_RX_MUX _SR_ADDR(SR_RX_DSP + 5) // called adc_mux in dsp_core_rx.v
+
+////////////////////////////////////////////////
+// GPIO, Slave 4
+////////////////////////////////////////////////
+//
+// These go to the daughterboard i/o pins
+//
+#define FR_GPIO_BASE 0xC800
+
+#define FR_GPIO_IO FR_GPIO_BASE + 0 // 32 bits, gpio io pins (tx high 16 bits, rx low 16 bits)
+#define FR_GPIO_DDR FR_GPIO_BASE + 4 // 32 bits, gpio ddr, 1 means output (tx high 16 bits, rx low 16 bits)
+#define FR_GPIO_TX_SEL FR_GPIO_BASE + 8 // 16 2-bit fields select which source goes to TX DB
+#define FR_GPIO_RX_SEL FR_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB
+
+// each 2-bit sel field is layed out this way
+#define FRF_GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define FRF_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
+#define FRF_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric
+#define FRF_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric
+
+///////////////////////////////////////////////////
+// ATR Controller, Slave 11
+////////////////////////////////////////////////
+#define FR_ATR_BASE 0xE400
+
+#define FR_ATR_IDLE_TXSIDE FR_ATR_BASE + 0
+#define FR_ATR_IDLE_RXSIDE FR_ATR_BASE + 2
+#define FR_ATR_INTX_TXSIDE FR_ATR_BASE + 4
+#define FR_ATR_INTX_RXSIDE FR_ATR_BASE + 6
+#define FR_ATR_INRX_TXSIDE FR_ATR_BASE + 8
+#define FR_ATR_INRX_RXSIDE FR_ATR_BASE + 10
+#define FR_ATR_FULL_TXSIDE FR_ATR_BASE + 12
+#define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14
+
+///////////////////////////////////////////////////
+// VITA RX CTRL regs
+///////////////////////////////////////////////////
+// The following 3 are logically a single command register.
+// They are clocked into the underlying fifo when time_ticks is written.
+#define FR_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30)
+#define FR_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1)
+#define FR_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2)
+
+#define FR_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun
+#define FR_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter
+#define FR_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet.
+#define FR_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6)
+#define FR_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
+#define FR_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+
+//helpful macros for dealing with stream cmd
+#define FR_RX_CTRL_MAX_SAMPS_PER_CMD 0x1fffffff
+#define FR_RX_CTRL_MAKE_CMD(nsamples, now, chain, reload) \
+ ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | (((reload) & 0x1) << 29) | ((nsamples) & 0x1fffffff))
+
+#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/lib/utils.cpp b/host/lib/utils.cpp
new file mode 100644
index 000000000..d2f4dfc6e
--- /dev/null
+++ b/host/lib/utils.cpp
@@ -0,0 +1,53 @@
+//
+// 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>
+#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_;
+}
+
+typedef boost::tuple<wax::obj, std::string> named_prop_tuple;
+
+named_prop_tuple uhd::extract_named_prop(
+ const wax::obj &key,
+ const std::string &name
+){
+ if (key.type() == typeid(named_prop_t)){
+ named_prop_t np = key.as<named_prop_t>();
+ return named_prop_tuple(np.key, np.name);
+ }
+ return named_prop_tuple(key, name);
+}
diff --git a/host/lib/wax.cpp b/host/lib/wax.cpp
new file mode 100644
index 000000000..0e2e82a3a
--- /dev/null
+++ b/host/lib/wax.cpp
@@ -0,0 +1,150 @@
+//
+// 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/wax.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+
+/*!
+ * The link args for internal use within this cpp file:
+ *
+ * It contains a link (in this case a pointer) to a wax object.
+ * Only the methods in this file may create or parse link args.
+ * The get_link method is the creator of a link args object.
+ * The [] operator will resolve the link and make the [] call.
+ *
+ * TODO: register the link args with the wax obj that it links to.
+ * That way, if the obj destructs, the link can be invalidated.
+ * The operator() will throw, rather than dereferencing bad memory.
+ */
+class link_args_t{
+public:
+ link_args_t(const wax::obj *obj_ptr) : _obj_ptr(obj_ptr){
+ /* NOP */
+ }
+ wax::obj & operator()(void) const{
+ //recursively resolve link args to get at original pointer
+ if (_obj_ptr->type() == typeid(link_args_t)){
+ return _obj_ptr->as<link_args_t>()();
+ }
+ return *const_cast<wax::obj *>(_obj_ptr);
+ }
+private:
+ const wax::obj *_obj_ptr;
+};
+
+/*!
+ * The proxy args for internal use within this cpp file:
+ *
+ * It contains a link and a key for setting/getting a property.
+ * Only the methods in this file may create or parse proxy args.
+ * Class methods have special handling for the case when the
+ * wax obj contains an instance of the proxy args.
+ */
+class proxy_args_t{
+public:
+ proxy_args_t(const wax::obj *obj_ptr, const wax::obj &key) : _key(key){
+ _obj_link = obj_ptr->get_link();
+ }
+ wax::obj & operator()(void) const{
+ return _obj_link.as<link_args_t>()();
+ }
+ const wax::obj & key(void) const{
+ return _key;
+ }
+private:
+ wax::obj _obj_link;
+ const wax::obj _key;
+};
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+wax::obj::obj(void){
+ /* NOP */
+}
+
+wax::obj::obj(const obj &o){
+ _contents = o._contents;
+}
+
+wax::obj::~obj(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Special Operators
+ **********************************************************************/
+wax::obj wax::obj::operator[](const obj &key){
+ if (_contents.type() == typeid(proxy_args_t)){
+ obj val = resolve();
+ //check if its a special link and call
+ if (val.type() == typeid(link_args_t)){
+ return val.as<link_args_t>()()[key];
+ }
+ //unknown obj
+ throw std::runtime_error("cannot use [] on non wax::obj link");
+ }
+ else{
+ return proxy_args_t(this, key);
+ }
+}
+
+wax::obj & wax::obj::operator=(const obj &val){
+ if (_contents.type() == typeid(proxy_args_t)){
+ proxy_args_t proxy_args = boost::any_cast<proxy_args_t>(_contents);
+ proxy_args().set(proxy_args.key(), val);
+ }
+ else{
+ _contents = val._contents;
+ }
+ return *this;
+}
+
+/***********************************************************************
+ * Public Methods
+ **********************************************************************/
+wax::obj wax::obj::get_link(void) const{
+ return link_args_t(this);
+}
+
+const std::type_info & wax::obj::type(void) const{
+ return resolve().type();
+}
+
+/***********************************************************************
+ * Private Methods
+ **********************************************************************/
+boost::any wax::obj::resolve(void) const{
+ if (_contents.type() == typeid(proxy_args_t)){
+ obj val;
+ proxy_args_t proxy_args = boost::any_cast<proxy_args_t>(_contents);
+ proxy_args().get(proxy_args.key(), val);
+ return val.resolve();
+ }
+ else{
+ return _contents;
+ }
+}
+
+void wax::obj::get(const obj &, obj &){
+ throw std::runtime_error("Cannot call get on wax obj base class");
+}
+
+void wax::obj::set(const obj &, const obj &){
+ throw std::runtime_error("Cannot call set on wax obj base class");
+}
diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt
new file mode 100644
index 000000000..61b0b503d
--- /dev/null
+++ b/host/test/CMakeLists.txt
@@ -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/>.
+#
+
+########################################################################
+# unit test suite
+########################################################################
+ADD_EXECUTABLE(main_test
+ main_test.cpp
+ addr_test.cpp
+ dict_test.cpp
+ error_test.cpp
+ gain_handler_test.cpp
+ vrt_test.cpp
+ wax_test.cpp
+)
+TARGET_LINK_LIBRARIES(main_test uhd)
+ADD_TEST(test main_test)
+
+########################################################################
+# demo of a loadable module
+########################################################################
+ADD_LIBRARY(module_test MODULE module_test.cpp)
diff --git a/host/test/addr_test.cpp b/host/test/addr_test.cpp
new file mode 100644
index 000000000..0c50200d6
--- /dev/null
+++ b/host/test/addr_test.cpp
@@ -0,0 +1,80 @@
+//
+// 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/types/mac_addr.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
+#include <algorithm>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_mac_addr){
+ std::cout << "Testing mac addr..." << std::endl;
+ const std::string mac_addr_str("00:01:23:45:67:89");
+ uhd::mac_addr_t mac_addr = uhd::mac_addr_t::from_string(mac_addr_str);
+ std::cout << "Input: " << mac_addr_str << std::endl;
+ std::cout << "Output: " << mac_addr.to_string() << std::endl;
+ BOOST_CHECK_EQUAL(mac_addr_str, mac_addr.to_string());
+}
+
+BOOST_AUTO_TEST_CASE(test_device_addr){
+ std::cout << "Testing device addr..." << std::endl;
+
+ //load the device address with something
+ uhd::device_addr_t dev_addr;
+ dev_addr["key1"] = "val1";
+ dev_addr["key2"] = "val2";
+
+ //convert to and from args string
+ std::cout << "Pretty Print: " << std::endl << dev_addr.to_pp_string();
+ std::string args_str = dev_addr.to_string();
+ std::cout << "Args String: " << args_str << std::endl;
+ 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());
+
+ //the keys should match
+ std::vector<std::string> old_dev_addr_keys = dev_addr.keys();
+ std::vector<std::string> new_dev_addr_keys = new_dev_addr.keys();
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ old_dev_addr_keys.begin(), old_dev_addr_keys.end(),
+ new_dev_addr_keys.begin(), new_dev_addr_keys.end()
+ );
+
+ //the vals should match
+ std::vector<std::string> old_dev_addr_vals = dev_addr.vals();
+ std::vector<std::string> new_dev_addr_vals = new_dev_addr.vals();
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ old_dev_addr_vals.begin(), old_dev_addr_vals.end(),
+ new_dev_addr_vals.begin(), new_dev_addr_vals.end()
+ );
+}
+
+BOOST_AUTO_TEST_CASE(test_dboard_id){
+ std::cout << "Testing dboard id..." << std::endl;
+
+ using namespace uhd::usrp;
+
+ BOOST_CHECK(dboard_id_t() == dboard_id_t::none());
+ BOOST_CHECK_EQUAL(dboard_id_t().to_uint16(), dboard_id_t::none().to_uint16());
+ BOOST_CHECK_EQUAL(dboard_id_t::from_string("0x1234").to_uint16(), 0x1234);
+ BOOST_CHECK_EQUAL(dboard_id_t::from_string("1234").to_uint16(), 1234);
+ std::cout << "Pretty Print: " << std::endl << dboard_id_t::none().to_pp_string();
+}
diff --git a/host/test/dict_test.cpp b/host/test/dict_test.cpp
new file mode 100644
index 000000000..0501a7878
--- /dev/null
+++ b/host/test/dict_test.cpp
@@ -0,0 +1,72 @@
+//
+// 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/types/dict.hpp>
+#include <boost/assign/list_of.hpp>
+
+BOOST_AUTO_TEST_CASE(test_dict_init){
+ uhd::dict<int, int> d;
+ d[-1] = 3;
+ d[0] = 4;
+ d[1] = 5;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_dict_assign){
+ uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_const_dict){
+ const uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+ BOOST_CHECK_THROW(d[2], std::exception);
+}
+
+BOOST_AUTO_TEST_CASE(test_dict_pop){
+ uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK_EQUAL(d.pop(0), 4);
+ BOOST_CHECK(not d.has_key(0));
+ BOOST_CHECK(d.keys()[0] == -1);
+ BOOST_CHECK(d.keys()[1] == 1);
+}
diff --git a/host/test/error_test.cpp b/host/test/error_test.cpp
new file mode 100644
index 000000000..c76a15ab7
--- /dev/null
+++ b/host/test/error_test.cpp
@@ -0,0 +1,48 @@
+//
+// 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/assert.hpp>
+#include <vector>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_assert_has){
+ std::vector<int> vec;
+ vec.push_back(2);
+ vec.push_back(3);
+ vec.push_back(5);
+
+ //verify the std::has utility
+ BOOST_CHECK(std::has(vec, 2));
+ BOOST_CHECK(not std::has(vec, 1));
+
+ std::cout << "The output of the assert_has error:" << std::endl;
+ try{
+ uhd::assert_has(vec, 1, "prime");
+ }catch(const std::exception &e){
+ std::cout << e.what() << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_assert_throw){
+ std::cout << "The output of the assert throw error:" << std::endl;
+ try{
+ UHD_ASSERT_THROW(2 + 2 == 5);
+ }catch(const std::exception &e){
+ std::cout << e.what() << std::endl;
+ }
+}
diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp
new file mode 100644
index 000000000..5a9f2b714
--- /dev/null
+++ b/host/test/gain_handler_test.cpp
@@ -0,0 +1,121 @@
+//
+// 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/main_test.cpp b/host/test/main_test.cpp
new file mode 100644
index 000000000..0b47303b7
--- /dev/null
+++ b/host/test/main_test.cpp
@@ -0,0 +1,3 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
diff --git a/host/test/module_test.cpp b/host/test/module_test.cpp
new file mode 100644
index 000000000..47a0e1af9
--- /dev/null
+++ b/host/test/module_test.cpp
@@ -0,0 +1,26 @@
+//
+// 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/static.hpp>
+#include <iostream>
+
+UHD_STATIC_BLOCK(module_test){
+ std::cout << "---------------------------------------" << std::endl;
+ std::cout << "-- Good news, everyone!" << std::endl;
+ std::cout << "-- The test module has been loaded." << std::endl;
+ std::cout << "---------------------------------------" << std::endl;
+}
diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp
new file mode 100644
index 000000000..939a61eb4
--- /dev/null
+++ b/host/test/vrt_test.cpp
@@ -0,0 +1,102 @@
+//
+// 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/transport/vrt.hpp>
+
+using namespace uhd::transport;
+
+static void pack_and_unpack(
+ const uhd::tx_metadata_t &metadata,
+ size_t num_payload_words32,
+ size_t packet_count
+){
+ boost::uint32_t header_buff[vrt::max_header_words32];
+ size_t num_header_words32;
+ size_t num_packet_words32;
+
+ //pack metadata into a vrt header
+ vrt::pack(
+ metadata, //input
+ header_buff, //output
+ num_header_words32, //output
+ num_payload_words32, //input
+ num_packet_words32, //output
+ packet_count, //input
+ 100e6
+ );
+
+ uhd::rx_metadata_t metadata_out;
+ size_t num_header_words32_out;
+ size_t num_payload_words32_out;
+ size_t packet_count_out;
+
+ //unpack the vrt header back into metadata
+ vrt::unpack(
+ metadata_out, //output
+ header_buff, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out, //output
+ 100e6
+ );
+
+ //check the the unpacked metadata is the same
+ BOOST_CHECK_EQUAL(packet_count, packet_count_out);
+ BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out);
+ BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out);
+ BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id);
+ if (metadata.has_stream_id and metadata_out.has_stream_id){
+ BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id);
+ }
+ BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec);
+ if (metadata.has_time_spec and metadata_out.has_time_spec){
+ BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs);
+ BOOST_CHECK_EQUAL(metadata.time_spec.nsecs, metadata_out.time_spec.nsecs);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_with_none){
+ uhd::tx_metadata_t metadata;
+ pack_and_unpack(metadata, 300, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_sid){
+ uhd::tx_metadata_t metadata;
+ metadata.has_stream_id = true;
+ metadata.stream_id = 6;
+ pack_and_unpack(metadata, 400, 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_time_spec){
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec.secs = 7;
+ metadata.time_spec.nsecs = 2000;
+ pack_and_unpack(metadata, 500, 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){
+ uhd::tx_metadata_t metadata;
+ metadata.has_stream_id = true;
+ metadata.stream_id = 2;
+ metadata.has_time_spec = true;
+ metadata.time_spec.secs = 5;
+ metadata.time_spec.nsecs = 1000;
+ pack_and_unpack(metadata, 600, 4);
+}
diff --git a/host/test/wax_test.cpp b/host/test/wax_test.cpp
new file mode 100644
index 000000000..731f470ed
--- /dev/null
+++ b/host/test/wax_test.cpp
@@ -0,0 +1,104 @@
+//
+// 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 <boost/shared_ptr.hpp>
+#include <uhd/wax.hpp>
+#include <iostream>
+
+enum opt_a_t{OPTION_A_0, OPTION_A_1};
+enum opt_b_t{OPTION_B_0, OPTION_B_1};
+
+BOOST_AUTO_TEST_CASE(test_enums){
+ wax::obj opta = OPTION_A_0;
+ BOOST_CHECK_THROW(opta.as<opt_b_t>(), wax::bad_cast);
+ BOOST_CHECK_EQUAL(opta.as<opt_a_t>(), OPTION_A_0);
+}
+
+/***********************************************************************
+ * demo class for wax framework
+ **********************************************************************/
+class wax_demo : public wax::obj{
+public:
+ typedef boost::shared_ptr<wax_demo> sptr;
+
+ wax_demo(size_t sub_demos, size_t len){
+ d_nums = std::vector<float>(len);
+ if (sub_demos != 0){
+ for (size_t i = 0; i < len; i++){
+ d_subs.push_back(sptr(new wax_demo(sub_demos-1, len)));
+ }
+ }
+ }
+ ~wax_demo(void){
+ /* NOP */
+ }
+private:
+ std::vector<float> d_nums;
+ std::vector<sptr> d_subs;
+
+ void get(const wax::obj &key, wax::obj &value){
+ if (d_subs.size() == 0){
+ value = d_nums[key.as<size_t>()];
+ }else{
+ value = d_subs[key.as<size_t>()]->get_link();
+ }
+ }
+ void set(const wax::obj &key, const wax::obj &value){
+ if (d_subs.size() == 0){
+ d_nums[key.as<size_t>()] = value.as<float>();
+ }else{
+ throw std::runtime_error("cant set to a wax demo with sub demos");
+ }
+ }
+};
+
+BOOST_AUTO_TEST_CASE(test_chaining){
+ wax_demo wd(2, 1);
+ std::cout << "chain 1" << std::endl;
+ wd[size_t(0)];
+ std::cout << "chain 2" << std::endl;
+ wd[size_t(0)][size_t(0)];
+ std::cout << "chain 3" << std::endl;
+ wd[size_t(0)][size_t(0)][size_t(0)];
+}
+
+BOOST_AUTO_TEST_CASE(test_set_get){
+ wax_demo wd(2, 10);
+ std::cout << "set and get all" << std::endl;
+ for (size_t i = 0; i < 10; i++){
+ for (size_t j = 0; j < 10; j++){
+ for (size_t k = 0; k < 10; k++){
+ float val = float(i * j * k + i + j + k);
+ //std::cout << i << " " << j << " " << k << std::endl;
+ wd[i][j][k] = val;
+ BOOST_CHECK_EQUAL(val, wd[i][j][k].as<float>());
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_proxy){
+ wax_demo wd(2, 1);
+ std::cout << "store proxy" << std::endl;
+ wax::obj p = wd[size_t(0)][size_t(0)];
+ p[size_t(0)] = float(5);
+
+ std::cout << "assign proxy" << std::endl;
+ wax::obj a = p[size_t(0)];
+ BOOST_CHECK_EQUAL(a.as<float>(), float(5));
+}
diff --git a/host/uhd.pc.in b/host/uhd.pc.in
new file mode 100644
index 000000000..2a34e9cfd
--- /dev/null
+++ b/host/uhd.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${prefix}/@LIBRARY_DIR@
+includedir=${prefix}/@INCLUDE_DIR@
+
+Name: @CPACK_PACKAGE_NAME@
+Description: Universal Hardware Driver
+Requires:
+Version: @CPACK_PACKAGE_VERSION@
+Libs: -L${libdir} -luhd
+Cflags: -I${includedir}
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
new file mode 100644
index 000000000..d28576e8c
--- /dev/null
+++ b/host/utils/CMakeLists.txt
@@ -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/>.
+#
+
+ADD_EXECUTABLE(uhd_find_devices uhd_find_devices.cpp)
+TARGET_LINK_LIBRARIES(uhd_find_devices uhd)
+INSTALL(TARGETS uhd_find_devices RUNTIME DESTINATION ${RUNTIME_DIR})
+
+ADD_EXECUTABLE(usrp2_addr_burner usrp2_addr_burner.cpp)
+TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd)
+INSTALL(TARGETS usrp2_addr_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
+
+ADD_EXECUTABLE(uhd_burn_db_eeprom uhd_burn_db_eeprom.cpp)
+TARGET_LINK_LIBRARIES(uhd_burn_db_eeprom uhd)
+INSTALL(TARGETS uhd_burn_db_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)
+
+INSTALL(PROGRAMS
+ usrp2_recovery.py
+ usrp2_card_burner.py
+ DESTINATION ${PKG_DATA_DIR}/utils
+)
diff --git a/host/utils/uhd_burn_db_eeprom.cpp b/host/utils/uhd_burn_db_eeprom.cpp
new file mode 100644
index 000000000..dfd9decba
--- /dev/null
+++ b/host/utils/uhd_burn_db_eeprom.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 <uhd/utils/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/assign.hpp>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+namespace po = boost::program_options;
+
+//used with lexical cast to parse a hex string
+template <class T> struct to_hex{
+ T value;
+ operator T() const {return value;}
+ friend std::istream& operator>>(std::istream& in, to_hex& out){
+ in >> std::hex >> out.value;
+ return in;
+ }
+};
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ //command line variables
+ std::string args, db_name, unit;
+ static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of
+ ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD)
+ ;
+
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
+ ("db", po::value<std::string>(&db_name)->default_value(""), "dboard name [default = \"\"]")
+ ("unit", po::value<std::string>(&unit)->default_value(""), "which unit [RX or TX]")
+ ("id", po::value<std::string>(), "dboard id to burn (hex string), omit for readback")
+ ;
+
+ 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 Burn DB EEPROM %s") % desc << std::endl;
+ std::cout << boost::format(
+ "Omit the id argument to perform readback,\n"
+ "Or specify a new id to burn into the eeprom.\n"
+ ) << std::endl;
+ return ~0;
+ }
+
+ //check inputs
+ if (not unit_to_db_prop.has_key(unit)){
+ std::cout << "Error: specify RX or TX for unit" << std::endl;
+ return ~0;
+ }
+
+ //make the device and extract the dboard w/ property
+ device::sptr dev = device::make(args);
+ wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], db_name)];
+ std::string prefix = (db_name == "")? unit : (unit + ":" + db_name);
+
+ //read the current dboard id from eeprom
+ if (vm.count("id") == 0){
+ std::cout << boost::format("Getting dbid on %s dboard...") % prefix << std::endl;
+ dboard_id_t id = dboard[DBOARD_PROP_DBOARD_ID].as<dboard_id_t>();
+ std::cout << boost::format(" Current dbid: %s") % id.to_pp_string() << std::endl;
+ }
+
+ //write a new dboard id to eeprom
+ else{
+ dboard_id_t id = dboard_id_t::from_string(vm["id"].as<std::string>());
+ std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl;
+ std::cout << boost::format(" New dbid: %s") % id.to_pp_string() << std::endl;
+ dboard[DBOARD_PROP_DBOARD_ID] = id;
+ }
+
+ std::cout << " Done" << std::endl << std::endl;
+ return 0;
+}
diff --git a/host/utils/uhd_find_devices.cpp b/host/utils/uhd_find_devices.cpp
new file mode 100644
index 000000000..b778eeb68
--- /dev/null
+++ b/host/utils/uhd_find_devices.cpp
@@ -0,0 +1,60 @@
+//
+// 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/safe_main.hpp>
+#include <uhd/device.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>()->default_value(""), "device address args")
+ ;
+
+ 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 Find Devices %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //discover the usrps and print the results
+ uhd::device_addrs_t device_addrs = uhd::device::find(vm["args"].as<std::string>());
+
+ if (device_addrs.size() == 0){
+ std::cerr << "No UHD Devices Found" << std::endl;
+ return ~0;
+ }
+
+ for (size_t i = 0; i < device_addrs.size(); i++){
+ std::cout << "--------------------------------------------------" << std::endl;
+ std::cout << "-- UHD Device " << i << std::endl;
+ std::cout << "--------------------------------------------------" << std::endl;
+ std::cout << device_addrs[i].to_pp_string() << std::endl << std::endl;
+ //uhd::device::make(device_addrs[i]); //test make
+ }
+
+ return 0;
+}
diff --git a/host/utils/usrp2_addr_burner.cpp b/host/utils/usrp2_addr_burner.cpp
new file mode 100644
index 000000000..08fc1e218
--- /dev/null
+++ b/host/utils/usrp2_addr_burner.cpp
@@ -0,0 +1,90 @@
+//
+// 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/safe_main.hpp>
+#include <uhd/usrp/usrp2.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("addr", po::value<std::string>(), "resolvable network address")
+ ("new-ip", po::value<std::string>(), "new ip address (optional)")
+ ("new-mac", po::value<std::string>(), "new mac address (optional)")
+ ;
+
+ 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("USRP2 Address Burner %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //load the options into the address
+ uhd::device_addr_t device_addr;
+ if (vm.count("addr")){
+ device_addr["addr"] = vm["addr"].as<std::string>();
+ }
+ else{
+ std::cerr << "Error: missing addr option" << std::endl;
+ return ~0;
+ }
+
+ //create a usrp2 device
+ uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr);
+ //FIXME usees the default mboard for now (until the mimo link is supported)
+ wax::obj u2_mb = (*u2_dev)[uhd::usrp::DEVICE_PROP_MBOARD];
+ std::cout << std::endl;
+
+ //fetch and print current settings
+ std::cout << "Fetching current settings from usrp2 eeprom:" << std::endl;
+ std::string curr_ip = u2_mb[std::string("ip-addr")].as<std::string>();
+ std::cout << boost::format(" Current IP Address: %s") % curr_ip << std::endl;
+ std::string curr_mac = u2_mb[std::string("mac-addr")].as<std::string>();
+ std::cout << boost::format(" Current MAC Address: %s") % curr_mac << std::endl;
+ std::cout << " Done" << std::endl << std::endl;
+
+ //try to set the new ip (if provided)
+ if (vm.count("new-ip")){
+ std::cout << "Burning a new ip address into the usrp2 eeprom:" << std::endl;
+ std::string new_ip = vm["new-ip"].as<std::string>();
+ std::cout << boost::format(" New IP Address: %s") % new_ip << std::endl;
+ u2_mb[std::string("ip-addr")] = new_ip;
+ std::cout << " Done" << std::endl << std::endl;
+ }
+
+ //try to set the new mac (if provided)
+ if (vm.count("new-mac")){
+ std::cout << "Burning a new mac address into the usrp2 eeprom:" << std::endl;
+ std::string new_mac = vm["new-mac"].as<std::string>();
+ std::cout << boost::format(" New MAC Address: %s") % new_mac << std::endl;
+ u2_mb[std::string("mac-addr")] = new_mac;
+ std::cout << " Done" << std::endl << std::endl;
+ }
+
+ std::cout << "Power-cycle the usrp2 for the changes to take effect." << std::endl;
+ return 0;
+}
diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py
new file mode 100755
index 000000000..dfdc663bc
--- /dev/null
+++ b/host/utils/usrp2_card_burner.py
@@ -0,0 +1,344 @@
+#!/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/>.
+#
+
+########################################################################
+# Deal with raw devices
+########################################################################
+import platform
+import tempfile
+import subprocess
+import urllib
+
+SECTOR_SIZE = 512 # bytes
+MAX_FILE_SIZE = 1 * (2**20) # maximum number of bytes we'll burn to a slot
+
+FPGA_OFFSET = 0 # offset in flash to fpga image
+FIRMWARE_OFFSET = 1 * (2**20) # offset in flash to firmware image
+
+MAX_SD_CARD_SIZE = 2048e6 # bytes (any bigger is sdhc)
+
+def command(*args):
+ p = subprocess.Popen(
+ args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ ret = p.wait()
+ verbose = p.stdout.read()
+ if ret != 0: raise Exception, verbose
+ return verbose
+
+def get_dd_path():
+ if platform.system() == 'Windows':
+ dd_path = os.path.join(tempfile.gettempdir(), 'dd.exe')
+ if not os.path.exists(dd_path):
+ print 'Downloading dd.exe to %s'%dd_path
+ dd_bin = urllib.urlopen('http://www.ettus.com/downloads/dd.exe').read()
+ open(dd_path, 'wb').write(dd_bin)
+ return dd_path
+ return 'dd'
+
+def get_raw_device_hints():
+ ####################################################################
+ # Platform Windows: parse the output of dd.exe --list
+ ####################################################################
+ if platform.system() == 'Windows':
+ volumes = list()
+ try: output = command(get_dd_path(), '--list')
+ except: return volumes
+
+ #coagulate info for identical links
+ link_to_info = dict()
+ for info in output.replace('\r', '').split('\n\\\\'):
+ if 'link to' not in info: continue
+ link = info.split('link to')[-1].split()[0].strip()
+ if not link_to_info.has_key(link): link_to_info[link] = '\n\n'
+ link_to_info[link] += info
+
+ #parse info only keeping viable volumes
+ for link, info in link_to_info.iteritems():
+ if 'removable' not in info.lower(): continue
+ if 'size is' in info:
+ size = info.split('size is')[-1].split()[0].strip()
+ if int(size) > MAX_SD_CARD_SIZE: continue
+ if 'Mounted on' in info:
+ volumes.append(info.split('Mounted on')[-1].split()[0])
+ continue
+ volumes.append(link)
+
+ return sorted(set(volumes))
+
+ ####################################################################
+ # Platform Linux: call blockdev on all the /dev/sd* devices
+ ####################################################################
+ if platform.system() == 'Linux':
+ devs = list()
+ try: output = open('/proc/partitions', 'r').read()
+ except: return devs
+ for line in output.splitlines():
+ try:
+ major, minor, blocks, name = line.split()
+ if name[-1].isdigit(): assert int(minor) == 0
+ dev = os.path.join('/dev/', name)
+ size = int(command('blockdev', '--getsz', dev))*512
+ assert size <= MAX_SD_CARD_SIZE
+ except: continue
+ devs.append(dev)
+
+ return sorted(set(devs))
+
+ ####################################################################
+ # Platform Others:
+ ####################################################################
+ return ()
+
+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]
+
+ #execute a dd subprocess
+ verbose = command(
+ get_dd_path(),
+ "of=%s"%tmp_file,
+ "if=%s"%device_file,
+ "skip=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ "count=%d"%(MAX_FILE_SIZE/SECTOR_SIZE),
+ )
+
+ #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
+ 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):
+ verbose = command(
+ get_dd_path(),
+ "if=%s"%image_file,
+ "of=%s"%device_file,
+ "seek=%d"%(offset/SECTOR_SIZE),
+ "bs=%d"%SECTOR_SIZE,
+ )
+
+ try: #exec the sync command (only works on linux)
+ if platform.system() == 'Linux': command('sync')
+ except: pass
+
+ return verbose
+
+def write_and_verify(image_file, device_file, offset):
+ if os.path.getsize(image_file) > MAX_FILE_SIZE:
+ raise Exception, 'Image file larger than %d bytes!'%MAX_FILE_SIZE
+ return '%s\n%s'%(
+ write_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ), verify_image(
+ image_file=image_file,
+ device_file=device_file,
+ offset=offset,
+ ),
+ )
+
+def burn_sd_card(dev, fw, fpga):
+ verbose = ''
+ if fw: verbose += 'Burn firmware image:\n%s\n'%write_and_verify(
+ image_file=fw, device_file=dev, offset=FIRMWARE_OFFSET
+ )
+ if fpga: verbose += 'Burn fpga image:\n%s\n'%write_and_verify(
+ image_file=fpga, device_file=dev, offset=FPGA_OFFSET
+ )
+ return verbose
+
+########################################################################
+# Graphical Tk stuff
+########################################################################
+import Tkinter, Tkconstants, tkFileDialog, tkFont, tkMessageBox
+import os
+
+class BinFileEntry(Tkinter.Frame):
+ """
+ Simple file entry widget for getting the file path of bin files.
+ Combines a label, entry, and button with file dialog callback.
+ """
+
+ def __init__(self, root, what, def_path=''):
+ self._what = what
+ Tkinter.Frame.__init__(self, root)
+ Tkinter.Label(self, text=what+":").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(self, width=50)
+ self._entry.insert(Tkinter.END, def_path)
+ self._entry.pack(side=Tkinter.LEFT)
+ Tkinter.Button(self, text="...", command=self._button_cb).pack(side=Tkinter.LEFT)
+
+ def _button_cb(self):
+ filename = tkFileDialog.askopenfilename(
+ parent=self,
+ filetypes=[('bin files', '*.bin'), ('all files', '*.*')],
+ title="Select bin file for %s"%self._what,
+ initialdir=os.path.dirname(self.get_filename()),
+ )
+
+ # open file on your own
+ if filename:
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, filename)
+
+ def get_filename(self):
+ return self._entry.get()
+
+class DeviceEntryWidget(Tkinter.Frame):
+ """
+ Simple entry widget for getting the raw device name.
+ Combines a label, entry, and helpful text box with hints.
+ """
+
+ def __init__(self, root, text=''):
+ Tkinter.Frame.__init__(self, root)
+
+ Tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack()
+
+ self._hints = Tkinter.Listbox(self)
+ self._hints.bind("<<ListboxSelect>>", self._listbox_cb)
+ self._reload_cb()
+ self._hints.pack(expand=Tkinter.YES, fill=Tkinter.X)
+
+ frame = Tkinter.Frame(self)
+ frame.pack()
+
+ Tkinter.Label(frame, text="Raw Device:").pack(side=Tkinter.LEFT)
+ self._entry = Tkinter.Entry(frame, width=50)
+ self._entry.insert(Tkinter.END, text)
+ self._entry.pack(side=Tkinter.LEFT)
+
+ def _reload_cb(self):
+ self._hints.delete(0, Tkinter.END)
+ for hint in get_raw_device_hints():
+ self._hints.insert(Tkinter.END, hint)
+
+ def _listbox_cb(self, event):
+ try:
+ sel = self._hints.get(self._hints.curselection()[0])
+ self._entry.delete(0, Tkinter.END)
+ self._entry.insert(0, sel)
+ except Exception, e: print e
+
+ def get_devname(self):
+ return self._entry.get()
+
+class SectionLabel(Tkinter.Label):
+ """
+ Make a text label with bold font.
+ """
+
+ def __init__(self, root, text):
+ Tkinter.Label.__init__(self, root, text=text)
+
+ #set the font bold
+ f = tkFont.Font(font=self['font'])
+ f['weight'] = 'bold'
+ self['font'] = f.name
+
+class USRP2CardBurnerApp(Tkinter.Frame):
+ """
+ The top level gui application for the usrp2 sd card burner.
+ Creates entry widgets and button with callback to write images.
+ """
+
+ def __init__(self, root, dev, fw, fpga):
+
+ Tkinter.Frame.__init__(self, root)
+
+ #pack the file entry widgets
+ SectionLabel(self, text="Select Images").pack(pady=5)
+ self._fw_img_entry = BinFileEntry(self, "Firmware Image", def_path=fw)
+ self._fw_img_entry.pack()
+ self._fpga_img_entry = BinFileEntry(self, "FPGA Image", def_path=fpga)
+ self._fpga_img_entry.pack()
+
+ #pack the destination entry widget
+ SectionLabel(self, text="Select Device").pack(pady=5)
+ self._raw_dev_entry = DeviceEntryWidget(self, text=dev)
+ self._raw_dev_entry.pack()
+
+ #the do it button
+ SectionLabel(self, text="").pack(pady=5)
+ Tkinter.Label(self, text="Warning! This tool can overwrite your hard drive. Use with caution.").pack()
+ Tkinter.Button(self, text="Burn SD Card", command=self._burn).pack()
+
+ def _burn(self):
+ #grab strings from the gui
+ fw = self._fw_img_entry.get_filename()
+ fpga = self._fpga_img_entry.get_filename()
+ dev = self._raw_dev_entry.get_devname()
+
+ #check input
+ if not dev:
+ tkMessageBox.showerror('Error:', 'No device specified!')
+ return
+ if not fw and not fpga:
+ tkMessageBox.showerror('Error:', 'No images specified!')
+ return
+ if fw and not os.path.exists(fw):
+ tkMessageBox.showerror('Error:', 'Firmware image not found!')
+ return
+ if fpga and not os.path.exists(fpga):
+ tkMessageBox.showerror('Error:', 'FPGA image not found!')
+ return
+
+ #burn the sd card
+ try:
+ verbose = burn_sd_card(dev=dev, fw=fw, fpga=fpga)
+ tkMessageBox.showinfo('Verbose:', verbose)
+ except Exception, e:
+ tkMessageBox.showerror('Verbose:', 'Error: %s'%str(e))
+
+########################################################################
+# Main
+########################################################################
+import optparse
+
+if __name__=='__main__':
+ parser = optparse.OptionParser()
+ parser.add_option("--dev", type="string", help="raw device path", default='')
+ parser.add_option("--fw", type="string", help="firmware image path (optional)", default='')
+ parser.add_option("--fpga", type="string", help="fpga image path (optional)", default='')
+ parser.add_option("--list", action="store_true", help="list possible raw devices", default=False)
+ parser.add_option("--gui", action="store_true", help="run in gui mode", default=False)
+ (options, args) = parser.parse_args()
+
+ if options.list:
+ print 'Possible raw devices:'
+ print ' ' + '\n '.join(get_raw_device_hints())
+ exit()
+
+ if options.gui:
+ root = Tkinter.Tk()
+ root.title('USRP2 SD Card Burner')
+ USRP2CardBurnerApp(root, dev=options.dev, fw=options.fw, fpga=options.fpga).pack()
+ root.mainloop()
+ exit()
+
+ if not options.dev: raise Exception, 'no raw device path specified'
+ print burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga)
diff --git a/host/utils/usrp2_recovery.py b/host/utils/usrp2_recovery.py
new file mode 100755
index 000000000..5654e93d3
--- /dev/null
+++ b/host/utils/usrp2_recovery.py
@@ -0,0 +1,68 @@
+#!/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/>.
+#
+
+"""
+The usrp2 recovery app:
+
+When the usrp2 has an unknown or bad ip address in its eeprom,
+it may not be possible to communicate with the usrp2 over ip/udp.
+
+This app will send a raw ethernet packet to bypass the ip layer.
+The packet will contain a known ip address to burn into eeprom.
+Because the recovery packet is sent with a broadcast mac address,
+only one usrp2 should be present on the interface upon execution.
+
+This app requires super-user privileges and only works on linux.
+"""
+
+import socket
+import struct
+import optparse
+
+BCAST_MAC_ADDR = 'ff:ff:ff:ff:ff:ff'
+RECOVERY_ETHERTYPE = 0xbeee
+IP_RECOVERY_CODE = 'addr'
+
+def mac_addr_repr_to_binary_string(mac_addr):
+ return ''.join(map(lambda x: chr(int(x, 16)), mac_addr.split(':')))
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage='usage: %prog [options]\n'+__doc__)
+ parser.add_option('--ifc', type='string', help='ethernet interface name [default=%default]', default='eth0')
+ parser.add_option('--new-ip', type='string', help='ip address to set [default=%default]', default='192.168.10.2')
+ (options, args) = parser.parse_args()
+
+ #create the raw socket
+ print "Opening raw socket on interface:", options.ifc
+ soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
+ soc.bind((options.ifc, RECOVERY_ETHERTYPE))
+
+ #create the recovery packet
+ print "Loading packet with ip address:", options.new_ip
+ packet = struct.pack(
+ '!6s6sH4s4s',
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ mac_addr_repr_to_binary_string(BCAST_MAC_ADDR),
+ RECOVERY_ETHERTYPE,
+ IP_RECOVERY_CODE,
+ socket.inet_aton(options.new_ip),
+ )
+
+ print "Sending packet (%d bytes)"%len(packet)
+ soc.send(packet)
+ print "Done"