diff options
Diffstat (limited to 'docs/doxygen')
-rw-r--r-- | docs/doxygen/CMakeLists.txt | 29 | ||||
-rw-r--r-- | docs/doxygen/Doxyfile.in | 2 | ||||
-rw-r--r-- | docs/doxygen/other/extra_pages.dox | 2 | ||||
-rw-r--r-- | docs/doxygen/other/group_defs.dox | 66 | ||||
-rw-r--r-- | docs/doxygen/other/logger.dox | 205 | ||||
-rw-r--r-- | docs/doxygen/other/main_page.dox | 61 | ||||
-rw-r--r-- | docs/doxygen/other/pfb_intro.dox | 3 | ||||
-rw-r--r-- | docs/doxygen/other/tagged_stream_blocks.dox | 271 |
8 files changed, 609 insertions, 30 deletions
diff --git a/docs/doxygen/CMakeLists.txt b/docs/doxygen/CMakeLists.txt index f328bd7a22..a59159a691 100644 --- a/docs/doxygen/CMakeLists.txt +++ b/docs/doxygen/CMakeLists.txt @@ -37,6 +37,34 @@ configure_file( set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) +if(ENABLE_GRUEL) + list(APPEND GENERATED_DEPS pmt_generated) +endif(ENABLE_GRUEL) + +if(ENABLE_GR_CORE) + list(APPEND GENERATED_DEPS general_generated gengen_generated filter_generated) +endif(ENABLE_GR_CORE) + +if(ENABLE_GR_BLOCKS) + list(APPEND GENERATED_DEPS blocks_generated_includes) +endif(ENABLE_GR_BLOCKS) + +if(ENABLE_GR_ANALOG) + list(APPEND GENERATED_DEPS analog_generated_includes) +endif(ENABLE_GR_ANALOG) + +if(ENABLE_GR_DIGITAL) + list(APPEND GENERATED_DEPS digital_generated_includes) +endif(ENABLE_GR_DIGITAL) + +if(ENABLE_GR_FILTER) + list(APPEND GENERATED_DEPS filter_generated_includes) +endif(ENABLE_GR_FILTER) + +if(ENABLE_GR_TRELLIS) + list(APPEND GENERATED_DEPS trellis_generated_includes) +endif(ENABLE_GR_TRELLIS) + ######################################################################## # Make and install doxygen docs ######################################################################## @@ -44,6 +72,7 @@ add_custom_command( OUTPUT ${BUILT_DIRS} COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${GENERATED_DEPS} COMMENT "Generating documentation with doxygen" ) diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in index 536661996b..aa4fc3b0be 100644 --- a/docs/doxygen/Doxyfile.in +++ b/docs/doxygen/Doxyfile.in @@ -674,13 +674,11 @@ EXCLUDE_SYMBOLS = ad9862 \ *app_top_block* \ *am_rx_graph* \ *_queue_watcher_thread* \ - *parse* \ *MyFrame* \ *MyApp* \ *PyObject* \ *wfm_rx_block* \ *_sptr* \ - *debug* \ *wfm_rx_sca_block* \ *tv_rx_block* \ *wxapt_rx_block* \ diff --git a/docs/doxygen/other/extra_pages.dox b/docs/doxygen/other/extra_pages.dox index d40c692e03..94c741864d 100644 --- a/docs/doxygen/other/extra_pages.dox +++ b/docs/doxygen/other/extra_pages.dox @@ -79,6 +79,8 @@ audio-osx and audio-windows to be either satisfied or built. \subsection dep_gr_comedi gr-comedi: Comedi hardware interface \li comedilib (>= 0.8) http://www.comedi.org/ +\subsection dep_gr_log gr-log: Logging Tools (Optional) +\li log4cpp (>= 1.0) http://log4cpp.sourceforge.net/ \section build_gr_cmake Building GNU Radio diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox index 4aee49ec85..1c96abf3dc 100644 --- a/docs/doxygen/other/group_defs.dox +++ b/docs/doxygen/other/group_defs.dox @@ -8,32 +8,46 @@ * @{ */ -/*! \defgroup container_blk Top Block and Hierarchical Block Base Classes */ -/*! \defgroup source_blk Signal Sources */ -/*! \defgroup sink_blk Signal Sinks */ -/*! \defgroup filter_blk Filters */ -/*! \defgroup math_blk Mathematics */ -/*! \defgroup modulation_blk Signal Modulation */ -/*! \defgroup demodulation_blk Signal Demodulation */ -/*! \defgroup coding_blk Information Coding and Decoding*/ -/*! \defgroup sync_blk Synchronization */ -/*! \defgroup eq_blk Equalization */ -/*! \defgroup converter_blk Type Conversions */ -/*! \defgroup level_blk Signal Level Control (AGC) */ -/*! \defgroup dft_blk Fourier Transform */ -/*! \defgroup wavelet_blk Wavelet Transform */ -/*! \defgroup ofdm_blk OFDM Blocks */ -/*! \defgroup pager_blk Pager Blocks */ -/*! \defgroup misc_blk Miscellaneous Blocks */ -/*! \defgroup slicedice_blk Slicing and Dicing Streams */ -/*! \defgroup vocoder_blk Voice Encoders and Decoders */ -/*! \defgroup digital Digital Modulation Blocks */ -/*! \defgroup analog Analog Communications Blocks */ -/*! \defgroup qtgui_blk QT Graphical Interfaces */ -/*! \defgroup uhd_blk UHD Interface */ -/*! \defgroup audio_blk Audio Interface */ -/*! \defgroup pfb_blk Polyphase Filterbank */ -/*! \defgroup snr_blk SNR estimators */ +/*! \defgroup container_blk Top Block and Hierarchical Block Base Classes */ +/*! \defgroup audio_blk Audio Signals */ +/*! \defgroup boolean_operators_blk Boolean Operators */ +/*! \defgroup byte_operators_blk Byte Operators */ +/*! \defgroup channel_models_blk Channel Models */ +/*! \defgroup channelizers_blk Channelizers */ +/*! \defgroup coding_blk Information Coding and Decoding */ +/*! \defgroup debug_tools_blk Debug Tools */ +/*! \defgroup deprecated_blk Deprecated */ +/*! \defgroup equalizers_blk Equalizers */ +/*! \defgroup error_coding_blk Error Coding and Decoding */ +/*! \defgroup fcd_blk FCD Interface */ +/*! \defgroup file_operators_blk File Operators */ +/*! \defgroup filter_blk Filters */ +/*! \defgroup fourier_analysis_blk Fourier Analysis */ +/*! \defgroup instrumentation_blk Instrumentation Tools */ +/*! \defgroup level_controllers_blk Level Controllers */ +/*! \defgroup math_operators_blk Math Operators */ +/*! \defgroup measurement_tools_blk Measurement Tools */ +/*! \defgroup message_tools_blk Message Tools */ +/*! \defgroup misc_blk Miscellaneous */ +/*! \defgroup modulators_blk Modulators and Demodulators */ +/*! \defgroup networking_tools_blk Netwroking Tools */ +/*! \defgroup noaa_blk NOAA Blocks */ +/*! \defgroup ofdm_blk OFDM Blocks */ +/*! \defgroup packet_operators_blk Packet/Frame Operators */ +/*! \defgroup peak_detectors_blk Peak Detectors */ +/*! \defgroup pager_blk Pager Blocks */ +/*! \defgroup qtgui_blk QT Graphical Interfaces */ +/*! \defgroup resamplers_blk Resamplers */ +/*! \defgroup stream_operators_blk Streams Operators */ +/*! \defgroup stream_tag_tools_blk Stream Tag Tools */ +/*! \defgroup symbol_coding_blk Symbol Coding */ +/*! \defgroup synchronizers_blk Synchronizers */ +/*! \defgroup trellis_coding_blk Trellis Coding */ +/*! \defgroup type_converters_blk Data Type Converters */ +/*! \defgroup uhd_blk UHD Interface */ +/*! \defgroup waveform_generators_blk Waveform Generators */ +/*! \defgroup wavelet_blk Wavelet Transforms */ +/*! \defgroup wxgui_blk WX Graphical Interfaces */ /*! * \defgroup base_blk Base classes for GR Blocks diff --git a/docs/doxygen/other/logger.dox b/docs/doxygen/other/logger.dox new file mode 100644 index 0000000000..22458051db --- /dev/null +++ b/docs/doxygen/other/logger.dox @@ -0,0 +1,205 @@ +/*! \page page_logger Logging + +\section logging Logging + +GNU Radio has a logging interface to enable various levels of logging +information to be printed to the console or a file. The logger derives +from log4cpp (http://log4cpp.sourceforge.net/) which is readily +available in most Linux distributions. This is an optional dependency +and GNU Radio will work without it. + +When configuring GNU Radio, the -DENABLE_GR_LOG=On|Off option to cmake +will allow the user to toggle use of the logger on and off. The logger +defaults to "on" and will use log4cpp if it is available. If log4cpp +is not found, the default logging will output to standard output or +standard error, depending on the level of the log message. + +Logging is useful for blocks to print out certain amounts of data at +different levels. These levels are: + +<pre> + DEBUG < INFO < WARN < TRACE < ERROR < ALERT < CRIT < FATAL < EMERG +</pre> + + +The order here determines the level of output. These levels are +hierarchical in that specifying any level also includes any level +above it. For example, when using the WARN level, all WARN and +higher messages are logged while DEBUG and INFO are ignored. + +\subsection configfile Logging Configuration + +The logging configuration can be found in the gnuradio-core.conf file +under the [LOG] section. This allows us fairly complete control over +the logging facilities. The main configuration functions are to set up +the level of the loggers and set the default output behavior of the +loggers. + +There are two default loggers that all gr_block's have access to: +d_logger and d_debug_logger. The first is a standard logger meant to +output simple information about the block while it is running. The +debug logger is meant for debugging purposes and is added to make it +convenient to use a secondary logger that outputs to a different +stream or file. + +The four main configure options are: + +<pre> + log_level = debug + debug_level = debug + log_file = stdout + debug_file = stderr +</pre> + +This establishes the two loggers as having access to all levels of +logging events (DEBUG through EMERG). They are also configured not to +use files but instead output to the console. The standard logger will +output to standard out while the debug logger outputs to standard +error. + +Changing these last two lines to another value will create files that +are used to store the log messages. All messages are appended to the +file. + +When using either standard error or standard out, the messages for the +two different loggers will look like: + +<pre> + gr::log :\<level\>: \<block alias\> - \<message\> + gr::debug :\<level\>: \<block alias\> - \<message\> +</pre> + +When using a file, the only difference in the format is that the +message prefix of "gr::log" or "gr::debug" is not used. Instead, the +time in milliseconds from the start of the program is inserted. + +Remember that a local "~/.gnuradio/config.conf" file can be used to +override any parameter in the global file (see \ref prefs for more +details). + +To use these loggers inside of a GNU Radio block, we use the protected +data members of d_logger and d_debug_logger of gr_block and pass them +to our pre-defined macros: + +\code + GR_LOG_<level>(<logger>, "<Message to print>"); +\endcode + +Where \<level\> is one of the levels as mentioned above, \<logger\> is +either d_logger or d_debug_logger, and \<Message to print\> is the +message we want to output. If we wanted to output an INFO level +message to the standard logger and a WARN level message to the debug +logger, it would look like this: + +\code + GR_LOG_INFO(d_logger, "Some info about the block"); + GR_LOG_WARN(d_debug_logger, "Some warning about the block"); +\endcode + +When this is printed to wherever you are directing the output of the +logger, it will look like: + +<pre> + gr::log :INFO: <block's alias> - Some info about the block + gr::debug :WARN: <block's alias> - Some warning about the block +</pre> + +This provides us information about where the message came from, the +level of the message, and the block that generated the message. We use +the concept of the block's alias which by default (i.e., unless +otherwise set by the user) includes the name of the block and a unique +ID to distinguish it from other blocks of the same type. + +The various logging macros are defined in gr_logger.h. Here are some +simple examples of using them: + +\code + GR_LOG_DEBUG(LOG, "DEBUG message"); + GR_LOG_INFO(LOG, "INFO message"); + GR_LOG_NOTICE(LOG, "NOTICE message"); + GR_LOG_WARN(LOG, "WARNING message"); + GR_LOG_ERROR(LOG, "ERROR message"); + GR_LOG_CRIT(LOG, "CRIT message"); + GR_LOG_ALERT(LOG, "ALERT message"); + GR_LOG_FATAL(LOG, "FATAL message"); + GR_LOG_EMERG(LOG, "EMERG message"); +\endcode + +If the logger is not enabled, then these macros become nops and do +nothing (and d_logger and d_debug_logger are NULL pointers). If +logging is enabled but the log4cpp library is not found, then TRACE, +INFO, and NOTICE levels go to stdout and the rest to stderr. + + +\subsection adv_config Advanced Configuration Options + +If not using the simplified settings discussed above, where we can +direct the logger messages to either a file or one of the standard +outputs, we must use a more complicated configuration file. We do this +by specifying the "log_config" option in the [LOG] section. The +log4cpp documentation will provide more information on how +configuration works and looks. Mostly, a default configuration script +provided with GNU Radio can be used. After installation, the default +configuration script is located at: + +<pre> + $prefix/etc/gnuradio/gr_log_default.xml +</pre> + +For the following examples, we will assume that our local +"~/.gnuradio/config.conf" looks like this: + +\code +[LOG] +log_config = /opt/gr/etc/gnuadio/gr_log_default.xml +log_level = debug +debug_level = Off +\endcode + +Inside of the XML default configuration file, we define the parameters +for the two logger's, the standard logger the separate debug logger. + +If the levels of the two loggers are specified in our configuration +file, as in the above example, these levels override any levels +specified in the XML file. Here, we have turned on the standard logger +(d_logger) to all levels and turned off the debug logger +(d_debug_logger). So even if the debug logger is used in the code, it +will not actually output any information. Conversely, any level of +output passed to the standard logger will output because we have +turned this value to the lowest level "debug." + +If both an XML configuration file is set and the "log_file" or +"debug_file" options are set at the same time, both systems are +actually used. So you can configure file access and the pattern +through the XML file while also still outputting to stdout or stderr. + + +\section advlog Advanced Usage + +The description above for using the logging facilities is specific to +GNU Radio blocks. We have put the code necessary to access the +debugger into the gr_block parent class to simplify access and make +sure all blocks have the ability to quickly and easily use the logger. + +For non gr_block-based code, we have to get some information about the +logger in order to properly access it. Each logger only exists once as +a singleton in the system, but we need to get a pointer to the right +logger and then set it up for our local use. The following code +snippet shows how to do this to get access to the standard logger, +which has a root of "gr_log." (access to the debug logger is similar +except we would use "gr_log_debug." in the GR_LOG_GETLOGGER call): + +\code + gr_prefs *p = gr_prefs::singleton(); + std::string log_file = p->get_string("LOG", "log_config", ""); + std::string log_level = p->get_string("LOG", "log_level", "off"); + GR_CONFIG_LOGGER(log_file); + GR_LOG_GETLOGGER(LOG, "gr_log." + "my_logger_name"); + GR_LOG_SET_LEVEL(LOG, log_level); +\endcode + +This creates a pointer called LOG (which is instantiated as a +log4cpp:LoggerPtr in the macro) that we can now use locally as the +input to our logging macros like 'GR_LOG_INFO(LOG, "message")'. + +*/ diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index e7d4685f75..916ac9bdd1 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -39,11 +39,13 @@ More details on packages in GNU Radio: \li \ref page_vocoder More details on GNU Radio concepts: +\li \ref page_logger \li \ref page_pmt \li \ref page_msg_passing \li \ref page_metadata \li \ref volk_guide \li \ref page_pfb +\li \ref page_tagged_stream_blocks \section flowgraph Operating a Flowgraph @@ -402,4 +404,63 @@ configuration variable and the section and option names are in uppercase. The value is the same format that would be used in the config file itself. + + +\section oot_config_page Out-of-Tree Configuration + +New as of 3.6.5. + +Using gr_modtool, each package comes with the ability to easily locate +the gnuradio-core library using the 'find_package(GnuradioCore)' cmake +command. This only locates that the library and include directories +exist, which is enough for most simple projects. + +As projects become more complicated and start needing to rely on other +GNU Radio components like gnuradio-blocks or gnuradio-filter, for +example, and when they become dependent on certain API compatibility +versions of GNU Radio, we need something more. And so we have +introduced the GnuradioConfig.cmake file. + +When GNU Radio is installed, it also installs a GNU Radio-specific +cmake config file that we can use for more advanced compatibility +issues of our projects. This tool allows us to specific the API +compatible version and a set of components that are required. + +Taking the above example, say we have built against version 3.6.5 with +features that were introduced in this version and we need the blocks +and filter components as well as the main core library. We fist set a +cmake variable GR_REQUIRED_COMPONENTS to the components we need. We +then use the 'find_package' command and also set a minimum required +API compatible version. Since we are on the 3.6 API version, the +minimum required version is "3.6.5". The code in the CMakeLists.txt +file would look like this: + +\code + set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER) + find_package(Gnuradio 3.6.5) +\endcode + +Note that the capitalization is important on both lines. + +If the installed version of GNU Radio is 3.6.4 or some other API +version like 3.5 or 3.7, the Cmake configuration will fail with the +version error. Likewise, if libgnuradio-filter was not installed as +part of GNU Radio, the configuration will also fail. + +\subsection oot_config_path_page Install Path + +Cmake has to know where to find these configuration files. They are +installed into $prefix/lib/cmake/gnuradio. If $prefix is '/usr' or +'/usr/local', then everything should work fine. If the GNU Radio +install $prefix is something else, then Cmake must be told where to +find it. This can be done in two ways. If you are installing the +out-of-tree module into the same $prefix, then you would be setting +'-DCMAKE_INSTALL_PREFIX' on the configuration command line. This is +enough to tell Cmake where to look for the configuration files. + +The other way to do it is to set the CMAKE_PREFIX_PATH environmental +variable to $prefix. You can then install your component anywhere +you'd like and it will be able to find and configure against the +installed GNU Radio. + */ diff --git a/docs/doxygen/other/pfb_intro.dox b/docs/doxygen/other/pfb_intro.dox index 01d08b0fad..2d285f0027 100644 --- a/docs/doxygen/other/pfb_intro.dox +++ b/docs/doxygen/other/pfb_intro.dox @@ -5,8 +5,7 @@ Polyphase filterbanks (PFB) are a very powerful set of filtering tools that can efficiently perform many multi-rate signal processing tasks. GNU Radio has a set of polyphase filterbank blocks to be used -in all sorts of applications. These blocks and their documentation can -be found in \ref pfb_blk. +in all sorts of applications. \section Usage diff --git a/docs/doxygen/other/tagged_stream_blocks.dox b/docs/doxygen/other/tagged_stream_blocks.dox new file mode 100644 index 0000000000..33e2bf6437 --- /dev/null +++ b/docs/doxygen/other/tagged_stream_blocks.dox @@ -0,0 +1,271 @@ +/*! \page page_tagged_stream_blocks Tagged Stream Blocks + +\section intro Introduction + +A tagged stream block is a block that works on streamed, but packetized input data. +Think of packet data transmission: A data packet consists of N bytes. However, in +traditional GNU Radio blocks, if we stream N bytes into a block, there's no way of +knowing the packet boundary. This might be relevant: Perhaps the modulator has to +prepend a synchronisation word before every packet, or append a CRC. So while some +blocks don't care about packet boundaries, other blocks do: These are <em>tagged +stream blocks</em>. + +These blocks are different from all the other GNU Radio block types (gr_block, gr_sync_block etc.) in that they are driven by the input: The PDU length tag tells the block how to +operate, whereas other blocks are output-driven (the scheduler tries to fill up the output +buffer are much as possible). + +\subsection howtheywork How do they work? + +As the name implies, tagged stream blocks use tags to identify PDU boundaries. +On the first item of a streamed PDU, there \em must be a tag with a specific +key, which stores the length of the PDU as a pmt_integer. If anything else, or no tag, +is on this first item, this will cause the flow graph to crash! + +The scheduler then takes care of everything. When the work function is called, it +is guaranteed to contain exactly one complete PDU and enough space in the output buffer for +the output. + +\subsection relatestootherblocks How do they relate to other block types (e.g. sync blocks)? + +Tagged stream blocks and sync blocks are really orthogonal concepts, and a block could be +both (gr::digital::ofdm_frame_equalizer_vcvc is such a block). However, because the work +function is defined differently in these block types, there is no way to derive a block +from both gr_tagged_stream_block and gr_sync_block. + +If a block needs the tagged stream mechanism (i.e. knowing about PDU boundaries), it must be +derived from gr_tagged_stream_block. If it's also a sync block, it is still possible to +set gr_block::set_relative_rate(1.0) and/or the fixed rate functions. + +The way gr_tagged_stream_block works, it is still beneficial to specify a relative rate, +if possible. + + +\section creating Creating a tagged stream block + +To create a tagged stream block, the block must be derived from gr_tagged_stream_block. +Here's a minimal example of how the header file could look: +\code +#include <digital/api.h> +#include <gr_tagged_stream_block.h> + +namespace gr { + namespace digital { + + class DIGITAL_API crc32_bb : virtual public gr_tagged_stream_block + { + public: + typedef boost::shared_ptr<crc32_bb> sptr; + + static sptr make(bool check=false, const std::string& len_tag_key="packet_len"); + }; + + } // namespace digital +} // namespace gr + +\endcode + +It is very similar to any other block definition. Two things are stand out: First, +gr_tagged_stream_block.h is included to allow deriving from gr_tagged_stream_block. + +The other thing is in the make function: the second argument is a string containing +the key of the length tags. This is not necessary (the block could get this information +hard-coded), but the usual way is to allow the user to change this tag, but give a +default value (in this case, \p packet_len). + +The implementation header (*_impl.h) also looks a bit different (again this is cropped to the relevant parts): +\code +#include <digital/crc32_bb.h> +namespace gr { + namespace digital { + + class crc32_bb_impl : public crc32_bb + { + public: + crc32_bb_impl(bool check, const std::string& len_tag_key); + ~crc32_bb_impl(); + + int calculate_output_stream_length(const gr_vector_int &ninput_items); + int work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr +\endcode + +First, the \p work function signature is new. The argument list looks like that from +gr_block::general_work() (note: the arguments mean the same, too), but it's called +\p work like with the other derived block types (such as gr_sync_block). Also, there's a new +function: \p calculate_output_stream_length() is, in a sense, the opposite function to +gr_block::forecast(). Given a number of input items, it calculates the required number of +output items. Note how this relates to the fact that these blocks are input-driven. + +These two overrides (\p work() and \p calculate_output_stream_length() ) are what you need +for most tagged stream blocks. There are cases when you don't need to override the latter +because the default behaviour is enough, and other cases where you have to override more +than these two functions. These are discussed in \ref adv_usage. + +Finally, this is part of the actual block implementation (heavily cropped again, to highlight the relevant parts): +\code +#include <gr_io_signature.h> +#include "crc32_bb_impl.h" + +namespace gr { + namespace digital { + + crc32_bb::sptr crc32_bb::make(bool check, const std::string& len_tag_key) + { + return gnuradio::get_initial_sptr (new crc32_bb_impl(check, len_tag_key)); + } + + crc32_bb_impl::crc32_bb_impl(bool check, const std::string& len_tag_key) + : gr_tagged_stream_block("crc32_bb", + gr_make_io_signature(1, 1, sizeof (char)), + gr_make_io_signature(1, 1, sizeof (char)), + len_tag_key), + d_check(check) + { + } + + int + crc32_bb_impl::calculate_output_stream_length(const gr_vector_int &ninput_items) + { + if (d_check) { + return ninput_items[0] - 4; + } else { + return ninput_items[0] + 4; + } + } + + int + crc32_bb_impl::work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + + // Do all the signal processing... + // Don't call consume! + + return new_packet_length; + } + + } // namespace digital +} // namespace gr +\endcode + +The make function is not different to any other block. The constructor calls +gr_tagged_stream_block::gr_tagged_stream_block() as expected, but note that it passes the +key of the length tag to the parent constructor. + +The block in question is a CRC block, and it has two modes: It can check the CRC (which is +then dropped), or it can append a CRC to a sequence of bytes. The \p calculate_output_stream_length() function +is thus very simple: depending on how the block is configured, the output is either 4 bytes +longer or shorter than the input stream. + +The \p work() function looks very similar to any other work function. When writing the +signal processing code, the following things must be kept in mind: +- The work function is called for exactly one PDU, and no more (or less) may be processed +- \p ninput_items contains the exact number of items in this PDU (at every port). + These items \em will be consumed after \p work() exits. +- Don't call \p consume() or \p consume_each() yourself! gr_tagged_stream_block will do that + for you. +- You can call \p produce() or \p produce_each(), if you're doing something complicated. + Don't forget to return WORK_CALLED_PRODUCE in that case. + + +\subsection note_on_tp A note on tag propagation + +Despite using tags for a special purpose, all tags that are not the length tag are treated +exactly as before: use gr_block::set_tag_propagation_policy() in the constructor. + +In a lot of the cases, though, you will need to specify set_tag_propagation_policy(TPP_DONT) +and manually handle the tag propagation in \p work(). This is because the unknown length of +the PDUs at compile time prohibits us from setting a precise relative rate of the block, +which is a requirement for automatic tag propagation. +Only if the tagged stream block is also a sync block (including interpolators and decimators, +i.e. blocks with an integer rate change), can automatic tag propagation be reliably used. + +The CRC block seems to a very simple block, but it's already complicated enough to confuse +the automatic tag propagation. For example, what happens to tags which are on the CRC? Do +they get removed, or do they get moved to the last item before the CRC? Also, the input to +output rate is different for every PDU length. + +In this case, it is necessary for the developer to define a tag propagation policy and +implement it in \p work(). Also, it is good practice to specify that tag propagation policy +in the blocks documentation. + +The actual length tags \em are treated differently, though. Most importantly, you don't have +to write the new length tag yourself. The key for the output length tag is the same as that +on the input, if you don't want this, you must override gr_tagged_stream_block::update_length_tags(). + + +\section adv_usage Advanced Usage + +It is generally recommended to read the block documentation of gr_tagged_stream_block. + +A few special cases are described here: + +\subsection multiplelentags Multiple length tags + +In some cases, a single tag is not enough. One example is the OFDM receiver: one OFDM frame contains a certain number of OFDM symbols, and another number of bytes--these numbers are only +very loosely related, and one cannot be calculated from the other. + +gr::digital::ofdm_serializer_vcc is such a block. It is driven by the number of OFDM frames, +but the output is determined by the number of complex symbols. In order to use multiple length +tag keys, it overrides update_length_tags(). + +\subsection backtogrblock Falling back to gr_block behaviour + +If, at compile-time, it is uncertain whether or not a block should be a +gr_tagged_stream_block, there is the possibility of falling back to gr_block behaviour. + +To do this, simple don't pass an empty string as length tag key. Instead of crashing, +a tagged stream block will behave like a gr_block. + +This has some consequences: The work function must have all the elements of a +gr_block::general_work() function, including calls to consume(). Because such a block must +allow both modes of operation (PDUs with tags, and infinite-stream), the work function +must check which mode is currently relevant. Checking if +gr_tagged_stream_block::d_length_tag_key_str is empty is a good choice. + +gr::digital::ofdm_cyclic_prefixer implements this. + +\subsection otherwaysdetermineninput Other ways to determine the number of input items + +If the number of input items is not stored as a pmt::pmt_integer, but there is a way to determine +it, gr_tagged_stream_block::parse_length_tags() can be overridden to figure out the length +of the PDU. + +\section examples Examples + +\subsection CRC32 CRC32 + +Block: gr::digital::crc32_bb + +This is a very simple block, and a good example to start with. + +\subsection ofdmeq OFDM Frame Equalizer + +Block: gr::digital::ofdm_frame_equalizer_vcvc + +This block would be a sync block if tagged stream blocks didn't exist. It also uses more +than one tag to determine the output. + +\subsection muxer Tagged Stream Muxer + +Block: gr::blocks::tagged_stream_mux + +Use this to multiplex any number of tagged streams. + +\subsection ofdmprefixer Cyclic Prefixer (OFDM) + +Block: gr::digital::ofdm_cyclic_prefixer + +This block uses the gr_block behaviour fallback. + +*/ |