aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-04-16 09:42:46 +0000
committerJosh Blum <josh@joshknows.com>2010-04-16 09:42:46 +0000
commit835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25 (patch)
tree4fe48bdaf92311deedfbe1a5e77dd209468a2d7d /host
parentf1838b9284a124fcfb5996eaf1647a69b4473278 (diff)
parent067491b58676cbdaa754334949a8ffc2daf32979 (diff)
downloaduhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.tar.gz
uhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.tar.bz2
uhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.zip
Merge branch 'master' of git@ettus.sourcerepo.com:ettus/uhdpriv into usrp_e
Conflicts: .gitignore
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt19
-rw-r--r--host/README74
-rw-r--r--host/examples/rx_timed_samples.cpp4
-rw-r--r--host/include/uhd/transport/CMakeLists.txt3
-rw-r--r--host/include/uhd/transport/convert_types.hpp59
-rw-r--r--host/include/uhd/transport/smart_buffer.hpp45
-rw-r--r--host/include/uhd/transport/udp_zero_copy.hpp28
-rw-r--r--host/include/uhd/transport/vrt.hpp10
-rw-r--r--host/include/uhd/transport/zero_copy.hpp133
-rw-r--r--host/include/uhd/types/metadata.hpp1
-rw-r--r--host/include/uhd/types/time_spec.hpp36
-rw-r--r--host/include/uhd/types/tune_result.hpp6
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt2
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp10
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp190
-rw-r--r--host/include/uhd/usrp/dboard_interface.hpp193
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp6
-rw-r--r--host/include/uhd/usrp/mboard_props.hpp1
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp1
-rw-r--r--host/include/uhd/usrp/subdev_props.hpp2
-rw-r--r--host/include/uhd/utils/algorithm.hpp6
-rw-r--r--host/lib/CMakeLists.txt76
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9510_regs.py224
-rw-r--r--host/lib/ic_reg_maps/gen_ad9777_regs.py202
-rwxr-xr-xhost/lib/ic_reg_maps/gen_adf4360_regs.py173
-rw-r--r--host/lib/transport/convert_types.cpp144
-rwxr-xr-xhost/lib/transport/gen_vrt.py24
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp106
-rw-r--r--host/lib/transport/vrt.cpp547
-rw-r--r--host/lib/types.cpp31
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp22
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp517
-rw-r--r--host/lib/usrp/dboard_base.cpp6
-rw-r--r--host/lib/usrp/dboard_interface.cpp53
-rw-r--r--host/lib/usrp/dboard_manager.cpp48
-rw-r--r--host/lib/usrp/simple_usrp.cpp4
-rw-r--r--host/lib/usrp/tune_helper.cpp4
-rw-r--r--host/lib/usrp/usrp2/clock_control.cpp156
-rw-r--r--host/lib/usrp/usrp2/clock_control.hpp60
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp279
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp15
-rw-r--r--host/lib/usrp/usrp2/dboard_interface.cpp280
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp28
-rw-r--r--host/lib/usrp/usrp2/fw_common.h7
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp153
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp67
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp168
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp103
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp84
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp47
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp5
-rw-r--r--host/test/vrt_test.cpp12
52 files changed, 2908 insertions, 1566 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index d2889fe58..6334b44ff 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -25,8 +25,8 @@ ENABLE_TESTING()
SET(CPACK_PACKAGE_VERSION_MAJOR 0)
SET(CPACK_PACKAGE_VERSION_MINOR 0)
SET(CPACK_PACKAGE_VERSION_PATCH 0)
-SET(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/README)
-SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE)
+SET(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README)
+SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE)
INCLUDE(CPack) #include after setting vars
########################################################################
@@ -42,18 +42,18 @@ MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
########################################################################
# Local Include Dir
########################################################################
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
########################################################################
# Optional Compiler Flags
########################################################################
INCLUDE(CheckCXXCompilerFlag)
-FUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have)
+MACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have)
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
IF(${have})
ADD_DEFINITIONS(${flag})
ENDIF(${have})
-ENDFUNCTION(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG)
+ENDMACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG)
IF(UNIX)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL)
@@ -114,7 +114,7 @@ ADD_CUSTOM_TARGET(uninstall
# Create Pkg Config File
########################################################################
CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/uhd.pc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/uhd.pc.in
${CMAKE_CURRENT_BINARY_DIR}/uhd.pc
@ONLY)
@@ -131,7 +131,7 @@ INCLUDE(FindDoxygen)
IF(DOXYGEN_FOUND)
SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/Doxyfile.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
@ONLY)
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR_DOXYGEN}
@@ -143,8 +143,9 @@ IF(DOXYGEN_FOUND)
ENDIF(DOXYGEN_FOUND)
INSTALL(FILES
- ${CMAKE_SOURCE_DIR}/README
- ${CMAKE_SOURCE_DIR}/LICENSE
+ ${CMAKE_CURRENT_SOURCE_DIR}/README
+ ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
+ ${CMAKE_CURRENT_SOURCE_DIR}/AUTHORS
DESTINATION ${PKG_DOC_DIR}
)
diff --git a/host/README b/host/README
index cdca42cd0..cbf18dbf7 100644
--- a/host/README
+++ b/host/README
@@ -17,9 +17,54 @@ LF RX
LF TX
########################################################################
-# CMake Instructions
+# Dependencies
########################################################################
-cd uhd/host
+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 ../
@@ -28,3 +73,28 @@ 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
+
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index e971e9f6a..d49f7d182 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -86,8 +86,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
);
if (num_rx_samps == 0) continue; //wait for packets with contents
- std::cout << boost::format("Got packet: %u samples, %u secs, %u ticks")
- % num_rx_samps % md.time_spec.secs % md.time_spec.ticks << std::endl;
+ std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs")
+ % num_rx_samps % md.time_spec.secs % md.time_spec.nsecs << std::endl;
num_acc_samps += num_rx_samps;
}
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index 14b5ccd29..4cefffa24 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -17,10 +17,11 @@
INSTALL(FILES
+ convert_types.hpp
if_addrs.hpp
- smart_buffer.hpp
udp_simple.hpp
udp_zero_copy.hpp
vrt.hpp
+ zero_copy.hpp
DESTINATION ${INCLUDE_DIR}/uhd/transport
)
diff --git a/host/include/uhd/transport/convert_types.hpp b/host/include/uhd/transport/convert_types.hpp
new file mode 100644
index 000000000..a4d999240
--- /dev/null
+++ b/host/include/uhd/transport/convert_types.hpp
@@ -0,0 +1,59 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP
+#define INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/io_type.hpp>
+#include <uhd/types/otw_type.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * Convert IO samples to OWT samples.
+ *
+ * \param io_buff memory containing samples
+ * \param io_type the type of these samples
+ * \param otw_buff memory to write converted samples
+ * \param otw_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+);
+
+/*!
+ * Convert OTW samples to IO samples.
+ *
+ * \param otw_buff memory containing samples
+ * \param otw_type the type of these samples
+ * \param io_buff memory to write converted samples
+ * \param io_type the type of these samples
+ * \param num_samps the number of samples in io_buff
+ */
+UHD_API void convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+);
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP */
diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp
deleted file mode 100644
index a9bc259e9..000000000
--- a/host/include/uhd/transport/smart_buffer.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP
-#define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP
-
-#include <boost/asio/buffer.hpp>
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace uhd{ namespace transport{
-
-/*!
- * A buffer that knows how to free itself:
- *
- * This is just the smart buffer interface.
- * A transport implementation will have its own
- * internal (custom) smart buffer implementation.
- *
- * A smart buffer contains a boost asio const buffer.
- * On destruction, the buffer contents will be freed.
- */
-class smart_buffer : boost::noncopyable{
-public:
- typedef boost::shared_ptr<smart_buffer> sptr;
- virtual const boost::asio::const_buffer &get(void) const = 0;
-};
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP */
diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp
index 0441a8e74..fd1cec46e 100644
--- a/host/include/uhd/transport/udp_zero_copy.hpp
+++ b/host/include/uhd/transport/udp_zero_copy.hpp
@@ -19,24 +19,22 @@
#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP
#include <uhd/config.hpp>
-#include <uhd/transport/smart_buffer.hpp>
-#include <boost/asio/buffer.hpp>
-#include <boost/utility.hpp>
+#include <uhd/transport/zero_copy.hpp>
#include <boost/shared_ptr.hpp>
namespace uhd{ namespace transport{
/*!
* A zero copy udp transport provides an efficient way to handle data.
- * by avoiding the extra copy when recv() is called on the socket.
- * Rather, the zero copy transport gives the caller a memory reference.
+ * by avoiding the extra copy when recv() or send() is called on the socket.
+ * Rather, the zero copy transport gives the caller memory references.
* The caller informs the transport when it is finished with the reference.
*
* On linux systems, the zero copy transport can use a kernel packet ring.
* If no platform specific solution is available, make returns a boost asio
- * implementation that wraps the functionality around a standard recv() call.
+ * implementation that wraps the functionality around a standard send/recv calls.
*/
-class UHD_API udp_zero_copy : boost::noncopyable{
+class UHD_API udp_zero_copy : public zero_copy_if{
public:
typedef boost::shared_ptr<udp_zero_copy> sptr;
@@ -54,22 +52,6 @@ public:
* \param port a string representing the destination port
*/
static sptr make(const std::string &addr, const std::string &port);
-
- /*!
- * Send a single buffer.
- * Blocks until the data is sent.
- * \param buff single asio buffer
- * \return the number of bytes sent
- */
- virtual size_t send(const boost::asio::const_buffer &buff) = 0;
-
- /*!
- * Receive a buffer.
- * Blocks until data is received or a timeout occurs.
- * The memory is managed by the implementation.
- * \return a smart buffer (empty on timeout)
- */
- virtual smart_buffer::sptr recv(void) = 0;
};
}} //namespace
diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp
index 04945b347..f2f42f9eb 100644
--- a/host/include/uhd/transport/vrt.hpp
+++ b/host/include/uhd/transport/vrt.hpp
@@ -26,7 +26,7 @@ namespace uhd{ namespace transport{
namespace vrt{
- static const size_t max_header_words32 = 7;
+ static const size_t max_header_words32 = 5; //hdr+sid+tsi+tsf (no class id supported)
/*!
* Pack a vrt header from metadata.
@@ -36,6 +36,7 @@ namespace vrt{
* \param num_payload_words32 the length of the payload
* \param num_packet_words32 the length of the packet
* \param packet_count the packet count sequence number
+ * \param tick_rate ticks per second used in time conversion
*/
UHD_API void pack(
const tx_metadata_t &metadata, //input
@@ -43,7 +44,8 @@ namespace vrt{
size_t &num_header_words32, //output
size_t num_payload_words32, //input
size_t &num_packet_words32, //output
- size_t packet_count //input
+ size_t packet_count, //input
+ double tick_rate //input
);
/*!
@@ -54,6 +56,7 @@ namespace vrt{
* \param num_payload_words32 the length of the payload
* \param num_packet_words32 the length of the packet
* \param packet_count the packet count sequence number
+ * \param tick_rate ticks per second used in time conversion
*/
UHD_API void unpack(
rx_metadata_t &metadata, //output
@@ -61,7 +64,8 @@ namespace vrt{
size_t &num_header_words32, //output
size_t &num_payload_words32, //output
size_t num_packet_words32, //input
- size_t &packet_count //output
+ size_t &packet_count, //output
+ double tick_rate //input
);
} //namespace vrt
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
new file mode 100644
index 000000000..4fc1df9de
--- /dev/null
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -0,0 +1,133 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP
+#define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP
+
+#include <uhd/config.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A managed receive buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after reading.
+ */
+class UHD_API managed_recv_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<managed_recv_buffer> sptr;
+
+ /*!
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to release the buffer to the transport.
+ * After calling, the referenced memory should be considered invalid.
+ */
+ virtual void done(void) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void){
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void){
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+private:
+ /*!
+ * Get a reference to the internal const buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio const buffer
+ */
+ virtual const boost::asio::const_buffer &get(void) = 0;
+};
+
+/*!
+ * A managed send buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after writing.
+ */
+class UHD_API managed_send_buffer : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<managed_send_buffer> sptr;
+
+ /*!
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to commit the write to the transport object.
+ * After calling, the referenced memory should be considered invalid.
+ * \param num_bytes the number of bytes written into the buffer
+ */
+ virtual void done(size_t num_bytes) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void){
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void){
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+private:
+ /*!
+ * Get a reference to the internal mutable buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio mutable buffer
+ */
+ virtual const boost::asio::mutable_buffer &get(void) = 0;
+};
+
+/*!
+ * A zero-copy interface for transport objects.
+ * Provides a way to get send and receive buffers
+ * with memory managed by the transport object.
+ */
+class UHD_API zero_copy_if : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<zero_copy_if> sptr;
+
+ /*!
+ * Get a new receive buffer from this transport object.
+ */
+ virtual managed_recv_buffer::sptr get_recv_buff(void) = 0;
+
+ /*!
+ * Get a new send buffer from this transport object.
+ */
+ virtual managed_send_buffer::sptr get_send_buff(void) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP */
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 20f483bed..d93b38b50 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_UHD_TYPES_METADATA_HPP
#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
#include <uhd/types/time_spec.hpp>
namespace uhd{
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 8c8f2bc25..f06d27118 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -20,33 +20,43 @@
#include <uhd/config.hpp>
#include <boost/cstdint.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
namespace uhd{
/*!
- * A time_spec_t holds a seconds and ticks time value.
- * The temporal width of a tick depends on the device's clock rate.
- * The time_spec_t can be used when setting the time on devices
+ * A time_spec_t holds a seconds and fractional seconds time value.
+ * The time_spec_t can be used when setting the time on devices,
+ * and for dealing with time stamped samples though the metadata.
* and for controlling the start of streaming for applicable dsps.
*/
struct UHD_API time_spec_t{
+
+ //! whole seconds count
boost::uint32_t secs;
- boost::uint32_t ticks;
+
+ //! fractional seconds count in nano-seconds
+ double nsecs;
/*!
- * Create a time_spec_t from seconds and ticks.
- * \param new_secs the new seconds (default = 0)
- * \param new_ticks the new ticks (default = 0)
+ * Convert the fractional nsecs to clock ticks.
+ * \param tick_rate the number of ticks per second
+ * \return the number of ticks in this time spec
*/
- time_spec_t(boost::uint32_t new_secs = 0, boost::uint32_t new_ticks = 0);
+ boost::uint32_t get_ticks(double tick_rate) const;
/*!
- * Create a time_spec_t from boost posix time.
- * \param time fine-grained boost posix time
- * \param tick_rate the rate of ticks per second
+ * Set the fractional nsecs from clock ticks.
+ * \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)
*/
- time_spec_t(boost::posix_time::ptime time, double tick_rate);
+ time_spec_t(boost::uint32_t new_secs = 0, double new_nsecs = 0);
};
diff --git a/host/include/uhd/types/tune_result.hpp b/host/include/uhd/types/tune_result.hpp
index 31742e1af..c428a7692 100644
--- a/host/include/uhd/types/tune_result.hpp
+++ b/host/include/uhd/types/tune_result.hpp
@@ -26,15 +26,15 @@ namespace uhd{
* The tune result struct holds result of a 2-phase tuning:
* The struct hold the result of tuning the dboard as
* the target and actual intermediate frequency.
- * The struct hold the result of tuning the DDC/DUC as
+ * The struct hold the result of tuning the DSP as
* the target and actual digital converter frequency.
* It also tell us weather or not the spectrum is inverted.
*/
struct UHD_API tune_result_t{
double target_inter_freq;
double actual_inter_freq;
- double target_dxc_freq;
- double actual_dxc_freq;
+ double target_dsp_freq;
+ double actual_dsp_freq;
bool spectrum_inverted;
tune_result_t(void);
};
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index c00daaaf0..4b880308e 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -27,7 +27,7 @@ INSTALL(FILES
#### dboard headers ###
dboard_base.hpp
dboard_id.hpp
- dboard_interface.hpp
+ dboard_iface.hpp
dboard_manager.hpp
### usrp headers ###
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
index 907a7814a..2025760ee 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -24,7 +24,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/tuple/tuple.hpp>
#include <uhd/usrp/dboard_id.hpp>
-#include <uhd/usrp/dboard_interface.hpp>
+#include <uhd/usrp/dboard_iface.hpp>
namespace uhd{ namespace usrp{
@@ -35,10 +35,10 @@ namespace uhd{ namespace usrp{
class UHD_API dboard_base : boost::noncopyable{
public:
typedef boost::shared_ptr<dboard_base> sptr;
- //the constructor args consist of a subdev name and an interface
+ //the constructor args consist of a subdev name, interface, and ids
//derived classes should pass the args into the dboard_base class ctor
//but should not have to deal with the internals of the args
- typedef boost::tuple<std::string, dboard_interface::sptr, dboard_id_t, dboard_id_t> ctor_args_t;
+ typedef boost::tuple<std::string, dboard_iface::sptr, dboard_id_t, dboard_id_t> ctor_args_t;
//structors
dboard_base(ctor_args_t const&);
@@ -52,13 +52,13 @@ public:
protected:
std::string get_subdev_name(void);
- dboard_interface::sptr get_interface(void);
+ dboard_iface::sptr get_iface(void);
dboard_id_t get_rx_id(void);
dboard_id_t get_tx_id(void);
private:
std::string _subdev_name;
- dboard_interface::sptr _dboard_interface;
+ dboard_iface::sptr _dboard_iface;
dboard_id_t _rx_id, _tx_id;
};
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
new file mode 100644
index 000000000..71c7be200
--- /dev/null
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -0,0 +1,190 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_DBOARD_IFACE_HPP
+#define INCLUDED_UHD_USRP_DBOARD_IFACE_HPP
+
+#include <uhd/config.hpp>
+#include <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.
+ * This interface provides i2c, spi, gpio, atr, aux dac/adc access.
+ * Each mboard should have a specially tailored iface for its dboard.
+ */
+class UHD_API dboard_iface{
+public:
+ typedef boost::shared_ptr<dboard_iface> sptr;
+ typedef std::vector<boost::uint8_t> byte_vector_t;
+
+ //tells the host which unit to use
+ enum unit_t{
+ UNIT_RX = 'r',
+ UNIT_TX = 't'
+ };
+
+ //possible atr registers
+ enum atr_reg_t{
+ ATR_REG_IDLE = 'i',
+ ATR_REG_TX_ONLY = 't',
+ ATR_REG_RX_ONLY = 'r',
+ ATR_REG_FULL_DUPLEX = 'f'
+ };
+
+ /*!
+ * Write to an aux dac.
+ *
+ * \param unit which unit rx or tx
+ * \param which_dac the dac index 0, 1, 2, 3...
+ * \param value the value in volts
+ */
+ virtual void write_aux_dac(unit_t unit, int which_dac, float value) = 0;
+
+ /*!
+ * Read from an aux adc.
+ *
+ * \param unit which unit rx or tx
+ * \param which_adc the adc index 0, 1, 2, 3...
+ * \return the value in volts
+ */
+ virtual float read_aux_adc(unit_t unit, int which_adc) = 0;
+
+ /*!
+ * Set a daughterboard ATR register.
+ *
+ * \param unit which unit rx or tx
+ * \param reg which ATR register to set
+ * \param value 16-bits, 0=FPGA output low, 1=FPGA output high
+ */
+ virtual void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0;
+
+ /*!
+ * Set daughterboard GPIO data direction register.
+ *
+ * \param unit which unit rx or tx
+ * \param value 16-bits, 0=FPGA input, 1=FPGA output
+ */
+ virtual void set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0;
+
+ /*!
+ * Read daughterboard GPIO pin values.
+ *
+ * \param unit which unit rx or tx
+ * \return the value of the gpio unit
+ */
+ virtual boost::uint16_t read_gpio(unit_t unit) = 0;
+
+ /*!
+ * Write to an I2C peripheral.
+ *
+ * \param i2c_addr I2C bus address (7-bits)
+ * \param buf the data to write
+ */
+ virtual void write_i2c(int i2c_addr, const byte_vector_t &buf) = 0;
+
+ /*!
+ * Read from an I2C peripheral.
+ *
+ * \param i2c_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;
+
+ /*!
+ * Write data to SPI bus peripheral.
+ *
+ * \param unit which unit, rx or tx
+ * \param config configuration settings
+ * \param data the bits to write LSB first
+ * \param num_bits the number of bits in data
+ */
+ virtual void write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ ) = 0;
+
+ /*!
+ * Read and write data to SPI bus peripheral.
+ *
+ * \param unit which unit, rx or tx
+ * \param config configuration settings
+ * \param data the bits to write LSB first
+ * \param num_bits the number of bits in data
+ * \return the data that was read
+ */
+ virtual boost::uint32_t read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ ) = 0;
+
+ /*!
+ * Get the rate of a dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \return the clock rate in Hz
+ */
+ virtual double get_clock_rate(unit_t unit) = 0;
+
+ /*!
+ * Enable or disable a dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \param enb true for enabled
+ */
+ virtual void set_clock_enabled(unit_t unit, bool enb) = 0;
+};
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_DBOARD_IFACE_HPP */
diff --git a/host/include/uhd/usrp/dboard_interface.hpp b/host/include/uhd/usrp/dboard_interface.hpp
deleted file mode 100644
index b3bab131d..000000000
--- a/host/include/uhd/usrp/dboard_interface.hpp
+++ /dev/null
@@ -1,193 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#ifndef INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP
-#define INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP
-
-#include <uhd/config.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/cstdint.hpp>
-#include <vector>
-
-namespace uhd{ namespace usrp{
-
-/*!
- * The daughter board dboard_interface to be subclassed.
- * A dboard instance dboard_interfaces with the mboard though this api.
- * This dboard_interface provides i2c, spi, gpio, atr, aux dac/adc access.
- * Each mboard should have a specially tailored dboard dboard_interface.
- */
-class UHD_API dboard_interface{
-public:
- typedef boost::shared_ptr<dboard_interface> sptr;
- typedef std::vector<boost::uint8_t> byte_vector_t;
-
- //tells the host which unit to use
- enum unit_type_t{
- UNIT_TYPE_RX = 'r',
- UNIT_TYPE_TX = 't'
- };
-
- //tells the host which device to use
- enum spi_dev_t{
- SPI_DEV_RX = 'r',
- SPI_DEV_TX = 't'
- };
-
- //args for spi format
- enum spi_edge_t{
- SPI_EDGE_RISE = 'r',
- SPI_EDGE_FALL = 'f'
- };
-
- //tell the host which gpio bank
- enum gpio_bank_t{
- GPIO_BANK_RX = 'r',
- GPIO_BANK_TX = 't'
- };
-
- //possible atr registers
- enum atr_reg_t{
- ATR_REG_IDLE = 'i',
- ATR_REG_TX_ONLY = 't',
- ATR_REG_RX_ONLY = 'r',
- ATR_REG_FULL_DUPLEX = 'f'
- };
-
- //structors
- dboard_interface(void);
- virtual ~dboard_interface(void);
-
- /*!
- * Write to an aux dac.
- * \param unit which unit rx or tx
- * \param which_dac the dac index 0, 1, 2, 3...
- * \param value the value to write
- */
- virtual void write_aux_dac(unit_type_t unit, int which_dac, int value) = 0;
-
- /*!
- * Read from an aux adc.
- * \param unit which unit rx or tx
- * \param which_adc the adc index 0, 1, 2, 3...
- * \return the value that was read
- */
- virtual int read_aux_adc(unit_type_t unit, int which_adc) = 0;
-
- /*!
- * Set a daughterboard ATR register.
- *
- * \param bank GPIO_TX_BANK or GPIO_RX_BANK
- * \param reg which ATR register to set
- * \param value 16-bits, 0=FPGA output low, 1=FPGA output high
- */
- virtual void set_atr_reg(gpio_bank_t bank, atr_reg_t reg, boost::uint16_t value) = 0;
-
- /*!
- * Set daughterboard GPIO data direction register.
- *
- * \param bank GPIO_TX_BANK or GPIO_RX_BANK
- * \param value 16-bits, 0=FPGA input, 1=FPGA output
- */
- virtual void set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value) = 0;
-
- /*!
- * Read daughterboard GPIO pin values
- *
- * \param bank GPIO_TX_BANK or GPIO_RX_BANK
- * \return the value of the gpio bank
- */
- virtual boost::uint16_t read_gpio(gpio_bank_t bank) = 0;
-
- /*!
- * \brief Write to I2C peripheral
- * \param i2c_addr I2C bus address (7-bits)
- * \param buf the data to write
- */
- virtual void write_i2c(int i2c_addr, const byte_vector_t &buf) = 0;
-
- /*!
- * \brief Read from I2C peripheral
- * \param i2c_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;
-
- /*!
- * \brief Write data to SPI bus peripheral.
- *
- * \param dev which spi device
- * \param edge args for format
- * \param buf the data to write
- */
- void write_spi(spi_dev_t dev, spi_edge_t edge, const byte_vector_t &buf);
-
- /*!
- * \brief Read data to SPI bus peripheral.
- *
- * \param dev which spi device
- * \param edge args for format
- * \param num_bytes number of bytes to read
- * \return the data that was read
- */
- byte_vector_t read_spi(spi_dev_t dev, spi_edge_t edge, size_t num_bytes);
-
- /*!
- * \brief Read and write data to SPI bus peripheral.
- * The data read back will be the same length as the input buffer.
- *
- * \param dev which spi device
- * \param edge args for format
- * \param buf the data to write
- * \return the data that was read
- */
- byte_vector_t read_write_spi(spi_dev_t dev, spi_edge_t edge, const byte_vector_t &buf);
-
- /*!
- * \brief Get the rate of the rx dboard clock.
- * \return the clock rate
- */
- virtual double get_rx_clock_rate(void) = 0;
-
- /*!
- * \brief Get the rate of the tx dboard clock.
- * \return the clock rate
- */
- virtual double get_tx_clock_rate(void) = 0;
-
-private:
- /*!
- * \brief Read and write data to SPI bus peripheral.
- *
- * \param dev which spi device
- * \param edge args for format
- * \param buf the data to write
- * \param readback false for write only
- * \return the data that was read
- */
- virtual byte_vector_t transact_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- const byte_vector_t &buf,
- bool readback
- ) = 0;
-};
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_DBOARD_INTERFACE_HPP */
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index ed8ee73ef..6de64b02d 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -59,16 +59,16 @@ public:
* Make a new dboard manager.
* \param rx_dboard_id the id of the rx dboard
* \param tx_dboard_id the id of the tx dboard
- * \param interface the custom dboard interface
+ * \param iface the custom dboard interface
* \return an sptr to the new dboard manager
*/
static sptr make(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
+ dboard_iface::sptr iface
);
- //dboard_interface
+ //dboard manager interface
virtual prop_names_t get_rx_subdev_names(void) = 0;
virtual prop_names_t get_tx_subdev_names(void) = 0;
virtual wax::obj get_rx_subdev(const std::string &subdev_name) = 0;
diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp
index 55c11b822..7ff454472 100644
--- a/host/include/uhd/usrp/mboard_props.hpp
+++ b/host/include/uhd/usrp/mboard_props.hpp
@@ -31,7 +31,6 @@ namespace uhd{ namespace usrp{
enum mboard_prop_t{
MBOARD_PROP_NAME = 'n', //ro, std::string
MBOARD_PROP_OTHERS = 'o', //ro, prop_names_t
- MBOARD_PROP_CLOCK_RATE = 'c', //ro, double
MBOARD_PROP_RX_DSP = 'd', //ro, wax::obj
MBOARD_PROP_RX_DSP_NAMES = 'D', //ro, prop_names_t
MBOARD_PROP_TX_DSP = 'u', //ro, wax::obj
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index 6f74a406b..c4e0338f7 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -52,7 +52,6 @@ public:
virtual void set_time_next_pps(const time_spec_t &time_spec) = 0;
virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0;
virtual void set_clock_config(const clock_config_t &clock_config) = 0;
- virtual double get_clock_rate(void) = 0;
/*******************************************************************
* RX methods
diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp
index d35793c6b..cd6b14ef5 100644
--- a/host/include/uhd/usrp/subdev_props.hpp
+++ b/host/include/uhd/usrp/subdev_props.hpp
@@ -35,7 +35,7 @@ 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
+ //SUBDEV_PROP_ENABLED = 'e', //rw, bool //---> dont need, we have atr
SUBDEV_PROP_QUADRATURE = 'q', //ro, bool
SUBDEV_PROP_IQ_SWAPPED = 'i', //ro, bool
SUBDEV_PROP_SPECTRUM_INVERTED = 's', //ro, bool
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
index 6635c8a4a..8fe9cde82 100644
--- a/host/include/uhd/utils/algorithm.hpp
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -49,12 +49,16 @@ namespace std{
return has(iterable.begin(), iterable.end(), elem);
}
- template<typename T> T signum(T n){
+ template<class T> T signum(T n){
if (n < 0) return -1;
if (n > 0) return 1;
return 0;
}
+ template<class T> T clip(T val, T minVal, T maxVal){
+ return std::min(std::max(val, minVal), maxVal);
+ }
+
}//namespace std
#endif /* INCLUDED_UHD_UTILS_ALGORITHM_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 3dfd54312..dfcb88ec9 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -15,6 +15,33 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+
+########################################################################
+# Setup Python
+########################################################################
+INCLUDE(FindPythonInterp)
+
+MACRO(PYTHON_CHECK_MODULE module have)
+ MESSAGE(STATUS "Checking for python module ${module}")
+ EXECUTE_PROCESS(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import ${module}"
+ RESULT_VARIABLE ${have}
+ )
+ IF(${have} EQUAL 0)
+ MESSAGE(STATUS "Checking for python module ${module} - found")
+ SET(${have} TRUE)
+ ELSE(${have} EQUAL 0)
+ MESSAGE(STATUS "Checking for python module ${module} - not found")
+ SET(${have} FALSE)
+ ENDIF(${have} EQUAL 0)
+ENDMACRO(PYTHON_CHECK_MODULE)
+
+PYTHON_CHECK_MODULE("Cheetah" HAVE_PYTHON_MODULE_CHEETAH)
+
+IF(NOT HAVE_PYTHON_MODULE_CHEETAH)
+ MESSAGE(FATAL_ERROR "Error: Cheetah Templates needed for pre-build generation.")
+ENDIF(NOT HAVE_PYTHON_MODULE_CHEETAH)
+
########################################################################
# Create a list of libuhd sources
########################################################################
@@ -24,20 +51,63 @@ SET(libuhd_sources
load_modules.cpp
types.cpp
wax.cpp
+ transport/convert_types.cpp
transport/if_addrs.cpp
transport/udp_simple.cpp
- transport/vrt.cpp
usrp/dboard/db_basic_and_lf.cpp
+ usrp/dboard/db_rfx.cpp
usrp/dboard_base.cpp
- usrp/dboard_interface.cpp
usrp/simple_usrp.cpp
usrp/dboard_manager.cpp
usrp/tune_helper.cpp
+)
+
+########################################################################
+# Generate Files
+########################################################################
+MACRO(UHD_PYTHON_GEN_SOURCE_FILE pyfile outfile)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${outfile} DEPENDS ${pyfile}
+ COMMAND ${PYTHON_EXECUTABLE} ${pyfile} ${outfile}
+ COMMENT "Calling ${pyfile} to generate ${outfile}"
+ )
+ LIST(APPEND libuhd_sources ${outfile})
+ENDMACRO(UHD_PYTHON_GEN_SOURCE_FILE)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/transport/gen_vrt.py
+ ${CMAKE_CURRENT_BINARY_DIR}/transport/vrt.cpp
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_adf4360_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/adf4360_regs.hpp
+)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad9510_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9510_regs.hpp
+)
+
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_ad9777_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad9777_regs.hpp
+)
+
+
+########################################################################
+# Add usrp2 sources
+########################################################################
+LIST(APPEND libuhd_sources
+ usrp/usrp2/clock_control.cpp
usrp/usrp2/dboard_impl.cpp
- usrp/usrp2/dboard_interface.cpp
+ usrp/usrp2/dboard_iface.cpp
usrp/usrp2/dsp_impl.cpp
usrp/usrp2/io_impl.cpp
usrp/usrp2/mboard_impl.cpp
+ usrp/usrp2/usrp2_iface.cpp
usrp/usrp2/usrp2_impl.cpp
)
diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py
new file mode 100755
index 000000000..90230b8f9
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py
@@ -0,0 +1,224 @@
+#!/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
+# 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,
+# 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.
+
+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)
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_TMPL="""\
+########################################################################
+## serial control port config
+########################################################################
+long_instruction 0[4] 1 8bits, 16bits
+soft_reset 0[5] 0
+lsb_first 0[6] 0 msb, lsb
+sdo_inactive 0[7] 0 active, inactive
+########################################################################
+## pll settings
+########################################################################
+acounter 4[0:5] 0
+bcounter_msb 5[0:4] 0
+bcounter_lsb 6[0:7] 0
+lor_enable 7[2] 0 enb, dis
+lor_ildd 7[5:6] 0 3cyc, 6cyc, 12cyc, 24cyc
+charge_pump_mode 8[0:1] 0 3state, pump_up, pump_down, normal
+pll_mux_control 8[2:5] 0 off, dld_high, ndiv, dld_low, rdiv, ald_nchan, acounter, prescaler, pfd_up, pfd_down, lor_high, 3state, ald_pchan, lor_lol_high, lor_lol_low, lor_low
+pfd_polarity 8[6] 0 neg, pos
+reset_all_counters 9[0] 0
+ncounter_reset 9[1] 0
+rcounter_reset 9[2] 0
+cp_current_setting 9[4:6] 0 0_60ma, 1_2ma, 1_8ma, 2_4ma, 3_0ma, 3_6ma, 4_2ma, 4_8ma
+pll_power_down A[0:1] 0 normal=0, async_pd=1, sync_pd=3
+prescaler_value A[2:4] 0 div1, div2, 2_3, 4_5, 8_9, 16_17, 32_33, div3
+b_counter_bypass A[6] 0
+ref_counter_msb B[0:5] 0
+ref_counter_lsb C[0:7] 0
+antibacklash_pw D[0:1] 0 1_3ns, 2_9ns, 6_0ns
+dld_window D[5] 0 9_5ns, 3_5ns
+lock_detect_disable D[6] 0 enb, dis
+########################################################################
+## fine delay adjust
+########################################################################
+#for $i, $o in ((5, 0), (6, 4))
+delay_control_out$i $hex(0x34+$o)[0] 0
+ramp_current_out$i $hex(0x35+$o)[0:2] 0 200ua, 400ua, 600ua, 800ua, 1000ua, 1200ua, 1400ua, 1600ua
+ramp_capacitor_out$i $hex(0x35+$o)[3:5] 0 4caps=0, 3caps=1, 2caps=3, 1cap=7
+delay_fine_adjust_out$i $hex(0x36+$o)[1:5] 0
+#end for
+########################################################################
+## outputs
+########################################################################
+#for $i, $o in ((0, 0), (1, 1), (2, 2), (3, 3))
+power_down_lvpecl_out$i $hex(0x3C+$o)[0:1] 0 normal, test, safe_pd, total_pd
+output_level_lvpecl_out$i $hex(0x3C+$o)[2:3] 2 500mv, 340mv, 810mv, 660mv
+#end for
+#for $i, $o in ((4, 0), (5, 1), (6, 2), (7, 3))
+power_down_lvds_cmos_out$i $hex(0x40+$o)[0] 0
+output_level_lvds_out$i $hex(0x40+$o)[1:2] 1 1_75ma, 3_5ma, 5_25ma, 7ma
+lvds_cmos_select_out$i $hex(0x40+$o)[3] 1 lvds, cmos
+inverted_cmos_driver_out$i $hex(0x40+$o)[4] 0 dis, enb
+#end for
+clock_select 45[0] 1 clk2_drives, clk1_drives
+clk1_power_down 45[1] 0
+clk2_power_down 45[2] 0
+prescaler_clock_pd 45[3] 0
+refin_power_down 45[4] 0
+all_clock_inputs_pd 45[5] 0
+########################################################################
+## dividers
+########################################################################
+#for $i, $o in ((0, 0), (1, 2), (2, 4), (3, 6), (4, 8), (5, 10), (6, 12), (7, 14))
+divider_high_cycles_out$i $hex(0x48+$o)[0:3] 0
+divider_low_cycles_out$i $hex(0x48+$o)[4:7] 0
+phase_offset_out$i $hex(0x49+$o)[0:3] 0
+start_out$i $hex(0x49+$o)[4] 0
+force_out$i $hex(0x49+$o)[5] 0
+nosync_out$i $hex(0x49+$o)[6] 0
+bypass_divider_out$i $hex(0x49+$o)[7] 0
+#end for
+########################################################################
+## function
+########################################################################
+sync_detect_enable 58[0] 0 dis, enb
+sync_select 58[1] 0 1_to_0_5, 0_5_to_1
+soft_sync 58[2] 0
+dist_power_down 58[3] 0
+sync_power_down 58[4] 0
+function_pin_select 58[5:6] 0 resetb, syncb, test, pdb
+update_registers 5A[0] 0
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_AD9510_REGS_HPP
+\#define INCLUDED_AD9510_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct ad9510_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
+
+ ad9510_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ boost::uint8_t get_reg(boost::uint16_t addr){
+ boost::uint8_t reg = 0;
+ switch(addr){
+ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs)))
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+ }
+
+ boost::uint32_t get_write_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | get_reg(addr);
+ }
+
+ boost::uint32_t get_read_reg(boost::uint16_t addr){
+ return (boost::uint32_t(addr) << 8) | (1 << 15);
+ }
+
+};
+
+\#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
new file mode 100644
index 000000000..6077b61b6
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py
@@ -0,0 +1,202 @@
+#!/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
+# 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,
+# 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.
+
+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)
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+sdio_bidirectional 0[7] 0 input, io
+lsb_msb_first 0[6] 0 msb, lsb
+soft_reset 0[5] 0
+sleep_mode 0[4] 0
+power_down_mode 0[3] 0
+x_1r_2r_mode 0[2] 0 2r, 1r
+pll_lock_indicator 0[1] 0
+########################################################################
+## address 1
+########################################################################
+filter_interp_rate 1[6:7] 0 1x, 2x, 4x, 8x
+modulation_mode 1[4:5] 0 none, fs_2, fs_4, fs_8
+zero_stuff_mode 1[3] 0
+mix_mode 1[2] 1 complex, real
+modulation_form 1[1] 0 e_minus_jwt, e_plus_jwt
+data_clk_pll_lock_sel 1[0] 0 pll_lock, data_clk
+########################################################################
+## address 2
+########################################################################
+signed_input_data 2[7] 0 signed, unsigned
+two_port_mode 2[6] 0 two_port, one_port
+dataclk_driver_strength 2[5] 0 weak, strong
+dataclk_invert 2[4] 0
+oneportclk_invert 2[2] 0
+iqsel_invert 2[1] 0
+iq_first 2[0] 0 i_first, q_first
+########################################################################
+## address 3
+########################################################################
+data_rate_clock_output 3[7] 0 pll_lock, spi_sdo
+pll_divide_ratio 3[0:1] 0 div1, div2, div4, div8
+########################################################################
+## address 4
+########################################################################
+pll_state 4[7] 0 off, on
+auto_cp_control 4[6] 0 dis, enb
+pll_cp_control 4[0:2] 0 50ua=0, 100ua=1, 200ua=2, 400ua=3, 800ua=7
+########################################################################
+## address 5 and 9
+########################################################################
+idac_fine_gain_adjust 5[0:7] 0
+qdac_fine_gain_adjust 9[0:7] 0
+########################################################################
+## address 6 and A
+########################################################################
+idac_coarse_gain_adjust 6[0:3] 0
+qdac_coarse_gain_adjust A[0:3] 0
+########################################################################
+## address 7, 8 and B, C
+########################################################################
+idac_offset_adjust_msb 7[0:7] 0
+idac_offset_adjust_lsb 8[0:1] 0
+idac_ioffset_direction 8[7] 0 out_a, out_b
+qdac_offset_adjust_msb B[0:7] 0
+qdac_offset_adjust_lsb C[0:1] 0
+qdac_ioffset_direction C[7] 0 out_a, out_b
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_AD9777_REGS_HPP
+\#define INCLUDED_AD9777_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct ad9777_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
+
+ ad9777_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ boost::uint8_t get_reg(boost::uint8_t addr){
+ boost::uint8_t reg = 0;
+ switch(addr){
+ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs)))
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+ }
+
+ boost::uint16_t get_write_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | get_reg(addr);
+ }
+
+ boost::uint16_t get_read_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | (1 << 7);
+ }
+};
+
+\#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
new file mode 100755
index 000000000..bcad1ffd3
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py
@@ -0,0 +1,173 @@
+#!/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
+# 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,
+# 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.
+
+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)
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+core_power_level 0[2:3] 0 5ma, 10ma, 15ma, 20ma
+counter_operation 0[4] 0 normal, reset
+muxout_control 0[5:7] 0 3state, dld, ndiv, dvdd, rdiv, nchan_od_ld, sdo, dgnd
+phase_detector_polarity 0[8] 0 neg, pos
+charge_pump_output 0[9] 0 normal, 3state
+cp_gain_0 0[10] 0 set1, set2
+mute_till_ld 0[11] 0 dis, enb
+output_power_level 0[12:13] 0 3_5ma, 5_0ma, 7_5ma, 11_0ma
+#set $current_setting_enums = ', '.join(map(lambda x: x+"ma", "0_31 0_62 0_93 1_25 1_56 1_87 2_18 2_50".split()))
+current_setting1 0[14:16] 0 $current_setting_enums
+current_setting2 0[17:19] 0 $current_setting_enums
+power_down 0[20:21] 0 normal_op=0, async_pd=1, sync_pd=3
+prescaler_value 0[22:23] 0 8_9, 16_17, 32_33
+########################################################################
+## address 2
+########################################################################
+a_counter 2[2:6] 0
+b_counter 2[8:20] 0
+cp_gain_1 2[21] 0 set1, set2
+divide_by_2_output 2[22] 0 fund, div2
+divide_by_2_prescaler 2[23] 0 fund, div2
+########################################################################
+## address 1
+########################################################################
+r_counter 1[2:15] 0
+ablpw 1[16:17] 0 3_0ns, 1_3ns, 6_0ns
+lock_detect_precision 1[18] 0 3cycles, 5cycles
+test_mode_bit 1[19] 0
+band_select_clock_div 1[20:21] 0 1, 2, 4, 8
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_ADF4360_REGS_HPP
+\#define INCLUDED_ADF4360_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct adf4360_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
+
+ adf4360_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ enum addr_t{
+ ADDR_CONTROL = 0,
+ ADDR_NCOUNTER = 2,
+ ADDR_RCOUNTER = 1
+ };
+
+ boost::uint32_t get_reg(addr_t addr){
+ boost::uint32_t reg = addr & 0x3;
+ switch(addr){
+ #for $addr in (0, 1, 2)
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+ }
+};
+
+\#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/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp
new file mode 100644
index 000000000..2a6854f50
--- /dev/null
+++ b/host/lib/transport/convert_types.cpp
@@ -0,0 +1,144 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/transport/convert_types.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/asio.hpp> //endianness conversion
+#include <boost/cstdint.hpp>
+
+using namespace uhd;
+
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+typedef std::complex<float> fc32_t;
+
+static const float shorts_per_float = float(1 << 15);
+static const float floats_per_short = float(1.0/shorts_per_float);
+
+#define unrolled_loop(__inst, __len){ \
+ size_t __i = 0; \
+ for(; __i < (__len & ~0x3); __i+= 4){ \
+ __inst(__i+0); __inst(__i+1); \
+ __inst(__i+2); __inst(__i+3); \
+ } \
+ for(; __i < __len; __i++){ \
+ __inst(__i); \
+ } \
+}
+
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
+static inline void host_floats_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const fc32_t *host_floats,
+ size_t num_samps
+){
+ #define host_floats_to_usrp2_items_i(i){ \
+ boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
+ boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
+ usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
+ }
+ unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
+}
+
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_floats_i(i){ \
+ boost::uint32_t item = ntohl(usrp2_items[i]); \
+ boost::int16_t real = boost::uint16_t(item >> 16); \
+ boost::int16_t imag = boost::uint16_t(item >> 0); \
+ host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
+ }
+ unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
+}
+
+static inline void host_items_to_usrp2_items(
+ boost::uint32_t *usrp2_items,
+ const boost::uint32_t *host_items,
+ size_t num_samps
+){
+ #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(host_items_to_usrp2_items_i, num_samps);
+ }
+}
+
+static inline void usrp2_items_to_host_items(
+ boost::uint32_t *host_items,
+ const boost::uint32_t *usrp2_items,
+ size_t num_samps
+){
+ #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
+ }
+ else{
+ unrolled_loop(usrp2_items_to_host_items_i, num_samps);
+ }
+}
+
+void transport::convert_io_type_to_otw_type(
+ const void *io_buff, const io_type_t &io_type,
+ void *otw_buff, const otw_type_t &otw_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps);
+ break;
+ case io_type_t::COMPLEX_INT16:
+ host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps);
+ break;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
+
+void transport::convert_otw_type_to_io_type(
+ const void *otw_buff, const otw_type_t &otw_type,
+ void *io_buff, const io_type_t &io_type,
+ size_t num_samps
+){
+ //all we handle for now:
+ ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN);
+
+ switch(io_type.tid){
+ case io_type_t::COMPLEX_FLOAT32:
+ usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ break;
+ case io_type_t::COMPLEX_INT16:
+ usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps);
+ break;
+ default:
+ throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid));
+ }
+}
diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py
index 918de3ad7..38a394dee 100755
--- a/host/lib/transport/gen_vrt.py
+++ b/host/lib/transport/gen_vrt.py
@@ -54,7 +54,8 @@ void vrt::pack(
size_t &num_header_words32, //output
size_t num_payload_words32, //input
size_t &num_packet_words32, //output
- size_t packet_count //input
+ size_t packet_count, //input
+ double tick_rate //input
){
boost::uint32_t vrt_hdr_flags;
@@ -91,7 +92,7 @@ void vrt::pack(
#if $pred & $tsf_p
header_buff[$num_header_words] = htonl(0);
#set $num_header_words += 1
- header_buff[$num_header_words] = htonl(metadata.time_spec.ticks);
+ header_buff[$num_header_words] = htonl(metadata.time_spec.get_ticks(tick_rate));
#set $num_header_words += 1
#set $flags |= (0x1 << 20);
#end if
@@ -127,7 +128,8 @@ void vrt::unpack(
size_t &num_header_words32, //output
size_t &num_payload_words32, //output
size_t num_packet_words32, //input
- size_t &packet_count //output
+ size_t &packet_count, //output
+ double tick_rate //input
){
//clear the metadata
metadata = rx_metadata_t();
@@ -180,7 +182,7 @@ void vrt::unpack(
#set $set_has_time_spec = True
#end if
#set $num_header_words += 1
- metadata.time_spec.ticks = ntohl(header_buff[$num_header_words]);
+ metadata.time_spec.set_ticks(ntohl(header_buff[$num_header_words]), tick_rate);
#set $num_header_words += 1
#end if
########## Trailer ##########
@@ -198,9 +200,15 @@ void vrt::unpack(
}
"""
-from Cheetah import Template
-def parse_str(_tmpl_text, **kwargs): return str(Template.Template(_tmpl_text, kwargs))
+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)
if __name__ == '__main__':
- from Cheetah import Template
- print parse_str(TMPL_TEXT, file=__file__)
+ safe_makedirs(os.path.dirname(sys.argv[1]))
+ open(sys.argv[1], 'w').write(parse_tmpl(TMPL_TEXT, file=__file__))
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index 1fc8ce14a..7e643abad 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -25,39 +25,74 @@
using namespace uhd::transport;
/***********************************************************************
- * Smart buffer implementation for udp zerocopy none
- *
- * This smart buffer implemention houses a const buffer.
- * When the smart buffer is deleted, the buffer is freed.
- * The memory in the const buffer is allocated with new [],
- * and so the destructor frees the buffer with delete [].
+ * Managed receive buffer implementation for udp zero-copy asio:
+ * Frees the memory held by the const buffer on done.
**********************************************************************/
-class smart_buffer_impl : public smart_buffer{
+class managed_recv_buffer_impl : public managed_recv_buffer{
public:
- smart_buffer_impl(const boost::asio::const_buffer &buff){
- _buff = buff;
+ managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){
+ _done = false;
}
- ~smart_buffer_impl(void){
+ ~managed_recv_buffer_impl(void){
+ if (not _done) this->done();
+ }
+
+ void done(void){
+ _done = true;
delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff);
}
- const boost::asio::const_buffer &get(void) const{
+private:
+ const boost::asio::const_buffer &get(void){
return _buff;
}
+ const boost::asio::const_buffer _buff;
+ bool _done;
+};
+
+/***********************************************************************
+ * Managed send buffer implementation for udp zero-copy asio:
+ * Sends and frees the memory held by the mutable buffer on done.
+ **********************************************************************/
+class managed_send_buffer_impl : public managed_send_buffer{
+public:
+ managed_send_buffer_impl(
+ const boost::asio::mutable_buffer &buff,
+ boost::asio::ip::udp::socket *socket
+ ) : _buff(buff){
+ _done = false;
+ _socket = socket;
+ }
+
+ ~managed_send_buffer_impl(void){
+ if (not _done) this->done(0);
+ }
+
+ void done(size_t num_bytes){
+ _done = true;
+ boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff);
+ _socket->send(boost::asio::buffer(mem, num_bytes));
+ delete [] mem;
+ }
+
private:
- boost::asio::const_buffer _buff;
+ const boost::asio::mutable_buffer &get(void){
+ return _buff;
+ }
+
+ const boost::asio::mutable_buffer _buff;
+ boost::asio::ip::udp::socket *_socket;
+ bool _done;
};
/***********************************************************************
- * UDP zero copy implementation class
- *
- * This is the portable zero copy implementation for systems
- * where a faster, platform specific solution is not available.
- *
- * It uses boost asio udp sockets and the standard recv() class,
- * and in-fact, is not actually doing a zero-copy implementation.
+ * Zero Copy UDP implementation with ASIO:
+ * This is the portable zero copy implementation for systems
+ * where a faster, platform specific solution is not available.
+ * However, it is not a true zero copy implementation as each
+ * send and recv requires a copy operation to/from userspace.
**********************************************************************/
class udp_zero_copy_impl : public udp_zero_copy{
public:
@@ -66,8 +101,8 @@ public:
~udp_zero_copy_impl(void);
//send/recv
- size_t send(const boost::asio::const_buffer &buff);
- smart_buffer::sptr recv(void);
+ managed_recv_buffer::sptr get_recv_buff(void);
+ managed_send_buffer::sptr get_send_buff(void);
private:
boost::asio::ip::udp::socket *_socket;
@@ -107,31 +142,32 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){
delete _socket;
}
-size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){
- return _socket->send(boost::asio::buffer(buff));
-}
-
-smart_buffer::sptr udp_zero_copy_impl::recv(void){
- size_t available = 0;
-
+managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){
//implement timeout through polling and sleeping
+ size_t available = 0;
boost::asio::deadline_timer timer(_socket->get_io_service());
timer.expires_from_now(boost::posix_time::milliseconds(100));
while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
- //allocate memory and create buffer
- boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];
- boost::asio::mutable_buffer buff(buff_mem, available);
-
//receive only if data is available
+ boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)];
if (available){
- _socket->receive(boost::asio::buffer(buff));
+ available = _socket->receive(boost::asio::buffer(buff_mem, available));
}
- //create a new smart buffer to house the data
- return smart_buffer::sptr(new smart_buffer_impl(buff));
+ //create a new managed buffer to house the data
+ return managed_recv_buffer::sptr(
+ new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available))
+ );
+}
+
+managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){
+ boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)];
+ return managed_send_buffer::sptr(
+ new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket)
+ );
}
size_t udp_zero_copy_impl::get_recv_buff_size(void){
diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp
deleted file mode 100644
index bebca5db9..000000000
--- a/host/lib/transport/vrt.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-
-
-
-/***********************************************************************
- * This file was generated by ./gen_vrt.py on Fri Mar 26 15:33:00 2010
- **********************************************************************/
-
-#include <uhd/transport/vrt.hpp>
-#include <boost/asio.hpp> //endianness conversion
-#include <stdexcept>
-
-using namespace uhd;
-using namespace uhd::transport;
-
-void vrt::pack(
- const tx_metadata_t &metadata, //input
- boost::uint32_t *header_buff, //output
- size_t &num_header_words32, //output
- size_t num_payload_words32, //input
- size_t &num_packet_words32, //output
- size_t packet_count //input
-){
- boost::uint32_t vrt_hdr_flags;
-
- boost::uint8_t pred = 0;
- if (metadata.has_stream_id) pred |= 0x1;
- if (metadata.has_time_spec) pred |= 0xc;
-
- switch(pred){
- case 0:
- num_header_words32 = 1;
- num_packet_words32 = 1 + num_payload_words32;
- vrt_hdr_flags = 0x0;
- break;
- case 1:
- header_buff[1] = htonl(metadata.stream_id);
- num_header_words32 = 2;
- num_packet_words32 = 2 + num_payload_words32;
- vrt_hdr_flags = 0x10000000;
- break;
- case 2:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- num_header_words32 = 3;
- num_packet_words32 = 3 + num_payload_words32;
- vrt_hdr_flags = 0x8000000;
- break;
- case 3:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- num_header_words32 = 4;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0x18000000;
- break;
- case 4:
- header_buff[1] = htonl(metadata.time_spec.secs);
- num_header_words32 = 2;
- num_packet_words32 = 2 + num_payload_words32;
- vrt_hdr_flags = 0xc00000;
- break;
- case 5:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(metadata.time_spec.secs);
- num_header_words32 = 3;
- num_packet_words32 = 3 + num_payload_words32;
- vrt_hdr_flags = 0x10c00000;
- break;
- case 6:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.secs);
- num_header_words32 = 4;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0x8c00000;
- break;
- case 7:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.secs);
- num_header_words32 = 5;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x18c00000;
- break;
- case 8:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 3;
- num_packet_words32 = 3 + num_payload_words32;
- vrt_hdr_flags = 0x100000;
- break;
- case 9:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 4;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0x10100000;
- break;
- case 10:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 5;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x8100000;
- break;
- case 11:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(0);
- header_buff[5] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 6;
- num_packet_words32 = 6 + num_payload_words32;
- vrt_hdr_flags = 0x18100000;
- break;
- case 12:
- header_buff[1] = htonl(metadata.time_spec.secs);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 4;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0xd00000;
- break;
- case 13:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(metadata.time_spec.secs);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 5;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x10d00000;
- break;
- case 14:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.secs);
- header_buff[4] = htonl(0);
- header_buff[5] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 6;
- num_packet_words32 = 6 + num_payload_words32;
- vrt_hdr_flags = 0x8d00000;
- break;
- case 15:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.secs);
- header_buff[5] = htonl(0);
- header_buff[6] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 7;
- num_packet_words32 = 7 + num_payload_words32;
- vrt_hdr_flags = 0x18d00000;
- break;
- case 16:
- num_header_words32 = 1;
- num_packet_words32 = 2 + num_payload_words32;
- vrt_hdr_flags = 0x4000000;
- break;
- case 17:
- header_buff[1] = htonl(metadata.stream_id);
- num_header_words32 = 2;
- num_packet_words32 = 3 + num_payload_words32;
- vrt_hdr_flags = 0x14000000;
- break;
- case 18:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- num_header_words32 = 3;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0xc000000;
- break;
- case 19:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- num_header_words32 = 4;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x1c000000;
- break;
- case 20:
- header_buff[1] = htonl(metadata.time_spec.secs);
- num_header_words32 = 2;
- num_packet_words32 = 3 + num_payload_words32;
- vrt_hdr_flags = 0x4c00000;
- break;
- case 21:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(metadata.time_spec.secs);
- num_header_words32 = 3;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0x14c00000;
- break;
- case 22:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.secs);
- num_header_words32 = 4;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0xcc00000;
- break;
- case 23:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.secs);
- num_header_words32 = 5;
- num_packet_words32 = 6 + num_payload_words32;
- vrt_hdr_flags = 0x1cc00000;
- break;
- case 24:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 3;
- num_packet_words32 = 4 + num_payload_words32;
- vrt_hdr_flags = 0x4100000;
- break;
- case 25:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 4;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x14100000;
- break;
- case 26:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 5;
- num_packet_words32 = 6 + num_payload_words32;
- vrt_hdr_flags = 0xc100000;
- break;
- case 27:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(0);
- header_buff[5] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 6;
- num_packet_words32 = 7 + num_payload_words32;
- vrt_hdr_flags = 0x1c100000;
- break;
- case 28:
- header_buff[1] = htonl(metadata.time_spec.secs);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 4;
- num_packet_words32 = 5 + num_payload_words32;
- vrt_hdr_flags = 0x4d00000;
- break;
- case 29:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(metadata.time_spec.secs);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 5;
- num_packet_words32 = 6 + num_payload_words32;
- vrt_hdr_flags = 0x14d00000;
- break;
- case 30:
- header_buff[1] = htonl(0);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(metadata.time_spec.secs);
- header_buff[4] = htonl(0);
- header_buff[5] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 6;
- num_packet_words32 = 7 + num_payload_words32;
- vrt_hdr_flags = 0xcd00000;
- break;
- case 31:
- header_buff[1] = htonl(metadata.stream_id);
- header_buff[2] = htonl(0);
- header_buff[3] = htonl(0);
- header_buff[4] = htonl(metadata.time_spec.secs);
- header_buff[5] = htonl(0);
- header_buff[6] = htonl(metadata.time_spec.ticks);
- num_header_words32 = 7;
- num_packet_words32 = 8 + num_payload_words32;
- vrt_hdr_flags = 0x1cd00000;
- break;
- }
-
- //set the burst flags
- if (metadata.start_of_burst) vrt_hdr_flags |= 0x2000000;
- if (metadata.end_of_burst) vrt_hdr_flags |= 0x1000000;
-
- //fill in complete header word
- header_buff[0] = htonl(vrt_hdr_flags |
- ((packet_count & 0xf) << 16) |
- (num_packet_words32 & 0xffff)
- );
-}
-
-void vrt::unpack(
- rx_metadata_t &metadata, //output
- const boost::uint32_t *header_buff, //input
- size_t &num_header_words32, //output
- size_t &num_payload_words32, //output
- size_t num_packet_words32, //input
- size_t &packet_count //output
-){
- //clear the metadata
- metadata = rx_metadata_t();
-
- //extract vrt header
- boost::uint32_t vrt_hdr_word = ntohl(header_buff[0]);
- size_t packet_words32 = vrt_hdr_word & 0xffff;
- packet_count = (vrt_hdr_word >> 16) & 0xf;
-
- //failure cases
- if (packet_words32 == 0 or num_packet_words32 < packet_words32)
- throw std::runtime_error("bad vrt header or packet fragment");
- if (vrt_hdr_word & (0x7 << 29))
- throw std::runtime_error("unsupported vrt packet type");
-
- boost::uint8_t pred = 0;
- if(vrt_hdr_word & 0x10000000) pred |= 0x1;
- if(vrt_hdr_word & 0x8000000) pred |= 0x2;
- if(vrt_hdr_word & 0xc00000) pred |= 0x4;
- if(vrt_hdr_word & 0x300000) pred |= 0x8;
- if(vrt_hdr_word & 0x4000000) pred |= 0x10;
-
- switch(pred){
- case 0:
- num_header_words32 = 1;
- num_payload_words32 = packet_words32 - 1;
- break;
- case 1:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- num_header_words32 = 2;
- num_payload_words32 = packet_words32 - 2;
- break;
- case 2:
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 3;
- break;
- case 3:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 4:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[1]);
- num_header_words32 = 2;
- num_payload_words32 = packet_words32 - 2;
- break;
- case 5:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[2]);
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 3;
- break;
- case 6:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 7:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 8:
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[2]);
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 3;
- break;
- case 9:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 10:
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 11:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[5]);
- num_header_words32 = 6;
- num_payload_words32 = packet_words32 - 6;
- break;
- case 12:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[1]);
- metadata.time_spec.ticks = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 13:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[2]);
- metadata.time_spec.ticks = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 14:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[3]);
- metadata.time_spec.ticks = ntohl(header_buff[5]);
- num_header_words32 = 6;
- num_payload_words32 = packet_words32 - 6;
- break;
- case 15:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[4]);
- metadata.time_spec.ticks = ntohl(header_buff[6]);
- num_header_words32 = 7;
- num_payload_words32 = packet_words32 - 7;
- break;
- case 16:
- num_header_words32 = 1;
- num_payload_words32 = packet_words32 - 2;
- break;
- case 17:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- num_header_words32 = 2;
- num_payload_words32 = packet_words32 - 3;
- break;
- case 18:
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 19:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 20:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[1]);
- num_header_words32 = 2;
- num_payload_words32 = packet_words32 - 3;
- break;
- case 21:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[2]);
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 22:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 23:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 6;
- break;
- case 24:
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[2]);
- num_header_words32 = 3;
- num_payload_words32 = packet_words32 - 4;
- break;
- case 25:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 26:
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 6;
- break;
- case 27:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.ticks = ntohl(header_buff[5]);
- num_header_words32 = 6;
- num_payload_words32 = packet_words32 - 7;
- break;
- case 28:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[1]);
- metadata.time_spec.ticks = ntohl(header_buff[3]);
- num_header_words32 = 4;
- num_payload_words32 = packet_words32 - 5;
- break;
- case 29:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[2]);
- metadata.time_spec.ticks = ntohl(header_buff[4]);
- num_header_words32 = 5;
- num_payload_words32 = packet_words32 - 6;
- break;
- case 30:
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[3]);
- metadata.time_spec.ticks = ntohl(header_buff[5]);
- num_header_words32 = 6;
- num_payload_words32 = packet_words32 - 7;
- break;
- case 31:
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(header_buff[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(header_buff[4]);
- metadata.time_spec.ticks = ntohl(header_buff[6]);
- num_header_words32 = 7;
- num_payload_words32 = packet_words32 - 8;
- break;
- }
-}
-
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index 61a63b710..0fd2522cf 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -26,6 +26,7 @@
#include <uhd/types/otw_type.hpp>
#include <uhd/types/io_type.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>
@@ -54,8 +55,8 @@ freq_range_t::freq_range_t(double min_, double max_){
tune_result_t::tune_result_t(void){
target_inter_freq = 0.0;
actual_inter_freq = 0.0;
- target_dxc_freq = 0.0;
- actual_dxc_freq = 0.0;
+ target_dsp_freq = 0.0;
+ actual_dsp_freq = 0.0;
spectrum_inverted = false;
}
@@ -101,29 +102,26 @@ tx_metadata_t::tx_metadata_t(void){
/***********************************************************************
* time spec
**********************************************************************/
-time_spec_t::time_spec_t(boost::uint32_t new_secs, boost::uint32_t new_ticks){
+time_spec_t::time_spec_t(boost::uint32_t new_secs, double new_nsecs){
secs = new_secs;
- ticks = new_ticks;
+ nsecs = new_nsecs;
}
-static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
-static double time_tick_rate = double(boost::posix_time::time_duration::ticks_per_second());
+boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
+ return boost::math::iround(nsecs*tick_rate*1e-9);
+}
-time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){
- boost::posix_time::time_duration td = time - epoch;
- secs = boost::uint32_t(td.total_seconds());
- double time_ticks_per_device_ticks = time_tick_rate/tick_rate;
- ticks = boost::uint32_t(td.fractional_seconds()/time_ticks_per_device_ticks);
+void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){
+ nsecs = double(ticks)*1e9/tick_rate;
}
/***********************************************************************
* device addr
**********************************************************************/
std::string device_addr_t::to_string(void) const{
- const device_addr_t &device_addr = *this;
std::stringstream ss;
- BOOST_FOREACH(std::string key, device_addr.keys()){
- ss << boost::format("%s: %s") % key % device_addr[key] << std::endl;
+ BOOST_FOREACH(std::string key, this->keys()){
+ ss << boost::format("%s: %s") % key % (*this)[key] << std::endl;
}
return ss.str();
}
@@ -137,9 +135,8 @@ static std::string trim(const std::string &in){
std::string device_addr_t::to_args_str(void) const{
std::string args_str;
- const device_addr_t &device_addr = *this;
- BOOST_FOREACH(const std::string &key, device_addr.keys()){
- args_str += key + pair_delim + device_addr[key] + arg_delim;
+ BOOST_FOREACH(const std::string &key, this->keys()){
+ args_str += key + pair_delim + (*this)[key] + arg_delim;
}
return args_str;
}
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index 3c14e473e..aad2398d8 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -75,11 +75,11 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){
return dboard_base::sptr(new basic_tx(args, 32e6));
}
-UHD_STATIC_BLOCK(reg_dboards){
+UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){
dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX");
- dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("ab")("a")("b"));
+ dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("AB")("A")("B"));
dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX");
- dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("ab")("a")("b"));
+ dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("AB")("A")("B"));
}
/***********************************************************************
@@ -138,12 +138,8 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_ENABLED:
- val = true; //always enabled
- return;
-
case SUBDEV_PROP_QUADRATURE:
- val = (get_subdev_name() == "ab"); //only quadrature in ab mode
+ val = (get_subdev_name() == "AB"); //only quadrature in ab mode
return;
case SUBDEV_PROP_IQ_SWAPPED:
@@ -175,9 +171,6 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){
ASSERT_THROW(val.as<std::string>() == std::string(""));
return;
- case SUBDEV_PROP_ENABLED:
- return; // it wont do you much good, but you can set it
-
case SUBDEV_PROP_FREQ:
return; // it wont do you much good, but you can set it
@@ -240,10 +233,6 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, ""); //vector of 1 empty string
return;
- case SUBDEV_PROP_ENABLED:
- val = true; //always enabled
- return;
-
case SUBDEV_PROP_QUADRATURE:
val = true;
return;
@@ -277,9 +266,6 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){
ASSERT_THROW(val.as<std::string>() == std::string(""));
return;
- case SUBDEV_PROP_ENABLED:
- return; // it wont do you much good, but you can set it
-
case SUBDEV_PROP_FREQ:
return; // it wont do you much good, but you can set it
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
new file mode 100644
index 000000000..cd5b8447b
--- /dev/null
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -0,0 +1,517 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+static const bool rfx_debug = false;
+
+// IO Pin functions
+#define POWER_IO (1 << 7) // Low enables power supply
+#define ANTSW_IO (1 << 6) // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2
+#define MIXER_IO (1 << 5) // Enable appropriate mixer
+#define LOCKDET_MASK (1 << 2) // Input pin
+
+// Mixer constants
+#define MIXER_ENB MIXER_IO
+#define MIXER_DIS 0
+
+// Power constants
+#define POWER_UP 0
+#define POWER_DOWN POWER_IO
+
+// Antenna constants
+#define ANT_TX 0 //the tx line is transmitting
+#define ANT_RX ANTSW_IO //the tx line is receiving
+#define ANT_TXRX 0 //the rx line is on txrx
+#define ANT_RX2 ANTSW_IO //the rx line in on rx2
+#define ANT_XX 0 //dont care how the antenna is set
+
+#include "adf4360_regs.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The RFX series of dboards
+ **********************************************************************/
+static const float _max_rx_pga0_gain = 45;
+
+class rfx_xcvr : public xcvr_dboard_base{
+public:
+ rfx_xcvr(
+ ctor_args_t const& args,
+ const freq_range_t &freq_range,
+ bool rx_div2, bool tx_div2
+ );
+ ~rfx_xcvr(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ freq_range_t _freq_range;
+ uhd::dict<dboard_iface::unit_t, bool> _div2;
+ double _rx_lo_freq, _tx_lo_freq;
+ std::string _rx_ant;
+ float _rx_pga0_gain;
+
+ void set_rx_lo_freq(double freq);
+ void set_tx_lo_freq(double freq);
+ void set_rx_ant(const std::string &ant);
+ void set_rx_pga0_gain(float gain);
+
+ /*!
+ * Set the LO frequency for the particular dboard unit.
+ * \param unit which unit rx or tx
+ * \param target_freq the desired frequency in Hz
+ * \return the actual frequency in Hz
+ */
+ double set_lo_freq(dboard_iface::unit_t unit, double target_freq);
+};
+
+/***********************************************************************
+ * Register the RFX dboards (min freq, max freq, rx div2, tx div2)
+ **********************************************************************/
+static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true));
+}
+
+static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6), true, true));
+}
+
+static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6), false, false));
+}
+
+static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6), true, true));
+}
+
+static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6), false, false));
+}
+
+UHD_STATIC_BLOCK(reg_rfx_dboards){
+ dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B");
+ dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B");
+ dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B");
+ dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B");
+ dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B");
+
+ dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B");
+ dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+rfx_xcvr::rfx_xcvr(
+ ctor_args_t const& args,
+ const freq_range_t &freq_range,
+ bool rx_div2, bool tx_div2
+) : xcvr_dboard_base(args){
+ _freq_range = freq_range;
+ _div2[dboard_iface::UNIT_RX] = rx_div2;
+ _div2[dboard_iface::UNIT_TX] = tx_div2;
+
+ //enable the clocks that we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);
+
+ //set the gpio directions
+ boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO;
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);
+
+ //setup the tx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP | ANT_RX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_TX | MIXER_ENB);
+
+ //setup the rx atr (this does not change with antenna)
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_RX2| MIXER_ENB);
+
+ //set some default values
+ set_rx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_tx_lo_freq((_freq_range.min + _freq_range.max)/2.0);
+ set_rx_ant("RX2");
+ set_rx_pga0_gain(0);
+}
+
+rfx_xcvr::~rfx_xcvr(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void rfx_xcvr::set_rx_lo_freq(double freq){
+ _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq);
+}
+
+void rfx_xcvr::set_tx_lo_freq(double freq){
+ _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq);
+}
+
+void rfx_xcvr::set_rx_ant(const std::string &ant){
+ //validate input
+ ASSERT_THROW(ant == "TX/RX" or ant == "RX2");
+
+ //set the rx atr regs that change with antenna setting
+ this->get_iface()->set_atr_reg(
+ dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
+ POWER_UP | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
+ );
+
+ //shadow the setting
+ _rx_ant = ant;
+}
+
+void rfx_xcvr::set_rx_pga0_gain(float gain){
+ //clip the input
+ gain = std::clip<float>(gain, 0, _max_rx_pga0_gain);
+
+ //voltage level constants
+ static const float max_volts = float(.2), min_volts = float(1.2);
+ static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain;
+
+ //calculate the voltage for the aux dac
+ float dac_volts = gain*slope + min_volts;
+
+ //write the new voltage to the aux dac
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 1, dac_volts);
+
+ //shadow the setting (does not account for precision loss)
+ _rx_pga0_gain = gain;
+}
+
+double rfx_xcvr::set_lo_freq(
+ dboard_iface::unit_t unit,
+ double target_freq
+){
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: target frequency %f Mhz"
+ ) % (target_freq/1e6) << std::endl;
+
+ //clip the input
+ target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max);
+ if (_div2[unit]) target_freq *= 2;
+
+ //map prescalers to the register enums
+ static const uhd::dict<int, adf4360_regs_t::prescaler_value_t> prescaler_to_enum = map_list_of
+ (8, adf4360_regs_t::PRESCALER_VALUE_8_9)
+ (16, adf4360_regs_t::PRESCALER_VALUE_16_17)
+ (32, adf4360_regs_t::PRESCALER_VALUE_32_33)
+ ;
+
+ //map band select clock dividers to enums
+ static const uhd::dict<int, adf4360_regs_t::band_select_clock_div_t> bandsel_to_enum = map_list_of
+ (1, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_1)
+ (2, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_2)
+ (4, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_4)
+ (8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8)
+ ;
+
+ double actual_freq, ref_freq = this->get_iface()->get_clock_rate(unit);
+ int R, BS, P, B, A;
+
+ /*
+ * The goal here to to loop though possible R dividers,
+ * band select clock dividers, and prescaler values.
+ * Calculate the A and B counters for each set of values.
+ * The loop exists when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * fvco = [P*B + A] * fref/R
+ * fvco*R/fref = P*B + A = N
+ */
+ for(R = 2; R <= 32; R+=2){
+ BOOST_FOREACH(BS, bandsel_to_enum.keys()){
+ if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock
+ BOOST_FOREACH(P, prescaler_to_enum.keys()){
+ //calculate B and A from N
+ double N = target_freq*R/ref_freq;
+ B = int(std::floor(N/P));
+ A = boost::math::iround(N - P*B);
+ if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B
+ //calculate the actual frequency
+ actual_freq = double(P*B + A)*ref_freq/R;
+ if (actual_freq/P > 300e6) continue; //constraint on prescaler output
+ //constraints met: exit loop
+ goto done_loop;
+ }
+ }
+ } done_loop:
+
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d"
+ ) % R % BS % P % B % A << std::endl;
+
+ //load the register values
+ adf4360_regs_t regs;
+ regs.core_power_level = adf4360_regs_t::CORE_POWER_LEVEL_10MA;
+ regs.counter_operation = adf4360_regs_t::COUNTER_OPERATION_NORMAL;
+ regs.muxout_control = adf4360_regs_t::MUXOUT_CONTROL_DLD;
+ regs.phase_detector_polarity = adf4360_regs_t::PHASE_DETECTOR_POLARITY_POS;
+ regs.charge_pump_output = adf4360_regs_t::CHARGE_PUMP_OUTPUT_NORMAL;
+ regs.cp_gain_0 = adf4360_regs_t::CP_GAIN_0_SET1;
+ regs.mute_till_ld = adf4360_regs_t::MUTE_TILL_LD_ENB;
+ regs.output_power_level = adf4360_regs_t::OUTPUT_POWER_LEVEL_3_5MA;
+ regs.current_setting1 = adf4360_regs_t::CURRENT_SETTING1_0_31MA;
+ regs.current_setting2 = adf4360_regs_t::CURRENT_SETTING2_0_31MA;
+ regs.power_down = adf4360_regs_t::POWER_DOWN_NORMAL_OP;
+ regs.prescaler_value = prescaler_to_enum[P];
+ regs.a_counter = A;
+ regs.b_counter = B;
+ regs.cp_gain_1 = adf4360_regs_t::CP_GAIN_1_SET1;
+ regs.divide_by_2_output = (_div2[unit])?
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
+ regs.divide_by_2_prescaler = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
+ regs.r_counter = R;
+ regs.ablpw = adf4360_regs_t::ABLPW_3_0NS;
+ regs.lock_detect_precision = adf4360_regs_t::LOCK_DETECT_PRECISION_5CYCLES;
+ regs.test_mode_bit = 0;
+ regs.band_select_clock_div = bandsel_to_enum[BS];
+
+ //write the registers
+ std::vector<adf4360_regs_t::addr_t> addrs = list_of //correct power-up sequence to write registers (R, C, N)
+ (adf4360_regs_t::ADDR_RCOUNTER)
+ (adf4360_regs_t::ADDR_CONTROL)
+ (adf4360_regs_t::ADDR_NCOUNTER)
+ ;
+ BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){
+ this->get_iface()->write_spi(
+ unit, spi_config_t::EDGE_RISE,
+ regs.get_reg(addr), 24
+ );
+ }
+
+ //return the actual frequency
+ if (_div2[unit]) actual_freq /= 2;
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: actual frequency %f Mhz"
+ ) % (actual_freq/1e6) << std::endl;
+ return actual_freq;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_rx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(name == "PGA0");
+ val = _rx_pga0_gain;
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ ASSERT_THROW(name == "PGA0");
+ val = gain_range_t(0, _max_rx_pga0_gain, float(0.022));
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(1, "PGA0");
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _rx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:{
+ prop_names_t ants = list_of("TX/RX")("RX2");
+ val = ants;
+ }
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+ }
+}
+
+void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ set_rx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ ASSERT_THROW(name == "PGA0");
+ set_rx_pga0_gain(val.as<float>());
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ set_rx_ant(val.as<std::string>());
+ return;
+
+ default:
+ throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_rx_id())));
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_tx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _tx_lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = _freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("TX/RX");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, "TX/RX");
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = true;
+ return;
+ }
+}
+
+void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ set_tx_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ //no gains to set!
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ //its always set to tx/rx, so we only allow this value
+ 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())));
+ }
+}
diff --git a/host/lib/usrp/dboard_base.cpp b/host/lib/usrp/dboard_base.cpp
index 09d3bbfd4..68e4743d1 100644
--- a/host/lib/usrp/dboard_base.cpp
+++ b/host/lib/usrp/dboard_base.cpp
@@ -25,7 +25,7 @@ using namespace uhd::usrp;
* dboard_base dboard dboard_base class
**********************************************************************/
dboard_base::dboard_base(ctor_args_t const& args){
- boost::tie(_subdev_name, _dboard_interface, _rx_id, _tx_id) = args;
+ boost::tie(_subdev_name, _dboard_iface, _rx_id, _tx_id) = args;
}
dboard_base::~dboard_base(void){
@@ -36,8 +36,8 @@ std::string dboard_base::get_subdev_name(void){
return _subdev_name;
}
-dboard_interface::sptr dboard_base::get_interface(void){
- return _dboard_interface;
+dboard_iface::sptr dboard_base::get_iface(void){
+ return _dboard_iface;
}
dboard_id_t dboard_base::get_rx_id(void){
diff --git a/host/lib/usrp/dboard_interface.cpp b/host/lib/usrp/dboard_interface.cpp
deleted file mode 100644
index c40c9b398..000000000
--- a/host/lib/usrp/dboard_interface.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/usrp/dboard_interface.hpp>
-
-using namespace uhd::usrp;
-
-dboard_interface::dboard_interface(void){
- /* NOP */
-}
-
-dboard_interface::~dboard_interface(void){
- /* NOP */
-}
-
-void dboard_interface::write_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- const byte_vector_t &buf
-){
- transact_spi(dev, edge, buf, false); //dont readback
-}
-
-dboard_interface::byte_vector_t dboard_interface::read_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- size_t num_bytes
-){
- byte_vector_t buf(num_bytes, 0x00); //dummy data
- return transact_spi(dev, edge, buf, true); //readback
-}
-
-dboard_interface::byte_vector_t dboard_interface::read_write_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- const byte_vector_t &buf
-){
- return transact_spi(dev, edge, buf, true); //readback
-}
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 4cf2e5820..06f8c55b6 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -25,6 +25,7 @@
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -124,11 +125,11 @@ public:
dboard_manager_impl(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
+ dboard_iface::sptr iface
);
~dboard_manager_impl(void);
- //dboard_interface
+ //dboard_iface
prop_names_t get_rx_subdev_names(void);
prop_names_t get_tx_subdev_names(void);
wax::obj get_rx_subdev(const std::string &subdev_name);
@@ -140,8 +141,8 @@ private:
//the subdevice proxy is internal to the cpp file
uhd::dict<std::string, subdev_proxy::sptr> _rx_dboards;
uhd::dict<std::string, subdev_proxy::sptr> _tx_dboards;
- dboard_interface::sptr _interface;
- void set_nice_gpio_pins(void);
+ dboard_iface::sptr _iface;
+ void set_nice_dboard_if(void);
};
/***********************************************************************
@@ -150,10 +151,10 @@ private:
dboard_manager::sptr dboard_manager::make(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
+ dboard_iface::sptr iface
){
return dboard_manager::sptr(
- new dboard_manager_impl(rx_dboard_id, tx_dboard_id, interface)
+ new dboard_manager_impl(rx_dboard_id, tx_dboard_id, iface)
);
}
@@ -189,9 +190,9 @@ static args_t get_dboard_args(
dboard_manager_impl::dboard_manager_impl(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
- dboard_interface::sptr interface
+ dboard_iface::sptr iface
){
- _interface = interface;
+ _iface = iface;
dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx");
@@ -200,14 +201,14 @@ dboard_manager_impl::dboard_manager_impl(
boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx");
//initialize the gpio pins before creating subdevs
- set_nice_gpio_pins();
+ set_nice_dboard_if();
//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);
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
dboard_base::sptr xcvr_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, tx_dboard_id)
);
//create a rx proxy for this xcvr board
_rx_dboards[subdev] = subdev_proxy::sptr(
@@ -225,7 +226,7 @@ dboard_manager_impl::dboard_manager_impl(
//make the rx subdevs
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
dboard_base::sptr rx_dboard = rx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, dboard_id::NONE)
+ dboard_base::ctor_args_t(subdev, iface, rx_dboard_id, dboard_id::NONE)
);
//create a rx proxy for this rx board
_rx_dboards[subdev] = subdev_proxy::sptr(
@@ -235,7 +236,7 @@ dboard_manager_impl::dboard_manager_impl(
//make the tx subdevs
BOOST_FOREACH(const std::string &subdev, tx_subdevs){
dboard_base::sptr tx_dboard = tx_dboard_ctor(
- dboard_base::ctor_args_t(subdev, interface, dboard_id::NONE, tx_dboard_id)
+ dboard_base::ctor_args_t(subdev, iface, dboard_id::NONE, tx_dboard_id)
);
//create a tx proxy for this tx board
_tx_dboards[subdev] = subdev_proxy::sptr(
@@ -246,7 +247,7 @@ dboard_manager_impl::dboard_manager_impl(
}
dboard_manager_impl::~dboard_manager_impl(void){
- set_nice_gpio_pins();
+ set_nice_dboard_if();
}
prop_names_t dboard_manager_impl::get_rx_subdev_names(void){
@@ -273,12 +274,17 @@ wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
return _tx_dboards[subdev_name]->get_link();
}
-void dboard_manager_impl::set_nice_gpio_pins(void){
- //std::cout << "Set nice GPIO pins" << std::endl;
-
- _interface->set_gpio_ddr(dboard_interface::GPIO_BANK_RX, 0x0000); //all inputs
- _interface->set_atr_reg(dboard_interface::GPIO_BANK_RX, dboard_interface::ATR_REG_IDLE, 0x0000); //all low
-
- _interface->set_gpio_ddr(dboard_interface::GPIO_BANK_TX, 0x0000); //all inputs
- _interface->set_atr_reg(dboard_interface::GPIO_BANK_TX, dboard_interface::ATR_REG_IDLE, 0x0000); //all low
+void dboard_manager_impl::set_nice_dboard_if(void){
+ //make a list of possible unit types
+ std::vector<dboard_iface::unit_t> units = boost::assign::list_of
+ (dboard_iface::UNIT_RX)
+ (dboard_iface::UNIT_TX)
+ ;
+
+ //set nice settings on each unit
+ BOOST_FOREACH(dboard_iface::unit_t unit, units){
+ _iface->set_gpio_ddr(unit, 0x0000); //all inputs
+ _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low
+ _iface->set_clock_enabled(unit, false); //clock off
+ }
}
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index fb3cc8eec..11ee3a798 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -83,10 +83,6 @@ public:
_mboard[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
}
- double get_clock_rate(void){
- return _mboard[MBOARD_PROP_CLOCK_RATE].as<double>();
- }
-
/*******************************************************************
* RX methods
******************************************************************/
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
index 2fb15064c..a7d695b4e 100644
--- a/host/lib/usrp/tune_helper.cpp
+++ b/host/lib/usrp/tune_helper.cpp
@@ -74,8 +74,8 @@ static tune_result_t tune_xx_subdev_and_dxc(
tune_result_t tune_result;
tune_result.target_inter_freq = target_inter_freq;
tune_result.actual_inter_freq = actual_inter_freq;
- tune_result.target_dxc_freq = target_dxc_freq;
- tune_result.actual_dxc_freq = actual_dxc_freq;
+ tune_result.target_dsp_freq = target_dxc_freq;
+ tune_result.actual_dsp_freq = actual_dxc_freq;
tune_result.spectrum_inverted = inverted;
return tune_result;
}
diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp
new file mode 100644
index 000000000..dcd7ce9da
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_control.cpp
@@ -0,0 +1,156 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_impl.hpp"
+#include "clock_control.hpp"
+#include "ad9510_regs.hpp"
+#include "usrp2_regs.hpp" //spi slave constants
+#include <boost/cstdint.hpp>
+
+using namespace uhd::usrp;
+
+/*!
+ * A usrp2 clock control specific to the ad9510 ic.
+ */
+class clock_control_ad9510 : public clock_control{
+public:
+ clock_control_ad9510(usrp2_iface::sptr iface){
+ _iface = iface;
+
+ _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
+ this->write_reg(0x09);
+
+ // Setup the clock registers to 100MHz:
+ // This was already done by the firmware (or the host couldnt communicate).
+ // We could remove this part, and just leave it to the firmware.
+ // But why not leave it in for those who want to mess with clock settings?
+ // 100mhz = 10mhz/R * (P*B + A)
+
+ _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL;
+ _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2;
+ this->write_reg(0x0A);
+
+ _ad9510_regs.acounter = 0;
+ this->write_reg(0x04);
+
+ _ad9510_regs.bcounter_msb = 0;
+ _ad9510_regs.bcounter_lsb = 5;
+ this->write_reg(0x05);
+ this->write_reg(0x06);
+
+ _ad9510_regs.ref_counter_msb = 0;
+ _ad9510_regs.ref_counter_lsb = 1; // r divider = 1
+ this->write_reg(0x0B);
+ this->write_reg(0x0C);
+
+ /* regs will be updated in commands below */
+
+ this->enable_external_ref(false);
+ this->enable_rx_dboard_clock(false);
+ this->enable_tx_dboard_clock(false);
+
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(true);
+ this->enable_adc_clock(true);
+
+ }
+
+ ~clock_control_ad9510(void){
+ /* private clock enables, must be set here */
+ this->enable_dac_clock(false);
+ this->enable_adc_clock(false);
+ }
+
+ //uses output clock 7 (cmos)
+ void enable_rx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
+ _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
+ this->write_reg(0x43);
+ this->update_regs();
+ }
+
+ //uses output clock 6 (cmos)
+ void enable_tx_dboard_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ this->write_reg(0x42);
+ this->update_regs();
+ }
+
+ /*!
+ * If we are to use an external reference, enable the charge pump.
+ * \param enb true to enable the CP
+ */
+ void enable_external_ref(bool enb){
+ _ad9510_regs.charge_pump_mode = (enb)?
+ ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL :
+ ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ;
+ _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH;
+ _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS;
+ this->write_reg(0x08);
+ this->update_regs();
+ }
+
+private:
+ /*!
+ * Write a single register to the spi regs.
+ * \param addr the address to write
+ */
+ void write_reg(boost::uint8_t addr){
+ boost::uint32_t data = _ad9510_regs.get_write_reg(addr);
+ _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/);
+ }
+
+ /*!
+ * Tells the ad9510 to latch the settings into the operational registers.
+ */
+ void update_regs(void){
+ _ad9510_regs.update_registers = 1;
+ this->write_reg(0x5a);
+ }
+
+ //uses output clock 3 (pecl)
+ void enable_dac_clock(bool enb){
+ _ad9510_regs.power_down_lvpecl_out3 = (enb)?
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
+ this->write_reg(0x3F);
+ this->update_regs();
+ }
+
+ //uses output clock 4 (lvds)
+ void enable_adc_clock(bool enb){
+ _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
+ _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ this->write_reg(0x40);
+ this->update_regs();
+ }
+
+ usrp2_iface::sptr _iface;
+ ad9510_regs_t _ad9510_regs;
+};
+
+/***********************************************************************
+ * Public make function for the ad9510 clock control
+ **********************************************************************/
+clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){
+ return clock_control::sptr(new clock_control_ad9510(iface));
+}
diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_control.hpp
new file mode 100644
index 000000000..b64a53196
--- /dev/null
+++ b/host/lib/usrp/usrp2/clock_control.hpp
@@ -0,0 +1,60 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_CLOCK_CONTROL_HPP
+#define INCLUDED_CLOCK_CONTROL_HPP
+
+#include "usrp2_iface.hpp"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class clock_control : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<clock_control> sptr;
+
+ /*!
+ * Make a clock config for the ad9510 ic.
+ * \param _iface a pointer to the usrp2 interface object
+ * \return a new clock control object
+ */
+ static sptr make_ad9510(usrp2_iface::sptr iface);
+
+ /*!
+ * Enable/disable the rx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_rx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable the tx dboard clock.
+ * \param enb true to enable
+ */
+ virtual void enable_tx_dboard_clock(bool enb) = 0;
+
+ /*!
+ * Enable/disable external reference.
+ * \param enb true to enable
+ */
+ virtual void enable_external_ref(bool enb) = 0;
+
+ /*!
+ * TODO other clock control api here....
+ */
+
+};
+
+#endif /* INCLUDED_CLOCK_CONTROL_HPP */
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
new file mode 100644
index 000000000..2859a7981
--- /dev/null
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -0,0 +1,279 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_iface.hpp"
+#include "clock_control.hpp"
+#include "usrp2_regs.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>
+
+using namespace uhd::usrp;
+
+class usrp2_dboard_iface : public dboard_iface{
+public:
+ usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl);
+ ~usrp2_dboard_iface(void);
+
+ void write_aux_dac(unit_t, int, float);
+ float read_aux_adc(unit_t, int);
+
+ void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
+ void set_gpio_ddr(unit_t, boost::uint16_t);
+ boost::uint16_t read_gpio(unit_t);
+
+ void write_i2c(int, const byte_vector_t &);
+ byte_vector_t read_i2c(int, size_t);
+
+ double get_clock_rate(unit_t);
+ void set_clock_enabled(unit_t, bool);
+ bool get_clock_enabled(unit_t);
+
+ void write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+ boost::uint32_t read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+ );
+
+private:
+ usrp2_iface::sptr _iface;
+ clock_control::sptr _clk_ctrl;
+ boost::uint32_t _ddr_shadow;
+};
+
+/***********************************************************************
+ * Make Function
+ **********************************************************************/
+dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_control::sptr clk_ctrl
+){
+ return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl));
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){
+ _iface = iface;
+ _clk_ctrl = clk_ctrl;
+ _ddr_shadow = 0;
+
+ //set the selection mux to use atr
+ boost::uint32_t new_sels = 0x0;
+ for(size_t i = 0; i < 16; i++){
+ new_sels |= FRF_GPIO_SEL_ATR << (i*2);
+ }
+ _iface->poke32(FR_GPIO_TX_SEL, new_sels);
+ _iface->poke32(FR_GPIO_RX_SEL, new_sels);
+}
+
+usrp2_dboard_iface::~usrp2_dboard_iface(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Clocks
+ **********************************************************************/
+double usrp2_dboard_iface::get_clock_rate(unit_t){
+ return _iface->get_master_clock_freq();
+}
+
+void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
+ switch(unit){
+ case UNIT_RX:
+ _clk_ctrl->enable_rx_dboard_clock(enb);
+ return;
+ case UNIT_TX:
+ _clk_ctrl->enable_tx_dboard_clock(enb);
+ return;
+ }
+}
+
+/***********************************************************************
+ * GPIO
+ **********************************************************************/
+static int unit_to_shift(dboard_iface::unit_t unit){
+ switch(unit){
+ case dboard_iface::UNIT_RX: return 0;
+ case dboard_iface::UNIT_TX: return 16;
+ }
+ throw std::runtime_error("unknown unit type");
+}
+
+void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
+ _ddr_shadow = \
+ (_ddr_shadow & ~(0xffff << unit_to_shift(unit))) |
+ (boost::uint32_t(value) << unit_to_shift(unit));
+ _iface->poke32(FR_GPIO_DDR, _ddr_shadow);
+}
+
+boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
+ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift(unit));
+}
+
+void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
+ //define mapping of unit to atr regs to register address
+ static const uhd::dict<
+ unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
+ > unit_to_atr_to_addr = boost::assign::map_list_of
+ (UNIT_RX, boost::assign::map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
+ )
+ (UNIT_TX, boost::assign::map_list_of
+ (ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
+ (ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
+ (ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
+ (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE)
+ )
+ ;
+ _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+}
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+/*!
+ * Static function to convert a unit type enum
+ * to an over-the-wire value for the spi device.
+ * \param unit the dboard interface unit type enum
+ * \return an over the wire representation
+ */
+static boost::uint8_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){
+ switch(unit){
+ case dboard_iface::UNIT_TX: return SPI_SS_TX_DB;
+ case dboard_iface::UNIT_RX: return SPI_SS_RX_DB;
+ }
+ throw std::invalid_argument("unknown unit type");
+}
+
+void usrp2_dboard_iface::write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/);
+}
+
+boost::uint32_t usrp2_dboard_iface::read_write_spi(
+ unit_t unit,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits
+){
+ return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/);
+}
+
+/***********************************************************************
+ * 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);
+}
+
+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;
+}
+
+/***********************************************************************
+ * 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, 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);
+}
+
+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);
+}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index d1515f2d5..fe74219d6 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -22,6 +22,9 @@
#include <uhd/usrp/dboard_props.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -33,7 +36,7 @@ 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 = ctrl_send_and_recv(out_data);
+ 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
@@ -41,11 +44,11 @@ void usrp2_impl::dboard_init(void){
dboard_id_t tx_dboard_id = ntohs(in_data.data.dboard_ids.tx_id);
//create a new dboard interface and manager
- dboard_interface::sptr _dboard_interface(
- make_usrp2_dboard_interface(this)
+ dboard_iface::sptr _dboard_iface(
+ make_usrp2_dboard_iface(_iface, _clk_ctrl)
);
_dboard_manager = dboard_manager::make(
- rx_dboard_id, tx_dboard_id, _dboard_interface
+ rx_dboard_id, tx_dboard_id, _dboard_iface
);
//load dboards
@@ -81,7 +84,7 @@ void usrp2_impl::update_rx_mux_config(void){
rx_mux = (((rx_mux >> 0) & 0x3) << 2) | (((rx_mux >> 2) & 0x3) << 0);
}
- this->poke32(FR_DSP_RX_MUX, rx_mux);
+ _iface->poke32(FR_DSP_RX_MUX, rx_mux);
}
void usrp2_impl::update_tx_mux_config(void){
@@ -94,7 +97,7 @@ void usrp2_impl::update_tx_mux_config(void){
tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);
}
- this->poke32(FR_DSP_TX_MUX, tx_mux);
+ _iface->poke32(FR_DSP_TX_MUX, tx_mux);
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp
deleted file mode 100644
index 6dd756420..000000000
--- a/host/lib/usrp/usrp2/dboard_interface.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include "usrp2_impl.hpp"
-#include "usrp2_regs.hpp"
-#include <uhd/types/dict.hpp>
-#include <uhd/utils/assert.hpp>
-#include <boost/assign/list_of.hpp>
-#include <algorithm>
-
-using namespace uhd::usrp;
-
-class usrp2_dboard_interface : public dboard_interface{
-public:
- usrp2_dboard_interface(usrp2_impl *impl);
- ~usrp2_dboard_interface(void);
-
- void write_aux_dac(unit_type_t, int, int);
- int read_aux_adc(unit_type_t, int);
-
- void set_atr_reg(gpio_bank_t, atr_reg_t, boost::uint16_t);
- void set_gpio_ddr(gpio_bank_t, boost::uint16_t);
- boost::uint16_t read_gpio(gpio_bank_t);
-
- void write_i2c(int, const byte_vector_t &);
- byte_vector_t read_i2c(int, size_t);
-
- double get_rx_clock_rate(void);
- double get_tx_clock_rate(void);
-
-private:
- byte_vector_t transact_spi(
- spi_dev_t, spi_edge_t, const byte_vector_t &, bool
- );
-
- usrp2_impl *_impl;
- boost::uint32_t _ddr_shadow;
-};
-
-/***********************************************************************
- * Make Function
- **********************************************************************/
-dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl){
- return dboard_interface::sptr(new usrp2_dboard_interface(impl));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_dboard_interface::usrp2_dboard_interface(usrp2_impl *impl){
- _impl = impl;
- _ddr_shadow = 0;
-
- //set the selection mux to use atr
- boost::uint32_t new_sels = 0x0;
- for(size_t i = 0; i < 16; i++){
- new_sels |= FRF_GPIO_SEL_ATR << (i*2);
- }
- _impl->poke32(FR_GPIO_TX_SEL, new_sels);
- _impl->poke32(FR_GPIO_RX_SEL, new_sels);
-}
-
-usrp2_dboard_interface::~usrp2_dboard_interface(void){
- /* NOP */
-}
-
-/***********************************************************************
- * Clock Rates
- **********************************************************************/
-double usrp2_dboard_interface::get_rx_clock_rate(void){
- return _impl->get_master_clock_freq();
-}
-
-double usrp2_dboard_interface::get_tx_clock_rate(void){
- return _impl->get_master_clock_freq();
-}
-
-/***********************************************************************
- * GPIO
- **********************************************************************/
-static int bank_to_shift(dboard_interface::gpio_bank_t bank){
- switch(bank){
- case dboard_interface::GPIO_BANK_RX: return 0;
- case dboard_interface::GPIO_BANK_TX: return 16;
- }
- throw std::runtime_error("unknown gpio bank type");
-}
-
-void usrp2_dboard_interface::set_gpio_ddr(gpio_bank_t bank, boost::uint16_t value){
- _ddr_shadow = \
- (_ddr_shadow & ~(0xffff << bank_to_shift(bank))) |
- (boost::uint32_t(value) << bank_to_shift(bank));
- _impl->poke32(FR_GPIO_DDR, _ddr_shadow);
-}
-
-boost::uint16_t usrp2_dboard_interface::read_gpio(gpio_bank_t bank){
- return boost::uint16_t(_impl->peek32(FR_GPIO_IO) >> bank_to_shift(bank));
-}
-
-void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, atr_reg_t atr, boost::uint16_t value){
- //define mapping of bank to atr regs to register address
- static const uhd::dict<
- gpio_bank_t, uhd::dict<atr_reg_t, boost::uint32_t>
- > bank_to_atr_to_addr = boost::assign::map_list_of
- (GPIO_BANK_RX, boost::assign::map_list_of
- (ATR_REG_IDLE, FR_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, FR_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, FR_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_RXSIDE)
- )
- (GPIO_BANK_TX, boost::assign::map_list_of
- (ATR_REG_IDLE, FR_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, FR_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, FR_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, FR_ATR_FULL_TXSIDE)
- )
- ;
- _impl->poke16(bank_to_atr_to_addr[bank][atr], value);
-}
-
-/***********************************************************************
- * SPI
- **********************************************************************/
-/*!
- * Static function to convert a spi dev enum
- * to an over-the-wire value for the usrp2 control.
- * \param dev the dboard interface spi dev enum
- * \return an over the wire representation
- */
-static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){
- switch(dev){
- case uhd::usrp::dboard_interface::SPI_DEV_TX: return SPI_SS_TX_DB;
- case uhd::usrp::dboard_interface::SPI_DEV_RX: return SPI_SS_RX_DB;
- }
- throw std::invalid_argument("unknown spi device type");
-}
-
-/*!
- * Static function to convert a spi edge enum
- * to an over-the-wire value for the usrp2 control.
- * \param edge the dboard interface spi edge enum
- * \return an over the wire representation
- */
-static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_edge_t edge){
- switch(edge){
- case uhd::usrp::dboard_interface::SPI_EDGE_RISE: return USRP2_CLK_EDGE_RISE;
- case uhd::usrp::dboard_interface::SPI_EDGE_FALL: return USRP2_CLK_EDGE_FALL;
- }
- throw std::invalid_argument("unknown spi edge type");
-}
-
-dboard_interface::byte_vector_t usrp2_dboard_interface::transact_spi(
- spi_dev_t dev,
- spi_edge_t edge,
- const byte_vector_t &buf,
- bool readback
-){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
- out_data.data.spi_args.dev = spi_dev_to_otw(dev);
- out_data.data.spi_args.edge = spi_edge_to_otw(edge);
- out_data.data.spi_args.readback = (readback)? 1 : 0;
- out_data.data.spi_args.bytes = buf.size();
-
- //limitation of spi transaction size
- ASSERT_THROW(buf.size() <= sizeof(out_data.data.spi_args.data));
-
- //copy in the data
- std::copy(buf.begin(), buf.end(), out_data.data.spi_args.data);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
- ASSERT_THROW(in_data.data.spi_args.bytes == buf.size());
-
- //copy out the data
- byte_vector_t result(buf.size());
- std::copy(in_data.data.spi_args.data, in_data.data.spi_args.data + buf.size(), result.begin());
- return result;
-}
-
-/***********************************************************************
- * I2C
- **********************************************************************/
-void usrp2_dboard_interface::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 = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE);
-}
-
-dboard_interface::byte_vector_t usrp2_dboard_interface::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 = _impl->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;
-}
-
-/***********************************************************************
- * 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 spi_dev_to_otw(dboard_interface::unit_type_t unit){
- switch(unit){
- case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX;
- case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX;
- }
- throw std::invalid_argument("unknown unit type type");
-}
-
-void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int 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 = spi_dev_to_otw(unit);
- out_data.data.aux_args.which = which;
- out_data.data.aux_args.value = htonl(value);
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE);
-}
-
-int usrp2_dboard_interface::read_aux_adc(dboard_interface::unit_type_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 = spi_dev_to_otw(unit);
- out_data.data.aux_args.which = which;
-
- //send and recv
- usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_ADC_DUDE);
- return ntohl(in_data.data.aux_args.value);
-}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 92b55d029..204277ba7 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -20,6 +20,7 @@
#include <uhd/usrp/dsp_props.hpp>
#include <uhd/utils/assert.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/math/special_functions/round.hpp>
@@ -39,7 +40,8 @@ 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){
- double scale_factor = std::pow(2.0, 32);
+ ASSERT_THROW(std::abs(freq) < clock_freq/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
//calculate the freq register word
boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
@@ -82,11 +84,11 @@ void usrp2_impl::init_ddc_config(void){
void usrp2_impl::update_ddc_config(void){
//set the decimation
- this->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
//set the scaling
static const boost::int16_t default_rx_scale_iq = 1024;
- this->poke32(FR_DSP_RX_SCALE_IQ,
+ _iface->poke32(FR_DSP_RX_SCALE_IQ,
calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
);
}
@@ -123,12 +125,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
- ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
- _ddc_freq = new_freq; //shadow
- this->poke32(FR_DSP_RX_FREQ,
- calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq())
+ _iface->poke32(FR_DSP_RX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
);
+ _ddc_freq = new_freq; //shadow
}
return;
@@ -170,10 +170,10 @@ void usrp2_impl::update_duc_config(void){
boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
//set the interpolation
- this->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
+ _iface->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
//set the scaling
- this->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
+ _iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
}
/***********************************************************************
@@ -208,12 +208,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
- ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
- _duc_freq = new_freq; //shadow
- this->poke32(FR_DSP_TX_FREQ,
- calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq())
+ _iface->poke32(FR_DSP_TX_FREQ,
+ calculate_freq_word_and_update_actual_freq(new_freq, get_master_clock_freq())
);
+ _duc_freq = new_freq; //shadow
}
return;
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 019f3b931..b600a2a70 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -110,10 +110,11 @@ typedef struct{
} dboard_ids;
struct {
_SINS_ uint8_t dev;
- _SINS_ uint8_t edge;
+ _SINS_ uint8_t miso_edge;
+ _SINS_ uint8_t mosi_edge;
_SINS_ uint8_t readback;
- _SINS_ uint8_t bytes;
- _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
+ _SINS_ uint32_t data;
+ _SINS_ uint8_t num_bits;
} spi_args;
struct {
_SINS_ uint8_t addr;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index a58e32619..367a1d9fb 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -15,9 +15,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <complex>
-#include <boost/format.hpp>
#include "usrp2_impl.hpp"
+#include <uhd/transport/convert_types.hpp>
+#include <boost/format.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
@@ -25,101 +27,26 @@ using namespace uhd::transport;
namespace asio = boost::asio;
/***********************************************************************
- * Constants
- **********************************************************************/
-typedef std::complex<float> fc32_t;
-typedef std::complex<boost::int16_t> sc16_t;
-
-static const float shorts_per_float = float(1 << 15);
-static const float floats_per_short = float(1.0/shorts_per_float);
-
-/***********************************************************************
* Helper Functions
**********************************************************************/
void usrp2_impl::io_init(void){
+ //setup otw type
+ _otw_type.width = 16;
+ _otw_type.shift = 0;
+ _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;
+
//initially empty copy buffer
_rx_copy_buff = asio::buffer("", 0);
//send a small data packet so the usrp2 knows the udp source port
//and the maximum number of lines (32 bit words) per packet
+ managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
boost::uint32_t data[2] = {
htonl(USRP2_INVALID_VRT_HEADER),
htonl(_max_rx_samples_per_packet)
};
- _data_transport->send(asio::buffer(&data, sizeof(data)));
-}
-
-#define unrolled_loop(__inst, __len){ \
- size_t __i = 0; \
- for(; __i < (__len & ~0x3); __i+= 4){ \
- __inst(__i+0); __inst(__i+1); \
- __inst(__i+2); __inst(__i+3); \
- } \
- for(; __i < __len; __i++){ \
- __inst(__i); \
- } \
-}
-
-// set a boolean flag that indicates the endianess
-#ifdef HAVE_BIG_ENDIAN
-static const bool is_big_endian = true;
-#else
-static const bool is_big_endian = false;
-#endif
-
-static inline void host_floats_to_usrp2_items(
- boost::uint32_t *usrp2_items,
- const fc32_t *host_floats,
- size_t num_samps
-){
- #define host_floats_to_usrp2_items_i(i){ \
- boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \
- boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \
- usrp2_items[i] = htonl((real << 16) | (imag << 0)); \
- }
- unrolled_loop(host_floats_to_usrp2_items_i, num_samps);
-}
-
-static inline void usrp2_items_to_host_floats(
- fc32_t *host_floats,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_floats_i(i){ \
- boost::uint32_t item = ntohl(usrp2_items[i]); \
- boost::int16_t real = boost::uint16_t(item >> 16); \
- boost::int16_t imag = boost::uint16_t(item >> 0); \
- host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \
- }
- unrolled_loop(usrp2_items_to_host_floats_i, num_samps);
-}
-
-static inline void host_items_to_usrp2_items(
- boost::uint32_t *usrp2_items,
- const boost::uint32_t *host_items,
- size_t num_samps
-){
- #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i])
- if (is_big_endian){
- std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(host_items_to_usrp2_items_i, num_samps);
- }
-}
-
-static inline void usrp2_items_to_host_items(
- boost::uint32_t *host_items,
- const boost::uint32_t *usrp2_items,
- size_t num_samps
-){
- #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i])
- if (is_big_endian){
- std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t));
- }
- else{
- unrolled_loop(usrp2_items_to_host_items_i, num_samps);
- }
+ memcpy(send_buff->cast<void*>(), data, sizeof(data));
+ send_buff->done(sizeof(data));
}
/***********************************************************************
@@ -127,15 +54,15 @@ static inline void usrp2_items_to_host_items(
**********************************************************************/
void usrp2_impl::recv_raw(rx_metadata_t &metadata){
//do a receive
- _rx_smart_buff = _data_transport->recv();
+ _rx_smart_buff = _data_transport->get_recv_buff();
//unpack the vrt header
- size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(boost::uint32_t);
+ size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t);
if (num_packet_words32 == 0){
_rx_copy_buff = boost::asio::buffer("", 0);
return; //must exit here after setting the buffer
}
- const boost::uint32_t *vrt_hdr = asio::buffer_cast<const boost::uint32_t *>(_rx_smart_buff->get());
+ const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>();
size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
try{
vrt::unpack(
@@ -144,7 +71,8 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){
num_header_words32_out, //output
num_payload_words32_out, //output
num_packet_words32, //input
- packet_count_out //output
+ packet_count_out, //output
+ get_master_clock_freq()
);
}catch(const std::exception &e){
std::cerr << "bad vrt header: " << e.what() << std::endl;
@@ -176,10 +104,12 @@ size_t usrp2_impl::send(
){
tx_metadata_t metadata = metadata_; //rw copy to change later
- boost::uint32_t tx_mem[_mtu/sizeof(boost::uint32_t)];
- size_t num_samps = std::min(
+ transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
+ boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();
+ size_t num_samps = std::min(std::min(
asio::buffer_size(buff)/io_type.size,
- size_t(_max_tx_samples_per_packet)
+ size_t(_max_tx_samples_per_packet)),
+ send_buff->size()/io_type.size
);
//kill the end of burst flag if this is a fragment
@@ -196,25 +126,21 @@ size_t usrp2_impl::send(
num_header_words32, //output
num_samps, //input
num_packet_words32, //output
- packet_count //input
+ packet_count, //input
+ get_master_clock_freq()
);
boost::uint32_t *items = tx_mem + num_header_words32; //offset for data
- //copy the samples into the send buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples into the send buffer
+ convert_io_type_to_otw_type(
+ asio::buffer_cast<const void*>(buff), io_type,
+ (void*)items, _otw_type,
+ num_samps
+ );
//send and return number of samples
- _data_transport->send(asio::buffer(tx_mem, num_packet_words32*sizeof(boost::uint32_t)));
+ send_buff->done(num_packet_words32*sizeof(boost::uint32_t));
return num_samps;
}
@@ -251,17 +177,12 @@ size_t usrp2_impl::recv(
metadata.fragment_offset = _fragment_offset_in_samps;
_fragment_offset_in_samps += num_samps; //set for next time
- //copy the samples from the recv buffer
- switch(io_type.tid){
- case io_type_t::COMPLEX_FLOAT32:
- usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
- break;
- case io_type_t::COMPLEX_INT16:
- usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps);
- break;
- default:
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid));
- }
+ //copy-convert the samples from the recv buffer
+ convert_otw_type_to_io_type(
+ (const void*)items, _otw_type,
+ asio::buffer_cast<void*>(buff), io_type,
+ num_samps
+ );
//update the rx copy buffer to reflect the bytes copied
_rx_copy_buff = asio::buffer(
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 94ab88a6b..d7728238c 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -17,10 +17,14 @@
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
+#include "ad9777_regs.hpp"
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/mac_addr.hpp>
#include <uhd/types/dict.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
+#include <boost/assign/list_of.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -34,9 +38,31 @@ void usrp2_impl::mboard_init(void){
boost::bind(&usrp2_impl::mboard_set, this, _1, _2)
);
- //set the time on the usrp2 as close as possible to the system utc time
- boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
- set_time_spec(time_spec_t(now, get_master_clock_freq()), true);
+ _clk_ctrl = clock_control::make_ad9510(_iface);
+
+ //setup the ad9777 dac
+ ad9777_regs_t ad9777_regs;
+ ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R;
+ ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X;
+ ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL;
+ ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1;
+ ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF;
+ ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB;
+ //I dac values
+ ad9777_regs.idac_fine_gain_adjust = 0;
+ ad9777_regs.idac_coarse_gain_adjust = 0xf;
+ ad9777_regs.idac_offset_adjust_lsb = 0;
+ ad9777_regs.idac_offset_adjust_msb = 0;
+ //Q dac values
+ ad9777_regs.qdac_fine_gain_adjust = 0;
+ ad9777_regs.qdac_coarse_gain_adjust = 0xf;
+ ad9777_regs.qdac_offset_adjust_lsb = 0;
+ ad9777_regs.qdac_offset_adjust_msb = 0;
+ //write all regs
+ for(boost::uint8_t addr = 0; addr <= 0xC; addr++){
+ boost::uint16_t data = ad9777_regs.get_write_reg(addr);
+ _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/);
+ }
}
void usrp2_impl::init_clock_config(void){
@@ -67,19 +93,28 @@ void usrp2_impl::update_clock_config(void){
}
//set the pps flags
- this->poke32(FR_TIME64_FLAGS, pps_flags);
+ _iface->poke32(FR_TIME64_FLAGS, pps_flags);
+
+ //clock source ref 10mhz
+ switch(_clock_config.ref_source){
+ case clock_config_t::REF_INT : _iface->poke32(FR_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;
+ }
- //TODO clock source ref 10mhz (spi ad9510)
+ //clock source ref 10mhz
+ bool use_external = _clock_config.ref_source != clock_config_t::REF_INT;
+ _clk_ctrl->enable_external_ref(use_external);
}
void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
//set ticks and seconds
- this->poke32(FR_TIME64_SECS, time_spec.secs);
- this->poke32(FR_TIME64_TICKS, time_spec.ticks);
+ _iface->poke32(FR_TIME64_SECS, time_spec.secs);
+ _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
//set the register to latch it all in
boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS;
- this->poke32(FR_TIME64_IMM, imm_flags);
+ _iface->poke32(FR_TIME64_IMM, imm_flags);
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
@@ -88,7 +123,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO);
out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0;
out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs);
- out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.ticks);
+ out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
//set these to defaults, then change in the switch statement
out_data.data.stream_cmd.continuous = 0;
@@ -115,7 +150,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
}
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ 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);
}
@@ -134,7 +169,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO);
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ 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);
//extract the address
@@ -148,7 +183,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ 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);
//extract the address
@@ -190,10 +225,6 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){
val = prop_names_t(1, "");
return;
- case MBOARD_PROP_CLOCK_RATE:
- val = double(get_master_clock_freq());
- return;
-
case MBOARD_PROP_RX_DSP:
ASSERT_THROW(name == "");
val = _rx_dsp_proxy->get_link();
@@ -236,7 +267,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr);
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ 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);
return;
}
@@ -248,7 +279,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){
out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_ulong());
//send and recv
- usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data);
+ 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);
return;
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
new file mode 100644
index 000000000..5c84fd8d3
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -0,0 +1,168 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_iface.hpp"
+#include <uhd/utils/assert.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/thread.hpp>
+#include <boost/asio.hpp> //used for htonl and ntohl
+#include <boost/assign/list_of.hpp>
+#include <stdexcept>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+class usrp2_iface_impl : public usrp2_iface{
+public:
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+ usrp2_iface_impl(transport::udp_simple::sptr ctrl_transport){
+ _ctrl_transport = ctrl_transport;
+ }
+
+ ~usrp2_iface_impl(void){
+ /* NOP */
+ }
+
+/***********************************************************************
+ * Peek and Poke
+ **********************************************************************/
+ void poke32(boost::uint32_t addr, boost::uint32_t data){
+ return this->poke<boost::uint32_t>(addr, data);
+ }
+
+ boost::uint32_t peek32(boost::uint32_t addr){
+ return this->peek<boost::uint32_t>(addr);
+ }
+
+ void poke16(boost::uint32_t addr, boost::uint16_t data){
+ return this->poke<boost::uint16_t>(addr, data);
+ }
+
+ boost::uint16_t peek16(boost::uint32_t addr){
+ return this->peek<boost::uint16_t>(addr);
+ }
+
+/***********************************************************************
+ * SPI
+ **********************************************************************/
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ static const uhd::dict<spi_config_t::edge_t, int> spi_edge_to_otw = boost::assign::map_list_of
+ (spi_config_t::EDGE_RISE, USRP2_CLK_EDGE_RISE)
+ (spi_config_t::EDGE_FALL, USRP2_CLK_EDGE_FALL)
+ ;
+
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
+ out_data.data.spi_args.dev = which_slave;
+ out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge];
+ out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge];
+ out_data.data.spi_args.readback = (readback)? 1 : 0;
+ out_data.data.spi_args.num_bits = num_bits;
+ out_data.data.spi_args.data = htonl(data);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE);
+
+ return ntohl(out_data.data.spi_args.data);
+ }
+
+/***********************************************************************
+ * Send/Recv over control
+ **********************************************************************/
+ usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ //fill in the seq number and send
+ usrp2_ctrl_data_t out_copy = out_data;
+ out_copy.seq = htonl(++_ctrl_seq_num);
+ _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
+
+ //loop until we get the packet or timeout
+ while(true){
+ usrp2_ctrl_data_t in_data;
+ size_t len = _ctrl_transport->recv(boost::asio::buffer(&in_data, sizeof(in_data)));
+ if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
+ return in_data;
+ }
+ if (len == 0) break; //timeout
+ //didnt get seq or bad packet, continue looking...
+ }
+ throw std::runtime_error("usrp2 no control response");
+ }
+
+/***********************************************************************
+ * Master Clock! Ahhhhh
+ **********************************************************************/
+ double get_master_clock_freq(void){
+ return 100e6;
+ }
+
+private:
+ //this lovely lady makes it all possible
+ transport::udp_simple::sptr _ctrl_transport;
+
+ //used in send/recv
+ boost::mutex _ctrl_mutex;
+ boost::uint32_t _ctrl_seq_num;
+
+/***********************************************************************
+ * Private Templated Peek and Poke
+ **********************************************************************/
+ template <class T> void poke(boost::uint32_t addr, T data){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.data = htonl(boost::uint32_t(data));
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
+ }
+
+ template <class T> T peek(boost::uint32_t addr){
+ //setup the out data
+ usrp2_ctrl_data_t out_data;
+ out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
+ out_data.data.poke_args.addr = htonl(addr);
+ out_data.data.poke_args.num_bytes = sizeof(T);
+
+ //send and recv
+ usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
+ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
+ return T(ntohl(out_data.data.poke_args.data));
+ }
+
+};
+
+/***********************************************************************
+ * Public make function for usrp2 interface
+ **********************************************************************/
+usrp2_iface::sptr usrp2_iface::make(transport::udp_simple::sptr ctrl_transport){
+ return usrp2_iface::sptr(new usrp2_iface_impl(ctrl_transport));
+}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
new file mode 100644
index 000000000..1298d87f1
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -0,0 +1,103 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_USRP2_IFACE_HPP
+#define INCLUDED_USRP2_IFACE_HPP
+
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/usrp/dboard_iface.hpp> //spi config
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/cstdint.hpp>
+#include "fw_common.h"
+
+/*!
+ * The usrp2 interface class:
+ * Provides a set of functions to implementation layer.
+ * Including spi, peek, poke, control...
+ */
+class usrp2_iface : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<usrp2_iface> sptr;
+
+ /*!
+ * Make a new usrp2 interface with the control transport.
+ * \param ctrl_transport the udp transport object
+ * \return a new usrp2 interface object
+ */
+ static sptr make(uhd::transport::udp_simple::sptr ctrl_transport);
+
+ /*!
+ * Perform a control transaction.
+ * \param data a control data struct
+ * \return the result control data
+ */
+ virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0;
+
+ /*!
+ * Write a register (32 bits)
+ * \param addr the address
+ * \param data the 32bit data
+ */
+ virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0;
+
+ /*!
+ * Read a register (32 bits)
+ * \param addr the address
+ * \return the 32bit data
+ */
+ virtual boost::uint32_t peek32(boost::uint32_t addr) = 0;
+
+ /*!
+ * Write a register (16 bits)
+ * \param addr the address
+ * \param data the 16bit data
+ */
+ virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0;
+
+ /*!
+ * Read a register (16 bits)
+ * \param addr the address
+ * \return the 16bit data
+ */
+ virtual boost::uint16_t peek16(boost::uint32_t addr) = 0;
+
+ /*!
+ * Perform an spi transaction.
+ * \param which_slave the slave device number
+ * \param config spi config args
+ * \param data the bits to write
+ * \param num_bits how many bits in data
+ * \param readback true to readback a value
+ * \return spi data if readback set
+ */
+ virtual boost::uint32_t transact_spi(
+ int which_slave,
+ const uhd::usrp::spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ) = 0;
+
+ /*!
+ * Get the master clock frequency.
+ * \return the frequency in Hz
+ */
+ virtual double get_master_clock_freq(void) = 0;
+};
+
+#endif /* INCLUDED_USRP2_IFACE_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index a7be2da8c..3bdc5bd02 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -15,15 +15,18 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "usrp2_impl.hpp"
#include <uhd/transport/if_addrs.hpp>
+#include <uhd/transport/udp_simple.hpp>
#include <uhd/usrp/device_props.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/utils/static.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
+#include <boost/asio.hpp> //htonl and ntohl
#include <iostream>
-#include "usrp2_impl.hpp"
using namespace uhd;
using namespace uhd::usrp;
@@ -60,7 +63,6 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
}
//create a udp transport to communicate
- //TODO if an addr is not provided, search all interfaces?
std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
udp_simple::sptr udp_transport = udp_simple::make_broadcast(
hint["addr"], ctrl_port
@@ -127,9 +129,11 @@ usrp2_impl::usrp2_impl(
udp_simple::sptr ctrl_transport,
udp_zero_copy::sptr data_transport
){
- _ctrl_transport = ctrl_transport;
_data_transport = data_transport;
+ //make a new interface for usrp2 stuff
+ _iface = usrp2_iface::make(ctrl_transport);
+
//load the allowed decim/interp rates
//_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
_allowed_decim_and_interp_rates.clear();
@@ -168,80 +172,6 @@ usrp2_impl::~usrp2_impl(void){
}
/***********************************************************************
- * Misc Access Methods
- **********************************************************************/
-double usrp2_impl::get_master_clock_freq(void){
- return 100e6;
-}
-
-template <class T> void impl_poke(usrp2_impl *impl, boost::uint32_t addr, T data){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.poke_args.addr = htonl(addr);
- out_data.data.poke_args.data = htonl(boost::uint32_t(data));
- out_data.data.poke_args.num_bytes = sizeof(T);
-
- //send and recv
- usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
-}
-
-template <class T> T impl_peek(usrp2_impl *impl, boost::uint32_t addr){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
- out_data.data.poke_args.addr = htonl(addr);
- out_data.data.poke_args.num_bytes = sizeof(T);
-
- //send and recv
- usrp2_ctrl_data_t in_data = impl->ctrl_send_and_recv(out_data);
- ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
- return T(ntohl(out_data.data.poke_args.data));
-}
-
-
-void usrp2_impl::poke32(boost::uint32_t addr, boost::uint32_t data){
- return impl_poke<boost::uint32_t>(this, addr, data);
-}
-
-boost::uint32_t usrp2_impl::peek32(boost::uint32_t addr){
- return impl_peek<boost::uint32_t>(this, addr);
-}
-
-void usrp2_impl::poke16(boost::uint32_t addr, boost::uint16_t data){
- return impl_poke<boost::uint16_t>(this, addr, data);
-}
-
-boost::uint16_t usrp2_impl::peek16(boost::uint32_t addr){
- return impl_peek<boost::uint16_t>(this, addr);
-}
-
-/***********************************************************************
- * Control Send/Recv
- **********************************************************************/
-usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
- boost::mutex::scoped_lock lock(_ctrl_mutex);
-
- //fill in the seq number and send
- usrp2_ctrl_data_t out_copy = out_data;
- out_copy.seq = htonl(++_ctrl_seq_num);
- _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
-
- //loop until we get the packet or timeout
- while(true){
- usrp2_ctrl_data_t in_data;
- size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data)));
- if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
- return in_data;
- }
- if (len == 0) break; //timeout
- //didnt get seq or bad packet, continue looking...
- }
- throw std::runtime_error("usrp2 no control response");
-}
-
-/***********************************************************************
* Device Properties
**********************************************************************/
void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index baa6530b8..dbcee367b 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -18,29 +18,29 @@
#ifndef INCLUDED_USRP2_IMPL_HPP
#define INCLUDED_USRP2_IMPL_HPP
+#include "usrp2_iface.hpp"
+#include "clock_control.hpp"
#include <uhd/usrp/usrp2.hpp>
#include <uhd/types/dict.hpp>
+#include <uhd/types/otw_type.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/clock_config.hpp>
-#include <boost/asio.hpp>
-#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <boost/assign/list_of.hpp>
#include <uhd/transport/vrt.hpp>
-#include <uhd/transport/udp_simple.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/usrp/dboard_manager.hpp>
-#include "fw_common.h"
-
-class usrp2_impl; //dummy class declaration
/*!
* Make a usrp2 dboard interface.
- * \param impl a pointer to the usrp2 impl object
+ * \param iface the usrp2 interface object
+ * \param clk_ctrl the clock control object
* \return a sptr to a new dboard interface
*/
-uhd::usrp::dboard_interface::sptr make_usrp2_dboard_interface(usrp2_impl *impl);
+uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
+ usrp2_iface::sptr iface,
+ clock_control::sptr clk_ctrl
+);
/*!
* Simple wax obj proxy class:
@@ -99,28 +99,23 @@ public:
~usrp2_impl(void);
- //performs a control transaction
- usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &);
-
- //peek and poke registers
- void poke32(boost::uint32_t addr, boost::uint32_t data);
- boost::uint32_t peek32(boost::uint32_t addr);
-
- void poke16(boost::uint32_t addr, boost::uint16_t data);
- boost::uint16_t peek16(boost::uint32_t addr);
-
- //misc access methods
- double get_master_clock_freq(void);
-
//the io interface
size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &);
size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &);
private:
+ double get_master_clock_freq(void){
+ return _iface->get_master_clock_freq();
+ }
+
//device properties interface
void get(const wax::obj &, wax::obj &);
void set(const wax::obj &, const wax::obj &);
+ //interfaces
+ clock_control::sptr _clk_ctrl;
+ usrp2_iface::sptr _iface;
+
//the raw io interface (samples are in the usrp2 native format)
void recv_raw(uhd::rx_metadata_t &);
uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq;
@@ -136,19 +131,15 @@ private:
(_mtu - _hdrs)/sizeof(boost::uint32_t) -
uhd::transport::vrt::max_header_words32
;
- uhd::transport::smart_buffer::sptr _rx_smart_buff;
+ uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;
boost::asio::const_buffer _rx_copy_buff;
size_t _fragment_offset_in_samps;
+ uhd::otw_type_t _otw_type;
void io_init(void);
//udp transports for control and data
- uhd::transport::udp_simple::sptr _ctrl_transport;
uhd::transport::udp_zero_copy::sptr _data_transport;
- //private vars for dealing with send/recv control
- boost::uint32_t _ctrl_seq_num;
- boost::mutex _ctrl_mutex;
-
//methods and shadows for clock configuration
uhd::clock_config_t _clock_config;
void init_clock_config(void);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 77d9f4ad9..0e2a18756 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -62,6 +62,11 @@
#define SPI_SS_TX_DB 128
/////////////////////////////////////////////////
+// Misc Control
+////////////////////////////////////////////////
+#define FR_CLOCK_CONTROL _SR_ADDR(0)
+
+/////////////////////////////////////////////////
// VITA49 64 bit time (write only)
////////////////////////////////////////////////
/*!
diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp
index 40116e110..939a61eb4 100644
--- a/host/test/vrt_test.cpp
+++ b/host/test/vrt_test.cpp
@@ -36,7 +36,8 @@ static void pack_and_unpack(
num_header_words32, //output
num_payload_words32, //input
num_packet_words32, //output
- packet_count //input
+ packet_count, //input
+ 100e6
);
uhd::rx_metadata_t metadata_out;
@@ -51,7 +52,8 @@ static void pack_and_unpack(
num_header_words32_out, //output
num_payload_words32_out, //output
num_packet_words32, //input
- packet_count_out //output
+ packet_count_out, //output
+ 100e6
);
//check the the unpacked metadata is the same
@@ -65,7 +67,7 @@ static void pack_and_unpack(
BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec);
if (metadata.has_time_spec and metadata_out.has_time_spec){
BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs);
- BOOST_CHECK_EQUAL(metadata.time_spec.ticks, metadata_out.time_spec.ticks);
+ BOOST_CHECK_EQUAL(metadata.time_spec.nsecs, metadata_out.time_spec.nsecs);
}
}
@@ -85,7 +87,7 @@ BOOST_AUTO_TEST_CASE(test_with_time_spec){
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
metadata.time_spec.secs = 7;
- metadata.time_spec.ticks = 2000;
+ metadata.time_spec.nsecs = 2000;
pack_and_unpack(metadata, 500, 3);
}
@@ -95,6 +97,6 @@ BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){
metadata.stream_id = 2;
metadata.has_time_spec = true;
metadata.time_spec.secs = 5;
- metadata.time_spec.ticks = 1000;
+ metadata.time_spec.nsecs = 1000;
pack_and_unpack(metadata, 600, 4);
}