summaryrefslogtreecommitdiff
path: root/docs/doxygen/other/msg_passing.dox
diff options
context:
space:
mode:
Diffstat (limited to 'docs/doxygen/other/msg_passing.dox')
-rw-r--r--docs/doxygen/other/msg_passing.dox381
1 files changed, 0 insertions, 381 deletions
diff --git a/docs/doxygen/other/msg_passing.dox b/docs/doxygen/other/msg_passing.dox
deleted file mode 100644
index 14de7bae4c..0000000000
--- a/docs/doxygen/other/msg_passing.dox
+++ /dev/null
@@ -1,381 +0,0 @@
-# Copyright (C) 2017 Free Software Foundation, Inc.
-#
-# Permission is granted to copy, distribute and/or modify this document
-# under the terms of the GNU Free Documentation License, Version 1.3
-# or any later version published by the Free Software Foundation;
-# with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
-# A copy of the license is included in the section entitled "GNU
-# Free Documentation License".
-
-/*! \page page_msg_passing Message Passing
-
-\section msg_passing_introduction Introduction
-
-GNU Radio was originally a streaming system with no other mechanism to
-pass data between blocks. Streams of data are a model that work well
-for samples, bits, etc., but are not really the right mechanism for
-control data, metadata, or packet structures (at least at
-some point in the processing chain).
-
-We solved part of this problem by introducing the tag stream (see \ref
-page_stream_tags). This is a parallel stream to the data
-streaming. The difference is that tags are designed to hold metadata
-and control information. Tags are specifically associated with a
-particular sample in the data stream and flow downstream alongside the
-data. This model allows other blocks to identify that an event or
-action has occurred or should occur on a particular item. The major
-limitation is that the tag stream is really only accessible inside a
-work function and only flows in one direction. Its benefit is that it
-is isosynchronous with the data.
-
-We want a more general message passing system for a couple of
-reasons. The first is to allow blocks downstream to communicate back
-to blocks upstream. The second is to allow an easier way for us to
-communicate back and forth between external applications and GNU
-Radio. GNU Radio's message passing interface handles these cases, although
-it does so on an asynchronous basis.
-
-The message passing interface heavily relies on Polymorphic Types
-(PMTs) in GNU Radio. For further information about these data
-structures, see the page \ref page_pmt.
-
-\section msg_passing_api Message Passing API
-
-The message passing interface is designed into the gr::basic_block,
-which is the parent class for all blocks in GNU Radio. Each block has
-a set of message queues to hold incoming messages and can post
-messages to the message queues of other blocks. The blocks also
-distinguish between input and output ports.
-
-A block has to declare its input and output message ports in its
-constructor. The message ports are described by a name, which is in
-practice a PMT symbol (<em>i.e.</em>, an interned string). The API calls
-to register a new port are:
-
-\code
- void message_port_register_in(pmt::pmt_t port_id)
- void message_port_register_out(pmt::pmt_t port_id)
-\endcode
-
-In Python:
-
-\code
- self.message_port_register_in(pmt.intern("port name"))
- self.message_port_register_out(pmt.intern("port name"))
-\endcode
-
-The ports are now identifiable by that port name. Other blocks who may
-want to post or receive messages on a port must subscribe to it. When
-a block has a message to send, they are published on a particular
-port using the following API:
-
-\code
- void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
-\endcode
-
-In Python:
-
-\code
- self.message_port_pub(pmt.intern("port name"), <pmt message>)
-\endcode
-
-Subscribing is usually done in the form of connecting message ports
-as part of the flowgraph, as discussed later. Internally, when message
-ports are connected, the gr::basic_block::message_port_sub method is
-called.
-
-Any block that has a subscription to another block's output message
-port will receive the message when it is published. Internally, when a
-block publishes a message, it simply iterates through all blocks that
-have subscribed and uses the gr::basic_block::_post method to send the
-message to that block's message queue.
-
-
-\subsection msg_passing_msg_handler Message Handler Functions
-
-A subscriber block must declare a message handler function to process
-the messages that are posted to it. After using the
-gr::basic_block::message_port_register_in to declare a subscriber port, we
-must then bind this port to the message handler. For this, we use
-Boost's 'bind' function:
-
-\code
- set_msg_handler(pmt::pmt_t port_id,
- boost::bind(&block_class::message_handler_function, this, _1));
-\endcode
-
-In Python:
-
-\code
- self.set_msg_handler(pmt.intern("port name"), <msg handler function>)
-\endcode
-
-When a new message is pushed onto a port's message queue,
-it is this function that is used to process the message.
-The 'port_id' is the same PMT as used when registering the input
-port. The 'block_class::message_handler_function' is the member
-function of the class designated to handle messages to this port. The
-'this' and '_1' are standard ways of using the Boost bind function to
-pass the 'this' pointer as the first argument to the class (standard
-OOP practice) and the _1 is an indicator that the function expects 1
-additional argument. The prototype for all message handling functions
-is:
-
-\code
- void block_class::message_handler_function(pmt::pmt_t msg);
-\endcode
-
-In Python the equivalent function would be:
-
-\code
- def handle_msg(self, msg):
-\endcode
-
-We give examples of using this below.
-
-
-\subsection msg_passing_fg_connect Connecting Messages through the Flowgraph
-
-From the flowgraph level, we have instrumented a gr::hier_block2::msg_connect
-method to make it easy to subscribe blocks to other blocks'
-messages. Assume that the block \b src has an output message port named
-\a pdus and the block \b dbg has an input port named \a print. The message
-connection in the flowgraph (in Python) looks like the following:
-
-\code
- self.tb.msg_connect(src, "pdus", dbg, "print")
-\endcode
-
-All messages published by the \b src block on port \a pdus will be
-received by \b dbg on port \a print. Note here how we are just using
-strings to define the ports, not PMT symbols. This is a convenience to
-the user to be able to more easily type in the port names (for
-reference, you can create a PMT symbol in Python using the
-pmt::intern function as pmt.intern("string")).
-
-Users can also query blocks for the names of their input and output
-ports using the following API calls:
-
-\code
- pmt::pmt_t message_ports_in();
- pmt::pmt_t message_ports_out();
-\endcode
-
-The return value for these are a PMT vector filled with PMT symbols,
-so PMT operators must be used to manipulate them.
-
-Each block has internal methods to handle posting and receiving of
-messages. The gr::basic_block::_post method takes in a message and
-places it into its queue. The publishing model uses the
-gr::basic_block::_post method of the blocks as the way to access the
-message queue. So the message queue of the right name will have a new
-message. Posting messages also has the benefit of waking up the
-block's thread if it is in a wait state. So if idle, as soon as a
-message is posted, it will wake up and call the message handler.
-
-
-\section msg_passing_posting Posting from External Sources
-
-An important feature of the message passing architecture
-is how it can be used to take in messages from an external source. We
-can call a block's gr::basic_block::_post method directly and pass it a
-message. So any block with an input message port can receive messages
-from the outside in this way.
-
-The following example uses a gr::blocks::pdu_to_tagged_stream block
-as the source block to a flowgraph. Its purpose is to wait for
-messages as PDUs posted to it and convert them to a normal stream. The
-payload will be sent on as a normal stream while the meta data will be
-decoded into tags and sent on the tagged stream.
-
-So if we have created a \b src block as a PDU to stream, it has a \a
-pdus input port, which is how we will inject PDU messages into the
-flowgraph. These PDUs could come from another block or flowgraph, but
-here, we will create and insert them by hand.
-
-\code
- port = pmt.intern("pdus")
- msg = pmt.cons(pmt.PMT_NIL, pmt.make_u8vector(16, 0xFF))
- src.to_basic_block()._post(port, msg)
-\endcode
-
-The PDU's metadata section is empty, hence the pmt::PMT_NIL
-object. The payload is now just a simple vector of 16 bytes of all
-1's. To post the message, we have to access the block's gr::basic_block
-class, which we do using the gr::basic_block::to_basic_block method and
-then call the gr::basic_block::_post method to pass the PDU to the
-right port.
-
-All of these mechanisms are explored and tested in the QA code of the
-file qa_pdu.py.
-
-There are some examples of using the message passing infrastructure
-through GRC in gr-blocks/examples/msg_passing.
-
-
-\section msg_passing_commands Using messages as commands
-
-One important use of messages is to send commands to blocks. Examples for this include:
-
-- gr::qtgui::freq_sink_c: The scaling of the frequency axis can be changed by messages
-- gr::uhd::usrp_source and gr::uhd::usrp_sink: Many transceiver-related settings can
- be manipulated through command messages, such as frequency, gain and LO offset
-- gr::digital::header_payload_demux, which receives an acknowledgement from a header parser
- block on how many payload items there are to process
-
-There is no special PMT type to encode commands, however, it is strongly recommended
-to use one of the following formats:
-
-- pmt::cons(KEY, VALUE): This format is useful for commands that take a single value.
- Think of KEY and VALUE as the argument name and value, respectively. For the case of
- the QT GUI Frequency Sink, KEY would be "freq" and VALUE would be the new center frequency
- in Hz.
-- pmt::dict((KEY1: VALUE1), (KEY2: VALUE2), ...): This is basically the same as the
- previous format, but you can provide multiple key/value pairs. This is particularly
- useful when a single command takes multiple arguments which can't be broken into
- multiple command messages (e.g., the USRP blocks might have both a timestamp and a
- center frequency in a command message, which are closely associated).
-
-In both cases, all KEYs should be pmt::symbols (i.e. strings). VALUEs can be
-whatever the block requires.
-
-It might be tempting to deviate from this format, e.g. the QT Frequency sink could
-simply take a float value as a command message, and it would still work fine.
-However, there are some very good reasons to stick to this format:
-
-- Interoperability: The more people use the standard format, the more likely it
- is that blocks from different sources can work together
-- Inspectability: A message debug block will display more useful information about
- a message if it's containing both a value and a key
-- Intuition: This format is pretty versatile and unlikely to create situations
- where it is not sufficient (especially considering that values are PMTs themselves).
- As a counterexample, using positional arguments (something like "the first argument
- is the frequency, the second the gain") is easily forgotten, or changed in one place
- and not another, etc.
-
-
-\section msg_passing_examples Code Examples
-
-The following is snippets of code from blocks currently in GNU Radio
-that take advantage of message passing. We will be using
-gr::blocks::message_debug and gr::blocks::tagged_stream_to_pdu below
-to show setting up both input and output message passing capabilities.
-
-The gr::blocks::message_debug block is used for debugging the message
-passing system. It describes three input message ports: \a print, \a
-store, and \a pdu_print. The \a print port simply prints out all
-messages to standard out while the \a store port keeps a list of all
-messages posted to it. The \a pdu_print port specially formats PDU
-messages for printing to standard out. The \a store port works in
-conjunction with a gr::blocks::message_debug::get_message(int i) call
-that allows us to retrieve message \p i afterward.
-
-The constructor of this block looks like this:
-
-\code
-{
- message_port_register_in(pmt::mp("print"));
- set_msg_handler(pmt::mp("print"),
- boost::bind(&message_debug_impl::print, this, _1));
-
- message_port_register_in(pmt::mp("store"));
- set_msg_handler(pmt::mp("store"),
- boost::bind(&message_debug_impl::store, this, _1));
-
- message_port_register_in(pmt::mp("print_pdu"));
- set_msg_handler(pmt::mp("print_pdu"),
- boost::bind(&message_debug_impl::print_pdu, this, _1));
-}
-\endcode
-
-The three message input ports are registered by their respective
-names. We then use the gr::basic_block::set_msg_handler function to
-identify this particular port name with a callback function. The
-Boost \a bind function (<a target="_blank"
-href="http://www.boost.org/doc/libs/1_52_0/libs/bind/bind.html">Boost::bind</a>)
-here binds the callback to a function of this block's class. So now
-the functions in the block's private implementation class,
-gr::blocks::message_debug_impl::print,
-gr::blocks::message_debug_impl::store, and
-gr::blocks::message_debug_impl::print_pdu, are assigned to handle
-messages passed to them. Below is the \a print function for reference.
-
-\code
-void
-message_debug_impl::print(pmt::pmt_t msg)
-{
- std::cout << "***** MESSAGE DEBUG PRINT ********\n";
- pmt::print(msg);
- std::cout << "**********************************\n";
-}
-\endcode
-
-The function simply takes in the PMT message and prints it. The method
-pmt::print is a function in the PMT library to print the
-PMT in a friendly and (mostly) pretty manner.
-
-The gr::blocks::tagged_stream_to_pdu block only defines a single
-output message port. In this case, its constructor contains the line:
-
-\code
-{
- message_port_register_out(pdu_port_id);
-}
-\endcode
-
-So we are only creating a single output port where \a pdu_port_id
-is defined in the file pdu.h as \a pdus.
-
-This block's purpose is to take in a stream of samples along with
-stream tags and construct a predefined PDU message from it. In GNU
-Radio, we define a PDU as a PMT pair of (metadata, data). The metadata
-describes the samples found in the data portion of the
-pair. Specifically, the metadata can contain the length of the data
-segment and any other information (sample rate, etc.). The PMT vectors
-know their own length, so the length value is not actually necessary
-unless useful for purposes down the line. The metadata is a PMT
-dictionary while the data segment is a PMT uniform vector of either
-bytes, floats, or complex values.
-
-In the end, when a PDU message is ready, the block calls its
-gr::blocks::tagged_stream_to_pdu_impl::send_message function that is
-shown below.
-
-\code
-void
-tagged_stream_to_pdu_impl::send_message()
-{
- if(pmt::length(d_pdu_vector) != d_pdu_length) {
- throw std::runtime_error("msg length not correct");
- }
-
- pmt::pmt_t msg = pmt::cons(d_pdu_meta,
- d_pdu_vector);
- message_port_pub(pdu_port_id, msg);
-
- d_pdu_meta = pmt::PMT_NIL;
- d_pdu_vector = pmt::PMT_NIL;
- d_pdu_length = 0;
- d_pdu_remain = 0;
- d_inpdu = false;
-}
-\endcode
-
-This function does a bit of checking to make sure the PDU is OK as
-well as some cleanup in the end. But it is the line where the message
-is published that is important to this discussion. Here, the block
-posts the PDU message to any subscribers by calling
-gr::basic_block::message_port_pub publishing method.
-
-There is similarly a gr::blocks::pdu_to_tagged_stream block that essentially
-does the opposite. It acts as a source to a flowgraph and waits for
-PDU messages to be posted to it on its input port \a pdus. It extracts
-the metadata and data and processes them. The metadata dictionary is
-split up into key:value pairs and stream tags are created out of
-them. The data is then converted into an output stream of items and
-passed along. The next section describes how PDUs can be passed into a
-flowgraph using the gr::blocks::pdu_to_tagged_stream block.
-
-For a Python block example, see \ref pyblocks_msgs.
-
-*/