summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt21
-rw-r--r--host/README87
-rw-r--r--host/docs/CMakeLists.txt101
-rw-r--r--host/docs/Doxyfile.in (renamed from host/Doxyfile.in)0
-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.rst128
-rw-r--r--host/examples/rx_timed_samples.cpp9
-rw-r--r--host/include/uhd/types/CMakeLists.txt1
-rw-r--r--host/include/uhd/types/device_addr.hpp20
-rw-r--r--host/include/uhd/types/io_type.hpp1
-rw-r--r--host/include/uhd/types/metadata.hpp10
-rw-r--r--host/include/uhd/types/serial.hpp122
-rw-r--r--host/include/uhd/types/time_spec.hpp23
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt1
-rw-r--r--host/include/uhd/usrp/dboard_eeprom.hpp60
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp40
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp1
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp3
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp58
-rw-r--r--host/include/uhd/usrp/subdev_props.hpp8
-rw-r--r--host/include/uhd/utils/assert.hpp33
-rw-r--r--host/include/uhd/utils/props.hpp54
-rw-r--r--host/include/uhd/utils/safe_main.hpp3
-rw-r--r--host/lib/CMakeLists.txt36
-rw-r--r--host/lib/device.cpp4
-rw-r--r--host/lib/ic_reg_maps/.gitignore1
-rw-r--r--host/lib/ic_reg_maps/common.py60
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad5624_regs.py82
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad7922_regs.py88
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9510_regs.py73
-rwxr-xr-x[-rw-r--r--]host/lib/ic_reg_maps/gen_ad9777_regs.py73
-rwxr-xr-xhost/lib/ic_reg_maps/gen_adf4360_regs.py73
-rwxr-xr-xhost/lib/ic_reg_maps/gen_max2829_regs.py166
-rw-r--r--host/lib/transport/convert_types.cpp5
-rw-r--r--host/lib/types.cpp90
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp28
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp43
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp627
-rw-r--r--host/lib/usrp/dboard_eeprom.cpp102
-rw-r--r--host/lib/usrp/dboard_manager.cpp7
-rw-r--r--host/lib/usrp/simple_usrp.cpp51
-rw-r--r--host/lib/usrp/usrp2/clock_control.cpp1
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp141
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp58
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp12
-rw-r--r--host/lib/usrp/usrp2/fw_common.h32
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp27
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp61
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp15
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp6
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp3
-rw-r--r--host/lib/utils.cpp44
-rw-r--r--host/test/addr_test.cpp2
-rw-r--r--host/test/gain_handler_test.cpp6
-rw-r--r--host/utils/CMakeLists.txt4
-rw-r--r--host/utils/uhd_burn_db_eeprom.cpp105
-rw-r--r--host/utils/uhd_find_devices.cpp14
61 files changed, 2710 insertions, 604 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 6334b44ff..bf8d71b21 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -76,7 +76,7 @@ ENDIF(WIN32)
# Setup Boost
########################################################################
SET(Boost_ADDITIONAL_VERSIONS "1.42.0" "1.42")
-FIND_PACKAGE(Boost 1.36 REQUIRED COMPONENTS
+FIND_PACKAGE(Boost 1.37 REQUIRED COMPONENTS
date_time
filesystem
program_options
@@ -124,24 +124,8 @@ INSTALL(
)
########################################################################
-# Setup Docs
+# Install Package Docs
########################################################################
-INCLUDE(FindDoxygen)
-
-IF(DOXYGEN_FOUND)
- 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)
- ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN}
- COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
- COMMENT "Generating documentation with doxygen"
- )
- ADD_CUSTOM_TARGET(docs ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN})
- INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN} DESTINATION ${PKG_DOC_DIR})
-ENDIF(DOXYGEN_FOUND)
-
INSTALL(FILES
${CMAKE_CURRENT_SOURCE_DIR}/README
${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
@@ -152,6 +136,7 @@ INSTALL(FILES
########################################################################
# Add the subdirectories
########################################################################
+ADD_SUBDIRECTORY(docs)
ADD_SUBDIRECTORY(examples)
ADD_SUBDIRECTORY(include)
ADD_SUBDIRECTORY(lib)
diff --git a/host/README b/host/README
index cbf18dbf7..e67bb25f8 100644
--- a/host/README
+++ b/host/README
@@ -15,86 +15,15 @@ Basic RX
Basic TX
LF RX
LF TX
+RFX Series
+XCVR 2450
########################################################################
-# Dependencies
+# Documentation
########################################################################
-Unix Notes:
- These dependencies can be acquired through the package manager.
-Windows Notes:
- These 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 (not needed for source downloads).
- On windows, install cygwin with git support to checkout the repository.
-
-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)
-########################################################################
-cd <uhd-repo-path>/host
-mkdir build
-cd build
-cmake ../
-make
-make test
-sudo make install
-
-For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<myprefix> ../
-
-########################################################################
-# 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 and uhd library path to your %PATH%.
-Usually c:\program files\boost\<version>\lib and c:\program files\uhd\lib
+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/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/Doxyfile.in b/host/docs/Doxyfile.in
index 7395516b5..7395516b5 100644
--- a/host/Doxyfile.in
+++ b/host/docs/Doxyfile.in
diff --git a/host/docs/build.rst b/host/docs/build.rst
new file mode 100644
index 000000000..81e61475e
--- /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.7 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..092332442
--- /dev/null
+++ b/host/docs/usrp2.rst
@@ -0,0 +1,128 @@
+========================================================================
+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 u2_flash_tool with caution. If you specify the wrong device node,
+you could overwrite your hard drive. Make sure that --dev= specifies the SD card.
+
+Load the FPGA image:
+
+::
+
+ cd <uhd-repo-path>/firmware/microblaze
+ sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t fpga -w <path_to_fpga_image>
+
+Load the firmware image:
+
+::
+
+ cd <uhd-repo-path>/firmware/microblaze directory
+ sudo ./u2_flash_tool --dev=/dev/sd<XXX> -t s/w -w <path_to_firmware_image>
+
+------------------------------------------------------------------------
+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_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
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**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.
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index d49f7d182..4b8774036 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -26,7 +26,7 @@ namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
- std::string transport_args;
+ std::string args;
int seconds_in_future;
size_t total_num_samps;
double rx_rate;
@@ -35,7 +35,7 @@ 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>(&transport_args)->default_value(""), "simple uhd transport args")
+ ("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")
@@ -52,9 +52,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...")
- % transport_args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(transport_args);
+ 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;
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
index e4cdf2cef..dbce21c98 100644
--- a/host/include/uhd/types/CMakeLists.txt
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -25,6 +25,7 @@ INSTALL(FILES
metadata.hpp
otw_type.hpp
ranges.hpp
+ serial.hpp
stream_cmd.hpp
time_spec.hpp
tune_result.hpp
diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp
index f5dd9371c..e8da2a1ab 100644
--- a/host/include/uhd/types/device_addr.hpp
+++ b/host/include/uhd/types/device_addr.hpp
@@ -32,13 +32,23 @@ namespace uhd{
*
* 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]
+ * - 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, rx_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 printable string.
@@ -52,14 +62,6 @@ namespace uhd{
* \return a string with delimiter markup
*/
std::string to_args_str(void) const;
-
- /*!
- * Make a device address from an args string.
- * The args string contains delimiter symbols.
- * \param args_str the arguments string
- * \return the new device address
- */
- static device_addr_t from_args_str(const std::string &args_str);
};
//handy typedef for a vector of device addresses
diff --git a/host/include/uhd/types/io_type.hpp b/host/include/uhd/types/io_type.hpp
index 930394d1b..5176374d6 100644
--- a/host/include/uhd/types/io_type.hpp
+++ b/host/include/uhd/types/io_type.hpp
@@ -23,6 +23,7 @@
namespace uhd{
/*!
+ * The Input/Output configuration struct:
* Used to specify the IO type with device send/recv.
*/
class UHD_API io_type_t{
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index d93b38b50..55add71cc 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -70,7 +70,10 @@ namespace uhd{
* Timed-out on receive?
*/
- //default constructor
+ /*!
+ * The default constructor:
+ * Sets the fields to default values (flags set to false).
+ */
rx_metadata_t(void);
};
@@ -103,7 +106,10 @@ namespace uhd{
bool start_of_burst;
bool end_of_burst;
- //default constructor
+ /*!
+ * The default constructor:
+ * Sets the fields to default values (flags set to false).
+ */
tx_metadata_t(void);
};
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/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index f06d27118..25d9e41d0 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -28,10 +28,19 @@ namespace uhd{
* 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 seconds count
+ //! whole/integer seconds count in seconds
boost::uint32_t secs;
//! fractional seconds count in nano-seconds
@@ -39,24 +48,26 @@ namespace uhd{
/*!
* Convert the fractional nsecs to clock ticks.
+ * Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
- * \return the number of ticks in this time spec
+ * \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 seconds and ticks.
- * \param new_secs the new seconds (default = 0)
- * \param new_nsecs the new nano-seconds (default = 0)
+ * 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 new_secs = 0, double new_nsecs = 0);
+ time_spec_t(boost::uint32_t secs = 0, double nsecs = 0);
};
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index 4b880308e..ff2636d8c 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -26,6 +26,7 @@ INSTALL(FILES
#### dboard headers ###
dboard_base.hpp
+ dboard_eeprom.hpp
dboard_id.hpp
dboard_iface.hpp
dboard_manager.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_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
index 71c7be200..1214a1a2f 100644
--- a/host/include/uhd/usrp/dboard_iface.hpp
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -19,39 +19,12 @@
#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>
-#include <vector>
namespace uhd{ namespace usrp{
-//spi configuration struct
-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){
- mosi_edge = edge;
- miso_edge = edge;
- }
-};
-
/*!
* The daughter board dboard interface to be subclassed.
* A dboard instance interfaces with the mboard though this api.
@@ -61,7 +34,6 @@ struct UHD_API spi_config_t{
class UHD_API dboard_iface{
public:
typedef boost::shared_ptr<dboard_iface> sptr;
- typedef std::vector<boost::uint8_t> byte_vector_t;
//tells the host which unit to use
enum unit_t{
@@ -123,19 +95,19 @@ public:
/*!
* Write to an I2C peripheral.
*
- * \param i2c_addr I2C bus address (7-bits)
- * \param buf the data to write
+ * \param addr I2C bus address (7-bits)
+ * \param bytes the data to write
*/
- virtual void write_i2c(int i2c_addr, const byte_vector_t &buf) = 0;
+ virtual void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) = 0;
/*!
* Read from an I2C peripheral.
*
- * \param i2c_addr I2C bus address (7-bits)
+ * \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(int i2c_addr, size_t num_bytes) = 0;
+ virtual byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) = 0;
/*!
* Write data to SPI bus peripheral.
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index 6de64b02d..007d85bb4 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -33,7 +33,6 @@ namespace uhd{ namespace usrp{
* Provide wax::obj access to the subdevs inside.
*/
class UHD_API dboard_manager : boost::noncopyable{
-
public:
typedef boost::shared_ptr<dboard_manager> sptr;
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
index 3b290319f..0208a6c2c 100644
--- a/host/include/uhd/usrp/dboard_props.hpp
+++ b/host/include/uhd/usrp/dboard_props.hpp
@@ -29,7 +29,8 @@ namespace uhd{ namespace usrp{
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_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
};
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index c4e0338f7..c4142b4e6 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -39,20 +39,72 @@ namespace uhd{ namespace usrp{
class UHD_API simple_usrp : boost::noncopyable{
public:
typedef boost::shared_ptr<simple_usrp> sptr;
- static sptr make(const std::string &args);
+ /*!
+ * 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
******************************************************************/
@@ -70,6 +122,8 @@ public:
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
******************************************************************/
@@ -86,6 +140,8 @@ public:
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;
};
}}
diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp
index cd6b14ef5..1f8e91d68 100644
--- a/host/include/uhd/usrp/subdev_props.hpp
+++ b/host/include/uhd/usrp/subdev_props.hpp
@@ -35,13 +35,13 @@ namespace uhd{ namespace usrp{
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_ENABLED = 'e', //rw, bool //---> dont need, we have atr
+ 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, //ro, float //----> not on all boards, use named prop
- //SUBDEV_PROP_BANDWIDTH //rw, double //----> not on all boards, use named prop
+ SUBDEV_PROP_USE_LO_OFFSET = 'l', //ro, bool
+ SUBDEV_PROP_RSSI = 'R', //ro, float
+ SUBDEV_PROP_BANDWIDTH = 'B' //rw, double
};
}} //namespace
diff --git a/host/include/uhd/utils/assert.hpp b/host/include/uhd/utils/assert.hpp
index 842ed8dfa..01beed757 100644
--- a/host/include/uhd/utils/assert.hpp
+++ b/host/include/uhd/utils/assert.hpp
@@ -18,27 +18,27 @@
#ifndef INCLUDED_UHD_UTILS_ASSERT_HPP
#define INCLUDED_UHD_UTILS_ASSERT_HPP
+#include <uhd/config.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
-#include <boost/current_function.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/exception/info.hpp>
#include <stdexcept>
+#include <string>
namespace uhd{
- class assert_error : public std::logic_error{
- public:
- explicit assert_error(const std::string& what_arg) : logic_error(what_arg){
- /* NOP */
- }
- };
+ //! The exception to throw when assertions fail
+ struct UHD_API assert_error : virtual std::exception, virtual boost::exception{};
- #define ASSERT_THROW(_x) if (not (_x)) { \
- throw uhd::assert_error(str(boost::format( \
- "Assertion Failed:\n %s:%d\n %s\n ---> %s <---" \
- ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \
- }
+ //! The assertion info, the code that failed
+ typedef boost::error_info<struct tag_assert_info, std::string> assert_info;
+
+ //! Throw an assert error with throw-site information
+ #define UHD_ASSERT_THROW(_x) if (not (_x)) \
+ BOOST_THROW_EXCEPTION(uhd::assert_error() << uhd::assert_info(#_x))
/*!
* Check that an element is found in a container.
@@ -58,17 +58,18 @@ namespace uhd{
){
if (std::has(iterable, elem)) return;
std::string possible_values = "";
- BOOST_FOREACH(T e, iterable){
- if (e != iterable.begin()[0]) possible_values += ", ";
+ size_t i = 0;
+ BOOST_FOREACH(const T &e, iterable){
+ if (i++ > 0) possible_values += ", ";
possible_values += boost::lexical_cast<std::string>(e);
}
- throw uhd::assert_error(str(boost::format(
+ boost::throw_exception(uhd::assert_error() << assert_info(str(boost::format(
"Error: %s is not a valid %s. "
"Possible values are: [%s]."
)
% boost::lexical_cast<std::string>(elem)
% what % possible_values
- ));
+ )));
}
}//namespace uhd
diff --git a/host/include/uhd/utils/props.hpp b/host/include/uhd/utils/props.hpp
index 6be0b2ce5..516102a5f 100644
--- a/host/include/uhd/utils/props.hpp
+++ b/host/include/uhd/utils/props.hpp
@@ -21,27 +21,63 @@
#include <uhd/config.hpp>
#include <uhd/wax.hpp>
#include <boost/tuple/tuple.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/exception/info.hpp>
+#include <stdexcept>
#include <vector>
#include <string>
namespace uhd{
- //typedef for handling named properties
+ //! The type for a vector of property names
typedef std::vector<std::string> prop_names_t;
- typedef boost::tuple<wax::obj, std::string> named_prop_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 = ""
+ );
+
+ //! The exception to throw for property errors
+ struct UHD_API prop_error : virtual std::exception, virtual boost::exception{};
+
+ //! The property error info (verbose or message)
+ typedef boost::error_info<struct tag_prop_info, std::string> prop_info;
+
+ /*!
+ * 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() \
+ BOOST_THROW_EXCEPTION(uhd::prop_error() << uhd::prop_info("cannot get this property"))
+
+ /*!
+ * Throw when setting a not-implemented or read-only property.
+ * Throw-site information will be included with this error.
*/
- inline UHD_API named_prop_t //must be exported as part of the api to work (TODO move guts to cpp file)
- extract_named_prop(const wax::obj &key, const std::string &name = ""){
- if (key.type() == typeid(named_prop_t)){
- return key.as<named_prop_t>();
- }
- return named_prop_t(key, name);
- }
+ #define UHD_THROW_PROP_SET_ERROR() \
+ BOOST_THROW_EXCEPTION(uhd::prop_error() << uhd::prop_info("cannot set this property"))
} //namespace uhd
diff --git a/host/include/uhd/utils/safe_main.hpp b/host/include/uhd/utils/safe_main.hpp
index b682aa540..a4e4e06e8 100644
--- a/host/include/uhd/utils/safe_main.hpp
+++ b/host/include/uhd/utils/safe_main.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_UHD_UTILS_SAFE_MAIN_HPP
#include <uhd/config.hpp>
+#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include <stdexcept>
@@ -33,6 +34,8 @@
int main(int argc, char *argv[]){ \
try { \
return _main(argc, argv); \
+ } catch(const boost::exception &e){ \
+ std::cerr << "Error: " << boost::diagnostic_information(e) << std::endl; \
} catch(const std::exception &e) { \
std::cerr << "Error: " << e.what() << std::endl; \
} catch(...) { \
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index ff7f2c0df..48fee5a80 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -50,13 +50,13 @@ SET(libuhd_sources
gain_handler.cpp
load_modules.cpp
types.cpp
+ utils.cpp
wax.cpp
transport/convert_types.cpp
transport/if_addrs.cpp
transport/udp_simple.cpp
- usrp/dboard/db_basic_and_lf.cpp
- usrp/dboard/db_rfx.cpp
usrp/dboard_base.cpp
+ usrp/dboard_eeprom.cpp
usrp/simple_usrp.cpp
usrp/dboard_manager.cpp
usrp/tune_helper.cpp
@@ -66,11 +66,18 @@ SET(libuhd_sources
# Generate Files
########################################################################
MACRO(UHD_PYTHON_GEN_SOURCE_FILE 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 "Calling ${pyfile} to generate ${outfile}"
+ COMMENT "Generating ${outfile}"
)
+
+ #make libuhd depend on the outfile
LIST(APPEND libuhd_sources ${outfile})
ENDMACRO(UHD_PYTHON_GEN_SOURCE_FILE)
@@ -96,6 +103,29 @@ UHD_PYTHON_GEN_SOURCE_FILE(
${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9777_regs.hpp
)
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad5624_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad5624_regs.hpp
+)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad7922_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad7922_regs.hpp
+)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_max2829_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/max2829_regs.hpp
+)
+
+########################################################################
+# Add dboard sources
+########################################################################
+LIST(APPEND libuhd_sources
+ usrp/dboard/db_basic_and_lf.cpp
+ usrp/dboard/db_rfx.cpp
+ usrp/dboard/db_xcvr2450.cpp
+)
########################################################################
# Add usrp2 sources
diff --git a/host/lib/device.cpp b/host/lib/device.cpp
index 0197a6232..706f64951 100644
--- a/host/lib/device.cpp
+++ b/host/lib/device.cpp
@@ -132,8 +132,8 @@ device::sptr device::make(const device_addr_t &hint, size_t which){
//try to find an existing device
try{
- ASSERT_THROW(hash_to_device.has_key(dev_hash));
- ASSERT_THROW(not hash_to_device[dev_hash].expired());
+ 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
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/common.py b/host/lib/ic_reg_maps/common.py
new file mode 100644
index 000000000..d05470706
--- /dev/null
+++ b/host/lib/ic_reg_maps/common.py
@@ -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/>.
+#
+
+import re
+import math
+from Cheetah.Template import Template
+
+def parse_tmpl(_tmpl_text, **kwargs):
+ return str(Template(_tmpl_text, kwargs))
+
+class reg:
+ def __init__(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 = int(addr, 16)
+ 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 = int(default, 16)
+
+ #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 = int(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_stdint_type(self):\
+ return '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
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..9e8ae5be5
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad5624_regs.py
@@ -0,0 +1,82 @@
+#!/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/>.
+#
+
+import sys
+from common import *
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_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
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_AD5624_REGS_HPP
+\#define INCLUDED_AD5624_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct ad5624_regs_t{
+#for $reg in $regs
+ #if $reg.get_enums()
+ enum $(reg.get_name())_t{
+ #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
+ } $reg.get_name();
+ #else
+ boost::$reg.get_stdint_type() $reg.get_name();
+ #end if
+#end for
+
+ ad5624_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ 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;
+ }
+
+};
+
+\#endif /* INCLUDED_AD5624_REGS_HPP */
+"""
+
+if __name__ == '__main__':
+ regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
+ open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, 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..23f28c0da
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad7922_regs.py
@@ -0,0 +1,88 @@
+#!/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/>.
+#
+
+import sys
+from common import *
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_TMPL="""\
+result 0[0:11] 0
+mod 0[12] 0
+chn 0[13] 0
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_AD7922_REGS_HPP
+\#define INCLUDED_AD7922_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct ad7922_regs_t{
+#for $reg in $regs
+ #if $reg.get_enums()
+ enum $(reg.get_name())_t{
+ #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
+ } $reg.get_name();
+ #else
+ boost::$reg.get_stdint_type() $reg.get_name();
+ #end if
+#end for
+
+ ad7922_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ 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 >> $reg.get_shift()) & $reg.get_mask();
+ #end for
+ }
+
+};
+
+\#endif /* INCLUDED_AD7922_REGS_HPP */
+"""
+
+if __name__ == '__main__':
+ regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
+ open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__))
diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py
index 90230b8f9..2dc19c691 100755
--- a/host/lib/ic_reg_maps/gen_ad9510_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py
@@ -1,32 +1,23 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
-import re
-import os
import sys
-from Cheetah.Template import Template
-def parse_tmpl(_tmpl_text, **kwargs):
- return str(Template(_tmpl_text, kwargs))
-def safe_makedirs(path):
- not os.path.isdir(path) and os.makedirs(path)
+from common import *
########################################################################
# Template for raw text data describing registers
@@ -177,48 +168,6 @@ struct ad9510_regs_t{
\#endif /* INCLUDED_AD9510_REGS_HPP */
"""
-class reg:
- def __init__(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 = int(addr, 16)
- if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':'))
- else: self._addr_spec = int(bit_range), int(bit_range)
- self._default = int(default, 16)
-
- #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 = int(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_stdint_type(self):
- if self.get_bit_width() <= 8: return 'uint8_t'
- if self.get_bit_width() <= 16: return 'uint16_t'
- if self.get_bit_width() <= 32: return 'uint32_t'
- if self.get_bit_width() <= 64: return 'uint64_t'
- raise Exception, 'too damn big'
- 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
-
if __name__ == '__main__':
regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
- safe_makedirs(os.path.dirname(sys.argv[1]))
open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__))
diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py
index 6077b61b6..2ac73efcf 100644..100755
--- a/host/lib/ic_reg_maps/gen_ad9777_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py
@@ -1,32 +1,23 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
-import re
-import os
import sys
-from Cheetah.Template import Template
-def parse_tmpl(_tmpl_text, **kwargs):
- return str(Template(_tmpl_text, kwargs))
-def safe_makedirs(path):
- not os.path.isdir(path) and os.makedirs(path)
+from common import *
########################################################################
# Template for raw text data describing registers
@@ -155,48 +146,6 @@ struct ad9777_regs_t{
\#endif /* INCLUDED_AD9777_REGS_HPP */
"""
-class reg:
- def __init__(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 = int(addr, 16)
- 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 = int(default, 16)
-
- #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 = int(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_stdint_type(self):
- if self.get_bit_width() <= 8: return 'uint8_t'
- if self.get_bit_width() <= 16: return 'uint16_t'
- if self.get_bit_width() <= 32: return 'uint32_t'
- if self.get_bit_width() <= 64: return 'uint64_t'
- raise Exception, 'too damn big'
- 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
-
if __name__ == '__main__':
regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
- safe_makedirs(os.path.dirname(sys.argv[1]))
open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__))
diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py
index bcad1ffd3..478e471a3 100755
--- a/host/lib/ic_reg_maps/gen_adf4360_regs.py
+++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py
@@ -1,32 +1,23 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
-import re
-import os
import sys
-from Cheetah.Template import Template
-def parse_tmpl(_tmpl_text, **kwargs):
- return str(Template(_tmpl_text, kwargs))
-def safe_makedirs(path):
- not os.path.isdir(path) and os.makedirs(path)
+from common import *
########################################################################
# Template for raw text data describing registers
@@ -126,48 +117,6 @@ struct adf4360_regs_t{
\#endif /* INCLUDED_ADF4360_REGS_HPP */
"""
-class reg:
- def __init__(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 = int(addr)
- if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':'))
- else: self._addr_spec = int(bit_range), int(bit_range)
- self._default = int(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 = int(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_stdint_type(self):
- if self.get_bit_width() <= 8: return 'uint8_t'
- if self.get_bit_width() <= 16: return 'uint16_t'
- if self.get_bit_width() <= 32: return 'uint32_t'
- if self.get_bit_width() <= 64: return 'uint64_t'
- raise Exception, 'too damn big'
- 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
-
if __name__ == '__main__':
regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
- safe_makedirs(os.path.dirname(sys.argv[1]))
open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, 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..7fef302a8
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_max2829_regs.py
@@ -0,0 +1,166 @@
+#!/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/>.
+#
+
+import sys
+from common import *
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_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] a2
+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 a[0:5] 0
+pa_bias_dac_delay a[6:9] f
+########################################################################
+## Rx Gain (11)
+########################################################################
+rx_vga_gain b[0:4] 1f
+rx_lna_gain b[5:6] 3
+########################################################################
+## Tx VGA Gain (12)
+########################################################################
+tx_vga_gain c[0:5] 0
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_MAX2829_REGS_HPP
+\#define INCLUDED_MAX2829_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct max2829_regs_t{
+#for $reg in $regs
+ #if $reg.get_enums()
+ enum $(reg.get_name())_t{
+ #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
+ } $reg.get_name();
+ #else
+ boost::$reg.get_stdint_type() $reg.get_name();
+ #end if
+#end for
+
+ max2829_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ boost::uint32_t get_reg(boost::uint8_t addr){
+ boost::uint16_t reg = 0;
+ switch(addr){
+ #for $addr in range(2, 12+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 (boost::uint32_t(reg) << 4) | (addr & 0xf);
+ }
+};
+
+\#endif /* INCLUDED_MAX2829_REGS_HPP */
+"""
+
+if __name__ == '__main__':
+ regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
+ open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__))
diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp
index 2a6854f50..8c3d6b17a 100644
--- a/host/lib/transport/convert_types.cpp
+++ b/host/lib/transport/convert_types.cpp
@@ -19,6 +19,7 @@
#include <uhd/utils/assert.hpp>
#include <boost/asio.hpp> //endianness conversion
#include <boost/cstdint.hpp>
+#include <complex>
using namespace uhd;
@@ -109,7 +110,7 @@ void transport::convert_io_type_to_otw_type(
size_t num_samps
){
//all we handle for now:
- ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+ 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:
@@ -129,7 +130,7 @@ void transport::convert_otw_type_to_io_type(
size_t num_samps
){
//all we handle for now:
- ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+ 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:
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index 0fd2522cf..14f7651d4 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -25,11 +25,14 @@
#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>
@@ -102,9 +105,9 @@ tx_metadata_t::tx_metadata_t(void){
/***********************************************************************
* time spec
**********************************************************************/
-time_spec_t::time_spec_t(boost::uint32_t new_secs, double new_nsecs){
- secs = new_secs;
- nsecs = new_nsecs;
+time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){
+ secs = secs_;
+ nsecs = nsecs_;
}
boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
@@ -118,46 +121,44 @@ void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){
/***********************************************************************
* device addr
**********************************************************************/
-std::string device_addr_t::to_string(void) const{
- std::stringstream ss;
- BOOST_FOREACH(std::string key, this->keys()){
- ss << boost::format("%s: %s") % key % (*this)[key] << std::endl;
- }
- return ss.str();
-}
-
-static const std::string arg_delim = ";";
+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);
}
-std::string device_addr_t::to_args_str(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;
-}
-
-device_addr_t device_addr_t::from_args_str(const std::string &args_str){
- device_addr_t addr;
-
+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_str, boost::is_any_of(arg_delim));
+ 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_str);
- addr[trim(key_val[0])] = trim(key_val[1]);
+ 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_string(void) const{
+ if (this->size() == 0) return "Empty Device Address";
- return addr;
+ 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_args_str(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;
}
/***********************************************************************
@@ -243,3 +244,38 @@ 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;
+}
+
+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/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index aad2398d8..b0fbbd2ec 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -153,6 +153,12 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
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();
}
}
@@ -164,19 +170,17 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
return;
case SUBDEV_PROP_ANTENNA:
- ASSERT_THROW(val.as<std::string>() == std::string(""));
+ 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: throw std::runtime_error(str(boost::format(
- "Error: trying to set read-only property on %s subdev"
- ) % dboard_id::to_string(get_rx_id())));
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -248,6 +252,12 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
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();
}
}
@@ -259,18 +269,16 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
switch(key.as<subdev_prop_t>()){
case SUBDEV_PROP_GAIN:
- ASSERT_THROW(val.as<float>() == float(0));
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
return;
case SUBDEV_PROP_ANTENNA:
- ASSERT_THROW(val.as<std::string>() == std::string(""));
+ 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: throw std::runtime_error(str(boost::format(
- "Error: trying to set read-only property on %s subdev"
- ) % dboard_id::to_string(get_tx_id())));
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index cd5b8447b..175f55eab 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -94,6 +94,15 @@ private:
* \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;
+ }
};
/***********************************************************************
@@ -192,7 +201,7 @@ void rfx_xcvr::set_tx_lo_freq(double freq){
void rfx_xcvr::set_rx_ant(const std::string &ant){
//validate input
- ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+ 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(
@@ -350,12 +359,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- ASSERT_THROW(name == "PGA0");
+ UHD_ASSERT_THROW(name == "PGA0");
val = _rx_pga0_gain;
return;
case SUBDEV_PROP_GAIN_RANGE:
- ASSERT_THROW(name == "PGA0");
+ UHD_ASSERT_THROW(name == "PGA0");
val = gain_range_t(0, _max_rx_pga0_gain, float(0.022));
return;
@@ -396,6 +405,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
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();
}
}
@@ -411,7 +426,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
return;
case SUBDEV_PROP_GAIN:
- ASSERT_THROW(name == "PGA0");
+ UHD_ASSERT_THROW(name == "PGA0");
set_rx_pga0_gain(val.as<float>());
return;
@@ -419,10 +434,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
set_rx_ant(val.as<std::string>());
return;
- default:
- throw std::runtime_error(str(boost::format(
- "Error: trying to set read-only property on %s subdev"
- ) % dboard_id::to_string(get_rx_id())));
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -430,7 +442,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
* TX Get and Set
**********************************************************************/
void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
- wax::obj key; std::string name;
+ wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
@@ -486,6 +498,12 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
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();
}
}
@@ -506,12 +524,9 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
case SUBDEV_PROP_ANTENNA:
//its always set to tx/rx, so we only allow this value
- ASSERT_THROW(val.as<std::string>() == "TX/RX");
+ UHD_ASSERT_THROW(val.as<std::string>() == "TX/RX");
return;
- default:
- throw std::runtime_error(str(boost::format(
- "Error: trying to set read-only property on %s subdev"
- ) % dboard_id::to_string(get_tx_id())));
+ 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..0dfef2a0a
--- /dev/null
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -0,0 +1,627 @@
+//
+// 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 const& 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 const& 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 const& 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;
+ }
+ BOOST_THROW_EXCEPTION(std::runtime_error("should not get here"));
+ return max2829_regs_t::TX_BASEBAND_GAIN_0DB;
+}
+
+/*!
+ * 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 = dboard_id::to_string(get_rx_id());
+ 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 = dboard_id::to_string(get_tx_id());
+ 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_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp
new file mode 100644
index 000000000..54e7a4fd9
--- /dev/null
+++ b/host/lib/usrp/dboard_eeprom.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 <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 = \
+ (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::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 >> 0);
+ bytes[DB_EEPROM_ID_MSB] = boost::uint8_t(id >> 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_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 06f8c55b6..390c1d3c9 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -177,10 +177,11 @@ static args_t get_dboard_args(
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
- throw std::runtime_error(str(
+ /*throw std::runtime_error(str(
boost::format("Unregistered %s dboard id: %s")
% xx_type % dboard_id::to_string(dboard_id)
- ));
+ ));*/
+ return get_dboard_args(dboard_id::NONE, xx_type);
}
//return the dboard args for this id
@@ -205,7 +206,7 @@ dboard_manager_impl::dboard_manager_impl(
//make xcvr subdevs (make one subdev for both rx and tx dboards)
if (rx_dboard_ctor == tx_dboard_ctor){
- ASSERT_THROW(rx_subdevs == tx_subdevs);
+ UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
dboard_base::sptr xcvr_dboard = rx_dboard_ctor(
dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, tx_dboard_id)
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index 11ee3a798..a8c104485 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -42,14 +42,14 @@ public:
_tx_dsp = _mboard[MBOARD_PROP_TX_DSP];
//extract rx subdevice
- wax::obj 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)];
+ _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
- wax::obj 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)];
+ _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){
@@ -61,7 +61,26 @@ public:
}
std::string get_name(void){
- return _mboard[MBOARD_PROP_NAME].as<std::string>();
+ 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>()
+ );
}
/*******************************************************************
@@ -83,6 +102,10 @@ public:
_mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
}
+ float read_rssi(void){
+ return _rx_subdev[SUBDEV_PROP_RSSI].as<float>();
+ }
+
/*******************************************************************
* RX methods
******************************************************************/
@@ -126,6 +149,10 @@ public:
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
******************************************************************/
@@ -169,11 +196,17 @@ public:
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;
};
@@ -181,6 +214,6 @@ private:
/***********************************************************************
* The Make Function
**********************************************************************/
-simple_usrp::sptr simple_usrp::make(const std::string &args){
- return sptr(new simple_usrp_impl(device_addr_t::from_args_str(args)));
+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/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp
index dcd7ce9da..72f1f1c7a 100644
--- a/host/lib/usrp/usrp2/clock_control.cpp
+++ b/host/lib/usrp/usrp2/clock_control.cpp
@@ -21,6 +21,7 @@
#include "usrp2_regs.hpp" //spi slave constants
#include <boost/cstdint.hpp>
+using namespace uhd;
using namespace uhd::usrp;
/*!
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 2859a7981..74d80163c 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -17,14 +17,17 @@
#include "usrp2_iface.hpp"
#include "clock_control.hpp"
-#include "usrp2_regs.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 <algorithm>
+#include "ad7922_regs.hpp" //aux adc
+#include "ad5624_regs.hpp" //aux dac
+using namespace uhd;
using namespace uhd::usrp;
class usrp2_dboard_iface : public dboard_iface{
@@ -39,8 +42,8 @@ public:
void set_gpio_ddr(unit_t, boost::uint16_t);
boost::uint16_t read_gpio(unit_t);
- void write_i2c(int, const byte_vector_t &);
- byte_vector_t read_i2c(int, size_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);
@@ -64,6 +67,9 @@ private:
usrp2_iface::sptr _iface;
clock_control::sptr _clk_ctrl;
boost::uint32_t _ddr_shadow;
+
+ uhd::dict<unit_t, ad5624_regs_t> _dac_regs;
+ void _write_aux_dac(unit_t);
};
/***********************************************************************
@@ -91,6 +97,16 @@ usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::s
}
_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){
@@ -196,84 +212,67 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(
/***********************************************************************
* I2C
**********************************************************************/
-void usrp2_dboard_iface::write_i2c(int i2c_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 = i2c_addr;
- out_data.data.i2c_args.bytes = buf.size();
-
- //limitation of i2c transaction size
- 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 = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
+void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
+ return _iface->write_i2c(addr, bytes);
}
-dboard_iface::byte_vector_t usrp2_dboard_iface::read_i2c(int i2c_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 = i2c_addr;
- out_data.data.i2c_args.bytes = num_bytes;
-
- //limitation of i2c transaction size
- ASSERT_THROW(num_bytes <= sizeof(out_data.data.i2c_args.data));
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
- 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;
+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
**********************************************************************/
-/*!
- * Static function to convert a unit type enum
- * to an over-the-wire value for the usrp2 control.
- * \param unit the dboard interface unit type enum
- * \return an over the wire representation
- */
-static boost::uint8_t unit_to_otw(dboard_iface::unit_t unit){
- switch(unit){
- case dboard_iface::UNIT_TX: return USRP2_DIR_TX;
- case dboard_iface::UNIT_RX: return USRP2_DIR_RX;
- }
- throw std::invalid_argument("unknown unit type");
+void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
+ static const uhd::dict<unit_t, int> unit_to_spi_dac = boost::assign::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){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO);
- out_data.data.aux_args.dir = unit_to_otw(unit);
- out_data.data.aux_args.which = which;
- out_data.data.aux_args.value = htonl(boost::math::iround(4095*value/3.3));
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE);
+ _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){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO);
- out_data.data.aux_args.dir = unit_to_otw(unit);
- out_data.data.aux_args.which = which;
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE);
- return float(3.3*ntohl(in_data.data.aux_args.value)/4095);
+ static const uhd::dict<unit_t, int> unit_to_spi_adc = boost::assign::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
index fe74219d6..403faf5cf 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -33,22 +33,16 @@ using namespace uhd::usrp;
* Helper Methods
**********************************************************************/
void usrp2_impl::dboard_init(void){
- //grab the dboard ids over the control line
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO);
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE);
-
- //extract the dboard ids an convert them
- dboard_id_t rx_dboard_id = ntohs(in_data.data.dboard_ids.rx_id);
- dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id);
+ //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, _clk_ctrl)
);
_dboard_manager = dboard_manager::make(
- rx_dboard_id, tx_dboard_id, _dboard_iface
+ _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface
);
//load dboards
@@ -72,7 +66,7 @@ void usrp2_impl::dboard_init(void){
void usrp2_impl::update_rx_mux_config(void){
//calculate the rx mux
boost::uint32_t rx_mux = 0;
- ASSERT_THROW(_rx_subdevs_in_use.size() == 1);
+ 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>()){
@@ -90,11 +84,11 @@ void usrp2_impl::update_rx_mux_config(void){
void usrp2_impl::update_tx_mux_config(void){
//calculate the tx mux
boost::uint32_t tx_mux = 0x10;
- ASSERT_THROW(_tx_subdevs_in_use.size() == 1);
+ 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) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);
+ tx_mux = (((tx_mux >> 0) & 0xf) << 4) | (((tx_mux >> 4) & 0xf) << 0);
}
_iface->poke32(FR_DSP_TX_MUX, tx_mux);
@@ -125,19 +119,28 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _rx_subdevs_in_use;
return;
- //case DBOARD_PROP_CODEC:
- // throw std::runtime_error("unhandled prop in usrp2 dboard");
+ 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){
- if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){
+ 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;
- }
- throw std::runtime_error("Cannot set on usrp2 dboard");
+ 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();
+ }
}
/***********************************************************************
@@ -165,17 +168,26 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _tx_subdevs_in_use;
return;
- //case DBOARD_PROP_CODEC:
- // throw std::runtime_error("unhandled prop in usrp2 dboard");
+ 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){
- if (key.as<dboard_prop_t>() == DBOARD_PROP_USED_SUBDEVS){
+ 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;
- }
- throw std::runtime_error("Cannot set on usrp2 dboard");
+ 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
index 204277ba7..84314a656 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -40,7 +40,7 @@ template <class T> T log2(T num){
* DDC Helper Methods
**********************************************************************/
static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){
- ASSERT_THROW(std::abs(freq) < clock_freq/2.0);
+ 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
@@ -117,6 +117,8 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
case DSP_PROP_HOST_RATE:
val = get_master_clock_freq()/_ddc_decim;
return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -139,8 +141,7 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
}
return;
- default:
- throw std::runtime_error("Error: trying to set read-only property on usrp2 ddc0");
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
@@ -200,6 +201,8 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
case DSP_PROP_HOST_RATE:
val = get_master_clock_freq()/_duc_interp;
return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -222,7 +225,6 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
}
return;
- default:
- throw std::runtime_error("Error: trying to set read-only property on usrp2 duc0");
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index b600a2a70..e80001ff2 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -32,6 +32,10 @@ extern "C" {
#define _SINS_
#endif
+//defines the protocol version in this shared header
+//increment this value when the protocol is changed
+#define USRP2_PROTO_VERSION 2
+
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -57,9 +61,6 @@ typedef enum{
USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE = 'M',
USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO = 'n',
- USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO = 'd',
- USRP2_CTRL_ID_THESE_ARE_MY_DBOARD_IDS_DUDE = 'D',
-
USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's',
USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S',
@@ -69,12 +70,6 @@ typedef enum{
USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',
USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H',
- USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO = 'x',
- USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE = 'X',
-
- USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO = 'y',
- USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE = 'Y',
-
USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO = '{',
USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE = '}',
@@ -89,26 +84,23 @@ typedef enum{
} usrp2_ctrl_id_t;
typedef enum{
- USRP2_DIR_RX,
- USRP2_DIR_TX
+ USRP2_DIR_RX = 'r',
+ USRP2_DIR_TX = 't'
} usrp2_dir_which_t;
typedef enum{
- USRP2_CLK_EDGE_RISE,
- USRP2_CLK_EDGE_FALL
+ 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;
_SINS_ uint8_t mac_addr[6];
struct {
- _SINS_ uint16_t rx_id;
- _SINS_ uint16_t tx_id;
- } dboard_ids;
- struct {
_SINS_ uint8_t dev;
_SINS_ uint8_t miso_edge;
_SINS_ uint8_t mosi_edge;
@@ -122,12 +114,6 @@ typedef struct{
_SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
} i2c_args;
struct {
- _SINS_ uint8_t dir;
- _SINS_ uint8_t which;
- _SINS_ uint8_t _pad[2];
- _SINS_ uint32_t value;
- } aux_args;
- struct {
_SINS_ uint8_t now; //stream now?
_SINS_ uint8_t continuous; //auto-reload commmands?
_SINS_ uint8_t chain;
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index d7728238c..36bef4f25 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -100,6 +100,7 @@ void usrp2_impl::update_clock_config(void){
case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break;
case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break;
case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break;
+ default: throw std::runtime_error("usrp2: unhandled clock configuration reference source");
}
//clock source ref 10mhz
@@ -151,7 +152,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
//send and recv
usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);
}
/***********************************************************************
@@ -170,7 +171,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
//send and recv
usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
//extract the address
val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string();
@@ -184,7 +185,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
//send and recv
usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
//extract the address
val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string();
@@ -208,7 +209,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_RX_DBOARD:
- ASSERT_THROW(name == "");
+ UHD_ASSERT_THROW(name == "");
val = _rx_dboard_proxy->get_link();
return;
@@ -217,7 +218,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DBOARD:
- ASSERT_THROW(name == "");
+ UHD_ASSERT_THROW(name == "");
val = _tx_dboard_proxy->get_link();
return;
@@ -226,7 +227,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_RX_DSP:
- ASSERT_THROW(name == "");
+ UHD_ASSERT_THROW(name == "");
val = _rx_dsp_proxy->get_link();
return;
@@ -235,7 +236,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
case MBOARD_PROP_TX_DSP:
- ASSERT_THROW(name == "");
+ UHD_ASSERT_THROW(name == "");
val = _tx_dsp_proxy->get_link();
return;
@@ -247,9 +248,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
val = _clock_config;
return;
- default:
- throw std::runtime_error("Error: trying to get write-only property on usrp2 mboard");
-
+ default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -268,7 +267,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
//send and recv
usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE);
return;
}
@@ -280,7 +279,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
//send and recv
usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE);
return;
}
}
@@ -305,8 +304,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
issue_ddc_stream_cmd(val.as<stream_cmd_t>());
return;
- default:
- throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard");
-
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 5c84fd8d3..e43b9678e 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -19,12 +19,13 @@
#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;
-using namespace uhd::usrp;
class usrp2_iface_impl : public usrp2_iface{
public:
@@ -85,9 +86,51 @@ public:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
+ UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
- return ntohl(out_data.data.spi_args.data);
+ 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;
}
/***********************************************************************
@@ -98,6 +141,7 @@ public:
//fill in the seq number and send
usrp2_ctrl_data_t out_copy = out_data;
+ out_copy.proto_ver = htonl(USRP2_PROTO_VERSION);
out_copy.seq = htonl(++_ctrl_seq_num);
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
@@ -105,6 +149,13 @@ public:
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;
}
@@ -142,7 +193,7 @@ private:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
+ 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){
@@ -154,7 +205,7 @@ private:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
+ 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));
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 1298d87f1..7158c58d0 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -19,18 +19,27 @@
#define INCLUDED_USRP2_IFACE_HPP
#include <uhd/transport/udp_simple.hpp>
-#include <uhd/usrp/dboard_iface.hpp> //spi config
+#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)
+////////////////////////////////////////////////////////////////////////
+
/*!
* The usrp2 interface class:
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp2_iface : boost::noncopyable{
+class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
@@ -87,7 +96,7 @@ public:
*/
virtual boost::uint32_t transact_spi(
int which_slave,
- const uhd::usrp::spi_config_t &config,
+ const uhd::spi_config_t &config,
boost::uint32_t data,
size_t num_bits,
bool readback
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 3bdc5bd02..4079357f9 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -70,6 +70,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
//send a hello control packet
usrp2_ctrl_data_t ctrl_data_out;
+ ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION);
ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
@@ -185,7 +186,7 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
return;
case DEVICE_PROP_MBOARD:
- ASSERT_THROW(name == "");
+ UHD_ASSERT_THROW(name == "");
val = _mboard_proxy->get_link();
return;
@@ -201,9 +202,10 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
val = size_t(_max_tx_samples_per_packet);
return;
+ default: UHD_THROW_PROP_GET_ERROR();
}
}
void usrp2_impl::set(const wax::obj &, const wax::obj &){
- throw std::runtime_error("Cannot set in usrp2 device");
+ UHD_THROW_PROP_SET_ERROR();
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index dbcee367b..1c9387744 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -25,6 +25,7 @@
#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>
@@ -161,12 +162,14 @@ private:
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);
diff --git a/host/lib/utils.cpp b/host/lib/utils.cpp
new file mode 100644
index 000000000..3a1e5aa3f
--- /dev/null
+++ b/host/lib/utils.cpp
@@ -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/>.
+//
+
+#include <uhd/utils/props.hpp>
+
+using namespace uhd;
+
+/***********************************************************************
+ * 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/test/addr_test.cpp b/host/test/addr_test.cpp
index 2ec6de14b..93b7cc0df 100644
--- a/host/test/addr_test.cpp
+++ b/host/test/addr_test.cpp
@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(test_device_addr){
std::cout << "Pretty Print: " << std::endl << dev_addr.to_string();
std::string args_str = dev_addr.to_args_str();
std::cout << "Args String: " << args_str << std::endl;
- uhd::device_addr_t new_dev_addr = uhd::device_addr_t::from_args_str(args_str);
+ 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());
diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp
index bf2ec5db7..5a9f2b714 100644
--- a/host/test/gain_handler_test.cpp
+++ b/host/test/gain_handler_test.cpp
@@ -72,6 +72,8 @@ private:
case PROP_GAIN_NAMES:
val = _gain_values.keys();
return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -87,9 +89,7 @@ private:
_gain_values[name] = val.as<float>();
return;
- case PROP_GAIN_RANGE:
- case PROP_GAIN_NAMES:
- throw std::runtime_error("cannot set this property");
+ default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 0b1e058ef..78970ad0e 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -27,4 +27,8 @@ ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp)
TARGET_LINK_LIBRARIES(usrp2_burner uhd)
INSTALL(TARGETS usrp2_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 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..c07b43f16
--- /dev/null
+++ b/host/utils/uhd_burn_db_eeprom.cpp
@@ -0,0 +1,105 @@
+//
+// 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/lexical_cast.hpp>
+#include <boost/format.hpp>
+#include <boost/assign.hpp>
+#include <iostream>
+#include <sstream>
+
+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") % dboard_id::to_string(id) << std::endl;
+ }
+
+ //write a new dboard id to eeprom
+ else{
+ dboard_id_t id = boost::lexical_cast<to_hex<dboard_id_t> >(vm["id"].as<std::string>());
+ std::cout << boost::format("Setting dbid on %s dboard...") % prefix << std::endl;
+ std::cout << boost::format(" New dbid: %s") % dboard_id::to_string(id) << 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
index 6c945cbca..8222dc1f4 100644
--- a/host/utils/uhd_find_devices.cpp
+++ b/host/utils/uhd_find_devices.cpp
@@ -27,8 +27,7 @@ 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")
- ("node", po::value<std::string>(), "path to linux device node")
+ ("args", po::value<std::string>()->default_value(""), "device address args")
;
po::variables_map vm;
@@ -41,17 +40,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
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>();
- }
- if (vm.count("node")){
- device_addr["node"] = vm["node"].as<std::string>();
- }
-
//discover the usrps and print the results
- uhd::device_addrs_t device_addrs = uhd::device::find(device_addr);
+ 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;