diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/docs/converters.dox | 85 | ||||
-rw-r--r-- | host/docs/stream.dox | 3 | ||||
-rw-r--r-- | host/docs/uhd.dox | 1 | ||||
-rw-r--r-- | host/include/uhd/convert.hpp | 12 | ||||
-rw-r--r-- | host/include/uhd/utils/byteswap.hpp | 8 | ||||
-rw-r--r-- | host/lib/convert/convert_common.hpp | 13 |
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) |