summaryrefslogtreecommitdiff
path: root/docs/doxygen/other/python_blocks.dox
diff options
context:
space:
mode:
Diffstat (limited to 'docs/doxygen/other/python_blocks.dox')
-rw-r--r--docs/doxygen/other/python_blocks.dox154
1 files changed, 154 insertions, 0 deletions
diff --git a/docs/doxygen/other/python_blocks.dox b/docs/doxygen/other/python_blocks.dox
new file mode 100644
index 0000000000..811eb84b68
--- /dev/null
+++ b/docs/doxygen/other/python_blocks.dox
@@ -0,0 +1,154 @@
+/*! \page page_python_blocks Python Blocks
+
+How to create blocks in Python
+
+\subsection pyblocks_streaming Streaming Data Blocks
+
+We create blocks in Python very much like we would in C++, just with
+more Python. Figure out which type of block you want to create:
+
+\li general block (gr.basic_block)
+\li synchronous block (gr.sync_block)
+\li decimator (gr.sync_decimator)
+\li interpolator (gr.sync_interpolator)
+
+The block class inherits from one of these base classes, and then in
+defining the parent class, we set the I/O signature. However, unlike
+in C++ where we use the gr::io_signature class, here we can just
+create a Python list of the I/O data sizes using numpy data types:
+
+\li numpy.int8
+\li numpy.int16
+\li numpy.int32
+\li numpy.float32
+\li numpy.float64
+
+Like a normal C++ version of the block, we then create and initialize
+any variables in the constructor, define any setters and getters, and
+create the work function. The prototype for the work function is quite
+simple:
+
+\code
+def work(self, input_items, output_items)
+\endcode
+
+The input_items and output_items are lists of lists. The input_items
+contains a vector of input samples for every input stream, and the
+output_items is a vector for each output stream where we can place
+items. Then length of output_items[0] is equivalent to the
+noutput_items concept we are so familiar with from the C++ blocks.
+
+Following is an example Python block that adds two input streams
+together. This block is used in the qa_block_gateway.py test code.
+
+\code
+class add_2_f32_1_f32(gr.sync_block):
+ def __init__(self):
+ gr.sync_block.__init__(
+ self,
+ name = "add 2 f32",
+ in_sig = [numpy.float32, numpy.float32],
+ out_sig = [numpy.float32],
+ )
+
+ def work(self, input_items, output_items):
+ output_items[0][:] = input_items[0] + input_items[1]
+ return len(output_items[0])
+\endcode
+
+The block defines two input floating point streams by setting in_sig
+to "[numpy.float32, numpy.float32]" and a single output float stream
+in out_sig of "[numpy.float32]."
+
+The work function then just adds the two input streams together. The
+streams are input_items[0] and input_items[1]. The block still returns
+the concept of noutput_items like we use in C++, only we get it here
+by getting len(output_items[0]). Because this is a sync_block, we also
+know that the size of the input_items for both streams is the same as
+the size of the output_items vector.
+
+
+
+\subsection pyblocks_tags Using Stream Tags
+
+Python blocks have access to the stream tag system like their C++
+counterparts. The interface is almost identical except they behave
+just a bit more like we would expect in Python.
+
+To add tags to the data stream, we use the add_item_tag function:
+
+\code
+def work(self, input_items, output_items):
+ ....
+ add_item_tag(which_output, abs_offset,
+ key, value, srcid)
+ ....
+\endcode
+
+The abs_offset is an integer of the sample that the tag is attached
+to, and key and value are both PMTs to set the key:value pair of the
+tag information, and the srcid is an optional PMT to define the source
+of the block that generate the tag.
+
+We then can get tags using either the get_tags_in_range or
+get_tags_in_window. Again, like their C++ counter parts, the
+get_tags_in_range uses the absolute item offset numbering (using
+nitems_read) while the get_tags_in_window uses relative offsets within
+the current window of items available to the work function. The main
+difference from the C++ function is that instead of having the first
+argument be a vector where the tags are stored, the Python version
+just returns a list of tags. We would use it like this:
+
+\code
+def work(self, input_items, output_items):
+ ....
+ tags = get_tags_in_window(which_input, rel_start, rel_end)
+ ....
+\endcode
+
+
+
+\subsection pyblocks_msgs Using Message Passing
+
+Again, like their C++ counterparts, Python blocks can use the
+asynchronous message passing interface. We define output message
+handlers using:
+
+\code
+self.message_port_register_out(pmt.intern("<port name>"))
+\endcode
+
+We can then post messages to this using the message_port_pub function:
+
+\code
+self.message_port_pub(pmt.intern("<port name>"), <pmt message>)
+\endcode
+
+We then register input messages and handlers in similar ways:
+
+\code
+self.message_port_register_in(pmt.intern("<port name>"))
+self.set_msg_handler(pmt.intern("<port name>"), <msg handler function>)
+\endcode
+
+Putting this together below is a very simple example:
+
+\code
+class msg_block(gr.basic_block):
+ def __init__(self):
+ gr.basic_block.__init__(
+ self,
+ name="msg_block",
+ in_sig=None,
+ out_sig=None)
+
+ self.message_port_register_out(pmt.intern('msg_out'))
+ self.message_port_register_in(pmt.intern('msg_in'))
+ self.set_msg_handler(pmt.intern('msg_in'), self.handle_msg)
+
+ def handle_msg(self, msg):
+ self.message_port_pub(pmt.intern('msg_out'),
+ pmt.intern('message received!'))
+\endcode
+
+*/ \ No newline at end of file