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 5cbe51a90..fcd0a25b0 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  \li \subpage page_rtp 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) | 
