aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/docs/converters.dox85
-rw-r--r--host/docs/stream.dox3
-rw-r--r--host/docs/uhd.dox1
-rw-r--r--host/include/uhd/convert.hpp12
-rw-r--r--host/include/uhd/utils/byteswap.hpp8
-rw-r--r--host/lib/convert/convert_common.hpp13
6 files changed, 118 insertions, 4 deletions
diff --git a/host/docs/converters.dox b/host/docs/converters.dox
new file mode 100644
index 000000000..c37c0e38f
--- /dev/null
+++ b/host/docs/converters.dox
@@ -0,0 +1,85 @@
+/*! \page page_converters Converters
+
+\section converters_overview Overview
+
+When streaming from device to host, the converter has a central role: It converts
+the sample (or streaming) data from a format the device understands to a format
+the user can deal with. During conversion, data is copied from the transport buffer
+to the buffer provided by the user (or vice versa). For zero-copy architectures,
+this means there are the fewest possible copies between the device transport and
+the user application.
+
+The conversion encompasses several elements. The most obvious is that of the data type:
+Most FPGAs use integer data types, the most common being complex 16-bit integers (16 bit
+for I and Q, respectively). If the user wants his data in float, the converter casts
+the data type, and also scales the data, typically such that the full dynamic range
+of the 16-Bit integers is mapped onto the float range of -1 to 1.
+The converter also handles the endianness: On the network, data is usually stored as
+big-endian, whereas most platforms store data internally as little-endian.
+
+The format used by the user application is coined the 'CPU Format', whereas the format
+used between the device and UHD is called the 'OTW Format' (*Over-the-wire* format).
+
+The most common combinations of OTW and CPU formats are shipped with UHD. If your
+application requires a more exotic CPU format, there is an API to register your own
+converters.
+
+\section converters_formats Formats and Converter Choice
+
+To obtain a list of names of data formats, see uhd::stream_args_t. This also provides
+an example for how to instantiate a streamer that uses `sc16` over the wire, and `fc32`
+as CPU format.
+
+Any pair of OTW and CPU formats can only be used if a converter was registered
+for that specific pair.
+
+\subsection converters_formats_internal Internal format strings
+
+The CPU format is always as defined by the host system, so for example `fc32` is always
+a `std::complex<float>`, whatever that is.
+
+For the OTW format, there are more subtleties to observe: On top of the actual
+data format, there are device-specific components to the OTW format, such as
+the endianness and the data encapsulation. Internally, the OTW format strings
+are thus more descriptive than the formats listed at uhd::stream_args_t::otw_format
+(i.e., the format types you can specify in the stream args).
+
+As an example, the N2x0 series encapsulates all data in 32-bit chunks, and
+always uses big-endian transport type. When using `sc16` over the wire, the
+internal format description would be `sc16_item32_be`, which describes all
+those elements. During a receive operation, UHD would instantiate a converter
+from `sc16_item32_be` to `fc32`. The same converter could not be used for the
+B2x0 series, for example, which uses little-endian transport format and would
+require a `sc16_item32_le` converter.
+
+\section converters_accel Hardware-specific Converters
+
+Given enough knowledge about the platform architecture, it is possible to
+have converters that use mechanisms to accelerate the conversion (e.g. chipset
+intrinsics). It is possible to register multiple converters for the same
+OTW/CPU format pair, and have UHD choose one depending on the current platform.
+
+\section converters_register Registering converters
+
+The converter architecture was designed to be dynamically extendable. If your
+application requires converters not shipped with UHD, they can be added from
+your application without having to modify UHD.
+Modifying UHD may be required, e.g. when adding new devices or functionality
+to UHD.
+
+\subsection converters_register_extra Outside of UHD
+
+Registering a converter from your application requires deriving
+from uhd::convert::converter and overriding all the pure virtual functions.
+
+Before any UHD operations are performed, this converter class needs to be
+registered by calling uhd::convert::converter::register_converter.
+
+\subsection converters_register_internal Inside UHD
+
+If the converters shipped with UHD need to be amended, new converter classes
+should be added to `lib/convert`. Use the DECLARE_CONVERTER convenience macro
+where possible. See this directory for examples.
+
+*/
+// vim:ft=doxygen:
diff --git a/host/docs/stream.dox b/host/docs/stream.dox
index 0c015c5bd..516d685f9 100644
--- a/host/docs/stream.dox
+++ b/host/docs/stream.dox
@@ -49,8 +49,7 @@ at the expense of precision, **complex-int8** may be used.
The user may request arbitrary combinations of host and link data types;
however, not all combinations are supported. The user may register
custom data type formats and conversion routines. See
-convert.hpp for further documentation.
+convert.hpp and \ref page_converters for further documentation.
-TODO: provide example of convert API
*/
// vim:ft=doxygen:
diff --git a/host/docs/uhd.dox b/host/docs/uhd.dox
index 5b0738969..949c710b1 100644
--- a/host/docs/uhd.dox
+++ b/host/docs/uhd.dox
@@ -10,6 +10,7 @@ publically available symbol in the UHD namespace.
Some additional pages on developing UHD are also available here:
\li \subpage page_coding
+\li \subpage page_converters
\li \subpage page_stream
*/
diff --git a/host/include/uhd/convert.hpp b/host/include/uhd/convert.hpp
index 6ac93fb66..d740d80fb 100644
--- a/host/include/uhd/convert.hpp
+++ b/host/include/uhd/convert.hpp
@@ -46,7 +46,14 @@ namespace uhd{ namespace convert{
private:
//! Callable method: input vectors, output vectors, num samples
- virtual void operator()(const input_type&, const output_type&, const size_t) = 0;
+ //
+ // This is the guts of the converter. When deriving new converter types,
+ // this is where the actual conversion routines go.
+ //
+ // \param in Pointers to the input buffers
+ // \param out Pointers to the output buffers
+ // \param num Number of items in the input buffers to convert
+ virtual void operator()(const input_type& in, const output_type& out, const size_t num) = 0;
};
//! Conversion factory function typedef
@@ -69,6 +76,9 @@ namespace uhd{ namespace convert{
/*!
* Register a converter function.
+ *
+ * Converters with higher priority are given preference.
+ *
* \param id identify the conversion
* \param fcn makes a new converter
* \param prio the function priority
diff --git a/host/include/uhd/utils/byteswap.hpp b/host/include/uhd/utils/byteswap.hpp
index 2b5a46c66..8e3b7dc8a 100644
--- a/host/include/uhd/utils/byteswap.hpp
+++ b/host/include/uhd/utils/byteswap.hpp
@@ -22,10 +22,10 @@
#include <boost/cstdint.hpp>
/*! \file byteswap.hpp
+ *
* Provide fast byteswaping routines for 16, 32, and 64 bit integers,
* by using the system's native routines/intrinsics when available.
*/
-
namespace uhd{
//! perform a byteswap on a 16 bit integer
@@ -44,9 +44,15 @@ namespace uhd{
template<typename T> T htonx(T);
//! worknet to host: short, long, or long-long
+ //
+ // The argument is assumed to be little-endian (i.e, the inverse
+ // of typical network endianness).
template<typename T> T wtohx(T);
//! host to worknet: short, long, or long-long
+ //
+ // The return value is little-endian (i.e, the inverse
+ // of typical network endianness).
template<typename T> T htowx(T);
} //namespace uhd
diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp
index ceaa1151c..6c2ea9fec 100644
--- a/host/lib/convert/convert_common.hpp
+++ b/host/lib/convert/convert_common.hpp
@@ -42,6 +42,19 @@
const input_type &inputs, const output_type &outputs, const size_t nsamps \
)
+/*! Convenience macro to declare a single-function converter
+ *
+ * Most converters consist of a single for loop, and can make use of
+ * this macro for declaration and registering.
+ *
+ * Following this macro should be a function block in curly braces
+ * which runs the conversion. Available parameters in this function block
+ * are:
+ * - `inputs`: Vector of pointers to the input data. Size of the vector == `num_in`
+ * - `outputs`: Vector of pointers to where the output data goes. Size of the vector == `num_out`
+ * - `nsamps`: Number of items per input buffer to convert
+ * - `scale_factor`: Scaling factor for float conversions
+ */
#define DECLARE_CONVERTER(in_form, num_in, out_form, num_out, prio) \
_DECLARE_CONVERTER(__convert_##in_form##_##num_in##_##out_form##_##num_out##_##prio, in_form, num_in, out_form, num_out, prio)