aboutsummaryrefslogtreecommitdiffstats
path: root/host/include
diff options
context:
space:
mode:
Diffstat (limited to 'host/include')
-rw-r--r--host/include/config.h.in6
-rw-r--r--host/include/uhd/CMakeLists.txt10
-rw-r--r--host/include/uhd/build_info.hpp55
-rw-r--r--host/include/uhd/config.h9
-rw-r--r--host/include/uhd/config.hpp20
-rw-r--r--host/include/uhd/device3.hpp146
-rw-r--r--host/include/uhd/error.h2
-rw-r--r--host/include/uhd/exception.hpp7
-rw-r--r--host/include/uhd/property_tree.hpp128
-rw-r--r--host/include/uhd/property_tree.ipp102
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt49
-rw-r--r--host/include/uhd/rfnoc/block_ctrl.hpp47
-rw-r--r--host/include/uhd/rfnoc/block_ctrl_base.hpp431
-rw-r--r--host/include/uhd/rfnoc/block_id.hpp211
-rw-r--r--host/include/uhd/rfnoc/blockdef.hpp126
-rw-r--r--host/include/uhd/rfnoc/blocks/CMakeLists.txt25
-rw-r--r--host/include/uhd/rfnoc/blocks/addsub.xml50
-rw-r--r--host/include/uhd/rfnoc/blocks/block.xml17
-rw-r--r--host/include/uhd/rfnoc/blocks/ddc.xml154
-rw-r--r--host/include/uhd/rfnoc/blocks/ddc_single.xml117
-rw-r--r--host/include/uhd/rfnoc/blocks/dma_fifo.xml64
-rw-r--r--host/include/uhd/rfnoc/blocks/duc.xml96
-rw-r--r--host/include/uhd/rfnoc/blocks/fft.xml116
-rw-r--r--host/include/uhd/rfnoc/blocks/fifo.xml34
-rw-r--r--host/include/uhd/rfnoc/blocks/fir.xml19
-rw-r--r--host/include/uhd/rfnoc/blocks/fosphor.xml157
-rw-r--r--host/include/uhd/rfnoc/blocks/keep_one_in_n.xml55
-rw-r--r--host/include/uhd/rfnoc/blocks/logpwr.xml49
-rw-r--r--host/include/uhd/rfnoc/blocks/nullblock.xml30
-rw-r--r--host/include/uhd/rfnoc/blocks/ofdmeq.xml31
-rw-r--r--host/include/uhd/rfnoc/blocks/packetresizer.xml55
-rw-r--r--host/include/uhd/rfnoc/blocks/radio_x300.xml60
-rw-r--r--host/include/uhd/rfnoc/blocks/siggen.xml116
-rw-r--r--host/include/uhd/rfnoc/blocks/window.xml47
-rw-r--r--host/include/uhd/rfnoc/constants.hpp108
-rw-r--r--host/include/uhd/rfnoc/ddc_block_ctrl.hpp50
-rw-r--r--host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp55
-rw-r--r--host/include/uhd/rfnoc/duc_block_ctrl.hpp51
-rw-r--r--host/include/uhd/rfnoc/graph.hpp62
-rw-r--r--host/include/uhd/rfnoc/node_ctrl_base.hpp244
-rw-r--r--host/include/uhd/rfnoc/node_ctrl_base.ipp128
-rw-r--r--host/include/uhd/rfnoc/radio_ctrl.hpp205
-rw-r--r--host/include/uhd/rfnoc/rate_node_ctrl.hpp67
-rw-r--r--host/include/uhd/rfnoc/scalar_node_ctrl.hpp74
-rw-r--r--host/include/uhd/rfnoc/sink_block_ctrl_base.hpp126
-rw-r--r--host/include/uhd/rfnoc/sink_node_ctrl.hpp145
-rw-r--r--host/include/uhd/rfnoc/source_block_ctrl_base.hpp140
-rw-r--r--host/include/uhd/rfnoc/source_node_ctrl.hpp136
-rw-r--r--host/include/uhd/rfnoc/stream_sig.hpp88
-rw-r--r--host/include/uhd/rfnoc/terminator_node_ctrl.hpp53
-rw-r--r--host/include/uhd/rfnoc/tick_node_ctrl.hpp70
-rw-r--r--host/include/uhd/transport/muxed_zero_copy_if.hpp72
-rw-r--r--host/include/uhd/transport/usb_control.hpp18
-rw-r--r--host/include/uhd/transport/usb_device_handle.hpp2
-rw-r--r--host/include/uhd/transport/usb_zero_copy.hpp10
-rw-r--r--host/include/uhd/transport/zero_copy_recv_offload.hpp50
-rw-r--r--host/include/uhd/types/CMakeLists.txt2
-rw-r--r--host/include/uhd/types/filters.hpp24
-rw-r--r--host/include/uhd/types/sensors.hpp17
-rw-r--r--host/include/uhd/types/serial.hpp6
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt4
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp7
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp91
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp79
-rw-r--r--host/include/uhd/usrp/fe_connection.hpp127
-rw-r--r--host/include/uhd/usrp/gpio_defs.hpp70
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp90
-rw-r--r--host/include/uhd/usrp/usrp.h79
-rw-r--r--host/include/uhd/utils/algorithm.hpp10
-rw-r--r--host/include/uhd/utils/atomic.hpp8
-rw-r--r--host/include/uhd/utils/cast.hpp4
-rw-r--r--host/include/uhd/utils/dirty_tracked.hpp16
-rw-r--r--host/include/uhd/utils/math.hpp13
-rw-r--r--host/include/uhd/utils/msg_task.hpp4
-rw-r--r--host/include/uhd/utils/soft_register.hpp58
-rw-r--r--host/include/uhd/version.hpp.in10
76 files changed, 5118 insertions, 196 deletions
diff --git a/host/include/config.h.in b/host/include/config.h.in
index bd690299e..8931d6580 100644
--- a/host/include/config.h.in
+++ b/host/include/config.h.in
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Ettus Research LLC
+ * Copyright 2015,2016 Ettus Research LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,8 @@
/* Version macros */
#cmakedefine UHD_VERSION_MAJOR ${TRIMMED_VERSION_MAJOR}
-#cmakedefine UHD_VERSION_MINOR ${TRIMMED_VERSION_MINOR}
+#cmakedefine UHD_VERSION_API ${TRIMMED_VERSION_API}
+#cmakedefine UHD_VERSION_ABI ${TRIMMED_VERSION_ABI}
#cmakedefine UHD_VERSION_PATCH ${TRIMMED_VERSION_PATCH}
+#cmakedefine ENABLE_USB
#cmakedefine UHD_VERSION @UHD_VERSION_ADDED@
diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt
index 083ec4951..e31ff80a0 100644
--- a/host/include/uhd/CMakeLists.txt
+++ b/host/include/uhd/CMakeLists.txt
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+ADD_SUBDIRECTORY(rfnoc)
ADD_SUBDIRECTORY(transport)
ADD_SUBDIRECTORY(types)
ADD_SUBDIRECTORY(usrp)
@@ -27,6 +28,7 @@ CONFIGURE_FILE(
)
UHD_INSTALL(FILES
+ build_info.hpp
config.hpp
convert.hpp
deprecated.hpp
@@ -41,6 +43,14 @@ UHD_INSTALL(FILES
COMPONENT headers
)
+IF(ENABLE_RFNOC)
+ UHD_INSTALL(FILES
+ device3.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd
+ COMPONENT headers
+ )
+ENDIF(ENABLE_RFNOC)
+
IF(ENABLE_C_API)
UHD_INSTALL(FILES
config.h
diff --git a/host/include/uhd/build_info.hpp b/host/include/uhd/build_info.hpp
new file mode 100644
index 000000000..2e6571ad0
--- /dev/null
+++ b/host/include/uhd/build_info.hpp
@@ -0,0 +1,55 @@
+//
+// Copyright 2015 National Instruments Corp.
+//
+// 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_BUILD_INFO_HPP
+#define INCLUDED_UHD_BUILD_INFO_HPP
+
+#include <uhd/config.hpp>
+
+#include <string>
+
+namespace uhd { namespace build_info {
+
+ //! Return the version of Boost this build was built with.
+ UHD_API const std::string boost_version();
+
+ //! Return the date and time (GMT) this UHD build was built.
+ UHD_API const std::string build_date();
+
+ //! Return the C compiler used for this build.
+ UHD_API const std::string c_compiler();
+
+ //! Return the C++ compiler used for this build.
+ UHD_API const std::string cxx_compiler();
+
+ //! Return the C flags passed into this build.
+ UHD_API const std::string c_flags();
+
+ //! Return the C++ flags passed into this build.
+ UHD_API const std::string cxx_flags();
+
+ //! Return the UHD components enabled for this build, comma-delimited.
+ UHD_API const std::string enabled_components();
+
+ //! Return the default CMake install prefix for this build.
+ UHD_API const std::string install_prefix();
+
+ //! Return the version of libusb this build was built with.
+ UHD_API const std::string libusb_version();
+}}
+
+#endif /* INCLUDED_UHD_BUILD_INFO_HPP */
diff --git a/host/include/uhd/config.h b/host/include/uhd/config.h
index 1677c80ec..a22dea424 100644
--- a/host/include/uhd/config.h
+++ b/host/include/uhd/config.h
@@ -43,7 +43,14 @@ typedef ptrdiff_t ssize_t;
#define UHD_DEPRECATED __declspec(deprecated)
#define UHD_ALIGNED(x) __declspec(align(x))
#define UHD_UNUSED(x) x __attribute__((unused))
-#elif defined(__GNUG__) && __GNUG__ >= 4
+#elif defined(__GNUC__) && __GNUC__ >= 4
+ #define UHD_EXPORT __attribute__((visibility("default")))
+ #define UHD_IMPORT __attribute__((visibility("default")))
+ #define UHD_INLINE inline __attribute__((always_inline))
+ #define UHD_DEPRECATED __attribute__((deprecated))
+ #define UHD_ALIGNED(x) __attribute__((aligned(x)))
+ #define UHD_UNUSED(x) x __attribute__((unused))
+#elif defined(__clang__)
#define UHD_EXPORT __attribute__((visibility("default")))
#define UHD_IMPORT __attribute__((visibility("default")))
#define UHD_INLINE inline __attribute__((always_inline))
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 00466501e..cef7d3bb4 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -36,7 +36,7 @@
# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ...
//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated
-//# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance
+# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance
# pragma warning(disable: 4200) // nonstandard extension used : zero-sized array in struct/union
// define logical operators
@@ -53,6 +53,7 @@ typedef ptrdiff_t ssize_t;
#define UHD_EXPORT __declspec(dllexport)
#define UHD_IMPORT __declspec(dllimport)
#define UHD_INLINE __forceinline
+ #define UHD_FORCE_INLINE __forceinline
#define UHD_DEPRECATED __declspec(deprecated)
#define UHD_ALIGNED(x) __declspec(align(x))
#define UHD_UNUSED(x) x
@@ -60,6 +61,7 @@ typedef ptrdiff_t ssize_t;
#define UHD_EXPORT __declspec(dllexport)
#define UHD_IMPORT __declspec(dllimport)
#define UHD_INLINE inline
+ #define UHD_FORCE_INLINE inline
#define UHD_DEPRECATED __declspec(deprecated)
#define UHD_ALIGNED(x) __declspec(align(x))
#define UHD_UNUSED(x) x __attribute__((unused))
@@ -67,6 +69,15 @@ typedef ptrdiff_t ssize_t;
#define UHD_EXPORT __attribute__((visibility("default")))
#define UHD_IMPORT __attribute__((visibility("default")))
#define UHD_INLINE inline __attribute__((always_inline))
+ #define UHD_FORCE_INLINE inline __attribute__((always_inline))
+ #define UHD_DEPRECATED __attribute__((deprecated))
+ #define UHD_ALIGNED(x) __attribute__((aligned(x)))
+ #define UHD_UNUSED(x) x __attribute__((unused))
+#elif defined(__clang__)
+ #define UHD_EXPORT __attribute__((visibility("default")))
+ #define UHD_IMPORT __attribute__((visibility("default")))
+ #define UHD_INLINE inline __attribute__((always_inline))
+ #define UHD_FORCE_INLINE inline __attribute__((always_inline))
#define UHD_DEPRECATED __attribute__((deprecated))
#define UHD_ALIGNED(x) __attribute__((aligned(x)))
#define UHD_UNUSED(x) x __attribute__((unused))
@@ -74,6 +85,7 @@ typedef ptrdiff_t ssize_t;
#define UHD_EXPORT
#define UHD_IMPORT
#define UHD_INLINE inline
+ #define UHD_FORCE_INLINE inline
#define UHD_DEPRECATED
#define UHD_ALIGNED(x)
#define UHD_UNUSED(x) x
@@ -85,6 +97,12 @@ typedef ptrdiff_t ssize_t;
#else
#define UHD_API UHD_IMPORT
#endif // UHD_DLL_EXPORTS
+#ifdef UHD_RFNOC_ENABLED
+ #define UHD_RFNOC_API UHD_API
+#else
+ #define UHD_RFNOC_API
+#endif // UHD_RFNOC_ENABLED
+
// Platform defines for conditional parts of headers:
// Taken from boost/config/select_platform_config.hpp,
diff --git a/host/include/uhd/device3.hpp b/host/include/uhd/device3.hpp
new file mode 100644
index 000000000..da23bb263
--- /dev/null
+++ b/host/include/uhd/device3.hpp
@@ -0,0 +1,146 @@
+//
+// Copyright 2014-2016 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_DEVICE3_HPP
+#define INCLUDED_UHD_DEVICE3_HPP
+
+#include <uhd/device.hpp>
+#include <uhd/rfnoc/graph.hpp>
+#include <uhd/rfnoc/block_ctrl_base.hpp>
+#include <boost/units/detail/utility.hpp>
+#include <vector>
+
+namespace uhd {
+
+/*!
+ * \brief Extends uhd::device for third-generation USRP devices.
+ *
+ * Generation-3 devices are characterized by the following traits:
+ * - They support RFNoC (RF Network-on-Chip).
+ * - Data transport uses the compressed VITA (CVITA/CHDR) data format.
+ */
+class UHD_API device3 : public uhd::device {
+
+ public:
+ typedef boost::shared_ptr<device3> sptr;
+
+ //! Same as uhd::device::make(), but will fail if not actually a device3
+ static sptr make(const device_addr_t &hint, const size_t which = 0);
+
+ virtual rfnoc::graph::sptr create_graph(const std::string &name="") = 0;
+
+ /*! Reset blocks after a stream.
+ *
+ * TODO write docs
+ */
+ void clear();
+
+ /*! \brief Checks if an RFNoC block exists on the device.
+ *
+ * \param block_id Canonical block name (e.g. "0/FFT_1").
+ * \return true if a block with the specified id exists
+ */
+ bool has_block(const rfnoc::block_id_t &block_id) const;
+
+ /*! Same as has_block(), but with a type check.
+ *
+ * \return true if a block of type T with the specified id exists
+ */
+ template <typename T>
+ bool has_block(const rfnoc::block_id_t &block_id) const
+ {
+ if (has_block(block_id)) {
+ return bool(boost::dynamic_pointer_cast<T>(get_block_ctrl(block_id)));
+ } else {
+ return false;
+ }
+ }
+
+ /*! \brief Returns a block controller class for an RFNoC block.
+ *
+ * If the given block ID is not valid (i.e. such a block does not exist
+ * on this device), it will throw a uhd::lookup_error.
+ *
+ * \param block_id Canonical block name (e.g. "0/FFT_1").
+ */
+ rfnoc::block_ctrl_base::sptr get_block_ctrl(const rfnoc::block_id_t &block_id) const;
+
+ /*! Same as get_block_ctrl(), but with a type cast.
+ *
+ * If you have a block controller class that is derived from block_ctrl_base,
+ * use this function to access its specific methods.
+ * If the given block ID is not valid (i.e. such a block does not exist
+ * on this device) or if the type does not match, it will throw a uhd::lookup_error.
+ *
+ * \code{.cpp}
+ * // Assume DEV is a device3::sptr
+ * uhd::rfnoc::my_block_ctrl::sptr block_controller = get_block_ctrl<my_block_ctrl>("0/MyBlock_0");
+ * block_controller->my_own_block_method();
+ * \endcode
+ */
+ template <typename T>
+ boost::shared_ptr<T> get_block_ctrl(const rfnoc::block_id_t &block_id) const
+ {
+ boost::shared_ptr<T> blk = boost::dynamic_pointer_cast<T>(get_block_ctrl(block_id));
+ if (blk) {
+ return blk;
+ } else {
+ throw uhd::lookup_error(str(boost::format("This device does not have a block of type %s with ID: %s")
+ % boost::units::detail::demangle(typeid(T).name())
+ % block_id.to_string()));
+ }
+ }
+
+ /*! Returns the block ids of all blocks that match the specified hint
+ * Uses block_ctrl_base::match() internally.
+ * If no matching block is found, it returns an empty vector.
+ *
+ * To access specialized block controller classes (i.e. derived from block_ctrl_base),
+ * use the templated version of this function, e.g.
+ * \code{.cpp}
+ * // Assume DEV is a device3::sptr
+ * null_block_ctrl::sptr null_block = DEV->find_blocks<null_block_ctrl>("NullSrcSink");
+ * \endcode
+ */
+ std::vector<rfnoc::block_id_t> find_blocks(const std::string &block_id_hint) const;
+
+ /*! Type-cast version of find_blocks().
+ */
+ template <typename T>
+ std::vector<rfnoc::block_id_t> find_blocks(const std::string &block_id_hint) const
+ {
+ std::vector<rfnoc::block_id_t> all_block_ids = find_blocks(block_id_hint);
+ std::vector<rfnoc::block_id_t> filt_block_ids;
+ for (size_t i = 0; i < all_block_ids.size(); i++) {
+ if (has_block<T>(all_block_ids[i])) {
+ filt_block_ids.push_back(all_block_ids[i]);
+ }
+ }
+ return filt_block_ids;
+ }
+
+ protected:
+ //! List of *all* RFNoC blocks available on this device.
+ // It is the responsibility of the deriving class to make
+ // sure this gets correctly populated.
+ std::vector< rfnoc::block_ctrl_base::sptr > _rfnoc_block_ctrl;
+};
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_DEVICE3_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/error.h b/host/include/uhd/error.h
index f0ac41d1f..77216dc72 100644
--- a/host/include/uhd/error.h
+++ b/host/include/uhd/error.h
@@ -158,7 +158,7 @@ extern "C" {
* strings into a buffer that can be queried with this function. Functions that
* do take in UHD structs/handles will place their error strings in both locations.
*/
-uhd_error uhd_get_last_error(
+UHD_API uhd_error uhd_get_last_error(
char* error_out,
size_t strbuffer_len
);
diff --git a/host/include/uhd/exception.hpp b/host/include/uhd/exception.hpp
index 7eddf5f26..98982b01f 100644
--- a/host/include/uhd/exception.hpp
+++ b/host/include/uhd/exception.hpp
@@ -141,6 +141,13 @@ namespace uhd{
virtual void dynamic_throw(void) const;
};
+ struct UHD_API syntax_error : exception{
+ syntax_error(const std::string &what);
+ virtual unsigned code(void) const;
+ virtual syntax_error *dynamic_clone(void) const;
+ virtual void dynamic_throw(void) const;
+ };
+
/*!
* Create a formatted string with throw-site information.
* Fills in the function name, file name, and line number.
diff --git a/host/include/uhd/property_tree.hpp b/host/include/uhd/property_tree.hpp
index a92654ba2..93353568a 100644
--- a/host/include/uhd/property_tree.hpp
+++ b/host/include/uhd/property_tree.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011,2014 Ettus Research LLC
+// Copyright 2011,2014-2016 Ettus Research
//
// 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
@@ -27,8 +27,51 @@
namespace uhd{
/*!
- * A templated property interface for holding a value
+ * A templated property interface for holding the state
+ * associated with a property in a uhd::property_tree
* and registering callbacks when that value changes.
+ *
+ * A property is defined to have two separate vales:
+ * - Desired value: Value requested by the user
+ * - Coerced value: Value that was actually possible
+ * given HW and other requirements
+ *
+ * By default, the desired and coerced values are
+ * identical as long as the property is not coerced.
+ * A property can be coerced in two way:
+ * 1. Using a coercer: A callback function that takes
+ * in a desired value and produces a coerced value.
+ * A property must have *exactly one* coercer.
+ * 2. Manual coercion: Manually calling the set_coerced
+ * API fnction to coerce the value of the propery. In
+ * order to use manual coercion, the propery must be
+ * created with the MANUAL_COERCE mode.
+ * If the coerce mode for a property is AUTO_COERCE then
+ * it always has a coercer. If the set_coercer API is
+ * never used, then the default coercer is used which
+ * simply set the coerced value to the desired value.
+ *
+ * It is possible to get notified every time the desired
+ * or coerced values of a property potentially change
+ * using subscriber callbacks. Every property can have
+ * zero or more desired and coerced subscribers.
+ *
+ * If storing the property readback state in software is
+ * not appropriate (for example if it needs to be queried
+ * from hardware) then it is possible to use a publisher
+ * callback to get the value of the property. Calling
+ * get on the property will always call the publisher and
+ * the cached desired and coerced values are updated only
+ * using set* calls. A preprty must have *at most one*
+ * publisher. It is legal to have both a coercer
+ * and publisher for a property but the only way to access
+ * the desired and coerced values in that case would be by
+ * notification using the desired and coerced subscribers.
+ * Publishers are useful for creating read-only properties.
+ *
+ * Requirements for the template type T:
+ * - T must have a copy constructor
+ * - T must have an assignment operator
*/
template <typename T> class property : boost::noncopyable{
public:
@@ -40,60 +83,107 @@ public:
/*!
* Register a coercer into the property.
- * A coercer is a special subscriber that coerces the value.
+ * A coercer is a callback function that updates the
+ * coerced value of a property.
+ *
* Only one coercer may be registered per property.
- * Registering a coercer replaces the previous coercer.
* \param coercer the coercer callback function
* \return a reference to this property for chaining
+ * \throws uhd::assertion_error if called more than once
*/
- virtual property<T> &coerce(const coercer_type &coercer) = 0;
+ virtual property<T> &set_coercer(const coercer_type &coercer) = 0;
/*!
* Register a publisher into the property.
- * A publisher is a special callback the provides the value.
- * Publishers are useful for creating read-only properties.
+ * A publisher is a callback function the provides the value
+ * for a property.
+ *
* Only one publisher may be registered per property.
- * Registering a publisher replaces the previous publisher.
* \param publisher the publisher callback function
* \return a reference to this property for chaining
+ * \throws uhd::assertion_error if called more than once
*/
- virtual property<T> &publish(const publisher_type &publisher) = 0;
+ virtual property<T> &set_publisher(const publisher_type &publisher) = 0;
/*!
* Register a subscriber into the property.
- * All subscribers are called when the value changes.
+ * All desired subscribers are called when the desired value
+ * potentially changes.
+ *
* Once a subscriber is registered, it cannot be unregistered.
* \param subscriber the subscriber callback function
* \return a reference to this property for chaining
*/
- virtual property<T> &subscribe(const subscriber_type &subscriber) = 0;
+ virtual property<T> &add_desired_subscriber(const subscriber_type &subscriber) = 0;
+
+ /*!
+ * Register a subscriber into the property.
+ * All coerced subscribers are called when the coerced value
+ * potentially changes.
+ *
+ * Once a subscriber is registered, it cannot be unregistered.
+ * \param subscriber the subscriber callback function
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &add_coerced_subscriber(const subscriber_type &subscriber) = 0;
/*!
* Update calls all subscribers w/ the current value.
+ *
* \return a reference to this property for chaining
+ * \throws uhd::assertion_error
*/
virtual property<T> &update(void) = 0;
/*!
- * Set the new value and call all subscribers.
- * The coercer (when provided) is called initially,
- * and the coerced value is used to set the subscribers.
+ * Set the new value and call all the necessary subscribers.
+ * Order of operations:
+ * - The desired value of the property is updated
+ * - All desired subscribers are called
+ * - If coerce mode is AUTO then the coercer is called
+ * - If coerce mode is AUTO then all coerced subscribers are called
+ *
* \param value the new value to set on this property
* \return a reference to this property for chaining
+ * \throws uhd::assertion_error
*/
virtual property<T> &set(const T &value) = 0;
/*!
+ * Set a coerced value and call all subscribers.
+ * The coercer is bypassed, and the specified value is
+ * used as the coerced value. All coerced subscribers
+ * are called. This function can only be used when the
+ * coerce mode is set to MANUAL_COERCE.
+ *
+ * \param value the new value to set on this property
+ * \return a reference to this property for chaining
+ * \throws uhd::assertion_error
+ */
+ virtual property<T> &set_coerced(const T &value) = 0;
+
+ /*!
* Get the current value of this property.
* The publisher (when provided) yields the value,
- * otherwise an internal shadow is used for the value.
+ * otherwise an internal coerced value is returned.
+ *
* \return the current value in the property
+ * \throws uhd::assertion_error
*/
- virtual T get(void) const = 0;
+ virtual const T get(void) const = 0;
+
+ /*!
+ * Get the current desired value of this property.
+ *
+ * \return the current desired value in the property
+ * \throws uhd::assertion_error
+ */
+ virtual const T get_desired(void) const = 0;
/*!
* A property is empty if it has never been set.
* A property with a publisher is never empty.
+ *
* \return true if the property is empty
*/
virtual bool empty(void) const = 0;
@@ -129,6 +219,8 @@ class UHD_API property_tree : boost::noncopyable{
public:
typedef boost::shared_ptr<property_tree> sptr;
+ enum coerce_mode_t { AUTO_COERCE, MANUAL_COERCE };
+
virtual ~property_tree(void) = 0;
//! Create a new + empty property tree
@@ -147,7 +239,9 @@ public:
virtual std::vector<std::string> list(const fs_path &path) const = 0;
//! Create a new property entry in the tree
- template <typename T> property<T> &create(const fs_path &path);
+ template <typename T> property<T> &create(
+ const fs_path &path,
+ coerce_mode_t coerce_mode = AUTO_COERCE);
//! Get access to a property in the tree
template <typename T> property<T> &access(const fs_path &path);
diff --git a/host/include/uhd/property_tree.ipp b/host/include/uhd/property_tree.ipp
index 93962c963..6ed1056e6 100644
--- a/host/include/uhd/property_tree.ipp
+++ b/host/include/uhd/property_tree.ipp
@@ -1,5 +1,5 @@
//
-// Copyright 2011,2014 Ettus Research LLC
+// Copyright 2011,2014-2016 Ettus Research
//
// 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
@@ -20,6 +20,7 @@
#include <uhd/exception.hpp>
#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
#include <vector>
/***********************************************************************
@@ -29,23 +30,38 @@ namespace uhd{ namespace /*anon*/{
template <typename T> class property_impl : public property<T>{
public:
+ property_impl<T>(property_tree::coerce_mode_t mode) : _coerce_mode(mode){
+ if (_coerce_mode == property_tree::AUTO_COERCE) {
+ _coercer = DEFAULT_COERCER;
+ }
+ }
~property_impl<T>(void){
/* NOP */
}
- property<T> &coerce(const typename property<T>::coercer_type &coercer){
+ property<T> &set_coercer(const typename property<T>::coercer_type &coercer){
+ if (not _coercer.empty()) uhd::assertion_error("cannot register more than one coercer for a property");
+ if (_coerce_mode == property_tree::MANUAL_COERCE) uhd::assertion_error("cannot register coercer for a manually coerced property");
+
_coercer = coercer;
return *this;
}
- property<T> &publish(const typename property<T>::publisher_type &publisher){
+ property<T> &set_publisher(const typename property<T>::publisher_type &publisher){
+ if (not _publisher.empty()) uhd::assertion_error("cannot register more than one publisher for a property");
+
_publisher = publisher;
return *this;
}
- property<T> &subscribe(const typename property<T>::subscriber_type &subscriber){
- _subscribers.push_back(subscriber);
+ property<T> &add_desired_subscriber(const typename property<T>::subscriber_type &subscriber){
+ _desired_subscribers.push_back(subscriber);
+ return *this;
+ }
+
+ property<T> &add_coerced_subscriber(const typename property<T>::subscriber_type &subscriber){
+ _coerced_subscribers.push_back(subscriber);
return *this;
}
@@ -54,17 +70,49 @@ public:
return *this;
}
+ void _set_coerced(const T &value){
+ init_or_set_value(_coerced_value, value);
+ BOOST_FOREACH(typename property<T>::subscriber_type &csub, _coerced_subscribers){
+ csub(get_value_ref(_coerced_value)); //let errors propagate
+ }
+ }
+
property<T> &set(const T &value){
- _value = boost::shared_ptr<T>(new T(_coercer.empty()? value : _coercer(value)));
- BOOST_FOREACH(typename property<T>::subscriber_type &subscriber, _subscribers){
- subscriber(*_value); //let errors propagate
+ init_or_set_value(_value, value);
+ BOOST_FOREACH(typename property<T>::subscriber_type &dsub, _desired_subscribers){
+ dsub(get_value_ref(_value)); //let errors propagate
}
+ if (not _coercer.empty()) {
+ _set_coerced(_coercer(get_value_ref(_value)));
+ } else {
+ if (_coerce_mode == property_tree::AUTO_COERCE) uhd::assertion_error("coercer missing for an auto coerced property");
+ }
+ return *this;
+ }
+
+ property<T> &set_coerced(const T &value){
+ if (_coerce_mode == property_tree::AUTO_COERCE) uhd::assertion_error("cannot set coerced value an auto coerced property");
+ _set_coerced(value);
return *this;
}
- T get(void) const{
- if (empty()) throw uhd::runtime_error("Cannot get() on an empty property");
- return _publisher.empty()? *_value : _publisher();
+ const T get(void) const{
+ if (empty()) {
+ throw uhd::runtime_error("Cannot get() on an uninitialized (empty) property");
+ }
+ if (not _publisher.empty()) {
+ return _publisher();
+ } else {
+ if (_coerced_value.get() == NULL and _coerce_mode == property_tree::MANUAL_COERCE)
+ throw uhd::runtime_error("uninitialized coerced value for manually coerced attribute");
+ return get_value_ref(_coerced_value);
+ }
+ }
+
+ const T get_desired(void) const{
+ if (_value.get() == NULL) throw uhd::runtime_error("Cannot get_desired() on an uninitialized (empty) property");
+
+ return get_value_ref(_value);
}
bool empty(void) const{
@@ -72,10 +120,30 @@ public:
}
private:
- std::vector<typename property<T>::subscriber_type> _subscribers;
- typename property<T>::publisher_type _publisher;
- typename property<T>::coercer_type _coercer;
- boost::shared_ptr<T> _value;
+ static T DEFAULT_COERCER(const T& value) {
+ return value;
+ }
+
+ static void init_or_set_value(boost::scoped_ptr<T>& scoped_value, const T& init_val) {
+ if (scoped_value.get() == NULL) {
+ scoped_value.reset(new T(init_val));
+ } else {
+ *scoped_value = init_val;
+ }
+ }
+
+ static const T& get_value_ref(const boost::scoped_ptr<T>& scoped_value) {
+ if (scoped_value.get() == NULL) throw uhd::assertion_error("Cannot use uninitialized property data");
+ return *scoped_value.get();
+ }
+
+ const property_tree::coerce_mode_t _coerce_mode;
+ std::vector<typename property<T>::subscriber_type> _desired_subscribers;
+ std::vector<typename property<T>::subscriber_type> _coerced_subscribers;
+ typename property<T>::publisher_type _publisher;
+ typename property<T>::coercer_type _coercer;
+ boost::scoped_ptr<T> _value;
+ boost::scoped_ptr<T> _coerced_value;
};
}} //namespace uhd::/*anon*/
@@ -85,8 +153,8 @@ private:
**********************************************************************/
namespace uhd{
- template <typename T> property<T> &property_tree::create(const fs_path &path){
- this->_create(path, typename boost::shared_ptr<property<T> >(new property_impl<T>()));
+ template <typename T> property<T> &property_tree::create(const fs_path &path, coerce_mode_t coerce_mode){
+ this->_create(path, typename boost::shared_ptr<property<T> >(new property_impl<T>(coerce_mode)));
return this->access<T>(path);
}
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
new file mode 100644
index 000000000..15a92ae8f
--- /dev/null
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -0,0 +1,49 @@
+#
+# Copyright 2014-2016 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/>.
+#
+
+IF(ENABLE_RFNOC)
+ UHD_INSTALL(FILES
+ # Infrastructure
+ block_ctrl_base.hpp
+ block_ctrl.hpp
+ blockdef.hpp
+ block_id.hpp
+ constants.hpp
+ graph.hpp
+ node_ctrl_base.hpp
+ node_ctrl_base.ipp
+ rate_node_ctrl.hpp
+ scalar_node_ctrl.hpp
+ sink_block_ctrl_base.hpp
+ sink_node_ctrl.hpp
+ source_block_ctrl_base.hpp
+ source_node_ctrl.hpp
+ stream_sig.hpp
+ terminator_node_ctrl.hpp
+ tick_node_ctrl.hpp
+ # Block controllers
+ ddc_block_ctrl.hpp
+ duc_block_ctrl.hpp
+ radio_ctrl.hpp
+ DESTINATION ${INCLUDE_DIR}/uhd/rfnoc
+ COMPONENT headers
+ )
+ENDIF(ENABLE_RFNOC)
+
+ADD_SUBDIRECTORY(blocks)
+#ADD_SUBDIRECTORY(components)
+
diff --git a/host/include/uhd/rfnoc/block_ctrl.hpp b/host/include/uhd/rfnoc/block_ctrl.hpp
new file mode 100644
index 000000000..b32192d86
--- /dev/null
+++ b/host/include/uhd/rfnoc/block_ctrl.hpp
@@ -0,0 +1,47 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP
+#define INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP
+
+#include <uhd/rfnoc/source_block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief This is the default implementation of a block_ctrl_base.
+ *
+ * For most blocks, this will be a sufficient implementation. All registers
+ * can be set by sr_write(). The default behaviour of functions is documented
+ * in uhd::rfnoc::block_ctrl_base.
+ */
+class UHD_RFNOC_API block_ctrl : public source_block_ctrl_base, public sink_block_ctrl_base
+{
+public:
+ // Required macro in RFNoC block classes
+ UHD_RFNOC_BLOCK_OBJECT(block_ctrl)
+
+ // Nothing else here -- all function definitions are in block_ctrl_base,
+ // source_block_ctrl_base and sink_block_ctrl_base
+
+}; /* class block_ctrl*/
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/block_ctrl_base.hpp b/host/include/uhd/rfnoc/block_ctrl_base.hpp
new file mode 100644
index 000000000..fa3ceadc5
--- /dev/null
+++ b/host/include/uhd/rfnoc/block_ctrl_base.hpp
@@ -0,0 +1,431 @@
+//
+// Copyright 2014-2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP
+
+#include <uhd/property_tree.hpp>
+#include <uhd/stream.hpp>
+#include <uhd/types/sid.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/wb_iface.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/block_id.hpp>
+#include <uhd/rfnoc/stream_sig.hpp>
+#include <uhd/rfnoc/blockdef.hpp>
+#include <uhd/rfnoc/constants.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+#include <stdint.h>
+
+namespace uhd {
+ namespace rfnoc {
+ namespace nocscript {
+ // Forward declaration
+ class block_iface;
+ }
+
+
+// TODO: Move this out of public section
+struct make_args_t
+{
+ make_args_t(const std::string &key="") :
+ device_index(0),
+ is_big_endian(true),
+ block_name(""),
+ block_key(key)
+ {}
+
+ //! A valid interface that allows us to do peeks and pokes
+ std::map<size_t, uhd::wb_iface::sptr> ctrl_ifaces;
+ //! This block's base address (address of block port 0)
+ uint32_t base_address;
+ //! The device index (or motherboard index).
+ size_t device_index;
+ //! A property tree for this motherboard. Example: If the root a device's
+ // property tree is /mboards/0, pass a subtree starting at /mboards/0
+ // to the constructor.
+ uhd::property_tree::sptr tree;
+ bool is_big_endian;
+ //! The name of the block as it will be addressed
+ std::string block_name;
+ //! The key of the block, i.e. how it was registered
+ std::string block_key;
+};
+
+//! This macro must be put in the public section of an RFNoC
+// block class
+#define UHD_RFNOC_BLOCK_OBJECT(class_name) \
+ typedef boost::shared_ptr< class_name > sptr;
+
+//! Shorthand for block constructor
+#define UHD_RFNOC_BLOCK_CONSTRUCTOR(CLASS_NAME) \
+ CLASS_NAME##_impl( \
+ const make_args_t &make_args \
+ ) : block_ctrl_base(make_args)
+
+//! This macro must be placed inside a block implementation file
+// after the class definition
+#define UHD_RFNOC_BLOCK_REGISTER(CLASS_NAME, BLOCK_NAME) \
+ block_ctrl_base::sptr CLASS_NAME##_make( \
+ const make_args_t &make_args \
+ ) { \
+ return block_ctrl_base::sptr(new CLASS_NAME##_impl(make_args)); \
+ } \
+ UHD_STATIC_BLOCK(register_rfnoc_##CLASS_NAME) \
+ { \
+ uhd::rfnoc::block_ctrl_base::register_block(&CLASS_NAME##_make, BLOCK_NAME); \
+ }
+
+/*! \brief Base class for all RFNoC block controller objects.
+ *
+ * For RFNoC, block controller objects must be derived from
+ * uhd::rfnoc::block_ctrl_base. This class provides all functions
+ * that a block *must* provide. Typically, you would not derive
+ * a block controller class directly from block_ctrl_base, but
+ * from a class such as uhd::usrp::rfnoc::source_block_ctrl_base or
+ * uhd::usrp::rfnoc::sink_block_ctrl_base which extends its functionality.
+ */
+class UHD_RFNOC_API block_ctrl_base;
+class block_ctrl_base : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<block_ctrl_base> sptr;
+ typedef boost::function<sptr(const make_args_t &)> make_t;
+
+ /***********************************************************************
+ * Factory functions
+ **********************************************************************/
+
+ /*! Register a block controller class into the discovery and factory system.
+ *
+ * Note: It is not recommended to call this function directly.
+ * Rather, use the UHD_RFNOC_BLOCK_REGISTER() macro, which will set up
+ * the discovery and factory system correctly.
+ *
+ * \param make A factory function that makes a block controller object
+ * \param name A unique block name, e.g. 'FFT'. If a block has this block name,
+ * it will use \p make to generate the block controller class.
+ */
+ static void register_block(const make_t &make, const std::string &name);
+
+ /*!
+ * \brief Create a block controller class given a NoC-ID or a block name.
+ *
+ * If a block name is given in \p make_args, it will directly try to
+ * generate a block of this type. If no block name is given, it will
+ * look up a name using the NoC-ID and use that.
+ * If it can't find a suitable block controller class, it will generate
+ * a uhd::rfnoc::block_ctrl. However, if a block name *is* specified,
+ * it will throw a uhd::runtime_error if this block type is not registered.
+ *
+ * \param make_args Valid make args.
+ * \param noc_id The 64-Bit NoC-ID.
+ * \return a shared pointer to a new device instance
+ */
+ static sptr make(const make_args_t &make_args, boost::uint64_t noc_id = ~0);
+
+ /***********************************************************************
+ * Block Communication and Control
+ *
+ * These functions do not require communication with the FPGA.
+ **********************************************************************/
+
+ /*! Returns the 16-Bit address for this block.
+ */
+ boost::uint32_t get_address(size_t block_port=0);
+
+ /*! Returns the unique block ID for this block (e.g. "0/FFT_1").
+ */
+ block_id_t get_block_id() const { return _block_id; };
+
+ /*! Shorthand for get_block_id().to_string()
+ */
+ std::string unique_id() const { return _block_id.to_string(); };
+
+ /***********************************************************************
+ * FPGA control & communication
+ **********************************************************************/
+
+ /*! Returns a list of valid ports that can be used for sr_write(), sr_read() etc.
+ */
+ std::vector<size_t> get_ctrl_ports() const;
+
+ /*! Allows setting one register on the settings bus.
+ *
+ * Note: There is no address translation ("memory mapping") necessary.
+ * Register 0 is 0, 1 is 1 etc.
+ *
+ * \param reg The settings register to write to.
+ * \param data New value of this register.
+ */
+ void sr_write(const boost::uint32_t reg, const boost::uint32_t data, const size_t port = 0);
+
+ /*! Allows setting one register on the settings bus.
+ *
+ * Like sr_write(), but takes a register name as argument.
+ *
+ * \param reg The settings register to write to.
+ * \param data New value of this register.
+ * \param port Port on which to write
+ * \throw uhd::key_error if \p reg is not a valid register name
+ *
+ */
+ void sr_write(const std::string &reg, const boost::uint32_t data, const size_t port = 0);
+
+ /*! Allows reading one register on the settings bus (64-Bit version).
+ *
+ * \param reg The settings register to be read.
+ * \param port Port on which to read
+ *
+ * Returns the readback value.
+ */
+ boost::uint64_t sr_read64(const settingsbus_reg_t reg, const size_t port = 0);
+
+ /*! Allows reading one register on the settings bus (32-Bit version).
+ *
+ * \param reg The settings register to be read.
+ * \param port Port on which to read
+ *
+ * Returns the readback value.
+ */
+ boost::uint32_t sr_read32(const settingsbus_reg_t reg, const size_t port = 0);
+
+ /*! Allows reading one user-defined register (64-Bit version).
+ *
+ * This is a shorthand for setting the requested address
+ * through sr_write() and then reading SR_READBACK_REG_USER
+ * with sr_read64().
+ *
+ * \param addr The user register address.
+ * \param port Port on which to read
+ * \returns the readback value.
+ */
+ boost::uint64_t user_reg_read64(const boost::uint32_t addr, const size_t port = 0);
+
+ /*! Allows reading one user-defined register (64-Bit version).
+ *
+ * Identical to user_reg_read64(), but takes a register name
+ * instead of a numeric address. The register name must be
+ * defined in the block definition file.
+ *
+ * \param addr The user register address.
+ * \param port Port on which to read
+ * \returns the readback value.
+ * \throws uhd::key_error if \p reg is not a valid register name
+ */
+ boost::uint64_t user_reg_read64(const std::string &reg, const size_t port = 0);
+
+ /*! Allows reading one user-defined register (32-Bit version).
+ *
+ * This is a shorthand for setting the requested address
+ * through sr_write() and then reading SR_READBACK_REG_USER
+ * with sr_read32().
+ *
+ * \param addr The user register address.
+ * \param port Port on which to read
+ * \returns the readback value.
+ */
+ boost::uint32_t user_reg_read32(const boost::uint32_t addr, const size_t port = 0);
+
+ /*! Allows reading one user-defined register (32-Bit version).
+ *
+ * Identical to user_reg_read32(), but takes a register name
+ * instead of a numeric address. The register name must be
+ * defined in the block definition file.
+ *
+ * \param reg The user register name.
+ * \returns the readback value.
+ * \throws uhd::key_error if \p reg is not a valid register name
+ */
+ boost::uint32_t user_reg_read32(const std::string &reg, const size_t port = 0);
+
+
+ /*! Sets a command time for all future command packets.
+ *
+ * \throws uhd::assertion_error if the underlying interface does not
+ * actually support timing.
+ */
+ void set_command_time(const time_spec_t &time_spec, const size_t port = ANY_PORT);
+
+ /*! Returns the current command time for all future command packets.
+ *
+ * \returns the command time as a time_spec_t.
+ */
+ time_spec_t get_command_time(const size_t port = 0);
+
+ /*! Sets a tick rate for the command timebase.
+ *
+ * \param the tick rate in Hz
+ * \port port Port
+ */
+ void set_command_tick_rate(const double tick_rate, const size_t port = ANY_PORT);
+
+ /*! Resets the command time.
+ * Any command packet after this call will no longer have a time associated
+ * with it.
+ *
+ * \throws uhd::assertion_error if the underlying interface does not
+ * actually support timing.
+ */
+ void clear_command_time(const size_t port);
+
+ /*! Reset block after streaming operation.
+ *
+ * This does the following:
+ * - Reset flow control (sequence numbers etc.)
+ * - Clear the list of connected blocks
+ *
+ * Internally, rfnoc::node_ctrl_base::clear() and _clear() are called
+ * (in that order).
+ *
+ * Between runs, it can be necessary to call this method,
+ * or blocks might be left hanging in a streaming state, and can get
+ * confused when a new application starts.
+ *
+ * For custom behaviour, overwrite _clear(). If you do so, you must take
+ * take care of resetting flow control yourself.
+ *
+ * TODO: Find better name (it disconnects, clears FC...)
+ */
+ void clear(const size_t port = 0/* reserved, currently not used */);
+
+ /***********************************************************************
+ * Argument handling
+ **********************************************************************/
+ /*! Set multiple block args. Calls set_arg() for all individual items.
+ *
+ * Note that this function will silently ignore any keys in \p args that
+ * aren't already registered as block arguments.
+ */
+ void set_args(const uhd::device_addr_t &args, const size_t port = 0);
+
+ //! Set a specific block argument. \p val is converted to the corresponding
+ // data type using by looking up its type in the block definition.
+ void set_arg(const std::string &key, const std::string &val, const size_t port = 0);
+
+ //! Direct access to set a block argument.
+ template <typename T>
+ void set_arg(const std::string &key, const T &val, const size_t port = 0) {
+ _tree->access<T>(get_arg_path(key, port) / "value").set(val);
+ }
+
+ //! Return all block arguments as a device_addr_t.
+ uhd::device_addr_t get_args(const size_t port = 0) const;
+
+ //! Return a single block argument in string format.
+ std::string get_arg(const std::string &key, const size_t port = 0) const;
+
+ //! Direct access to get a block argument.
+ template <typename T>
+ T get_arg(const std::string &key, const size_t port = 0) const {
+ return _tree->access<T>(get_arg_path(key, port) / "value").get();
+ }
+
+ std::string get_arg_type(const std::string &key, const size_t port = 0) const;
+
+protected:
+ /***********************************************************************
+ * Structors
+ **********************************************************************/
+ block_ctrl_base(void) {}; // To allow pure virtual (interface) sub-classes
+ virtual ~block_ctrl_base();
+
+ /*! Constructor. This is only called from the internal block factory!
+ *
+ * \param make_args All arguments to this constructor are passed in this object.
+ * Its details are subject to change. Use the UHD_RFNOC_BLOCK_CONSTRUCTOR()
+ * macro to set up your block's constructor in a portable fashion.
+ */
+ block_ctrl_base(
+ const make_args_t &make_args
+ );
+
+ /***********************************************************************
+ * Helpers
+ **********************************************************************/
+ stream_sig_t _resolve_port_def(const blockdef::port_t &port_def) const;
+
+ //! Return the property tree path to a block argument \p key on \p port
+ uhd::fs_path get_arg_path(const std::string &key, size_t port = 0) const {
+ return _root_path / "args" / port / key;
+ };
+
+ //! Get a control interface object for block port \p block_port
+ wb_iface::sptr get_ctrl_iface(const size_t block_port);
+
+
+ /***********************************************************************
+ * Hooks & Derivables
+ **********************************************************************/
+
+ //! Override this function if your block does something else
+ // than reset register SR_CLEAR_TX_FC.
+ virtual void _clear(const size_t port = 0);
+
+ /***********************************************************************
+ * Protected members
+ **********************************************************************/
+
+ //! Property sub-tree
+ uhd::property_tree::sptr _tree;
+
+ //! Root node of this block's properties
+ uhd::fs_path _root_path;
+
+ //! Endianness of underlying transport (for data transport)
+ bool _transport_is_big_endian;
+
+ //! Block definition (stores info about the block such as ports)
+ blockdef::sptr _block_def;
+
+private:
+ //! Helper function to initialize the port definition nodes in the prop tree
+ void _init_port_defs(
+ const std::string &direction,
+ blockdef::ports_t ports,
+ const size_t first_port_index=0
+ );
+
+ //! Helper function to initialize the block args (used by ctor only)
+ void _init_block_args();
+
+ /***********************************************************************
+ * Private members
+ **********************************************************************/
+ //! Objects to actually send and receive the commands
+ std::map<size_t, wb_iface::sptr> _ctrl_ifaces;
+
+ //! The base address of this block (the address of block port 0)
+ uint32_t _base_address;
+
+ //! The (unique) block ID.
+ block_id_t _block_id;
+
+ //! Interface to NocScript parser
+ boost::shared_ptr<nocscript::block_iface> _nocscript_iface;
+}; /* class block_ctrl_base */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/block_id.hpp b/host/include/uhd/rfnoc/block_id.hpp
new file mode 100644
index 000000000..a8f2aec5a
--- /dev/null
+++ b/host/include/uhd/rfnoc/block_id.hpp
@@ -0,0 +1,211 @@
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_TYPES_BLOCK_ID_HPP
+#define INCLUDED_UHD_TYPES_BLOCK_ID_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include <iostream>
+#include <string>
+
+namespace uhd {
+ struct fs_path;
+
+ namespace rfnoc {
+
+ /*!
+ * Identifies an RFNoC block.
+ *
+ * An RFNoC block ID is a string such as: 0/FFT_1
+ *
+ * The rules for formatting such a string are:
+ *
+ * DEVICE/BLOCKNAME_COUNTER
+ *
+ * DEVICE: Identifies the device (usually the motherboard index)
+ * BLOCKNAME: A name given to this block
+ * COUNTER: If is are more than one block with a BLOCKNAME, this counts up.
+ *
+ * So, 0/FFT_1 means we're addressing the second block called FFT
+ * on the first device.
+ *
+ * This class can represent these block IDs.
+ */
+ class UHD_RFNOC_API block_id_t
+ {
+ public:
+ block_id_t();
+ block_id_t(const std::string &block_str);
+ //! \param device_no Device number
+ //! \param block_name Block name
+ //! \param block_ctr Which block of this type is this on this device?
+ block_id_t(const size_t device_no, const std::string &block_name, const size_t block_ctr=0);
+
+ //! Return a string like this: "0/FFT_1" (includes all components, if set)
+ std::string to_string() const;
+
+ //! Check if a given string is valid as a block name.
+ //
+ // Note: This only applies to the block *name*, not the entire block ID.
+ // Examples:
+ // * is_valid_blockname("FFT") will return true.
+ // * is_valid_blockname("FIR_Filter") will return false, because an underscore
+ // is not allowed in a block name.
+ //
+ // Internally, this matches the string with uhd::rfnoc::VALID_BLOCKNAME_REGEX.
+ static bool is_valid_blockname(const std::string &block_name);
+
+ //! Check if a given string is valid as a block ID.
+ //
+ // Note: This does necessary require a complete complete ID. If this returns
+ // true, then it is a valid input for block_id_t::match().
+ //
+ // Examples:
+ // * is_valid_block_id("FFT") will return true.
+ // * is_valid_block_id("0/Filter_1") will return true.
+ // * is_valid_block_id("0/Filter_Foo") will return false.
+ //
+ // Internally, this matches the string with uhd::rfnoc::VALID_BLOCKID_REGEX.
+ static bool is_valid_block_id(const std::string &block_id);
+
+ //! Check if block_str matches this block.
+ //
+ // A match is a less strict version of equality.
+ // Less specific block IDs will match more specific ones,
+ // e.g. "FFT" will match "0/FFT_1", "1/FFT_2", etc.
+ // "FFT_1" will only match the former, etc.
+ bool match(const std::string &block_str);
+
+ // Getters
+
+ //! Short for to_string()
+ std::string get() const { return to_string(); };
+
+ //! Like get(), but only returns the local part ("FFT_1")
+ std::string get_local() const;
+
+ //! Returns the property tree root for this block (e.g. "/mboards/0/xbar/FFT_1/")
+ uhd::fs_path get_tree_root() const;
+
+ //! Return device number
+ size_t get_device_no() const { return _device_no; };
+
+ //! Return block count
+ size_t get_block_count() const { return _block_ctr; };
+
+ //! Return block name
+ std::string get_block_name() const { return _block_name; };
+
+ // Setters
+
+ //! Set from string such as "0/FFT_1", "FFT_0", ...
+ // Returns true if successful (i.e. if string valid)
+ bool set(const std::string &new_name);
+
+ //! Sets from individual compontents, like calling set_device_no(), set_block_name()
+ // and set_block_count() one after another, only if \p block_name is invalid, stops
+ // and returns false before chaning anything
+ bool set(const size_t device_no, const std::string &block_name, const size_t block_ctr=0);
+
+ //! Set the device number
+ void set_device_no(size_t device_no) { _device_no = device_no; };
+
+ //! Set the block name. Will return false if invalid block string.
+ bool set_block_name(const std::string &block_name);
+
+ //! Set the block count.
+ void set_block_count(size_t count) { _block_ctr = count; };
+
+ // Overloaded operators
+
+ //! Assignment: Works like set(std::string)
+ block_id_t operator = (const std::string &new_name) {
+ set(new_name);
+ return *this;
+ }
+
+ bool operator == (const block_id_t &block_id) const {
+ return (_device_no == block_id.get_device_no())
+ and (_block_name == block_id.get_block_name())
+ and (_block_ctr == block_id.get_block_count());
+ }
+
+ bool operator != (const block_id_t &block_id) const {
+ return not (*this == block_id);
+ }
+
+ bool operator < (const block_id_t &block_id) const {
+ return (
+ _device_no < block_id.get_device_no()
+ or (_device_no == block_id.get_device_no() and _block_name < block_id.get_block_name())
+ or (_device_no == block_id.get_device_no() and _block_name == block_id.get_block_name() and _block_ctr < block_id.get_block_count())
+ );
+ }
+
+ bool operator > (const block_id_t &block_id) const {
+ return (
+ _device_no > block_id.get_device_no()
+ or (_device_no == block_id.get_device_no() and _block_name > block_id.get_block_name())
+ or (_device_no == block_id.get_device_no() and _block_name == block_id.get_block_name() and _block_ctr > block_id.get_block_count())
+ );
+ }
+
+ //! Check if a string matches the entire block ID (not like match())
+ bool operator == (const std::string &block_id_str) const {
+ return get() == block_id_str;
+ }
+
+ //! Check if a string matches the entire block ID (not like match())
+ bool operator == (const char *block_id_str) const {
+ std::string comp = std::string(block_id_str);
+ return *this == comp;
+ }
+
+ //! Type-cast operator does the same as to_string()
+ operator std::string() const {
+ return to_string();
+ }
+
+ //! Increment the block count ("FFT_1" -> "FFT_2")
+ block_id_t operator++() {
+ _block_ctr++;
+ return *this;
+ }
+
+ //! Increment the block count ("FFT_1" -> "FFT_2")
+ block_id_t operator++(int) {
+ _block_ctr++;
+ return *this;
+ }
+
+ private:
+ size_t _device_no;
+ std::string _block_name;
+ size_t _block_ctr;
+ };
+
+ //! Shortcut for << block_id.to_string()
+ inline std::ostream& operator<< (std::ostream& out, block_id_t block_id) {
+ out << block_id.to_string();
+ return out;
+ }
+
+}} //namespace uhd::rfnoc
+
+#endif /* INCLUDED_UHD_TYPES_BLOCK_ID_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/blockdef.hpp b/host/include/uhd/rfnoc/blockdef.hpp
new file mode 100644
index 000000000..fc3505d3c
--- /dev/null
+++ b/host/include/uhd/rfnoc/blockdef.hpp
@@ -0,0 +1,126 @@
+//
+// Copyright 2014-2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_BLOCKDEF_HPP
+#define INCLUDED_LIBUHD_RFNOC_BLOCKDEF_HPP
+
+#include <boost/cstdint.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <uhd/config.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <vector>
+#include <set>
+
+namespace uhd { namespace rfnoc {
+
+/*! Reads and stores block definitions for blocks and components.
+ */
+class UHD_RFNOC_API blockdef : public boost::enable_shared_from_this<blockdef>
+{
+public:
+ typedef boost::shared_ptr<blockdef> sptr;
+
+ //! Describes port options for a block definition.
+ //
+ // This is not the same as a uhd::rfnoc::stream_sig_t. This is used
+ // to describe which ports are defined in a block definition, and
+ // to describe what kind of connection is allowed for this port.
+ //
+ // All the keys listed in PORT_ARGS will be available in this class.
+ class port_t : public uhd::dict<std::string, std::string> {
+ public:
+ //! A list of args a port can have.
+ static const device_addr_t PORT_ARGS;
+
+ port_t();
+
+ //! Checks if the value at \p key is a variable (e.g. '$fftlen')
+ bool is_variable(const std::string &key) const;
+ //! Checks if the value at \p key is a keyword (e.g. '%vlen')
+ bool is_keyword(const std::string &key) const;
+ //! Basic validity check of this port definition. Variables and
+ // keywords are not resolved.
+ bool is_valid() const;
+ //! Returns a string with the most important keys
+ std::string to_string() const;
+ };
+ typedef std::vector<port_t> ports_t;
+
+ //! Describes arguments in a block definition.
+ class arg_t : public uhd::dict<std::string, std::string> {
+ public:
+ //! A list of args an argument can have.
+ static const device_addr_t ARG_ARGS;
+ static const std::set<std::string> VALID_TYPES;
+
+ arg_t();
+
+ //! Basic validity check of this argument definition.
+ bool is_valid() const;
+ //! Returns a string with the most important keys
+ std::string to_string() const;
+
+ };
+ typedef std::vector<arg_t> args_t;
+
+ typedef uhd::dict<std::string, size_t> registers_t;
+
+ /*! Create a block definition object for a NoC block given
+ * a NoC ID. This cannot be used for components.
+ *
+ * Note: If nothing is found, returns an
+ * empty sptr. Does not throw.
+ */
+ static sptr make_from_noc_id(boost::uint64_t noc_id);
+
+ //! Returns true if this represents a NoC block
+ virtual bool is_block() const = 0;
+
+ //! Returns true if this represents a component
+ virtual bool is_component() const = 0;
+
+ //! Returns block key (i.e. what is used for the registry)
+ virtual std::string get_key() const = 0;
+
+ //! For blocks, returns the block name. For components, returns it's canonical name.
+ virtual std::string get_name() const = 0;
+
+ //! Return the one NoC that is valid for this block
+ virtual boost::uint64_t noc_id() const = 0;
+
+ virtual ports_t get_input_ports() = 0;
+ virtual ports_t get_output_ports() = 0;
+
+ //! Returns the full list of port numbers used
+ virtual std::vector<size_t> get_all_port_numbers() = 0;
+
+ //! Returns the args for this block. Checks if args are valid.
+ //
+ // \throws uhd::runtime_error if args are invalid.
+ virtual args_t get_args() = 0;
+
+ //! Returns a list of settings registers by name.
+ virtual registers_t get_settings_registers() = 0;
+
+ //! Returns a list of readback (user) registers by name.
+ virtual registers_t get_readback_registers() = 0;
+};
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_BLOCKDEF_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/blocks/CMakeLists.txt b/host/include/uhd/rfnoc/blocks/CMakeLists.txt
new file mode 100644
index 000000000..341db3366
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/CMakeLists.txt
@@ -0,0 +1,25 @@
+#
+# Copyright 2014-2016 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/>.
+#
+
+FILE(GLOB xml_files "*.xml")
+
+# We always need this, even when RFNoC is 'disabled'
+UHD_INSTALL(
+ FILES ${xml_files}
+ DESTINATION ${PKG_DATA_DIR}/rfnoc/blocks
+ COMPONENT headers # TODO: Different component
+)
diff --git a/host/include/uhd/rfnoc/blocks/addsub.xml b/host/include/uhd/rfnoc/blocks/addsub.xml
new file mode 100644
index 000000000..2412e5022
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/addsub.xml
@@ -0,0 +1,50 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <!--The Adder & Subtractor takes inputs from Block Ports 0 & 1 and-->
+ <!--outputs the addition / subtraction of the values on Block Ports 0 & 1.-->
+ <!--- Block Port 0 + Block Port 1 => Block Port 0-->
+ <!--- Block Port 0 - Block Port 1 => Block Port 1-->
+ <name>Adder &amp; Subtractor</name>
+ <blockname>AddSub</blockname>
+ <ids>
+ <id revision="0">ADD0</id>
+ </ids>
+ <!--Order matters. The first listed port is port 0, etc.-->
+ <ports>
+ <sink>
+ <name>in0</name>
+ <type>sc16</type>
+ <port>0</port>
+ </sink>
+ <sink>
+ <name>in1</name>
+ <type>sc16</type>
+ <port>1</port>
+ </sink>
+ <source>
+ <name>sum</name>
+ <type>sc16</type>
+ </source>
+ <source>
+ <name>diff</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/block.xml b/host/include/uhd/rfnoc/blocks/block.xml
new file mode 100644
index 000000000..dfe616c45
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/block.xml
@@ -0,0 +1,17 @@
+<!--Default XML file-->
+<nocblock>
+ <name>Block</name>
+ <blockname>Block</blockname>
+ <ids>
+ <id revision="0">FFFFFFFFFFFFFFFF</id>
+ </ids>
+ <!--One input, one output. If this is used, better have all the info the C++ file.-->
+ <ports>
+ <sink>
+ <name>in</name>
+ </sink>
+ <source>
+ <name>out</name>
+ </source>
+ </ports>
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/ddc.xml b/host/include/uhd/rfnoc/blocks/ddc.xml
new file mode 100644
index 000000000..a88616117
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/ddc.xml
@@ -0,0 +1,154 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Rx DSP (DDC/CORDIC)</name>
+ <blockname>DDC</blockname>
+ <key>DDC</key>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">DDC0</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!-- AXI rate change block registers -->
+ <setreg>
+ <name>N</name>
+ <address>128</address>
+ </setreg>
+ <setreg>
+ <name>M</name>
+ <address>129</address>
+ </setreg>
+ <setreg>
+ <!-- 1 bit, enable clear user -->
+ <name>CONFIG</name>
+ <address>130</address>
+ </setreg>
+ <!-- DDC block registers -->
+ <setreg>
+ <!-- CORDIC phase increment word -->
+ <name>CORDIC_FREQ</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <!-- Scaling factor to compensate for gain through filters and CORDIC -->
+ <name>SCALE_IQ</name>
+ <address>133</address>
+ </setreg>
+ <setreg>
+ <!-- DDC control word, 10 bits total, 2 bits for Halfbands, 8 bits for CIC rate -->
+ <name>DECIM_WORD</name>
+ <address>134</address>
+ </setreg>
+ <setreg>
+ <!-- Real mode, swap IQ -->
+ <name>MODE</name>
+ <address>135</address>
+ </setreg>
+ <setreg>
+ <!-- Filter coefficients reload -->
+ <name>RELOAD</name>
+ <address>136</address>
+ </setreg>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>freq</name>
+ <type>double</type>
+ <value>0.0</value>
+ <port>0</port>
+ <!--<action>-->
+ <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)-->
+ <!--</action>-->
+ <!--FIXME Calculate this properly-->
+ </arg>
+ <arg>
+ <name>input_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($input_rate, 0.0)</check>
+ <check_message>The input rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>output_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($output_rate, 0.0)</check>
+ <check_message>The output rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>fullscale</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($fullscale, 0.0)</check>
+ </arg>
+ <arg>
+ <name>scalar_correction</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ </arg>
+ <arg>
+ <name>freq</name>
+ <type>double</type>
+ <value>0.0</value>
+ <port>1</port>
+ <!--<action>-->
+ <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)-->
+ <!--</action>-->
+ <!--FIXME Calculate this properly-->
+ </arg>
+ <arg>
+ <name>input_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>1</port>
+ <check>GE($input_rate, 0.0)</check>
+ <check_message>The input rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>output_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>1</port>
+ <check>GE($output_rate, 0.0)</check>
+ <check_message>The output rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>fullscale</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>1</port>
+ <check>GE($fullscale, 0.0)</check>
+ </arg>
+ <arg>
+ <name>scalar_correction</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>1</port>
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in0</name>
+ <type>sc16</type>
+ </sink>
+ <sink>
+ <name>in1</name>
+ <type>sc16</type>
+ </sink>
+ <source>
+ <name>out0</name>
+ <type>sc16</type>
+ </source>
+ <source>
+ <name>out1</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+</nocblock>
+
diff --git a/host/include/uhd/rfnoc/blocks/ddc_single.xml b/host/include/uhd/rfnoc/blocks/ddc_single.xml
new file mode 100644
index 000000000..581487388
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/ddc_single.xml
@@ -0,0 +1,117 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Rx DSP (DDC/CORDIC)</name>
+ <blockname>DDC</blockname>
+ <key>DDC</key>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">DDC0000000000001</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!-- AXI rate change block registers -->
+ <setreg>
+ <name>N</name>
+ <address>128</address>
+ </setreg>
+ <setreg>
+ <name>M</name>
+ <address>129</address>
+ </setreg>
+ <setreg>
+ <!-- 1 bit, enable clear user -->
+ <name>CONFIG</name>
+ <address>130</address>
+ </setreg>
+ <!-- DDC block registers -->
+ <setreg>
+ <!-- CORDIC phase increment word -->
+ <name>CORDIC_FREQ</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <!-- Scaling factor to compensate for gain through filters and CORDIC -->
+ <name>SCALE_IQ</name>
+ <address>133</address>
+ </setreg>
+ <setreg>
+ <!-- DDC control word, 10 bits total, 2 bits for Halfbands, 8 bits for CIC rate -->
+ <name>DECIM_WORD</name>
+ <address>134</address>
+ </setreg>
+ <setreg>
+ <!-- Real mode, swap IQ -->
+ <name>MODE</name>
+ <address>135</address>
+ </setreg>
+ <setreg>
+ <!-- Filter coefficients reload -->
+ <name>RELOAD</name>
+ <address>136</address>
+ </setreg>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>freq</name>
+ <type>double</type>
+ <value>0.0</value>
+ <port>0</port>
+ <!--<action>-->
+ <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)-->
+ <!--</action>-->
+ <!--FIXME Calculate this properly-->
+ </arg>
+ <arg>
+ <name>input_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($input_rate, 0.0)</check>
+ <check_message>The input rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>output_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($output_rate, 0.0)</check>
+ <check_message>The output rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>fullscale</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($fullscale, 0.0)</check>
+ </arg>
+ <arg>
+ <name>scalar_correction</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ </arg>
+ <arg>
+ <name>freq</name>
+ <type>double</type>
+ <value>0.0</value>
+ <port>1</port>
+ <!--<action>-->
+ <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)-->
+ <!--</action>-->
+ <!--FIXME Calculate this properly-->
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in0</name>
+ <type>sc16</type>
+ </sink>
+ <source>
+ <name>out0</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+</nocblock>
+
diff --git a/host/include/uhd/rfnoc/blocks/dma_fifo.xml b/host/include/uhd/rfnoc/blocks/dma_fifo.xml
new file mode 100644
index 000000000..fb30d58fe
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/dma_fifo.xml
@@ -0,0 +1,64 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>DMA FIFO</name>
+ <blockname>DmaFIFO</blockname>
+ <key>DmaFIFO</key>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">F1F0D000</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>base_addr</name>
+ <type>int</type>
+ <!--<value>0</value>-->
+ <port>0</port>
+ <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check>
+ <check_message>The base address must be 0 or a positive power of 2.</check_message>
+ </arg>
+ <arg>
+ <name>depth</name>
+ <type>int</type>
+ <!--<value>33554432</value>-->
+ <port>0</port>
+ <check>IS_PWR_OF_2($depth)</check>
+ <check_message>The FIFO depth must be a positive power of 2.</check_message>
+ </arg>
+ <arg>
+ <name>base_addr</name>
+ <type>int</type>
+ <!--<value>33554432</value>-->
+ <port>1</port>
+ <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check>
+ <check_message>The base address must be 0 or a positive power of 2.</check_message>
+ </arg>
+ <arg>
+ <name>depth</name>
+ <type>int</type>
+ <!--<value>33554432</value>-->
+ <port>1</port>
+ <check>IS_PWR_OF_2($depth)</check>
+ <check_message>The FIFO depth must be a positive power of 2.</check_message>
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in0</name>
+ </sink>
+ <sink>
+ <name>in1</name>
+ </sink>
+ <source>
+ <name>out0</name>
+ </source>
+ <source>
+ <name>out1</name>
+ </source>
+ </ports>
+</nocblock>
+
diff --git a/host/include/uhd/rfnoc/blocks/duc.xml b/host/include/uhd/rfnoc/blocks/duc.xml
new file mode 100644
index 000000000..62f005372
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/duc.xml
@@ -0,0 +1,96 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Tx DSP (DUC/CORDIC)</name>
+ <blockname>DUC</blockname>
+ <key>DUC</key>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">D0C0</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!-- AXI rate change block registers -->
+ <setreg>
+ <name>N</name>
+ <address>128</address>
+ </setreg>
+ <setreg>
+ <name>M</name>
+ <address>129</address>
+ </setreg>
+ <setreg>
+ <!-- 1 bit, enable clear user -->
+ <name>CONFIG</name>
+ <address>130</address>
+ </setreg>
+ <!-- DUC block registers -->
+ <setreg>
+ <name>INTERP_WORD</name> <!--Includes the half-bands and the CIC-->
+ <address>131</address>
+ </setreg>
+ <setreg>
+ <name>CORDIC_FREQ</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <name>SCALE_IQ</name>
+ <address>133</address>
+ </setreg>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>freq</name>
+ <type>double</type>
+ <value>0.0</value>
+ <port>0</port>
+ <!--<action>-->
+ <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)-->
+ <!--</action>-->
+ <!--FIXME Calculate this properly-->
+ </arg>
+ <arg>
+ <name>input_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($input_rate, 0.0)</check>
+ <check_message>The input rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>output_rate</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($output_rate, 0.0)</check>
+ <check_message>The output rate must be a positive value (in Hz).</check_message>
+ </arg>
+ <arg>
+ <name>fullscale</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ <check>GE($fullscale, 0.0)</check>
+ <check_message>The output rate must be a positive value (in Hz).</check_message>
+ <!--FIXME Calculate this properly-->
+ </arg>
+ <arg>
+ <name>scalar_correction</name>
+ <type>double</type>
+ <value>1.0</value>
+ <port>0</port>
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+</nocblock>
+
diff --git a/host/include/uhd/rfnoc/blocks/fft.xml b/host/include/uhd/rfnoc/blocks/fft.xml
new file mode 100644
index 000000000..7dd2eff46
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/fft.xml
@@ -0,0 +1,116 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>FFT</name>
+ <blockname>FFT</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">FF70</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!--Note: AXI config bus uses 129 & 130-->
+ <setreg>
+ <name>FFT_RESET</name>
+ <address>131</address>
+ </setreg>
+ <setreg>
+ <name>FFT_SIZE_LOG2</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <name>MAGNITUDE_OUT</name>
+ <address>133</address>
+ </setreg>
+ <readback>
+ <name>RB_FFT_RESET</name>
+ <address>0</address>
+ </readback>
+ <readback>
+ <name>RB_MAGNITUDE_OUT</name>
+ <address>1</address>
+ </readback>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <!--This controls only the fft shift part, so remember to also set the ctrl_word-->
+ <name>spp</name>
+ <type>int</type>
+ <value>256</value>
+ <check>GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)</check>
+ <check_message>FFT size must be in [16, 4096] and a power of two.</check_message>
+ <action>SR_WRITE("FFT_SIZE_LOG2", LOG2($spp)) AND SR_WRITE("AXIS_CONFIG_BUS", ADD(873472, LOG2($spp)))</action>
+ </arg>
+ <arg>
+ <name>ctrl_word</name>
+ <type>int</type>
+ <value>873472</value>
+ <!--<check>EQUAL($otype, "sc16")</check>-->
+ <!--<check_message>Output data type must be sc16.</check_message>-->
+ <!--TODO: Check against mag-out value (requires GET() function) -->
+ <action>SR_WRITE("AXIS_CONFIG_BUS", ADD($ctrl_word, LOG2($spp)))</action>
+ </arg>
+ <arg>
+ <name>otype</name>
+ <type>string</type>
+ <value>sc16</value>
+ <check>EQUAL($otype, "sc16")</check>
+ <check_message>Output data type must be sc16.</check_message>
+ <!--TODO: Check against mag-out value (requires GET() function) -->
+ </arg>
+ <arg>
+ <name>reset</name>
+ <type>int</type>
+ <value>1</value>
+ <action>
+ IF(NOT(EQUAL($reset, 0)), SR_WRITE("FFT_RESET", 1) AND SR_WRITE("FFT_RESET", 0))
+ </action>
+ <!--TODO: Set to zero after setting, add publisher-->
+ </arg>
+ <arg>
+ <name>magnitude_out</name>
+ <type>string</type>
+ <value>COMPLEX</value>
+ <check>EQUAL($magnitude_out, "COMPLEX") OR EQUAL($magnitude_out, "MAGNITUDE") OR EQUAL($magnitude_out, "MAGNITUDE_SQUARED")</check>
+ <check_message>Output format must be one of: COMPLEX, MAGNITUDE, MAGNITUDE_SQUARED.</check_message>
+ <action>
+ IF(EQUAL($magnitude_out, "COMPLEX"), SR_WRITE("MAGNITUDE_OUT", 0)) OR
+ IF(EQUAL($magnitude_out, "MAGNITUDE"), SR_WRITE("MAGNITUDE_OUT", 1)) OR
+ IF(EQUAL($magnitude_out, "MAGNITUDE_SQUARED"), SR_WRITE("MAGNITUDE_OUT", 2))
+ </action>
+ <!--TODO: add publisher-->
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>$otype</type> <!--TODO make this dependent on the output type -->
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/fifo.xml b/host/include/uhd/rfnoc/blocks/fifo.xml
new file mode 100644
index 000000000..9e8900b89
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/fifo.xml
@@ -0,0 +1,34 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>FIFO</name>
+ <blockname>FIFO</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">F1F00000</id>
+ </ids>
+ <ports>
+ <sink>
+ <name>in0</name>
+ </sink>
+ <source>
+ <name>out0</name>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/fir.xml b/host/include/uhd/rfnoc/blocks/fir.xml
new file mode 100644
index 000000000..9a97e3a84
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/fir.xml
@@ -0,0 +1,19 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>FIR Filter</name>
+ <blockname>FIR</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">F112</id>
+ </ids>
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/fosphor.xml b/host/include/uhd/rfnoc/blocks/fosphor.xml
new file mode 100644
index 000000000..762b7c1bd
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/fosphor.xml
@@ -0,0 +1,157 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>fosphor</name>
+ <blockname>fosphor</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">666F</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <setreg>
+ <name>DECIM</name>
+ <address>129</address>
+ </setreg>
+ <setreg>
+ <name>OFFSET</name>
+ <address>130</address>
+ </setreg>
+ <setreg>
+ <name>SCALE</name>
+ <address>131</address>
+ </setreg>
+ <setreg>
+ <name>TRISE</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <name>TDECAY</name>
+ <address>133</address>
+ </setreg>
+ <setreg>
+ <name>ALPHA</name>
+ <address>134</address>
+ </setreg>
+ <setreg>
+ <name>EPSILON</name>
+ <address>135</address>
+ </setreg>
+ <setreg>
+ <name>RANDOM</name>
+ <address>136</address>
+ </setreg>
+ <setreg>
+ <name>CLEAR</name>
+ <address>137</address>
+ </setreg>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>spp</name>
+ <type>int</type>
+ <value>1024</value>
+ </arg>
+ <arg>
+ <name>decim</name>
+ <type>int</type>
+ <value>2</value>
+ <check>GE($decim, 2) AND LE($decim, 1024)</check>
+ <check_message>fosphor decim constant must be within [2, 1024]</check_message>
+ <action>SR_WRITE("DECIM", ADD($decim, -2))</action>
+ </arg>
+ <arg>
+ <name>offset</name>
+ <type>int</type>
+ <value>0</value>
+ <check>GE($offset, 0) AND LE($offset, 65536)</check>
+ <check_message>"fosphor offset value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("OFFSET", $offset)</action>
+ </arg>
+ <arg>
+ <name>scale</name>
+ <type>int</type>
+ <value>256</value>
+ <check>GE($scale, 0) AND LE($scale, 65536)</check>
+ <check_message>"fosphor scale value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("SCALE", $scale)</action>
+ </arg>
+ <arg>
+ <name>trise</name>
+ <type>int</type>
+ <value>4096</value>
+ <check>GE($trise, 0) AND LE($trise, 65536)</check>
+ <check_message>"fosphor trise value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("TRISE", $trise)</action>
+ </arg>
+ <arg>
+ <name>tdecay</name>
+ <type>int</type>
+ <value>16384</value>
+ <check>GE($tdecay, 0) AND LE($tdecay, 65536)</check>
+ <check_message>"fosphor tdecay value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("TDECAY", $tdecay)</action>
+ </arg>
+ <arg>
+ <name>alpha</name>
+ <type>int</type>
+ <value>65280</value>
+ <check>GE($alpha, 0) AND LE($alpha, 65536)</check>
+ <check_message>"fosphor alpha value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("ALPHA", $alpha)</action>
+ </arg>
+ <arg>
+ <name>epsilon</name>
+ <type>int</type>
+ <value>1</value>
+ <check>GE($epsilon, 0) AND LE($epsilon, 65536)</check>
+ <check_message>"fosphor epsilon value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("EPSILON", $epsilon)</action>
+ </arg>
+ <arg>
+ <name>random</name>
+ <type>int</type>
+ <value>1</value>
+ <check>GE($random, 0) AND LE($random, 3)</check>
+ <check_message>"fosphor random value must be within [0, 65535]"</check_message>
+ <action>SR_WRITE("RANDOM", $random)</action>
+ </arg>
+ <arg>
+ <name>clear</name>
+ <type>int</type>
+ <action>IF(NOT(EQUAL($clear, 0)), SR_WRITE("CLEAR", $clear))</action>
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>u8</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml b/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml
new file mode 100644
index 000000000..5a99685de
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml
@@ -0,0 +1,55 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Keep One in N</name>
+ <blockname>KeepOneInN</blockname>
+ <doc>
+ Block controller for the Keep One in N RFNoC block.
+
+ For every N packets received, this block will output a single packet.
+ - One input / output block port
+ - N up to 65535
+ </doc>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">0246</id>
+ </ids>
+ <registers>
+ <setreg>
+ <name>SR_N</name>
+ <address>129</address>
+ </setreg>
+ </registers>
+ <args>
+ <arg>
+ <name>n</name>
+ <type>int</type>
+ <value>256</value>
+ <action>SR_WRITE("SR_N", $n)</action>
+ </arg>
+ </args>
+ <ports>
+ <sink>
+ <name>in</name>
+ </sink>
+ <source>
+ <name>out</name>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/logpwr.xml b/host/include/uhd/rfnoc/blocks/logpwr.xml
new file mode 100644
index 000000000..9307446e3
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/logpwr.xml
@@ -0,0 +1,49 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Log Power</name>
+ <blockname>LogPwr</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">4C50</id>
+ </ids>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>spp</name>
+ <type>int</type>
+ <value>256</value>
+ </arg>
+ </args>
+ <!--All the connections to the outside world are listed in 'ports':-->
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/nullblock.xml b/host/include/uhd/rfnoc/blocks/nullblock.xml
new file mode 100644
index 000000000..f1ed3bbd2
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/nullblock.xml
@@ -0,0 +1,30 @@
+<nocblock>
+ <name>Null Source/Sink</name>
+ <blockname>NullSrcSink</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">0000000000000000</id>
+ </ids>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>line_rate</name>
+ <type>int</type>
+ <value>65535</value>
+ </arg>
+ <arg>
+ <name>bpp</name>
+ <type>int</type>
+ <value>256</value>
+ </arg>
+ </args>
+ <!-- Ports -->
+ <ports>
+ <sink>
+ <name>dump</name>
+ </sink>
+ <source>
+ <name>src</name>
+ </source>
+ </ports>
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/ofdmeq.xml b/host/include/uhd/rfnoc/blocks/ofdmeq.xml
new file mode 100644
index 000000000..50218e976
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/ofdmeq.xml
@@ -0,0 +1,31 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>OFDM Equalizer</name>
+ <blockname>OFDMEq</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">FF42</id>
+ </ids>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>fftsize</name>
+ <type>int</type>
+ <value>64</value>
+ </arg>
+ </args>
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ <vlen>$fftsize</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>sc16</type>
+ <vlen>$fftsize</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </source>
+ </ports>
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/packetresizer.xml b/host/include/uhd/rfnoc/blocks/packetresizer.xml
new file mode 100644
index 000000000..306218318
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/packetresizer.xml
@@ -0,0 +1,55 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Packet Resizer</name>
+ <blockname>PacketResizer</blockname>
+ <doc>
+ Block controller for the Packet Resizer RFNoC block.
+
+ The Packet Resizer RFNoC block changes the packet length of a stream. It can break large
+ packets into smaller packets or combine small packets into a single larger packet.
+ </doc>
+ <ids>
+ <id revision="0">12E5</id>
+ </ids>
+ <registers>
+ <setreg>
+ <name>SR_PKT_SIZE</name>
+ <address>129</address>
+ </setreg>
+ </registers>
+ <args>
+ <arg>
+ <name>pkt_size</name>
+ <type>int</type>
+ <value>32</value>
+ <check>GT($pkt_size, 0)</check>
+ <check_message>Packet size must be positive, non-zero.</check_message>
+ <action>SR_WRITE("SR_PKT_SIZE", $pkt_size)</action>
+ </arg>
+ </args>
+ <ports>
+ <sink>
+ <name>in</name>
+ </sink>
+ <source>
+ <name>out</name>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/radio_x300.xml b/host/include/uhd/rfnoc/blocks/radio_x300.xml
new file mode 100644
index 000000000..4130522a5
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/radio_x300.xml
@@ -0,0 +1,60 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Radio (X300)</name>
+ <blockname>Radio</blockname>
+ <key>X300Radio</key>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">12AD100000000001</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!--<setreg>-->
+ <!--<name>FFT_RESET</name>-->
+ <!--<address>131</address>-->
+ <!--</setreg>-->
+ <!--<readback>-->
+ <!--<name>RB_MAGNITUDE_OUT</name>-->
+ <!--<address>1</address>-->
+ <!--</readback>-->
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>spp</name>
+ <type>int</type>
+ <value>364</value>
+ <!--<value>256</value>-->
+ <!--<check>GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)</check>-->
+ <!--<check_message>FFT size must be in [16, 4096] and a power of two.</check_message>-->
+ <!--<action>SR_WRITE("FFT_SIZE_LOG2", LOG2($spp)) AND SR_WRITE("AXIS_CONFIG_BUS", ADD(873472, LOG2($spp)))</action>-->
+ </arg>
+ </args>
+ <ports>
+ <sink>
+ <name>in0</name>
+ <type>sc16</type>
+ <!--<vlen>$spp</vlen>-->
+ <!--<pkt_size>%vlen</pkt_size>-->
+ </sink>
+ <sink>
+ <name>in1</name>
+ <type>sc16</type>
+ <!--<vlen>$spp</vlen>-->
+ <!--<pkt_size>%vlen</pkt_size>-->
+ </sink>
+ <source>
+ <name>out0</name>
+ <type>sc16</type>
+ <!--<vlen>$spp</vlen>-->
+ <!--<pkt_size>%vlen</pkt_size>-->
+ </source>
+ <source>
+ <name>out1</name>
+ <type>sc16</type>
+ <!--<vlen>$spp</vlen>-->
+ <!--<pkt_size>%vlen</pkt_size>-->
+ </source>
+ </ports>
+</nocblock>
+
diff --git a/host/include/uhd/rfnoc/blocks/siggen.xml b/host/include/uhd/rfnoc/blocks/siggen.xml
new file mode 100644
index 000000000..2850e6804
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/siggen.xml
@@ -0,0 +1,116 @@
+<nocblock>
+ <name>Signal Generator</name>
+ <blockname>SigGen</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">5166311000000000</id>
+ </ids>
+ <!-- Registers -->
+ <registers>
+ <!-- Reg 128 used for FREQ -->
+ <setreg>
+ <name>FREQ</name>
+ <address>129</address>
+ </setreg>
+ <setreg>
+ <name>CARTESIAN</name>
+ <address>130</address>
+ </setreg>
+ <setreg>
+ <name>ENABLE</name>
+ <address>132</address>
+ </setreg>
+ <setreg>
+ <name>CONSTANT</name>
+ <address>138</address>
+ </setreg>
+ <setreg>
+ <name>GAIN</name>
+ <address>139</address>
+ </setreg>
+ <setreg>
+ <name>PKT_SIZE</name>
+ <address>140</address>
+ </setreg>
+ <setreg>
+ <name>WAVEFORM</name>
+ <address>142</address>
+ </setreg>
+ </registers>
+ <!-- Args -->
+ <args>
+ <arg>
+ <name>enable</name>
+ <type>int</type>
+ <value>0</value>
+ <check>EQUAL($enable, 0) OR EQUAL($enable, 1)</check>
+ <check_message>Enable is either 0 or 1.</check_message>
+ <action>SR_WRITE("ENABLE", $enable)</action>
+ </arg>
+ <arg>
+ <name>spp</name>
+ <type>int</type>
+ <value>256</value>
+ <action>SR_WRITE("PKT_SIZE", $spp)</action>
+ </arg>
+ <!-- Overall Gain -->
+ <arg>
+ <name>gain</name>
+ <type>double</type>
+ <value>1.0</value>
+ <check>GE($gain, 0.0) AND LE($gain, 1.0)</check>
+ <check_message>Invalid gain.</check_message>
+ <action>
+ SR_WRITE("GAIN", IROUND(MULT(32767.0,$gain)))
+ </action>
+ </arg>
+ <!-- Sine Wave, Constant I / Q -->
+ <arg>
+ <name>amplitude_i</name>
+ <type>double</type>
+ <value>1.0</value>
+ <check>GE($amplitude_i, -1.0) AND LE($amplitude_i, 1.0)</check>
+ <check_message>Invalid amplitude.</check_message>
+ </arg>
+ <arg>
+ <name>amplitude_q</name>
+ <type>double</type>
+ <value>1.0</value>
+ <check>GE($amplitude_q, -1.0) AND LE($amplitude_q, 1.0)</check>
+ <check_message>Invalid amplitude.</check_message>
+ <action>
+ SR_WRITE("CONSTANT", ADD(MULT(65536,IROUND(MULT(32767.0, $amplitude_i))),IROUND(MULT(32767.0, $amplitude_q))))
+ </action>
+ </arg>
+ <arg>
+ <name>frequency</name>
+ <type>double</type>
+ <value>0.1</value>
+ <check>GE($frequency, -1.0) AND LE($frequency, 1.0)</check>
+ <check_message>Invalid frequency.</check_message>
+ <action>SR_WRITE("FREQ", IROUND(MULT(-8192.0, $frequency)))</action>
+ </arg>
+ <arg>
+ <name>waveform</name>
+ <type>string</type>
+ <value>CONSTANT</value>
+ <check>EQUAL($waveform, "CONSTANT") OR EQUAL($waveform, "SINE_WAVE") OR EQUAL($waveform, "NOISE")</check>
+ <check_message>Waveform type should be one of: CONSTANT, SINE WAVE, NOISE.</check_message>
+ <action>
+ IF(EQUAL($waveform, "CONSTANT"), SR_WRITE("WAVEFORM", 0) AND SR_WRITE("CONSTANT", ADD(MULT(65536,IROUND(MULT(32767.0, $amplitude_i))),IROUND(MULT(32767.0, $amplitude_q))))) OR
+ IF(EQUAL($waveform, "SINE_WAVE"), SR_WRITE("WAVEFORM", 1) AND SR_WRITE("CARTESIAN", MULT(65536,28000))) OR
+ IF(EQUAL($waveform, "NOISE"), SR_WRITE("WAVEFORM", 2))
+ </action>
+ </arg>
+ </args>
+ <!-- Ports -->
+ <ports>
+ <sink>
+ <name>dump</name>
+ </sink>
+ <source>
+ <name>src</name>
+ <type>sc16</type>
+ </source>
+ </ports>
+</nocblock>
diff --git a/host/include/uhd/rfnoc/blocks/window.xml b/host/include/uhd/rfnoc/blocks/window.xml
new file mode 100644
index 000000000..df36f4b4f
--- /dev/null
+++ b/host/include/uhd/rfnoc/blocks/window.xml
@@ -0,0 +1,47 @@
+<!--This defines one NoC-Block.-->
+<nocblock>
+ <name>Window</name>
+ <blockname>Window</blockname>
+ <!--There can be several of these:-->
+ <ids>
+ <id revision="0">D053</id>
+ </ids>
+ <args>
+ <arg>
+ <name>spp</name>
+ <type>int</type>
+ <value>256</value>
+ </arg>
+ </args>
+ <ports>
+ <sink>
+ <name>in</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>sc16</type>
+ <vlen>$spp</vlen>
+ <pkt_size>%vlen</pkt_size>
+ </source>
+ </ports>
+ <!--<components>-->
+ <!--<component>-->
+ <!--<key revision="1">nocshell</key>-->
+ <!--</component>-->
+ <!--<component srbase="0">-->
+ <!--[>Will look for a component with this key:<]-->
+ <!--<key revision="1">componentname</key>-->
+ <!--</component>-->
+ <!--</components>-->
+ <!--<connection>-->
+ <!--<source port="0">nocshell</source>-->
+ <!--<sink port="0">componentname</sink>-->
+ <!--</connection>-->
+ <!--<connection>-->
+ <!--<source port="0">componentname</source>-->
+ <!--<sink port="0">nocshell</sink>-->
+ <!--</connection>-->
+</nocblock>
diff --git a/host/include/uhd/rfnoc/constants.hpp b/host/include/uhd/rfnoc/constants.hpp
new file mode 100644
index 000000000..14e0da55c
--- /dev/null
+++ b/host/include/uhd/rfnoc/constants.hpp
@@ -0,0 +1,108 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_CONSTANTS_HPP
+#define INCLUDED_LIBUHD_RFNOC_CONSTANTS_HPP
+
+#include <uhd/types/dict.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/cstdint.hpp>
+#include <string>
+
+namespace uhd {
+ namespace rfnoc {
+
+// All these configure the XML reader
+//! Where the RFNoC block/component definition files lie, relative to UHD_PKG_DIR
+static const std::string XML_DEFAULT_PATH = "share/uhd/rfnoc";
+//! The name of the environment variable storing the bath to the block definition files
+static const std::string XML_PATH_ENV = "UHD_RFNOC_DIR";
+
+//! If the block name can't be automatically detected, this name is used
+static const std::string DEFAULT_BLOCK_NAME = "Block";
+static const boost::uint64_t DEFAULT_NOC_ID = 0xFFFFFFFFFFFFFFFF;
+
+static const size_t MAX_PACKET_SIZE = 8000; // bytes
+static const size_t DEFAULT_PACKET_SIZE = 1456; // bytes
+
+// One line in FPGA is 64 Bits
+static const size_t BYTES_PER_LINE = 8;
+
+//! For flow control within a single crossbar
+static const size_t DEFAULT_FC_XBAR_PKTS_PER_ACK = 2;
+//! For flow control when data is flowing from device to host (rx)
+static const size_t DEFAULT_FC_RX_RESPONSE_FREQ = 64; // ACKs per flow control window
+//! For flow control when data is flowing from host to device (tx)
+static const size_t DEFAULT_FC_TX_RESPONSE_FREQ = 8; // ACKs per flow control window
+//! On the receive side, how full do we want the buffers?
+// Why not 100% full? Because we need to have some headroom to account for the inaccuracy
+// when computing the window size. We compute the flow control window based on the frame
+// size but the buffer can have overhead due to things like UDP headers, page alignment,
+// housekeeping info, etc. This number has to be transport agnostic so 20% of headroom is safe.
+static const double DEFAULT_FC_RX_SW_BUFF_FULL_FACTOR = 0.80;
+
+// Common settings registers.
+static const boost::uint32_t SR_FLOW_CTRL_CYCS_PER_ACK = 0;
+static const boost::uint32_t SR_FLOW_CTRL_PKTS_PER_ACK = 1;
+static const boost::uint32_t SR_FLOW_CTRL_WINDOW_SIZE = 2;
+static const boost::uint32_t SR_FLOW_CTRL_WINDOW_EN = 3;
+static const boost::uint32_t SR_ERROR_POLICY = 4;
+static const boost::uint32_t SR_BLOCK_SID = 5; // TODO rename to SRC_SID
+static const boost::uint32_t SR_NEXT_DST_SID = 6;
+static const boost::uint32_t SR_RESP_IN_DST_SID = 7;
+static const boost::uint32_t SR_RESP_OUT_DST_SID = 8;
+
+static const boost::uint32_t SR_READBACK_ADDR = 124;
+static const boost::uint32_t SR_READBACK = 127;
+
+static const boost::uint32_t SR_CLEAR_RX_FC = 125;
+static const boost::uint32_t SR_CLEAR_TX_FC = 126;
+
+//! Settings register readback
+enum settingsbus_reg_t {
+ SR_READBACK_REG_ID = 0,
+ SR_READBACK_REG_GLOBAL_PARAMS = 1,
+ SR_READBACK_REG_FIFOSIZE = 2, // fifo size
+ SR_READBACK_REG_MTU = 3,
+ SR_READBACK_REG_BLOCKPORT_SIDS = 4,
+ SR_READBACK_REG_USER = 5
+ /* 6 currently unused */
+};
+
+// AXI stream configuration bus (output master bus of axi wrapper) registers
+static const boost::uint32_t AXI_WRAPPER_BASE = 128;
+static const boost::uint32_t AXIS_CONFIG_BUS = AXI_WRAPPER_BASE+1; // tdata with tvalid asserted
+static const boost::uint32_t AXIS_CONFIG_BUS_TLAST = AXI_WRAPPER_BASE+2; // tdata with tvalid & tlast asserted
+
+// Named settings registers
+static const uhd::dict<std::string, boost::uint32_t> DEFAULT_NAMED_SR = boost::assign::map_list_of
+ ("AXIS_CONFIG_BUS", AXIS_CONFIG_BUS)
+ ("AXIS_CONFIG_BUS_TLAST", AXIS_CONFIG_BUS_TLAST)
+;
+
+// Block ports
+static const size_t ANY_PORT = size_t(~0);
+static const size_t MAX_NUM_PORTS = 16;
+
+// Regular expressions
+static const std::string VALID_BLOCKNAME_REGEX = "[A-Za-z][A-Za-z0-9]*";
+static const std::string VALID_BLOCKID_REGEX = "(?:(\\d+)(?:/))?([A-Za-z][A-Za-z0-9]*)(?:(?:_)(\\d\\d?))?";
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_CONSTANTS_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/ddc_block_ctrl.hpp b/host/include/uhd/rfnoc/ddc_block_ctrl.hpp
new file mode 100644
index 000000000..d9dab3e71
--- /dev/null
+++ b/host/include/uhd/rfnoc/ddc_block_ctrl.hpp
@@ -0,0 +1,50 @@
+//
+// Copyright 2016 Ettus Research
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP
+#define INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP
+
+#include <uhd/rfnoc/source_block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
+#include <uhd/rfnoc/rate_node_ctrl.hpp>
+#include <uhd/rfnoc/scalar_node_ctrl.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief DDC block controller
+ *
+ * This block provides DSP for Rx operations.
+ * Its main component is a DDC chain, which can decimate over a wide range
+ * of decimation rates (using a CIC and halfband filters).
+ *
+ * It also includes a CORDIC component to shift signals in frequency.
+ */
+class UHD_RFNOC_API ddc_block_ctrl :
+ public source_block_ctrl_base,
+ public sink_block_ctrl_base,
+ public rate_node_ctrl,
+ public scalar_node_ctrl
+{
+public:
+ UHD_RFNOC_BLOCK_OBJECT(ddc_block_ctrl)
+
+}; /* class ddc_block_ctrl*/
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP */
diff --git a/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp b/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp
new file mode 100644
index 000000000..fe55fc678
--- /dev/null
+++ b/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp
@@ -0,0 +1,55 @@
+//
+// Copyright 2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP
+#define INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP
+
+#include <uhd/rfnoc/source_block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Block controller for a DMA FIFO block.
+ *
+ * The DMA FIFO block has the following features:
+ * - One input- and output-port (type agnostic)
+ * - Configurable base address and FIFO depth
+ * - The base storage for the FIFO can be device
+ * specific. Usually it will be an off-chip SDRAM
+ * bank.
+ *
+ */
+class UHD_RFNOC_API dma_fifo_block_ctrl : public source_block_ctrl_base, public sink_block_ctrl_base
+{
+public:
+ UHD_RFNOC_BLOCK_OBJECT(dma_fifo_block_ctrl)
+
+ //! Configure the base address and depth of the FIFO (in bytes).
+ virtual void resize(const uint32_t base_addr, const uint32_t depth, const size_t chan) = 0;
+
+ //! Returns the base address of the FIFO (in bytes).
+ uint32_t get_base_addr(const size_t chan) const;
+
+ //! Returns the depth of the FIFO (in bytes).
+ uint32_t get_depth(const size_t chan) const;
+
+}; /* class dma_fifo_block_ctrl*/
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP */
diff --git a/host/include/uhd/rfnoc/duc_block_ctrl.hpp b/host/include/uhd/rfnoc/duc_block_ctrl.hpp
new file mode 100644
index 000000000..38c54aa31
--- /dev/null
+++ b/host/include/uhd/rfnoc/duc_block_ctrl.hpp
@@ -0,0 +1,51 @@
+//
+// Copyright 2016 Ettus Research
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP
+#define INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP
+
+#include <uhd/rfnoc/source_block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
+#include <uhd/rfnoc/rate_node_ctrl.hpp>
+#include <uhd/rfnoc/scalar_node_ctrl.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief DUC block controller
+ *
+ * This block provides DSP for Tx operations.
+ * Its main component is a DUC chain, which can interpolate over a wide range
+ * of interpolation rates (using a CIC and halfband filters).
+ *
+ * It also includes a CORDIC component to shift signals in frequency.
+ */
+class UHD_RFNOC_API duc_block_ctrl :
+ public source_block_ctrl_base,
+ public sink_block_ctrl_base,
+ public rate_node_ctrl,
+ public scalar_node_ctrl
+{
+public:
+ UHD_RFNOC_BLOCK_OBJECT(duc_block_ctrl)
+
+}; /* class duc_block_ctrl*/
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP */
+
diff --git a/host/include/uhd/rfnoc/graph.hpp b/host/include/uhd/rfnoc/graph.hpp
new file mode 100644
index 000000000..8f9005d12
--- /dev/null
+++ b/host/include/uhd/rfnoc/graph.hpp
@@ -0,0 +1,62 @@
+//
+// Copyright 2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_GRAPH_HPP
+#define INCLUDED_LIBUHD_RFNOC_GRAPH_HPP
+
+#include <boost/noncopyable.hpp>
+#include <uhd/rfnoc/block_id.hpp>
+
+namespace uhd { namespace rfnoc {
+
+class graph : boost::noncopyable
+{
+public:
+ typedef boost::shared_ptr<uhd::rfnoc::graph> sptr;
+
+ /*! Connect a RFNOC block with block ID \p src_block to another with block ID \p dst_block.
+ *
+ * This will:
+ * - Check if this connection is valid (IO signatures, see if types match)
+ * - Configure the flow control for the blocks
+ * - Configure SID for the upstream block
+ * - Register the upstream block in the downstream block
+ */
+ virtual void connect(
+ const block_id_t &src_block,
+ size_t src_block_port,
+ const block_id_t &dst_block,
+ size_t dst_block_port,
+ const size_t pkt_size = 0
+ ) = 0;
+
+ /*! Shorthand for connect().
+ *
+ * Using default ports for both source and destination.
+ */
+ virtual void connect(
+ const block_id_t &src_block,
+ const block_id_t &dst_block
+ ) = 0;
+
+ virtual std::string get_name() const = 0;
+};
+
+}}; /* name space uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_GRAPH_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/node_ctrl_base.hpp b/host/include/uhd/rfnoc/node_ctrl_base.hpp
new file mode 100644
index 000000000..82e095b1d
--- /dev/null
+++ b/host/include/uhd/rfnoc/node_ctrl_base.hpp
@@ -0,0 +1,244 @@
+//
+// Copyright 2014-2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP
+
+#include <uhd/types/device_addr.hpp>
+#include <uhd/rfnoc/constants.hpp>
+#include <uhd/utils/log.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/function.hpp>
+#include <map>
+#include <set>
+
+namespace uhd {
+ namespace rfnoc {
+
+#define UHD_RFNOC_BLOCK_TRACE() UHD_LOGV(never) << "[" << unique_id() << "] "
+
+/*! \brief Abstract base class for streaming nodes.
+ *
+ */
+class UHD_RFNOC_API node_ctrl_base;
+class node_ctrl_base : boost::noncopyable, public boost::enable_shared_from_this<node_ctrl_base>
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<node_ctrl_base> sptr;
+ typedef boost::weak_ptr<node_ctrl_base> wptr;
+ typedef std::map< size_t, wptr > node_map_t;
+ typedef std::pair< size_t, wptr > node_map_pair_t;
+
+ /***********************************************************************
+ * Node control
+ **********************************************************************/
+ //! Returns a unique string that identifies this block.
+ virtual std::string unique_id() const;
+
+ /***********************************************************************
+ * Connections
+ **********************************************************************/
+ /*! Clears the list of connected nodes.
+ */
+ virtual void clear();
+
+ node_map_t list_downstream_nodes() { return _downstream_nodes; };
+ node_map_t list_upstream_nodes() { return _upstream_nodes; };
+
+ // TODO we need a more atomic connect procedure, this is too error-prone.
+
+ /*! For an existing connection, store the remote port number.
+ *
+ * \throws uhd::value_error if \p this_port is not connected.
+ */
+ void set_downstream_port(const size_t this_port, const size_t remote_port);
+
+ /*! Return the remote port of a connection on a given port.
+ *
+ * \throws uhd::value_error if \p this_port is not connected.
+ */
+ size_t get_downstream_port(const size_t this_port);
+
+ /*! For an existing connection, store the remote port number.
+ *
+ * \throws uhd::value_error if \p this_port is not connected.
+ */
+ void set_upstream_port(const size_t this_port, const size_t remote_port);
+
+ /*! Return the remote port of a connection on a given port.
+ *
+ * \throws uhd::value_error if \p this_port is not connected.
+ */
+ size_t get_upstream_port(const size_t this_port);
+
+ /*! Find nodes downstream that match a predicate.
+ *
+ * Uses a non-recursive breadth-first search algorithm.
+ * On every branch, the search stops if a block matches.
+ * See this example:
+ * <pre>
+ * A -> B -> C -> C
+ * </pre>
+ * Say node A searches for nodes of type C. It will only find the
+ * first 'C' block, not the second.
+ *
+ * Returns blocks that are of type T.
+ *
+ * Search only goes downstream.
+ */
+ template <typename T>
+ UHD_INLINE std::vector< boost::shared_ptr<T> > find_downstream_node()
+ {
+ return _find_child_node<T, true>();
+ }
+
+ /*! Same as find_downstream_node(), but only search upstream.
+ */
+ template <typename T>
+ UHD_INLINE std::vector< boost::shared_ptr<T> > find_upstream_node()
+ {
+ return _find_child_node<T, false>();
+ }
+
+ /*! Checks if downstream nodes share a common, unique property.
+ *
+ * This will use find_downstream_node() to find all nodes downstream of
+ * this that are of type T. Then it will use \p get_property to return a
+ * property from all of them. If all these properties are identical, it will
+ * return that property. Otherwise, it will throw a uhd::runtime_error.
+ *
+ * \p get_property A functor to return the property from a node
+ * \p null_value If \p get_property returns this value, that node is skipped.
+ * \p explored_nodes A list of nodes to exclude from the search. This is typically
+ * to avoid recursion loops.
+ */
+ template <typename T, typename value_type>
+ UHD_INLINE value_type find_downstream_unique_property(
+ boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property,
+ value_type null_value,
+ const std::set< boost::shared_ptr<T> > &exclude_nodes=std::set< boost::shared_ptr<T> >()
+ ) {
+ return _find_unique_property<T, value_type, true>(get_property, null_value, exclude_nodes);
+ }
+
+ /*! Like find_downstream_unique_property(), but searches upstream.
+ */
+ template <typename T, typename value_type>
+ UHD_INLINE value_type find_upstream_unique_property(
+ boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property,
+ value_type null_value,
+ const std::set< boost::shared_ptr<T> > &exclude_nodes=std::set< boost::shared_ptr<T> >()
+ ) {
+ return _find_unique_property<T, value_type, false>(get_property, null_value, exclude_nodes);
+ }
+
+protected:
+ /***********************************************************************
+ * Structors
+ **********************************************************************/
+ node_ctrl_base(void) {};
+ virtual ~node_ctrl_base() {};
+
+ /***********************************************************************
+ * Protected members
+ **********************************************************************/
+
+ //! Stores default arguments
+ uhd::device_addr_t _args;
+
+ // TODO make these private
+
+ //! List of upstream nodes
+ node_map_t _upstream_nodes;
+
+ //! List of downstream nodes
+ node_map_t _downstream_nodes;
+
+ /***********************************************************************
+ * Connections
+ **********************************************************************/
+ /*! Registers another node as downstream of this node, connected to a given port.
+ *
+ * This implies that this node is a source node, and the downstream node is
+ * a sink node.
+ * See also uhd::rfnoc::source_node_ctrl::_register_downstream_node().
+ */
+ virtual void _register_downstream_node(
+ node_ctrl_base::sptr downstream_node,
+ size_t port
+ );
+
+ /*! Registers another node as upstream of this node, connected to a given port.
+ *
+ * This implies that this node is a sink node, and the upstream node is
+ * a source node.
+ * See also uhd::rfnoc::sink_node_ctrl::_register_upstream_node().
+ */
+ virtual void _register_upstream_node(
+ node_ctrl_base::sptr upstream_node,
+ size_t port
+ );
+
+private:
+ /*! Implements the search algorithm for find_downstream_node() and
+ * find_upstream_node().
+ *
+ * Depending on \p downstream, "child nodes" are either defined as
+ * nodes connected downstream or upstream.
+ *
+ * \param downstream Set to true if search goes downstream, false for upstream.
+ */
+ template <typename T, bool downstream>
+ std::vector< boost::shared_ptr<T> > _find_child_node();
+
+ /*! Implements the search algorithm for find_downstream_unique_property() and
+ * find_upstream_unique_property().
+ *
+ * Depending on \p downstream, "child nodes" are either defined as
+ * nodes connected downstream or upstream.
+ *
+ * \param downstream Set to true if search goes downstream, false for upstream.
+ */
+ template <typename T, typename value_type, bool downstream>
+ value_type _find_unique_property(
+ boost::function<value_type(boost::shared_ptr<T>, size_t)> get_property,
+ value_type NULL_VALUE,
+ const std::set< boost::shared_ptr<T> > &exclude_nodes
+ );
+
+ /*! Stores the remote port number of a downstream connection.
+ */
+ std::map<size_t, size_t> _upstream_ports;
+
+ /*! Stores the remote port number of a downstream connection.
+ */
+ std::map<size_t, size_t> _downstream_ports;
+
+}; /* class node_ctrl_base */
+
+}} /* namespace uhd::rfnoc */
+
+#include <uhd/rfnoc/node_ctrl_base.ipp>
+
+#endif /* INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/node_ctrl_base.ipp b/host/include/uhd/rfnoc/node_ctrl_base.ipp
new file mode 100644
index 000000000..136354cd2
--- /dev/null
+++ b/host/include/uhd/rfnoc/node_ctrl_base.ipp
@@ -0,0 +1,128 @@
+//
+// Copyright 2014 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/>.
+//
+
+// Implements templated functions from node_ctrl_base.hpp
+
+#ifndef INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP
+#define INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP
+
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+namespace uhd {
+ namespace rfnoc {
+
+ template <typename T, bool downstream>
+ std::vector< boost::shared_ptr<T> > node_ctrl_base::_find_child_node()
+ {
+ typedef boost::shared_ptr<T> T_sptr;
+ static const size_t MAX_ITER = 20;
+ size_t iters = 0;
+ // List of return values:
+ std::set< T_sptr > results_s;
+ // To avoid cycles:
+ std::set< sptr > explored;
+ // Initialize our search queue with ourself:
+ std::set< sptr > search_q;
+ search_q.insert(shared_from_this());
+ std::set< sptr > next_q;
+
+ while (iters++ < MAX_ITER) {
+ next_q.clear();
+ BOOST_FOREACH(const sptr &this_node, search_q) {
+ // Add this node to the list of explored nodes
+ explored.insert(this_node);
+ // Create set of all child nodes of this_node that are not in explored:
+ std::set< sptr > next_nodes;
+ {
+ node_map_t all_next_nodes = downstream ? this_node->list_downstream_nodes() : this_node->list_upstream_nodes();
+ for (
+ node_map_t::iterator it = all_next_nodes.begin();
+ it != all_next_nodes.end();
+ ++it
+ ) {
+ sptr one_next_node = it->second.lock();
+ if (not one_next_node or explored.count(one_next_node)) {
+ continue;
+ }
+ T_sptr next_node_sptr = boost::dynamic_pointer_cast<T>(one_next_node);
+ if (next_node_sptr) {
+ results_s.insert(next_node_sptr);
+ } else {
+ next_nodes.insert(one_next_node);
+ }
+ }
+ }
+ // Add all of these nodes to the next search queue
+ next_q.insert(next_nodes.begin(), next_nodes.end());
+ }
+ // If next_q is empty, we've exhausted our graph
+ if (next_q.empty()) {
+ break;
+ }
+ // Re-init the search queue
+ search_q = next_q;
+ }
+
+ std::vector< T_sptr > results(results_s.begin(), results_s.end());
+ return results;
+ }
+
+ template <typename T, typename value_type, bool downstream>
+ value_type node_ctrl_base::_find_unique_property(
+ boost::function<value_type(boost::shared_ptr<T>, size_t)> get_property,
+ value_type NULL_VALUE,
+ const std::set< boost::shared_ptr<T> > &exclude_nodes
+ ) {
+ std::vector< boost::shared_ptr<T> > descendant_rate_nodes = _find_child_node<T, downstream>();
+ value_type ret_val = NULL_VALUE;
+ std::string first_node_id;
+ BOOST_FOREACH(const boost::shared_ptr<T> &node, descendant_rate_nodes) {
+ if (exclude_nodes.count(node)) {
+ continue;
+ }
+ // FIXME we need to know the port!!!
+ size_t port = ANY_PORT; // NOOO! this is wrong!!!! FIXME
+ value_type this_property = get_property(node, port);
+ if (this_property == NULL_VALUE) {
+ continue;
+ }
+ // We use the first property we find as reference
+ if (ret_val == NULL_VALUE) {
+ ret_val = this_property;
+ first_node_id = node->unique_id();
+ continue;
+ }
+ // In all subsequent finds, we make sure the property is equal to the reference
+ if (this_property != ret_val) {
+ throw uhd::runtime_error(
+ str(
+ boost::format("Node %1% specifies %2%, node %3% specifies %4%")
+ % first_node_id % ret_val % node->unique_id() % this_property
+ )
+ );
+ }
+ }
+ return ret_val;
+ }
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/radio_ctrl.hpp b/host/include/uhd/rfnoc/radio_ctrl.hpp
new file mode 100644
index 000000000..1d7842051
--- /dev/null
+++ b/host/include/uhd/rfnoc/radio_ctrl.hpp
@@ -0,0 +1,205 @@
+//
+// Copyright 2015-2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP
+#define INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP
+
+#include <uhd/types/direction.hpp>
+#include <uhd/rfnoc/source_block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
+#include <uhd/rfnoc/rate_node_ctrl.hpp>
+#include <uhd/rfnoc/tick_node_ctrl.hpp>
+#include <uhd/rfnoc/scalar_node_ctrl.hpp>
+#include <uhd/rfnoc/terminator_node_ctrl.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Block controller for all RFNoC-based radio blocks
+ */
+class UHD_RFNOC_API radio_ctrl :
+ public source_block_ctrl_base,
+ public sink_block_ctrl_base,
+ public rate_node_ctrl,
+ public tick_node_ctrl,
+ public terminator_node_ctrl
+{
+public:
+ UHD_RFNOC_BLOCK_OBJECT(radio_ctrl)
+
+ virtual ~radio_ctrl(){}
+
+ /************************************************************************
+ * API calls
+ ***********************************************************************/
+ /*! Return the tick rate on all channels (rx and tx).
+ *
+ * \return The tick rate.
+ */
+ virtual double get_rate() const = 0;
+
+ /*! Set the tick/sample rate on all channels (rx and tx).
+ *
+ * Will coerce to the nearest possible rate and return the actual value.
+ */
+ virtual double set_rate(double rate) = 0;
+
+ /*! Return the selected TX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::string get_tx_antenna(const size_t chan) /* const */ = 0;
+
+ /*! Select RX antenna \p for channel \p chan.
+ *
+ * \throws uhd::value_error if \p ant is not a valid value.
+ */
+ virtual void set_tx_antenna(const std::string &ant, const size_t chan) = 0;
+
+ /*! Return the selected RX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::string get_rx_antenna(const size_t chan) /* const */ = 0;
+
+ /*! Select RX antenna \p for channel \p chan.
+ *
+ * \throws uhd::value_error if \p ant is not a valid value.
+ */
+ virtual void set_rx_antenna(const std::string &ant, const size_t chan) = 0;
+
+ /*! Return the current transmit LO frequency on channel \p chan.
+ *
+ * Note that the AD9361 only has one LO for all TX channels, and the
+ * \p chan parameter is thus only for API compatibility.
+ *
+ * \return The current LO frequency.
+ */
+ virtual double get_tx_frequency(const size_t chan) /* const */ = 0;
+
+ /*! Tune the TX LO for channel \p chan.
+ *
+ * This function will attempt to tune as close as possible, and return a
+ * coerced value of the actual tuning result.
+ *
+ * \param freq Frequency in Hz
+ * \param chan Channel to tune
+ *
+ * \return The actual LO frequency.
+ */
+ virtual double set_tx_frequency(const double freq, size_t chan) = 0;
+
+ /*! Return the current receive LO frequency on channel \p chan.
+ *
+ * \return The current LO frequency.
+ */
+ virtual double get_rx_frequency(const size_t chan) /* const */ = 0;
+
+ /*! Tune the RX LO for channel \p.
+ *
+ * This function will attempt to tune as close as possible, and return a
+ * coerced value of the actual tuning result.
+ *
+ * \return The actual LO frequency.
+ */
+ virtual double set_rx_frequency(const double freq, const size_t chan) = 0;
+
+ /*! Return the transmit gain on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_tx_gain(const size_t chan) = 0;
+
+ /*! Set the transmit gain on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * \return The actual gain value
+ */
+ virtual double set_tx_gain(const double gain, const size_t chan) = 0;
+
+ /*! Return the transmit gain on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_rx_gain(const size_t chan) = 0;
+
+ /*! Set the transmit gain on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * \return The actual gain value
+ */
+ virtual double set_rx_gain(const double gain, const size_t chan) = 0;
+
+ /*! Sets the time in the radio's timekeeper to the given value.
+ *
+ * Note that there is a non-deterministic delay between calling this
+ * function and the valung written to the register. For setting the
+ * time in alignment with a certain reference time, use
+ * set_time_next_pps().
+ */
+ virtual void set_time_now(const time_spec_t &time_spec) = 0;
+
+ /*! Set the time registers at the next pps tick.
+ *
+ * The values will not be latched in until the pulse occurs.
+ * It is recommended that the user sleep(1) after calling to ensure
+ * that the time registers will be in a known state prior to use.
+ *
+ * Note: Because this call sets the time on the "next" pps,
+ * the seconds in the time spec should be current seconds + 1.
+ *
+ * \param time_spec the time to latch into the timekeeper
+ */
+ virtual void set_time_next_pps(const time_spec_t &time_spec) = 0;
+
+ /*! Get the current time in the timekeeper registers.
+ *
+ * Note that there is a non-deterministic delay between the time the
+ * register is read and the time the function value is returned.
+ * To get the time with respect to a tick edge, use get_time_last_pps().
+ *
+ * \return A timespec representing current radio time
+ */
+ virtual time_spec_t get_time_now() = 0;
+
+ /*! Get the time when the last PPS pulse occurred.
+ *
+ * \return A timespec representing the last PPS
+ */
+ virtual time_spec_t get_time_last_pps() = 0;
+
+ /*! Given a frontend name, return the channel mapping.
+ *
+ * E.g.: For a TwinRX board, there's two frontends, '0' and '1', which
+ * map to channels 0 and 1 respectively. A BasicRX boards has alphabetical
+ * frontends (A, B) which map to channels differently.
+ */
+ virtual size_t get_chan_from_dboard_fe(const std::string &fe, const uhd::direction_t dir) = 0;
+
+ /*! The inverse function to get_chan_from_dboard_fe()
+ */
+ virtual std::string get_dboard_fe_from_chan(const size_t chan, const uhd::direction_t dir) = 0;
+
+}; /* class radio_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP */
diff --git a/host/include/uhd/rfnoc/rate_node_ctrl.hpp b/host/include/uhd/rfnoc/rate_node_ctrl.hpp
new file mode 100644
index 000000000..580f86fe2
--- /dev/null
+++ b/host/include/uhd/rfnoc/rate_node_ctrl.hpp
@@ -0,0 +1,67 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/constants.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Sampling-rate-aware node control
+ *
+ * A "rate" node is a streaming node is a point in the flow graph
+ * that is aware of sampling rates. Such nodes include:
+ * - Radio Controls (these actually set a sampling rate)
+ * - Decimating FIR filters (their output rates depend on both
+ * incoming rates and their own settings, i.e. the decimation)
+ * - Streaming terminators (these need to know the sampling rates
+ * to configure the connected streamers)
+ */
+class UHD_RFNOC_API rate_node_ctrl;
+class rate_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<rate_node_ctrl> sptr;
+ //! This value is used by rate nodes that don't actually set a rate themselves
+ static const double RATE_UNDEFINED;
+
+ /***********************************************************************
+ * Rate controls
+ **********************************************************************/
+ /*! Returns the sampling rate this block expects at its input.
+ *
+ * A radio will simply return the sampling rate it is set to.
+ * A decimating FIR filter will ask downstream for the input sampling rate
+ * and then return that value multiplied by the decimation factor.
+ *
+ */
+ virtual double get_input_samp_rate(size_t port=ANY_PORT);
+ virtual double get_output_samp_rate(size_t port=ANY_PORT);
+
+}; /* class rate_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
+
diff --git a/host/include/uhd/rfnoc/scalar_node_ctrl.hpp b/host/include/uhd/rfnoc/scalar_node_ctrl.hpp
new file mode 100644
index 000000000..1b29f959e
--- /dev/null
+++ b/host/include/uhd/rfnoc/scalar_node_ctrl.hpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/constants.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Scaling node control
+ *
+ * A "scalar" node is a streaming node in which a scaling takes
+ * place, usually for the conversion between fixed point and floating
+ * point (the latter usually being normalized between -1 and 1).
+ *
+ * Such blocks include:
+ * - Radio Controls
+ * - Potentially FFTs or FIRs, if they affect scaling
+ */
+class UHD_RFNOC_API scalar_node_ctrl;
+class scalar_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<scalar_node_ctrl> sptr;
+ //! Undefined scaling
+ static const double SCALE_UNDEFINED;
+
+ /***********************************************************************
+ * Scaling controls
+ **********************************************************************/
+ /*! Returns the scaling factor for this block on input.
+ *
+ * A DUC block will return the scaling factor as determined by the duc
+ * stage.
+ *
+ * \param port Port Number
+ */
+ virtual double get_input_scale_factor(size_t port=ANY_PORT);
+
+ /*! Returns the scaling factor for this block on output.
+ *
+ * A DDC block will return the scaling factor as determined by the ddc
+ * stage.
+ *
+ * \param port Port Number
+ */
+ virtual double get_output_scale_factor(size_t port=ANY_PORT);
+
+}; /* class scalar_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp b/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp
new file mode 100644
index 000000000..ebc2370f2
--- /dev/null
+++ b/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp
@@ -0,0 +1,126 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/block_ctrl_base.hpp>
+#include <uhd/rfnoc/sink_node_ctrl.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Extends block_ctrl_base with input capabilities.
+ *
+ * A sink block is an RFNoC block that can receive data at an input.
+ * We can use this block to transmit data (In RFNoC nomenclature, a
+ * transmit operation means streaming data to the device from the host).
+ *
+ * Every input is defined by a port definition (port_t).
+ */
+class UHD_RFNOC_API sink_block_ctrl_base;
+class sink_block_ctrl_base : virtual public block_ctrl_base, virtual public sink_node_ctrl
+{
+public:
+ typedef boost::shared_ptr<sink_block_ctrl_base> sptr;
+
+ /***********************************************************************
+ * Stream signatures
+ **********************************************************************/
+ /*! Return the input stream signature for a given block port.
+ *
+ * The actual signature is determined by the current configuration
+ * and the block definition file. The value returned here is calculated
+ * on-the-fly and is only valid as long as the configuration does not
+ * change.
+ *
+ * \returns The stream signature for port \p block_port
+ * \throws uhd::runtime_error if \p block_port is not a valid port
+ */
+ stream_sig_t get_input_signature(size_t block_port=0) const;
+
+ /*! Return a list of valid input ports.
+ */
+ std::vector<size_t> get_input_ports() const;
+
+ /***********************************************************************
+ * FPGA Configuration
+ **********************************************************************/
+ /*! Return the size of input buffer on a given block port.
+ *
+ * This is necessary for setting up flow control, among other things.
+ * Note: This does not query the block's settings register. The FIFO size
+ * is queried once during construction and cached.
+ *
+ * If the block port is not defined, it will return 0, and not throw.
+ *
+ * \param block_port The block port (0 through 15).
+ *
+ * Returns the size of the buffer in bytes.
+ */
+ size_t get_fifo_size(size_t block_port=0) const;
+
+ /*! Configure flow control for incoming streams.
+ *
+ * If flow control is enabled for incoming streams, this block will periodically
+ * send out ACKs, telling the upstream block which packets have been consumed,
+ * so the upstream block can increase his flow control credit.
+ *
+ * In the default implementation, this just sets registers
+ * SR_FLOW_CTRL_CYCS_PER_ACK and SR_FLOW_CTRL_PKTS_PER_ACK accordingly.
+ *
+ * Override this function if your block has port-specific flow control settings.
+ *
+ * \param cycles Send an ACK after this many clock cycles.
+ * Setting this to zero disables this type of flow control acknowledgement.
+ * \param packets Send an ACK after this many packets have been consumed.
+ * Setting this to zero disables this type of flow control acknowledgement.
+ * \param block_port Set up flow control for a stream coming in on this particular block port.
+ */
+ virtual void configure_flow_control_in(
+ size_t cycles,
+ size_t packets,
+ size_t block_port=0
+ );
+
+ /*! Configure the behaviour for errors on incoming packets
+ * (e.g. sequence errors).
+ *
+ *
+ */
+ virtual void set_error_policy(
+ const std::string &policy
+ );
+
+protected:
+ /***********************************************************************
+ * Hooks
+ **********************************************************************/
+ /*! Like sink_node_ctrl::_request_input_port(), but also checks
+ * the port has an input signature.
+ */
+ virtual size_t _request_input_port(
+ const size_t suggested_port,
+ const uhd::device_addr_t &args
+ ) const;
+
+}; /* class sink_block_ctrl_base */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/sink_node_ctrl.hpp b/host/include/uhd/rfnoc/sink_node_ctrl.hpp
new file mode 100644
index 000000000..5142a269e
--- /dev/null
+++ b/host/include/uhd/rfnoc/sink_node_ctrl.hpp
@@ -0,0 +1,145 @@
+//
+// Copyright 2014-2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/constants.hpp>
+#include <uhd/rfnoc/sink_node_ctrl.hpp>
+#include <boost/thread.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Abstract class for sink nodes.
+ *
+ * Sink nodes can have upstream blocks.
+ */
+class UHD_RFNOC_API sink_node_ctrl;
+class sink_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<sink_node_ctrl> sptr;
+ typedef std::map< size_t, boost::weak_ptr<sink_node_ctrl> > node_map_t;
+ typedef std::pair< size_t, boost::weak_ptr<sink_node_ctrl> > node_map_pair_t;
+
+ /***********************************************************************
+ * Sink block controls
+ **********************************************************************/
+ /*! Connect another node upstream of this node.
+ *
+ * *Note:* If additional settings are required to make this connection work,
+ * e.g. configure flow control, these need to be done separately.
+ *
+ * If the requested connection is not possible, this function will throw.
+ *
+ * \p upstream_node Pointer to the node class to connect
+ * \p port Suggested port number on this block to connect the upstream
+ * block to.
+ * \p args Any arguments that can be useful for determining the port number.
+ *
+ * \returns The actual port number used.
+ */
+ size_t connect_upstream(
+ node_ctrl_base::sptr upstream_node,
+ size_t port=ANY_PORT,
+ const uhd::device_addr_t &args=uhd::device_addr_t()
+ );
+
+ /*! Call this function to notify a node about its streamer activity.
+ *
+ * When \p active is set to true, this means this block is now part of
+ * an active tx streamer chain. Conversely, when set to false, this means
+ * the node has been removed from an tx streamer chain.
+ */
+ virtual void set_tx_streamer(bool active, const size_t port);
+
+
+protected:
+
+ /*! For every input port, store tx streamer activity.
+ *
+ * If _tx_streamer_active[0] == true, this means that an active tx
+ * streamer is operating on port 0. If it is false, or if the entry
+ * does not exist, there is no streamer.
+ * Values are toggled by set_tx_streamer().
+ */
+ std::map<size_t, bool> _tx_streamer_active;
+
+ /*! Ask for a port number to connect an upstream block to.
+ *
+ * Typically, this will be overridden for custom behaviour.
+ * The default is to return the suggested port, disregarding
+ * \p args, unless \p port == ANY_PORT, in which case the first
+ * unused input port is returned.
+ *
+ * When deriving this function for custom behaviour, consider:
+ * - The result is used to call register_upstream_node(), which
+ * has its own checks in place.
+ * - This function may throw if the arguments can't be resolved.
+ * The exception will propagate to the user space.
+ * - Alternatively, the function may return ANY_PORT to signify
+ * failure.
+ * - \p args and \p suggested_port should be treated as strong
+ * suggestions, but there's no reason to just return any valid
+ * port.
+ *
+ * *Note:* For reasons of thread safety, it is recommended to
+ * never, ever call this function directly. It will be used by
+ * connect_upstream() which will handle the connection process
+ * in a thread-safe manner.
+ *
+ * \param suggested_port Try and connect here.
+ * \param args When deciding on a port number, these arguments may be used.
+ *
+ * \returns A valid input port, or ANY_PORT on failure.
+ */
+ virtual size_t _request_input_port(
+ const size_t suggested_port,
+ const uhd::device_addr_t &args
+ ) const;
+
+private:
+ /*! Makes connecting something to the input thread-safe.
+ */
+ boost::mutex _input_mutex;
+
+ /*! Register a node upstream of this one (i.e., a node that can send data to this node).
+ *
+ * By definition, the upstream node must of type source_node_ctrl.
+ *
+ * This saves a *weak pointer* to the upstream node and checks the port is
+ * available. Will throw otherwise.
+ *
+ * \param upstream_node A pointer to the node instantiation
+ * \param port Port number the upstream node is connected to
+ */
+ void _register_upstream_node(
+ node_ctrl_base::sptr upstream_node,
+ size_t port
+ );
+
+}; /* class sink_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/source_block_ctrl_base.hpp b/host/include/uhd/rfnoc/source_block_ctrl_base.hpp
new file mode 100644
index 000000000..02882307c
--- /dev/null
+++ b/host/include/uhd/rfnoc/source_block_ctrl_base.hpp
@@ -0,0 +1,140 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/block_ctrl_base.hpp>
+#include <uhd/rfnoc/source_node_ctrl.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Extends block_ctrl_base with receive capabilities.
+ *
+ * In RFNoC nomenclature, a receive operation means streaming
+ * data from the device (the crossbar) to the host.
+ * If a block has receive capabilities, this means we can receive
+ * data *from* this block.
+ */
+class UHD_RFNOC_API source_block_ctrl_base;
+class source_block_ctrl_base : virtual public block_ctrl_base, virtual public source_node_ctrl
+{
+public:
+ typedef boost::shared_ptr<source_block_ctrl_base> sptr;
+
+ /***********************************************************************
+ * Streaming operations
+ **********************************************************************/
+ /*! Issue a stream command for this block.
+ *
+ * There is no guaranteed action for this command. The default implementation
+ * is to send this command to the next upstream block, or issue a warning if
+ * there is no upstream block registered.
+ *
+ * However, implementations of block_ctrl_base might choose to do whatever seems
+ * appropriate, including throwing exceptions. This may also be true for some
+ * stream commands and not for others (i.e. STREAM_MODE_START_CONTINUOUS may be
+ * implemented, and STREAM_MODE_NUM_SAMPS_AND_DONE may be not).
+ *
+ * This function does not check for infinite loops. Example: Say you have two blocks,
+ * which are both registered as upstream from one another. If they both use
+ * block_ctrl_base::issue_stream_cmd(), then the stream command will be passed from
+ * one block to another indefinitely. This will not happen if one the block's
+ * controller classes overrides this function and actually handles it.
+ *
+ * See also register_upstream_block().
+ *
+ * \param stream_cmd The stream command.
+ */
+ virtual void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t chan=0);
+
+ /***********************************************************************
+ * Stream signatures
+ **********************************************************************/
+ /*! Return the output stream signature for a given block port.
+ *
+ * The actual signature is determined by the current configuration
+ * and the block definition file. The value returned here is calculated
+ * on-the-fly and is only valid as long as the configuration does not
+ * change.
+ *
+ * \returns The stream signature for port \p block_port
+ * \throws uhd::runtime_error if \p block_port is not a valid port
+ */
+ stream_sig_t get_output_signature(size_t block_port=0) const;
+
+ /*! Return a list of valid output ports.
+ */
+ std::vector<size_t> get_output_ports() const;
+
+ /***********************************************************************
+ * FPGA Configuration
+ **********************************************************************/
+ /*! Configures data flowing from port \p output_block_port to go to \p next_address
+ *
+ * \param next_address Address of the downstream block
+ * \param output_block_port Port for which this is valid
+ *
+ * In the default implementation, this will write the value in \p next_address
+ * to register SR_NEXT_DST of this blocks settings bus. The value will also
+ * have bit 16 set to 1, since some blocks require this to respect this value.
+ */
+ virtual void set_destination(
+ boost::uint32_t next_address,
+ size_t output_block_port = 0
+ );
+
+ /*! Configure flow control for outgoing streams.
+ *
+ * In the default implementation, this just sets registers SR_FLOW_CTRL_BUF_SIZE
+ * and SR_FLOW_CTRL_ENABLE accordingly; \b block_port and \p sid are ignored.
+ *
+ * Override this function if your block has port-specific flow control settings.
+ *
+ * \param buf_size_pkts The size of the downstream block's input FIFO size in number of packets. Setting
+ * this to zero disables flow control. The block will then produce data as fast as it can.
+ * \b Warning: This can cause head-of-line blocking, and potentially lock up your device!
+ * \param Specify on which outgoing port this setting is valid.
+ * \param sid The SID for which this is valid. This is meant for cases where the outgoing block port is
+ * not sufficient to set the flow control, and as such is rarely used.
+ */
+ virtual void configure_flow_control_out(
+ size_t buf_size_pkts,
+ size_t block_port=0,
+ const uhd::sid_t &sid=uhd::sid_t()
+ );
+
+
+protected:
+ /***********************************************************************
+ * Hooks
+ **********************************************************************/
+ /*! Like source_node_ctrl::_request_output_port(), but also checks if
+ * the port has an output signature.
+ */
+ virtual size_t _request_output_port(
+ const size_t suggested_port,
+ const uhd::device_addr_t &args
+ ) const;
+
+}; /* class source_block_ctrl_base */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/source_node_ctrl.hpp b/host/include/uhd/rfnoc/source_node_ctrl.hpp
new file mode 100644
index 000000000..a351f6c8e
--- /dev/null
+++ b/host/include/uhd/rfnoc/source_node_ctrl.hpp
@@ -0,0 +1,136 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/constants.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <boost/thread.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Abstract class for source nodes.
+ *
+ * Source nodes can have downstream blocks.
+ */
+class UHD_RFNOC_API source_node_ctrl;
+class source_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<source_node_ctrl> sptr;
+ typedef std::map< size_t, boost::weak_ptr<source_node_ctrl> > node_map_t;
+ typedef std::pair< size_t, boost::weak_ptr<source_node_ctrl> > node_map_pair_t;
+
+ /***********************************************************************
+ * Source block controls
+ **********************************************************************/
+ /*! Issue a stream command for this block.
+ * \param stream_cmd The stream command.
+ * \param chan Channel Index
+ */
+ virtual void issue_stream_cmd(
+ const uhd::stream_cmd_t &stream_cmd,
+ const size_t chan=0
+ ) = 0;
+
+ /*! Connect another node downstream of this node.
+ *
+ * *Note:* If additional settings are required to make this connection work,
+ * e.g. configure flow control, these need to be done separately.
+ *
+ * If the requested connection is not possible, this function will throw.
+ *
+ * \p downstream_node Pointer to the node class to connect
+ * \p port Suggested port number on this block to connect the downstream
+ * block to.
+ * \p args Any arguments that can be useful for determining the port number.
+ *
+ * \returns The actual port number used.
+ */
+ size_t connect_downstream(
+ node_ctrl_base::sptr downstream_node,
+ size_t port=ANY_PORT,
+ const uhd::device_addr_t &args=uhd::device_addr_t()
+ );
+
+ /*! Call this function to notify a node about its streamer activity.
+ *
+ * When \p active is set to true, this means this block is now part of
+ * an active rx streamer chain. Conversely, when set to false, this means
+ * the node has been removed from an rx streamer chain.
+ */
+ virtual void set_rx_streamer(bool active, const size_t port);
+
+protected:
+
+ /*! For every output port, store rx streamer activity.
+ *
+ * If _rx_streamer_active[0] == true, this means that an active rx
+ * streamer is operating on port 0. If it is false, or if the entry
+ * does not exist, there is no streamer.
+ * Values are toggled by set_rx_streamer().
+ */
+ std::map<size_t, bool> _rx_streamer_active;
+
+ /*! Ask for a port number to connect a downstream block to.
+ *
+ * See sink_node_ctrl::_request_input_port(). This is the same
+ * for output.
+ *
+ * \param suggested_port Try and connect here.
+ * \param args When deciding on a port number, these arguments may be used.
+ *
+ * \returns A valid input port, or ANY_PORT on failure.
+ */
+ virtual size_t _request_output_port(
+ const size_t suggested_port,
+ const uhd::device_addr_t &args
+ ) const;
+
+
+private:
+ /*! Makes connecting something to the output thread-safe.
+ */
+ boost::mutex _output_mutex;
+
+ /*! Register a node downstream of this one (i.e., a node that receives data from this node).
+ *
+ * By definition, the upstream node must of type sink_node_ctrl.
+ *
+ * This saves a *weak pointer* to the downstream node and checks
+ * the port is available. Will throw otherwise.
+ *
+ * \param downstream_node A pointer to the node instantiation
+ * \param port Port number the downstream node is connected to
+ */
+ void _register_downstream_node(
+ node_ctrl_base::sptr downstream_node,
+ size_t port
+ );
+
+}; /* class source_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/stream_sig.hpp b/host/include/uhd/rfnoc/stream_sig.hpp
new file mode 100644
index 000000000..28f2efbe7
--- /dev/null
+++ b/host/include/uhd/rfnoc/stream_sig.hpp
@@ -0,0 +1,88 @@
+//
+// Copyright 2014-2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP
+#define INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP
+
+#include <iostream>
+#include <uhd/config.hpp>
+
+namespace uhd { namespace rfnoc {
+
+/*! Describes a stream signature for data going to or coming from
+ * RFNoC ports.
+ *
+ * The stream signature may depend on a block's configuration. Even
+ * so, some attributes may be left undefined (e.g., a FIFO block
+ * works for any item type, so it doesn't need to set it).
+ */
+class UHD_RFNOC_API stream_sig_t {
+ public:
+ /***********************************************************************
+ * Structors
+ ***********************************************************************/
+ stream_sig_t();
+
+ /***********************************************************************
+ * The stream signature attributes
+ ***********************************************************************/
+ //! The data type of the individual items (e.g. 'sc16'). If undefined, set
+ // to empty.
+ std::string item_type;
+
+ //! The vector length in multiples of items. If undefined, set to zero.
+ size_t vlen;
+
+ //! Packet size in bytes. If undefined, set to zero.
+ size_t packet_size;
+
+ bool is_bursty;
+
+ /***********************************************************************
+ * Helpers
+ ***********************************************************************/
+ //! Compact string representation
+ std::string to_string();
+ //! Pretty-print string representation
+ std::string to_pp_string();
+
+ //! Returns the number of bytes necessary to store one item.
+ // Note: The vector length is *not* considered here.
+ //
+ // \returns Number of bytes per item or 0 if the item type is
+ // undefined.
+ // \throws uhd::key_error if the item type is invalid.
+ size_t get_bytes_per_item() const;
+
+ /*! Check if an output with signature \p output_sig could
+ * stream to an input signature \p input_sig.
+ *
+ * \return true if streams are compatible
+ */
+ static bool is_compatible(const stream_sig_t &output_sig, const stream_sig_t &input_sig);
+};
+
+//! Shortcut for << stream_sig.to_string()
+UHD_INLINE std::ostream& operator<< (std::ostream& out, stream_sig_t stream_sig) {
+ out << stream_sig.to_string().c_str();
+ return out;
+}
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/terminator_node_ctrl.hpp b/host/include/uhd/rfnoc/terminator_node_ctrl.hpp
new file mode 100644
index 000000000..3cc4d0cb3
--- /dev/null
+++ b/host/include/uhd/rfnoc/terminator_node_ctrl.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Abstract class for terminator nodes (i.e. nodes that terminate
+ * the flow graph).
+ *
+ * Terminator nodes have the following properties:
+ * - Data flowing into such a node is not propagated to any other node, and
+ * data coming out of this node originates in this node.
+ * - Chain commands are not propagated past this node.
+ *
+ * A block may be a terminator node, but have both upstream and downstream
+ * nodes. An example is the radio block, which can be used for Rx and Tx.
+ * Even if it's used for both, the data going into the radio block is not
+ * the data coming out.
+ */
+class UHD_RFNOC_API terminator_node_ctrl;
+class terminator_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<terminator_node_ctrl> sptr;
+
+}; /* class terminator_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/rfnoc/tick_node_ctrl.hpp b/host/include/uhd/rfnoc/tick_node_ctrl.hpp
new file mode 100644
index 000000000..3f52bbad7
--- /dev/null
+++ b/host/include/uhd/rfnoc/tick_node_ctrl.hpp
@@ -0,0 +1,70 @@
+//
+// Copyright 2014 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP
+#define INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP
+
+#include <uhd/rfnoc/node_ctrl_base.hpp>
+#include <uhd/rfnoc/constants.hpp>
+
+namespace uhd {
+ namespace rfnoc {
+
+/*! \brief Tick-rate-aware node control
+ *
+ * A "rate" node is a streaming node is a point in the flow graph
+ * that is aware of tick rates (time base). Such nodes include:
+ * - Radio Controls
+ * - Data generating blocks that add time stamps
+ */
+class UHD_RFNOC_API tick_node_ctrl;
+class tick_node_ctrl : virtual public node_ctrl_base
+{
+public:
+ /***********************************************************************
+ * Types
+ **********************************************************************/
+ typedef boost::shared_ptr<tick_node_ctrl> sptr;
+
+ /***********************************************************************
+ * Constants
+ **********************************************************************/
+ //! This value is used by rate nodes that don't actually set a rate themselves
+ static const double RATE_UNDEFINED;
+
+ /***********************************************************************
+ * Rate controls
+ **********************************************************************/
+ /*! Return a tick rate.
+ *
+ * This might be either a tick rate defined by this block (see also _get_tick_rate())
+ * or it's a tick rate defined by an adjacent block.
+ * In that case, performs a graph search to figure out the tick rate.
+ */
+ double get_tick_rate(
+ const std::set< node_ctrl_base::sptr > &_explored_nodes=std::set< node_ctrl_base::sptr >()
+ );
+
+protected:
+ virtual double _get_tick_rate() { return RATE_UNDEFINED; };
+
+}; /* class tick_node_ctrl */
+
+}} /* namespace uhd::rfnoc */
+
+#endif /* INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP */
+// vim: sw=4 et:
diff --git a/host/include/uhd/transport/muxed_zero_copy_if.hpp b/host/include/uhd/transport/muxed_zero_copy_if.hpp
new file mode 100644
index 000000000..17213885e
--- /dev/null
+++ b/host/include/uhd/transport/muxed_zero_copy_if.hpp
@@ -0,0 +1,72 @@
+//
+// Copyright 2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TRANSPORT_MUXED_ZERO_COPY_IF_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_MUXED_ZERO_COPY_IF_HPP
+
+#include <uhd/transport/zero_copy.hpp>
+#include <uhd/config.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <stdint.h>
+
+namespace uhd { namespace transport {
+
+/*!
+ * Implements a software muxed-demuxed zero-copy transport
+ * This is a wrapper around a base transport that allows
+ * creation of virtual zero_copy_if streams that are
+ * indistinguishable from physical transport streams.
+ * This class handles demuxing receive streams into the
+ * appropriate virtual streams with the given classifier
+ * function. A worker therad is spawned to handle the demuxing.
+ */
+class muxed_zero_copy_if : private boost::noncopyable {
+public:
+ typedef boost::shared_ptr<muxed_zero_copy_if> sptr;
+
+ /*!
+ * Function to classify the stream based on the payload.
+ * The classifier must return a stream number, an arbitrary
+ * identifier for a virtual stream that is consistent with
+ * the stream number used in the make_stream and remove_stream
+ * fuctions
+ * \param buff a pointer to the payload of the frame
+ * \param size number of bytes in the frame payload
+ * \return stream number
+ */
+ typedef boost::function<uint32_t(void* buff, size_t size)> stream_classifier_fn;
+
+ //! virtual dtor
+ virtual ~muxed_zero_copy_if() {}
+
+ //! Make a virtual transport for the specified stream number
+ virtual zero_copy_if::sptr make_stream(const uint32_t stream_num) = 0;
+
+ //! Unregister the stream number. All packets destined to the stream will be dropped.
+ virtual void remove_stream(const uint32_t stream_num) = 0;
+
+ //! Get number of frames dropped due to unregistered streams
+ virtual size_t get_num_dropped_frames() const = 0;
+
+ //! Make a new demuxer from a transport and parameters
+ static sptr make(zero_copy_if::sptr base_xport, stream_classifier_fn classify_fn, size_t max_streams);
+};
+
+}} //namespace uhd::transport
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_MUXED_ZERO_COPY_IF_HPP */
diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp
index 23f35d7e8..4576d6e92 100644
--- a/host/include/uhd/transport/usb_control.hpp
+++ b/host/include/uhd/transport/usb_control.hpp
@@ -26,7 +26,7 @@ class UHD_API usb_control : boost::noncopyable {
public:
typedef boost::shared_ptr<usb_control> sptr;
- virtual ~usb_control(void) = 0;
+ virtual ~usb_control(void);
/*!
* Create a new USB control transport:
@@ -36,7 +36,7 @@ public:
* \param handle a device handle that uniquely identifies a USB device
* \param interface the USB interface number for the control transport
*/
- static sptr make(usb_device_handle::sptr handle, const size_t interface);
+ static sptr make(usb_device_handle::sptr handle, const int interface);
/*!
* Submit a USB device request:
@@ -56,13 +56,13 @@ public:
* \param timeout 4-byte (timeout, default is infinite wait)
* \return number of bytes submitted or error code
*/
- virtual ssize_t submit(boost::uint8_t request_type,
- boost::uint8_t request,
- boost::uint16_t value,
- boost::uint16_t index,
- unsigned char *buff,
- boost::uint16_t length,
- boost::int32_t timeout = 0) = 0;
+ virtual int submit(boost::uint8_t request_type,
+ boost::uint8_t request,
+ boost::uint16_t value,
+ boost::uint16_t index,
+ unsigned char *buff,
+ boost::uint16_t length,
+ boost::uint32_t timeout = 0) = 0;
};
}} //namespace
diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp
index bf122f549..a8bbfc965 100644
--- a/host/include/uhd/transport/usb_device_handle.hpp
+++ b/host/include/uhd/transport/usb_device_handle.hpp
@@ -43,6 +43,8 @@ public:
typedef boost::shared_ptr<usb_device_handle> sptr;
typedef std::pair<boost::uint16_t, boost::uint16_t> vid_pid_pair_t;
+ virtual ~usb_device_handle(void);
+
/*!
* Return the device's serial number
* \return a string describing the device's serial number
diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp
index ae1926e1b..092873803 100644
--- a/host/include/uhd/transport/usb_zero_copy.hpp
+++ b/host/include/uhd/transport/usb_zero_copy.hpp
@@ -38,6 +38,8 @@ class UHD_API usb_zero_copy : public virtual zero_copy_if {
public:
typedef boost::shared_ptr<usb_zero_copy> sptr;
+ virtual ~usb_zero_copy(void);
+
/*!
* Make a new zero copy USB transport:
* This transport is for sending and receiving between the host
@@ -55,10 +57,10 @@ public:
*/
static sptr make(
usb_device_handle::sptr handle,
- const size_t recv_interface,
- const size_t recv_endpoint,
- const size_t send_interface,
- const size_t send_endpoint,
+ const int recv_interface,
+ const unsigned char recv_endpoint,
+ const int send_interface,
+ const unsigned char send_endpoint,
const device_addr_t &hints = device_addr_t()
);
};
diff --git a/host/include/uhd/transport/zero_copy_recv_offload.hpp b/host/include/uhd/transport/zero_copy_recv_offload.hpp
new file mode 100644
index 000000000..793753276
--- /dev/null
+++ b/host/include/uhd/transport/zero_copy_recv_offload.hpp
@@ -0,0 +1,50 @@
+//
+// Copyright 2016 Ettus Research
+//
+// 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_ZERO_COPY_RECV_OFFLOAD_HPP
+#define INCLUDED_UHD_ZERO_COPY_RECV_OFFLOAD_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace uhd{ namespace transport{
+
+/*!
+ * A threaded transport offload that is meant to relieve the main thread of
+ * the responsibility of making receive calls.
+ */
+class UHD_API zero_copy_recv_offload : public virtual zero_copy_if {
+public:
+ typedef boost::shared_ptr<zero_copy_recv_offload> sptr;
+
+ /*!
+ * This transport offload adds a receive thread in order to
+ * communicate with the underlying transport. It is meant to be
+ * used in cases where the main thread needs to be relieved of the burden
+ * of the underlying transport receive calls.
+ *
+ * \param transport a shared pointer to the transport interface
+ * \param timeout a general timeout for pushing and pulling on the bounded buffer
+ */
+ static sptr make(zero_copy_if::sptr transport,
+ const double timeout);
+};
+
+}} //namespace
+
+#endif /* INCLUDED_ZERO_COPY_OFFLOAD_HPP */
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
index 3f34782e2..682d3cd9b 100644
--- a/host/include/uhd/types/CMakeLists.txt
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011,2015 Ettus Research LLC
+# Copyright 2010-2011,2015-2016 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
diff --git a/host/include/uhd/types/filters.hpp b/host/include/uhd/types/filters.hpp
index 976ae233d..2c30c1007 100644
--- a/host/include/uhd/types/filters.hpp
+++ b/host/include/uhd/types/filters.hpp
@@ -55,12 +55,12 @@ namespace uhd{
//NOP
}
- inline virtual bool is_bypassed()
+ UHD_INLINE virtual bool is_bypassed()
{
return _bypass;
}
- inline filter_type get_type()
+ UHD_INLINE filter_type get_type()
{
return _type;
}
@@ -98,7 +98,7 @@ namespace uhd{
//NOP
}
- inline const std::string& get_analog_type()
+ UHD_INLINE const std::string& get_analog_type()
{
return _analog_type;
}
@@ -128,17 +128,17 @@ namespace uhd{
//NOP
}
- inline double get_cutoff()
+ UHD_INLINE double get_cutoff()
{
return _cutoff;
}
- inline double get_rolloff()
+ UHD_INLINE double get_rolloff()
{
return _cutoff;
}
- inline void set_cutoff(const double cutoff)
+ UHD_INLINE void set_cutoff(const double cutoff)
{
_cutoff = cutoff;
}
@@ -181,32 +181,32 @@ namespace uhd{
//NOP
}
- inline double get_output_rate()
+ UHD_INLINE double get_output_rate()
{
return (_bypass ? _rate : (_rate / _decimation * _interpolation));
}
- inline double get_input_rate()
+ UHD_INLINE double get_input_rate()
{
return _rate;
}
- inline double get_interpolation()
+ UHD_INLINE double get_interpolation()
{
return _interpolation;
}
- inline double get_decimation()
+ UHD_INLINE double get_decimation()
{
return _decimation;
}
- inline double get_tap_full_scale()
+ UHD_INLINE double get_tap_full_scale()
{
return _tap_full_scale;
}
- inline std::vector<tap_t>& get_taps()
+ UHD_INLINE std::vector<tap_t>& get_taps()
{
return _taps;
}
diff --git a/host/include/uhd/types/sensors.hpp b/host/include/uhd/types/sensors.hpp
index 529e1e3e3..de1ed014f 100644
--- a/host/include/uhd/types/sensors.hpp
+++ b/host/include/uhd/types/sensors.hpp
@@ -91,6 +91,12 @@ namespace uhd{
const std::string &unit
);
+ /*!
+ * Create a sensor value from another sensor value.
+ * \param source the source sensor value to copy
+ */
+ sensor_value_t(const sensor_value_t& source);
+
//! convert the sensor value to a boolean
bool to_bool(void) const;
@@ -101,21 +107,21 @@ namespace uhd{
double to_real(void) const;
//! The name of the sensor value
- const std::string name;
+ std::string name;
/*!
* The sensor value as a string.
* For integer and real number types, this will be the output of the formatter.
* For boolean types, the value will be the string literal "true" or "false".
*/
- const std::string value;
+ std::string value;
/*!
* The sensor value's unit type.
* For boolean types, this will be the one of the two units
* depending upon the value of the boolean true or false.
*/
- const std::string unit;
+ std::string unit;
//! Enumeration of possible data types in a sensor
enum data_type_t {
@@ -126,10 +132,13 @@ namespace uhd{
};
//! The data type of the value
- const data_type_t type;
+ data_type_t type;
//! Convert this sensor value into a printable string
std::string to_pp_string(void) const;
+
+ //! Assignment operator for sensor value
+ sensor_value_t& operator=(const sensor_value_t& value);
};
} //namespace uhd
diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp
index dca0cfb2a..cb90d7c71 100644
--- a/host/include/uhd/types/serial.hpp
+++ b/host/include/uhd/types/serial.hpp
@@ -118,6 +118,12 @@ namespace uhd{
//! on what edge is the miso data valid?
edge_t miso_edge;
+ //! Set the clock speed for this transaction
+ bool use_custom_divider;
+
+ //! Optionally set the SPI clock divider for this transaction
+ size_t divider;
+
/*!
* Create a new spi config.
* \param edge the default edge for mosi and miso
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index e974f808d..7a7dd02f4 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011,2015 Ettus Research LLC
+# Copyright 2010-2011,2014-2015 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
UHD_INSTALL(FILES
#### dboard headers ###
+ fe_connection.hpp
dboard_base.hpp
dboard_eeprom.hpp
dboard_id.hpp
@@ -26,6 +27,7 @@ UHD_INSTALL(FILES
### utilities ###
gps_ctrl.hpp
+ gpio_defs.hpp
mboard_eeprom.hpp
subdev_spec.hpp
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
index 31b3643c7..b106a1ac6 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -44,6 +44,10 @@ public:
//structors
dboard_base(ctor_args_t);
+ virtual ~dboard_base() {}
+
+ //post-construction initializer
+ virtual void initialize() {}
protected:
std::string get_subdev_name(void);
@@ -67,6 +71,7 @@ public:
* Create a new xcvr dboard object, override in subclasses.
*/
xcvr_dboard_base(ctor_args_t);
+ virtual ~xcvr_dboard_base() {}
};
/*!
@@ -79,6 +84,7 @@ public:
* Create a new rx dboard object, override in subclasses.
*/
rx_dboard_base(ctor_args_t);
+ virtual ~rx_dboard_base() {}
};
/*!
@@ -91,6 +97,7 @@ public:
* Create a new rx dboard object, override in subclasses.
*/
tx_dboard_base(ctor_args_t);
+ virtual ~tx_dboard_base() {}
};
}} //namespace
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
index 686deb48d..7c730f59d 100644
--- a/host/include/uhd/usrp/dboard_iface.hpp
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2013 Ettus Research LLC
+// Copyright 2010-2013,2015-2016 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
@@ -22,8 +22,11 @@
#include <uhd/utils/pimpl.hpp>
#include <uhd/types/serial.hpp>
#include <uhd/types/time_spec.hpp>
+#include <uhd/usrp/fe_connection.hpp>
+#include <uhd/usrp/gpio_defs.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/cstdint.hpp>
+#include <boost/thread/thread.hpp>
#include <string>
#include <vector>
@@ -63,16 +66,9 @@ public:
//! tells the host which unit to use
enum unit_t{
- UNIT_RX = int('r'),
- UNIT_TX = int('t')
- };
-
- //! possible atr registers
- enum atr_reg_t{
- ATR_REG_IDLE = int('i'),
- ATR_REG_TX_ONLY = int('t'),
- ATR_REG_RX_ONLY = int('r'),
- ATR_REG_FULL_DUPLEX = int('f')
+ UNIT_RX = int('r'),
+ UNIT_TX = int('t'),
+ UNIT_BOTH = int('b'),
};
//! aux dac selection enums (per unit)
@@ -89,6 +85,10 @@ public:
AUX_ADC_B = int('b')
};
+ typedef uhd::usrp::gpio_atr::gpio_atr_reg_t atr_reg_t;
+
+ virtual ~dboard_iface(void) {};
+
/*!
* Get special properties information for this dboard slot.
* This call helps the dboard code to handle implementation
@@ -123,8 +123,8 @@ public:
* \param mask 16-bits, 0=do not change, 1=change value
*/
virtual void set_pin_ctrl(
- unit_t unit, boost::uint16_t value, boost::uint16_t mask = 0xffff
- );
+ unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffff
+ ) = 0;
/*!
* Read back the pin control setting.
@@ -132,7 +132,7 @@ public:
* \param unit which unit rx or tx
* \return the 16-bit settings value
*/
- virtual boost::uint16_t get_pin_ctrl(unit_t unit);
+ virtual boost::uint32_t get_pin_ctrl(unit_t unit) = 0;
/*!
* Set a daughterboard ATR register.
@@ -143,8 +143,8 @@ public:
* \param mask 16-bits, 0=do not change, 1=change value
*/
virtual void set_atr_reg(
- unit_t unit, atr_reg_t reg, boost::uint16_t value, boost::uint16_t mask = 0xffff
- );
+ unit_t unit, atr_reg_t reg, boost::uint32_t value, boost::uint32_t mask = 0xffff
+ ) = 0;
/*!
* Read back an ATR register setting.
@@ -153,7 +153,7 @@ public:
* \param reg which ATR register
* \return the 16-bit settings value
*/
- virtual boost::uint16_t get_atr_reg(unit_t unit, atr_reg_t reg);
+ virtual boost::uint32_t get_atr_reg(unit_t unit, atr_reg_t reg) = 0;
/*!
* Set daughterboard GPIO data direction setting.
@@ -163,8 +163,8 @@ public:
* \param mask 16-bits, 0=do not change, 1=change value
*/
virtual void set_gpio_ddr(
- unit_t unit, boost::uint16_t value, boost::uint16_t mask = 0xffff
- );
+ unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffff
+ ) = 0;
/*!
* Read back the GPIO data direction setting.
@@ -172,7 +172,7 @@ public:
* \param unit which unit rx or tx
* \return the 16-bit settings value
*/
- virtual boost::uint16_t get_gpio_ddr(unit_t unit);
+ virtual boost::uint32_t get_gpio_ddr(unit_t unit) = 0;
/*!
* Set daughterboard GPIO pin output setting.
@@ -182,8 +182,8 @@ public:
* \param mask 16-bits, 0=do not change, 1=change value
*/
virtual void set_gpio_out(
- unit_t unit, boost::uint16_t value, boost::uint16_t mask = 0xffff
- );
+ unit_t unit, boost::uint32_t value, boost::uint32_t mask = 0xffff
+ ) = 0;
/*!
* Read back the GPIO pin output setting.
@@ -191,15 +191,7 @@ public:
* \param unit which unit rx or tx
* \return the 16-bit settings value
*/
- virtual boost::uint16_t get_gpio_out(unit_t unit);
-
- /*!
- * Setup the GPIO debug mux.
- *
- * \param unit which unit rx or tx
- * \param which which debug: 0, 1
- */
- virtual void set_gpio_debug(unit_t unit, int which) = 0;
+ virtual boost::uint32_t get_gpio_out(unit_t unit) = 0;
/*!
* Read daughterboard GPIO pin values.
@@ -207,7 +199,7 @@ public:
* \param unit which unit rx or tx
* \return the value of the gpio unit
*/
- virtual boost::uint16_t read_gpio(unit_t unit) = 0;
+ virtual boost::uint32_t read_gpio(unit_t unit) = 0;
/*!
* Write data to SPI bus peripheral.
@@ -282,30 +274,35 @@ public:
virtual double get_codec_rate(unit_t unit) = 0;
/*!
+ * Configure the front-end connection parameters.
+ *
+ * \param unit which unit rx or tx
+ * \param fe_name name of the front-end to update
+ * \param fe_conn connection parameters class
+ */
+ virtual void set_fe_connection(
+ unit_t unit,
+ const std::string& fe_name,
+ const uhd::usrp::fe_connection_t& fe_conn
+ ) = 0;
+
+ /*!
* Get the command time.
* \return the command time
*/
- virtual uhd::time_spec_t get_command_time(void);
+ virtual uhd::time_spec_t get_command_time(void) = 0;
/*!
* Set the command time.
* \param t the time
*/
- virtual void set_command_time(const uhd::time_spec_t& t);
-
-private:
- UHD_PIMPL_DECL(impl) _impl;
-
- virtual void _set_pin_ctrl(unit_t unit, boost::uint16_t value) = 0;
- virtual void _set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0;
- virtual void _set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0;
- virtual void _set_gpio_out(unit_t unit, boost::uint16_t value) = 0;
-
-protected:
- dboard_iface(void);
-public:
- virtual ~dboard_iface(void);
+ virtual void set_command_time(const uhd::time_spec_t& t) = 0;
+ /*!
+ * Sleep for a set time
+ * \param time time to sleep in nanoseconds
+ */
+ virtual void sleep(const boost::chrono::nanoseconds& time);
};
}} //namespace
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index d3a3ffb5c..e07b87ad8 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -45,15 +45,17 @@ public:
* Register a rx or tx dboard into the system.
* For single subdevice boards, omit subdev_names.
* \param dboard_id the dboard id (rx or tx)
- * \param dboard_ctor the dboard constructor function pointer
+ * \param db_subdev_ctor the dboard sub-device constructor function pointer (one instance per subdev name)
* \param name the canonical name for the dboard represented
* \param subdev_names the names of the subdevs on this dboard
+ * \param db_container_ctor the dboard container constructor function pointer (one instance per dboard)
*/
static void register_dboard(
const dboard_id_t &dboard_id,
- dboard_ctor_t dboard_ctor,
+ dboard_ctor_t db_subdev_ctor,
const std::string &name,
- const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0")
+ const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0"),
+ dboard_ctor_t db_container_ctor = NULL
);
/*!
@@ -61,16 +63,58 @@ public:
* For single subdevice boards, omit subdev_names.
* \param rx_dboard_id the rx unit dboard id
* \param tx_dboard_id the tx unit dboard id
- * \param dboard_ctor the dboard constructor function pointer
+ * \param db_subdev_ctor the dboard sub-device constructor function pointer (one instance per subdev name)
* \param name the canonical name for the dboard represented
* \param subdev_names the names of the subdevs on this dboard
+ * \param db_container_ctor the dboard container constructor function pointer (one instance per dboard)
*/
static void register_dboard(
const dboard_id_t &rx_dboard_id,
const dboard_id_t &tx_dboard_id,
- dboard_ctor_t dboard_ctor,
+ dboard_ctor_t db_subdev_ctor,
const std::string &name,
- const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0")
+ const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0"),
+ dboard_ctor_t db_container_ctor = NULL
+ );
+
+ /*!
+ * Register a restricted rx or tx dboard into the system.
+ * A restricted dboard does not add its dboard_iface object into the property tree.
+ * For single subdevice boards, omit subdev_names.
+ * The iface for a restricted board is not registered into the property tree.
+ * \param dboard_id the dboard id (rx or tx)
+ * \param db_subdev_ctor the dboard sub-device constructor function pointer (one instance per subdev name)
+ * \param name the canonical name for the dboard represented
+ * \param subdev_names the names of the subdevs on this dboard
+ * \param db_container_ctor the dboard container constructor function pointer (one instance per dboard)
+ */
+ static void register_dboard_restricted(
+ const dboard_id_t &dboard_id,
+ dboard_ctor_t db_subdev_ctor,
+ const std::string &name,
+ const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0"),
+ dboard_ctor_t db_container_ctor = NULL
+ );
+
+ /*!
+ * Register a restricted xcvr dboard into the system.
+ * A restricted dboard does not add its dboard_iface object into the property tree.
+ * For single subdevice boards, omit subdev_names.
+ * The iface for a restricted board is not registered into the property tree.
+ * \param rx_dboard_id the rx unit dboard id
+ * \param tx_dboard_id the tx unit dboard id
+ * \param db_subdev_ctor the dboard sub-device constructor function pointer (one instance per subdev name)
+ * \param name the canonical name for the dboard represented
+ * \param subdev_names the names of the subdevs on this dboard
+ * \param db_container_ctor the dboard container constructor function pointer (one instance per dboard)
+ */
+ static void register_dboard_restricted(
+ const dboard_id_t &rx_dboard_id,
+ const dboard_id_t &tx_dboard_id,
+ dboard_ctor_t db_subdev_ctor,
+ const std::string &name,
+ const std::vector<std::string> &subdev_names = std::vector<std::string>(1, "0"),
+ dboard_ctor_t db_container_ctor = NULL
);
/*!
@@ -80,6 +124,7 @@ public:
* \param gdboard_id the id of the grand-dboard
* \param iface the custom dboard interface
* \param subtree the subtree to load with props
+ * \param defer_db_init initialising the daughterboards (DEPRECATED)
* \return an sptr to the new dboard manager
*/
static sptr make(
@@ -87,8 +132,28 @@ public:
dboard_id_t tx_dboard_id,
dboard_id_t gdboard_id,
dboard_iface::sptr iface,
- property_tree::sptr subtree
+ property_tree::sptr subtree,
+ bool defer_db_init = false
);
+
+ virtual ~dboard_manager() {}
+
+ /*!
+ * Run dboard post constructor initializations if defered during make
+ */
+ virtual void initialize_dboards() = 0;
+
+ /*!
+ * Returns a vector of RX frontend (subdev) names
+ * \return a vector of names
+ */
+ virtual const std::vector<std::string>& get_rx_frontends() const = 0;
+
+ /*!
+ * Returns a vector of TX frontend (subdev) names
+ * \return a vector of names
+ */
+ virtual const std::vector<std::string>& get_tx_frontends() const = 0;
};
}} //namespace
diff --git a/host/include/uhd/usrp/fe_connection.hpp b/host/include/uhd/usrp/fe_connection.hpp
new file mode 100644
index 000000000..969246087
--- /dev/null
+++ b/host/include/uhd/usrp/fe_connection.hpp
@@ -0,0 +1,127 @@
+//
+// Copyright 2016 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_FE_CONNECTION_HPP
+#define INCLUDED_UHD_USRP_FE_CONNECTION_HPP
+
+#include <uhd/config.hpp>
+#include <boost/operators.hpp>
+#include <string>
+
+namespace uhd { namespace usrp {
+
+ class UHD_API fe_connection_t : boost::equality_comparable<fe_connection_t> {
+ public:
+ /** Sampling mode.
+ * Represents the sampling architecture for the front-end
+ */
+ enum sampling_t {
+ QUADRATURE, /**< Complex sampling (Complex input, Complex output). */
+ HETERODYNE, /**< Heterodyne sampling (Real input, Complex output). Only one of the I and Q inputs is used. */
+ REAL /**< Real sampling (Real input, Real output). Only one of the I and Q inputs is used. */
+ };
+
+ /*!
+ * Create a frontend connection class from individual settings.
+ * \param sampling_mode can be { QUADRATURE, HETERODYNE, REAL }
+ * \param iq_swapped indicates if the IQ channels are swapped (after inverion and heterodyne correction)
+ * \param i_inverted indicates if the I channel is inverted (negated)
+ * \param q_inverted indicates if the Q channel is inverted (negated)
+ * \param if_freq the baseband sampling frequency.
+ */
+ fe_connection_t(
+ sampling_t sampling_mode, bool iq_swapped,
+ bool i_inverted, bool q_inverted, double if_freq = 0.0
+ );
+
+ /*!
+ * Create a frontend connection class from a connection string
+ * The connection string can be:
+ * - in {I, Q}: Real mode sampling with no inversion.
+ * - in {Ib, Qb}: Real mode sampling with inversion.
+ * - in {IQ, QI}: Quadrature sampling with no inversion.
+ * - in {IbQb, QbIb}: Quadrature sampling with inversion.
+ * - in {II, QQ}: Heterodyne sampling with no inversion.
+ * - in {IbIb, QbQb}: Heterodyne sampling with inversion.
+ *
+ * \param conn_str the connection string.
+ * \param if_freq the baseband sampling frequency.
+ */
+ fe_connection_t(const std::string& conn_str, double if_freq = 0.0);
+
+ /*!
+ * Accessor for sampling mode
+ */
+ inline sampling_t get_sampling_mode() const {
+ return _sampling_mode;
+ }
+
+ /*!
+ * Accessor for IQ swap parameter
+ */
+ inline bool is_iq_swapped() const {
+ return _iq_swapped;
+ }
+
+ /*!
+ * Accessor for I inversion parameter
+ */
+ inline bool is_i_inverted() const {
+ return _i_inverted;
+ }
+
+ /*!
+ * Accessor for Q inversion parameter
+ */
+ inline bool is_q_inverted() const {
+ return _q_inverted;
+ }
+
+ /*!
+ * Accessor for IF frequency
+ */
+ inline double get_if_freq() const {
+ return _if_freq;
+ }
+
+ /*!
+ * Mutator for IF frequency
+ */
+ inline void set_if_freq(double freq) {
+ _if_freq = freq;
+ }
+
+ private:
+ sampling_t _sampling_mode;
+ bool _iq_swapped;
+ bool _i_inverted;
+ bool _q_inverted;
+ double _if_freq;
+ };
+
+ /*!
+ * Comparator operator overloaded for fe_connection_t.
+ * The boost::equality_comparable provides the !=.
+ * \param lhs the fe_connection_t to the left of the operator
+ * \param rhs the fe_connection_t to the right of the operator
+ * \return true when the fe connections are equal
+ */
+ UHD_API bool operator==(const fe_connection_t &lhs, const fe_connection_t &rhs);
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_USRP_FE_CONNECTION_HPP */
diff --git a/host/include/uhd/usrp/gpio_defs.hpp b/host/include/uhd/usrp/gpio_defs.hpp
new file mode 100644
index 000000000..c32f22f28
--- /dev/null
+++ b/host/include/uhd/usrp/gpio_defs.hpp
@@ -0,0 +1,70 @@
+//
+// Copyright 2011,2014,2015 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_GPIO_DEFS_HPP
+#define INCLUDED_LIBUHD_USRP_GPIO_DEFS_HPP
+
+#include <uhd/config.hpp>
+#include <boost/assign.hpp>
+#include <boost/utility.hpp>
+#include <map>
+
+namespace uhd { namespace usrp { namespace gpio_atr {
+
+enum gpio_atr_reg_t {
+ ATR_REG_IDLE = int('i'),
+ ATR_REG_TX_ONLY = int('t'),
+ ATR_REG_RX_ONLY = int('r'),
+ ATR_REG_FULL_DUPLEX = int('f')
+};
+
+enum gpio_atr_mode_t {
+ MODE_ATR = 0, //Output driven by the auto-transmit-receive engine
+ MODE_GPIO = 1 //Output value is static
+};
+
+enum gpio_ddr_t {
+ DDR_INPUT = 0,
+ DDR_OUTPUT = 1
+};
+
+enum gpio_attr_t {
+ GPIO_CTRL,
+ GPIO_DDR,
+ GPIO_OUT,
+ GPIO_ATR_0X,
+ GPIO_ATR_RX,
+ GPIO_ATR_TX,
+ GPIO_ATR_XX
+};
+
+typedef std::map<gpio_attr_t, std::string> gpio_attr_map_t;
+
+static const gpio_attr_map_t gpio_attr_map =
+ boost::assign::map_list_of
+ (GPIO_CTRL, "CTRL")
+ (GPIO_DDR, "DDR")
+ (GPIO_OUT, "OUT")
+ (GPIO_ATR_0X, "ATR_0X")
+ (GPIO_ATR_RX, "ATR_RX")
+ (GPIO_ATR_TX, "ATR_TX")
+ (GPIO_ATR_XX, "ATR_XX")
+;
+
+}}} //namespaces
+
+#endif /* INCLUDED_LIBUHD_USRP_GPIO_DEFS_HPP */
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index 715a57242..8c50178eb 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -31,6 +31,7 @@
#define UHD_USRP_MULTI_USRP_GPIO_API
#define UHD_USRP_MULTI_USRP_REGISTER_API
#define UHD_USRP_MULTI_USRP_FILTER_API
+#define UHD_USRP_MULTI_USRP_LO_CONFIG_API
#include <uhd/config.hpp>
#include <uhd/device.hpp>
@@ -112,6 +113,9 @@ public:
//! A wildcard gain element name
static const std::string ALL_GAINS;
+ //! A wildcard gain element name
+ static const std::string ALL_LOS;
+
/*!
* Make a new multi usrp from the device address.
* \param dev_addr the device address
@@ -122,7 +126,7 @@ public:
/*!
* Get the underlying device object.
* This is needed to get access to the streaming API and properties.
- * \return the device object within this single usrp
+ * \return the device object within this USRP
*/
virtual device::sptr get_device(void) = 0;
@@ -487,6 +491,90 @@ public:
virtual freq_range_t get_fe_rx_freq_range(size_t chan = 0) = 0;
/*!
+ * Get a list of possible LO stage names
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible LO names
+ */
+ virtual std::vector<std::string> get_rx_lo_names(size_t chan = 0) = 0;
+
+ /*!
+ * Set the LO source for the usrp device.
+ * For usrps that support selectable LOs, this function
+ * allows switching between them.
+ * Typical options for source: internal, external.
+ * \param src a string representing the LO source
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_rx_lo_source(const std::string &src, const std::string &name = ALL_LOS, size_t chan = 0) = 0;
+
+ /*!
+ * Get the currently set LO source.
+ * Channels without controllable LO sources will return
+ * "internal"
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO source
+ */
+ virtual const std::string get_rx_lo_source(const std::string &name = ALL_LOS, size_t chan = 0) = 0;
+
+ /*!
+ * Get a list of possible LO sources.
+ * Channels which do not have controllable LO sources
+ * will return "internal".
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_rx_lo_sources(const std::string &name = ALL_LOS, size_t chan = 0) = 0;
+
+ /*!
+ * Set whether the LO used by the usrp device is exported
+ * For usrps that support exportable LOs, this function
+ * configures if the LO used by chan is exported or not.
+ * \param enabled if true then export the LO
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1 for the source channel
+ */
+ virtual void set_rx_lo_export_enabled(bool enabled, const std::string &name = ALL_LOS, size_t chan = 0) = 0;
+
+ /*!
+ * Returns true if the currently selected LO is being exported.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ */
+ virtual bool get_rx_lo_export_enabled(const std::string &name = ALL_LOS, size_t chan = 0) = 0;
+
+ /*!
+ * Set the RX LO frequency (Advanced).
+ * \param freq the frequency to set the LO to
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ * \return a coerced LO frequency
+ */
+ virtual double set_rx_lo_freq(double freq, const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the current RX LO frequency (Advanced).
+ * If the channel does not have independently configurable LOs
+ * the current rf frequency will be returned.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO frequency
+ */
+ virtual double get_rx_lo_freq(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the LO frequency range of the RX LO.
+ * If the channel does not have independently configurable LOs
+ * the rf frequency range will be returned.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a frequency range object
+ */
+ virtual freq_range_t get_rx_lo_freq_range(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
* Set the RX gain value for the specified gain element.
* For an empty name, distribute across all gain elements.
* \param gain the gain in dB
diff --git a/host/include/uhd/usrp/usrp.h b/host/include/uhd/usrp/usrp.h
index 651279e22..f24d12b85 100644
--- a/host/include/uhd/usrp/usrp.h
+++ b/host/include/uhd/usrp/usrp.h
@@ -1,5 +1,5 @@
//
-// Copyright 2015 Ettus Research LLC
+// Copyright 2015-2016 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
@@ -726,6 +726,83 @@ UHD_API uhd_error uhd_usrp_get_fe_rx_freq_range(
uhd_meta_range_handle freq_range_out
);
+//! A wildcard for all LO names
+UHD_UNUSED(static const char* UHD_USRP_ALL_LOS) = "all";
+
+//! Get a list of possible LO stage names
+/*
+ * See uhd::usrp::multi_usrp::get_rx_lo_names() for more details.
+ */
+UHD_API uhd_error uhd_usrp_get_rx_lo_names(
+ uhd_usrp_handle h,
+ size_t chan,
+ uhd_string_vector_handle *rx_lo_names_out
+);
+
+//! Set the LO source for the USRP device
+/*
+ * See uhd::usrp::multi_usrp::set_rx_lo_source() for more details.
+ */
+UHD_API uhd_error uhd_usrp_set_rx_lo_source(
+ uhd_usrp_handle h,
+ const char* src,
+ const char* name,
+ size_t chan
+);
+
+//! Get the currently set LO source
+UHD_API uhd_error uhd_usrp_get_rx_lo_source(
+ uhd_usrp_handle h,
+ const char* name,
+ size_t chan,
+ char* rx_lo_source_out,
+ size_t strbuffer_len
+);
+
+//! Get a list of possible LO sources
+UHD_API uhd_error uhd_usrp_get_rx_lo_sources(
+ uhd_usrp_handle h,
+ const char* name,
+ size_t chan,
+ uhd_string_vector_handle *rx_lo_sources_out
+);
+
+//! Set whether the LO used by the USRP device is exported
+/*
+ * See uhd::usrp::multi_usrp::set_rx_lo_enabled() for more details.
+ */
+UHD_API uhd_error uhd_usrp_set_rx_lo_export_enabled(
+ uhd_usrp_handle h,
+ bool enabled,
+ const char* name,
+ size_t chan
+);
+
+//! Returns true if the currently selected LO is being exported.
+UHD_API uhd_error uhd_usrp_get_rx_lo_export_enabled(
+ uhd_usrp_handle h,
+ const char* name,
+ size_t chan,
+ bool* result_out
+);
+
+//! Set the RX LO frequency.
+UHD_API uhd_error uhd_usrp_set_rx_lo_freq(
+ uhd_usrp_handle h,
+ double freq,
+ const char* name,
+ size_t chan,
+ double* coerced_freq_out
+);
+
+//! Get the current RX LO frequency.
+UHD_API uhd_error uhd_usrp_get_rx_lo_freq(
+ uhd_usrp_handle h,
+ const char* name,
+ size_t chan,
+ double* rx_lo_freq_out
+);
+
//! Set the RX gain for the given channel and name
UHD_API uhd_error uhd_usrp_set_rx_gain(
uhd_usrp_handle h,
diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp
index 704d745d9..6c6cdf033 100644
--- a/host/include/uhd/utils/algorithm.hpp
+++ b/host/include/uhd/utils/algorithm.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2014 Ettus Research LLC
+// Copyright 2010-2015 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
@@ -39,7 +39,7 @@ namespace uhd{
* \param range the range of elements to be sorted
* \return a new range with the elements sorted
*/
- template<typename Range> inline Range sorted(const Range &range){
+ template<typename Range> UHD_INLINE Range sorted(const Range &range){
Range r(range); std::sort(boost::begin(r), boost::end(r)); return r;
}
@@ -53,7 +53,7 @@ namespace uhd{
* \param range the range of elements to be reversed
* \return a new range with the elements reversed
*/
- template<typename Range> inline Range reversed(const Range &range){
+ template<typename Range> UHD_INLINE Range reversed(const Range &range){
Range r(range); std::reverse(boost::begin(r), boost::end(r)); return r;
}
@@ -66,7 +66,7 @@ namespace uhd{
* \param value the match to look for in the range
* \return true when the value is found in the range
*/
- template<typename Range, typename T> inline
+ template<typename Range, typename T> UHD_INLINE
bool has(const Range &range, const T &value){
return boost::end(range) != std::find(boost::begin(range), boost::end(range), value);
}
@@ -78,7 +78,7 @@ namespace uhd{
* \param bound2 the upper or lower bound
* \return the value clipped at the bounds
*/
- template<typename T> inline T clip(const T &val, const T &bound1, const T &bound2){
+ template<typename T> UHD_INLINE T clip(const T &val, const T &bound1, const T &bound2){
const T minimum = std::min(bound1, bound2);
if (val < minimum) return minimum;
const T maximum = std::max(bound1, bound2);
diff --git a/host/include/uhd/utils/atomic.hpp b/host/include/uhd/utils/atomic.hpp
index 55769d2fd..8c5e6a5da 100644
--- a/host/include/uhd/utils/atomic.hpp
+++ b/host/include/uhd/utils/atomic.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2013,2016 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
@@ -26,11 +26,7 @@
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/version.hpp>
-#if BOOST_VERSION >= 104800
-# define BOOST_IPC_DETAIL boost::interprocess::ipcdetail
-#else
-# define BOOST_IPC_DETAIL boost::interprocess::detail
-#endif
+#define BOOST_IPC_DETAIL boost::interprocess::ipcdetail
namespace uhd{
diff --git a/host/include/uhd/utils/cast.hpp b/host/include/uhd/utils/cast.hpp
index 9db92c526..869d53053 100644
--- a/host/include/uhd/utils/cast.hpp
+++ b/host/include/uhd/utils/cast.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2014 Ettus Research LLC
+// Copyright 2014-2015 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
@@ -28,7 +28,7 @@ namespace uhd{ namespace cast{
// Example:
// boost::uint16_t x = hexstr_cast<boost::uint16_t>("0xDEADBEEF");
// Uses stringstream.
- template<typename T> inline T hexstr_cast(const std::string &in)
+ template<typename T> UHD_INLINE T hexstr_cast(const std::string &in)
{
T x;
std::stringstream ss;
diff --git a/host/include/uhd/utils/dirty_tracked.hpp b/host/include/uhd/utils/dirty_tracked.hpp
index d228a9e65..561beec9b 100644
--- a/host/include/uhd/utils/dirty_tracked.hpp
+++ b/host/include/uhd/utils/dirty_tracked.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2014 Ettus Research LLC
+// Copyright 2010-2015 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
@@ -60,7 +60,7 @@ namespace uhd{
/*!
* Get underlying data
*/
- inline const data_t& get() const {
+ UHD_INLINE const data_t& get() const {
return _data;
}
@@ -68,21 +68,21 @@ namespace uhd{
* Has the underlying data changed since the last
* time it was cleaned?
*/
- inline bool is_dirty() const {
+ UHD_INLINE bool is_dirty() const {
return _dirty;
}
/*!
* Mark the underlying data as clean
*/
- inline void mark_clean() {
+ UHD_INLINE void mark_clean() {
_dirty = false;
}
/*!
* Mark the underlying data as dirty
*/
- inline void force_dirty() {
+ UHD_INLINE void force_dirty() {
_dirty = true;
}
@@ -91,7 +91,7 @@ namespace uhd{
* Store the specified value and mark it as dirty
* if it is not equal to the underlying data.
*/
- inline dirty_tracked& operator=(const data_t& value)
+ UHD_INLINE dirty_tracked& operator=(const data_t& value)
{
if(!(_data == value)) { //data_t must have an equality operator
_dirty = true;
@@ -107,7 +107,7 @@ namespace uhd{
* This exists to optimize out an implicit cast from dirty_tracked
* type to data type.
*/
- inline dirty_tracked& operator=(const dirty_tracked& source) {
+ UHD_INLINE dirty_tracked& operator=(const dirty_tracked& source) {
if (!(_data == source._data)) {
_dirty = true;
_data = source._data;
@@ -118,7 +118,7 @@ namespace uhd{
/*!
* Explicit conversion from this type to data_t
*/
- inline operator const data_t&() const {
+ UHD_INLINE operator const data_t&() const {
return get();
}
diff --git a/host/include/uhd/utils/math.hpp b/host/include/uhd/utils/math.hpp
index 088983167..0b35f1f17 100644
--- a/host/include/uhd/utils/math.hpp
+++ b/host/include/uhd/utils/math.hpp
@@ -32,19 +32,6 @@ namespace uhd {
namespace math {
/*!
- * Numeric limits of certain types.
- *
- * There are many sources for getting these, including std::numeric_limits,
- * `<cstdint>`, `<climits>`, and Boost. The `<cstdint>` option is preferable as it
- * gives us fixed-width constants, but unfortunately is new as of C++11.
- * Since this isn't available on many systems, we need to use one of the
- * other options. We will use the Boost option, here, since we use Boost
- * data types for portability across UHD.
- */
- static const boost::int32_t BOOST_INT32_MAX = boost::numeric::bounds<boost::int32_t>::highest();
- static const boost::int32_t BOOST_INT32_MIN = boost::numeric::bounds<boost::int32_t>::lowest();
-
- /*!
* Define epsilon values for floating point comparisons.
*
* There are a lot of different sources for epsilon values that we could use
diff --git a/host/include/uhd/utils/msg_task.hpp b/host/include/uhd/utils/msg_task.hpp
index d46fdd69e..8ae789d72 100644
--- a/host/include/uhd/utils/msg_task.hpp
+++ b/host/include/uhd/utils/msg_task.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011-2014 Ettus Research LLC
+// Copyright 2011-2015 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
@@ -42,7 +42,7 @@ namespace uhd{
*/
virtual msg_payload_t get_msg_from_dump_queue(boost::uint32_t sid) = 0;
- inline static std::vector<boost::uint8_t> buff_to_vector(boost::uint8_t* p, size_t n) {
+ UHD_INLINE static std::vector<boost::uint8_t> buff_to_vector(boost::uint8_t* p, size_t n) {
if(p and n > 0){
std::vector<boost::uint8_t> v(n);
memcpy(&v.front(), p, n);
diff --git a/host/include/uhd/utils/soft_register.hpp b/host/include/uhd/utils/soft_register.hpp
index a2c34a4ec..09a69fce2 100644
--- a/host/include/uhd/utils/soft_register.hpp
+++ b/host/include/uhd/utils/soft_register.hpp
@@ -57,7 +57,7 @@ namespace uhd {
//TODO: These hints were added to boost 1.53.
/** \brief hint for the branch prediction */
-inline bool likely(bool expr)
+UHD_INLINE bool likely(bool expr)
{
#ifdef __GNUC__
return __builtin_expect(expr, true);
@@ -67,7 +67,7 @@ inline bool likely(bool expr)
}
/** \brief hint for the branch prediction */
-inline bool unlikely(bool expr)
+UHD_INLINE bool unlikely(bool expr)
{
#ifdef __GNUC__
return __builtin_expect(expr, false);
@@ -86,16 +86,16 @@ inline bool unlikely(bool expr)
typedef boost::uint32_t soft_reg_field_t;
namespace soft_reg_field {
- inline size_t width(const soft_reg_field_t field) {
+ UHD_INLINE size_t width(const soft_reg_field_t field) {
return (field & 0xFF);
}
- inline size_t shift(const soft_reg_field_t field) {
+ UHD_INLINE size_t shift(const soft_reg_field_t field) {
return ((field >> 8) & 0xFF);
}
template<typename data_t>
- inline size_t mask(const soft_reg_field_t field) {
+ UHD_INLINE size_t mask(const soft_reg_field_t field) {
static const data_t ONE = static_cast<data_t>(1);
//Behavior for the left shift operation is undefined in C++
//if the shift amount is >= bitwidth of the datatype
@@ -122,7 +122,7 @@ public:
* Cast the soft_register generic reference to a more specific type
*/
template <typename soft_reg_t>
- inline static soft_reg_t& cast(soft_register_base& reg) {
+ UHD_INLINE static soft_reg_t& cast(soft_register_base& reg) {
soft_reg_t* ptr = dynamic_cast<soft_reg_t*>(&reg);
if (ptr) {
return *ptr;
@@ -150,7 +150,7 @@ public:
/*!
* Generic constructor for all soft_register types
*/
- explicit soft_register_t(
+ soft_register_t(
wb_iface::wb_addr_type wr_addr,
wb_iface::wb_addr_type rd_addr,
soft_reg_flush_mode_t mode = ALWAYS_FLUSH):
@@ -172,7 +172,7 @@ public:
* Can be optionally synced with hardware.
* NOTE: Memory management of the iface is up to the caller
*/
- inline void initialize(wb_iface& iface, bool sync = false)
+ UHD_INLINE void initialize(wb_iface& iface, bool sync = false)
{
_iface = &iface;
@@ -186,7 +186,7 @@ public:
* Performs a read-modify-write operation so all other field are preserved.
* NOTE: This does not write the value to hardware.
*/
- inline void set(const soft_reg_field_t field, const reg_data_t value)
+ UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
{
_soft_copy = (_soft_copy & ~soft_reg_field::mask<reg_data_t>(field)) |
((value << soft_reg_field::shift(field)) & soft_reg_field::mask<reg_data_t>(field));
@@ -196,7 +196,7 @@ public:
* Get the value of the specified field from the soft-copy.
* NOTE: This does not read anything from hardware.
*/
- inline reg_data_t get(const soft_reg_field_t field)
+ UHD_INLINE reg_data_t get(const soft_reg_field_t field)
{
return (_soft_copy & soft_reg_field::mask<reg_data_t>(field)) >> soft_reg_field::shift(field);
}
@@ -204,7 +204,7 @@ public:
/*!
* Write the contents of the soft-copy to hardware.
*/
- inline void flush()
+ UHD_INLINE void flush()
{
if (writable && _iface) {
//If optimized flush then poke only if soft copy is dirty
@@ -223,14 +223,14 @@ public:
_soft_copy.mark_clean();
}
} else {
- throw uhd::not_implemented_error("soft_register is not writable.");
+ throw uhd::not_implemented_error("soft_register is not writable or uninitialized.");
}
}
/*!
* Read the contents of the register from hardware and update the soft copy.
*/
- inline void refresh()
+ UHD_INLINE void refresh()
{
if (readable && _iface) {
if (get_bitwidth() <= 16) {
@@ -244,14 +244,14 @@ public:
}
_soft_copy.mark_clean();
} else {
- throw uhd::not_implemented_error("soft_register is not readable.");
+ throw uhd::not_implemented_error("soft_register is not readable or uninitialized.");
}
}
/*!
* Shortcut for a set and a flush.
*/
- inline void write(const soft_reg_field_t field, const reg_data_t value)
+ UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
{
set(field, value);
flush();
@@ -260,7 +260,7 @@ public:
/*!
* Shortcut for refresh and get
*/
- inline reg_data_t read(const soft_reg_field_t field)
+ UHD_INLINE reg_data_t read(const soft_reg_field_t field)
{
refresh();
return get(field);
@@ -269,7 +269,7 @@ public:
/*!
* Get bitwidth for this register
*/
- inline size_t get_bitwidth()
+ UHD_INLINE size_t get_bitwidth()
{
static const size_t BITS_IN_BYTE = 8;
return sizeof(reg_data_t) * BITS_IN_BYTE;
@@ -278,7 +278,7 @@ public:
/*!
* Is the register readable?
*/
- inline bool is_readable()
+ UHD_INLINE bool is_readable()
{
return readable;
}
@@ -286,7 +286,7 @@ public:
/*!
* Is the register writable?
*/
- inline bool is_writable()
+ UHD_INLINE bool is_writable()
{
return writable;
}
@@ -308,7 +308,7 @@ class UHD_API soft_register_sync_t : public soft_register_t<reg_data_t, readable
public:
typedef boost::shared_ptr< soft_register_sync_t<reg_data_t, readable, writable> > sptr;
- explicit soft_register_sync_t(
+ soft_register_sync_t(
wb_iface::wb_addr_type wr_addr,
wb_iface::wb_addr_type rd_addr,
soft_reg_flush_mode_t mode = ALWAYS_FLUSH):
@@ -321,43 +321,43 @@ public:
soft_register_t<reg_data_t, readable, writable>(addr, mode), _mutex()
{}
- inline void initialize(wb_iface& iface, bool sync = false)
+ UHD_INLINE void initialize(wb_iface& iface, bool sync = false)
{
boost::lock_guard<boost::mutex> lock(_mutex);
soft_register_t<reg_data_t, readable, writable>::initialize(iface, sync);
}
- inline void set(const soft_reg_field_t field, const reg_data_t value)
+ UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
{
boost::lock_guard<boost::mutex> lock(_mutex);
soft_register_t<reg_data_t, readable, writable>::set(field, value);
}
- inline reg_data_t get(const soft_reg_field_t field)
+ UHD_INLINE reg_data_t get(const soft_reg_field_t field)
{
boost::lock_guard<boost::mutex> lock(_mutex);
return soft_register_t<reg_data_t, readable, writable>::get(field);
}
- inline void flush()
+ UHD_INLINE void flush()
{
boost::lock_guard<boost::mutex> lock(_mutex);
soft_register_t<reg_data_t, readable, writable>::flush();
}
- inline void refresh()
+ UHD_INLINE void refresh()
{
boost::lock_guard<boost::mutex> lock(_mutex);
soft_register_t<reg_data_t, readable, writable>::refresh();
}
- inline void write(const soft_reg_field_t field, const reg_data_t value)
+ UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
{
boost::lock_guard<boost::mutex> lock(_mutex);
soft_register_t<reg_data_t, readable, writable>::write(field, value);
}
- inline reg_data_t read(const soft_reg_field_t field)
+ UHD_INLINE reg_data_t read(const soft_reg_field_t field)
{
boost::lock_guard<boost::mutex> lock(_mutex);
return soft_register_t<reg_data_t, readable, writable>::read(field);
@@ -469,7 +469,7 @@ public:
/*!
* Get the name of this register map
*/
- virtual inline const std::string& get_name() const { return _name; }
+ virtual UHD_INLINE const std::string& get_name() const { return _name; }
/*!
* Initialize all registers in this register map using a bus.
@@ -542,7 +542,7 @@ protected:
/*!
* Add a register to this map with an identifier "name" and visibility
*/
- inline void add_to_map(soft_register_base& reg, const std::string& name, const visibility_t visible = PRIVATE) {
+ UHD_INLINE void add_to_map(soft_register_base& reg, const std::string& name, const visibility_t visible = PRIVATE) {
boost::lock_guard<boost::mutex> lock(_mutex);
if (visible == PUBLIC) {
//Only add to the map if this register is publicly visible
diff --git a/host/include/uhd/version.hpp.in b/host/include/uhd/version.hpp.in
index e2c64812d..10f6a97ba 100644
--- a/host/include/uhd/version.hpp.in
+++ b/host/include/uhd/version.hpp.in
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2014 Ettus Research LLC
+// Copyright 2010-2016 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
@@ -27,14 +27,14 @@
* The format is oldest API compatible release - ABI compat number.
* The compatibility number allows pre-release ABI to be versioned.
*/
-#define UHD_VERSION_ABI_STRING "3.9.0-0"
+#define UHD_VERSION_ABI_STRING "@TRIMMED_VERSION_MAJOR@.@TRIMMED_VERSION_API@.@TRIMMED_VERSION_ABI@"
/*!
* A macro to check UHD version at compile-time.
- * The value of this macro is MAJOR * 10000 + MINOR * 100 + PATCH
- * (e.g., for UHD 3.8.1 this is 30801).
+ * The value of this macro is MAJOR * 1000000 + API * 10000 + ABI * 100 + PATCH
+ * (e.g., for UHD 3.10.0.1 this is 3100001).
*/
-#cmakedefine UHD_VERSION @UHD_VERSION_ADDED@
+#define UHD_VERSION @UHD_VERSION_ADDED@
namespace uhd{