docs: Amended docs for conversion routines

This commit is contained in:
Martin Braun 2015-01-14 16:49:34 +01:00
parent ec11128445
commit b60704d8b7
6 changed files with 118 additions and 4 deletions

85
host/docs/converters.dox Normal file
View File

@ -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:

View File

@ -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:

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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)