summaryrefslogtreecommitdiff
path: root/docs/doxygen/other
diff options
context:
space:
mode:
authorTom Rondeau <trondeau@vt.edu>2013-07-06 20:38:56 +0100
committerJohnathan Corgan <johnathan@corganlabs.com>2013-07-16 14:37:38 -0700
commit0cb377640f68f45840e3f0cb5b426e345f87974a (patch)
tree9ca7080f9c716f8d37d8414988762b42dd29e36f /docs/doxygen/other
parent5d23b8df58958708bea765678d4eba692a63c9b3 (diff)
docs: Updated and improved the message passing docs page.
Diffstat (limited to 'docs/doxygen/other')
-rw-r--r--docs/doxygen/other/msg_passing.dox134
1 files changed, 87 insertions, 47 deletions
diff --git a/docs/doxygen/other/msg_passing.dox b/docs/doxygen/other/msg_passing.dox
index dc0d5bbb3f..c184681f23 100644
--- a/docs/doxygen/other/msg_passing.dox
+++ b/docs/doxygen/other/msg_passing.dox
@@ -8,16 +8,16 @@ for samples, bits, etc., but are not really the right mechanism for
control data, metadata, and, often, packet structures (at least at
some point in the processing chain).
-We solved part of this problem a few years ago by introducing the tag
-stream. 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 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
@@ -32,7 +32,7 @@ structures, see the page \ref page_pmt.
\section api Message Passing API
-The message passing interface is designed into the gr_basic_block,
+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
@@ -65,10 +65,42 @@ port. The subscribe and publish API looks like:
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
+have subscribed and uses the gr::basic_block::_post method to send the
message to that block's message queue.
-From the flowgraph level, we have instrumented a gr_hier_block2::msg_connect
+
+\subsection 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
+
+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
+
+We give an example of using this below.
+
+
+\subsection msg_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. The message connection method looks like the following
code. Assume that the block \b src has an output message port named
@@ -97,9 +129,9 @@ 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
+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
+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
@@ -117,16 +149,17 @@ it is this function that is used to process the message.
The following is snippets of code from blocks current in GNU Radio
that take advantage of message passing. We will be using
-gr_message_debug and gr_tagged_stream_to_pdu below to show setting up
-both input and output message passing capabilities.
-
-The gr_message_debug block is used for debugging the message passing
-system. It describes two input message ports: \a print and \a
-store. 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. This latter port works in conjunction with a
-gr_message_debug::get_message(int i) call that allows us to retrieve
-message \p i afterward.
+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:
@@ -134,27 +167,33 @@ The constructor of this block looks like this:
{
message_port_register_in(pmt::mp("print"));
set_msg_handler(pmt::mp("print"),
- boost::bind(&gr_message_debug::print, this, _1));
+ boost::bind(&message_debug_impl::print, this, _1));
message_port_register_in(pmt::mp("store"));
set_msg_handler(pmt::mp("store"),
- boost::bind(&gr_message_debug::store, this, _1));
+ 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
-So the two ports are registered by their respective names. We then use
-the gr_basic_block::set_msg_handler function to identify this
+So the three 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 block's gr_message_debug::print and gr_message_debug::store
-functions are assigned to handle messages passed to them. Below is the
-\a print function for reference.
+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
-gr_message_debug::print(pmt::pmt_t msg)
+message_debug_impl::print(pmt::pmt_t msg)
{
std::cout << "***** MESSAGE DEBUG PRINT ********\n";
pmt::print(msg);
@@ -166,8 +205,8 @@ 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, (mostly) pretty manner.
-The gr_tagged_stream_to_pdu block only defines a single
-output message port. In this case, its constructor looks like:
+The gr::blocks::tagged_stream_to_pdu block only defines a single
+output message port. In this case, its constructor contains the line:
\code
{
@@ -176,7 +215,7 @@ output message port. In this case, its constructor looks like:
\endcode
So we are only creating a single output port where \a pdu_port_id
-is defined in the file gr_pdu.h as \a pdus.
+is defined in the file pdu.h as \a pdus.
This blocks purpose is to take in a stream of samples along with
stream tags and construct a predefined PDU message from this. In GNU
@@ -190,18 +229,19 @@ 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_tagged_stream_to_pdu::send_message function that is shown below.
+gr::blocks::tagged_stream_to_pdu_impl::send_message function that is
+shown below.
\code
void
-gr_tagged_stream_to_pdu::send_meassage()
+tagged_stream_to_pdu_impl::send_meassage()
{
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);
+ d_pdu_vector);
message_port_pub(pdu_port_id, msg);
d_pdu_meta = pmt::PMT_NIL;
@@ -216,26 +256,26 @@ 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.
+gr::basic_block::message_port_pub publishing method.
-There is similarly a gr_pdu_to_tagged_stream block that essentially
+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_pdu_to_tagged_stream block.
+flowgraph using the gr::blocks::pdu_to_tagged_stream block.
\section posting Posting from External Sources
The last feature of the message passing architecture to discuss here
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
+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_pdu_to_tagged_stream block
+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
@@ -255,9 +295,9 @@ here, we will create and insert them by hand.
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
+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