diff options
Diffstat (limited to 'docs/doxygen/other/python_blocks.dox')
-rw-r--r-- | docs/doxygen/other/python_blocks.dox | 154 |
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 |