Tuesday 22 March 2011

Writing a Block in GNURadio

GNU Radio provides a data flow abstraction.This abstraction is implemented by the Python gr.flow_graph class.Each block has a set of input ports and output ports.When we write the block, we need to construct them as shared libraries that may be dynamically loaded into Python using the `import' mechanism. SWIG, the Simplified Wrapper and Interface Generator, is used to generate the glue that allows our code to be used from Python. Writing a new signal processing block involves creating 3 files: The .h and .cc files that define the new block class and the .i file that tells SWIG how to generate the glue that binds the class into Python. The new class must derive from gr_block or one of it's subclasses. The C++ class gr_block is the base of all signal processing blocks in GNU Radio.


d_name is a string saving the block's name. d_unique_id is a long integer, defined as the `ID' of the block. The class gr_io_signature is defined in /src/lib/runtime/gr_io_signature.h.The definition of gr_io_signature.h.


For a block's input (output), the class gr_io_signature defines the minimal (d_min_streams) and maximal (d_max_streams) number of streams as the lower and upper bound. The `size' (number of bytes occupied) of an item in the stream is given by d_sizeof_stream_item, a member variable with the type of size_t.
gr_runtime.h is included in gr_block.h. In gr_runtime.h, gr_io_signature_sptr is a type defined as:
Further, gr_runtime.h includes gr_type.h first. In gr_type.h, an interesting header file is included.

GNU Radio takes the advantage of Boost smart pointers. Boost is a collection of C++ libraries, a pre-required package for the installation of GNU Radio. Boost provides powerful extensions to C++ from many aspects, such as algorithm implementation, math/numerics, input/output, iterators, etc. Interested programmers can refer to for more information. GNU Radio borrows one cool feature from Boost: the smart_ptr library, so called . Smart pointers are objects which store pointers to dynamically allocated objects. They behave much like built-in C++ pointers except that they automatically delete the object pointed to at the appropriate time. Smart pointers are particularly useful in the face of exceptions as they ensure proper destruction of dynamically allocated objects.the smart pointers are defined as class templates. The library smart_ptr provides five smart pointer class templates, but in GNU Radio, we only use one of them: shared_ptr, defined in <boost/shared_ptr.hpp>. shared_ptr is used for the case when the pointed object ownership is shared by multiple pointers. Using Smart pointers in GNURadio: boost::shared_ptr<T> pointer_name These smart pointer class templates have a template parameter, T, which specifies the type of the object pointed to by the smart pointer. For example, boost::shared_ptr<gr_io_signature> declares a smart pointer pointing to an object with the class type of gr_io_signature.
Datatypes in GNURadio:
The core of a block: the method general_work() The method general_work() is pure virtual, we definitely need to override that. general_work is the method that does the actual signal processing, which is the CPU of the block.

The method general_work() compute the output streams from the input streamsA block may have x input streams and y output streams. ninput_items is an integer `vector' of length x, the ith element of which gives the number of available items on the ith input stream.However noutput_items (output flow) is simply an integer and not a vector.This is because GNU Radio of the current version only supports a block having the same data rates for all output streams, i.e. the number of output items to write on each output stream is the same for all output streams. The data rates for input streams could be different. . input_items is a vector of pointers to the input items, one entry per input stream. output_items is a vector of pointers to the output items, one entry per output stream. We actually use these pointers to get the input data and write the computed output data to appropriate streams. The returned value of general_work() is the number of items actually written to each output stream, or -1 on EOF. It is OK to return a value less than noutput_items. Finally and significantly, when we override general_work() for our own block, we MUST call consume() or consume_each() methods to indicate how many items have been consumed on each input stream.
The method consume() tells the scheduler how many items (given by how_many_items') of the ith input stream (given by `which_input') have been consumed. If each input stream has consumed the same number of items, we can use consume_each() instead. It tells the scheduler each input stream has consumed `how_many_items' items. The reason why we have to call the consume() or consume_each() method is we have to tell the scheduler how many items of the input streams have been consumed, so that the scheduler can arrange the upstream buffer and associated pointers accordingly.
The method forecast(): The method forecast() is used to estimate the input requirements given an output request. The first parameter noutput_items has been introduced in general_work(), which is the number of output items to produce for each output stream. The second parameter ninput_items_required is an integer vector, saving the number of input items required on each input stream. When we override the forecast() method, we need to estimate the number of data items required on each input stream, given the request to produce `noutput_items' items for each output stream. The estimate doesn't have to be exact, but should be close. The argument ninput_items_required is passed by reference, so that the calculated estimates can be saved into it directly. Naming Conventions: In GNU Radio, with the exception of macros and other constant values, all identifiers shall be in lower case with `words_separated_like_this'. Macros and constant values shall be in UPPER_CASE. Package prefix: All globally visible names (types, functions, variables, constants, etc.) shall begin with a package prefix', followed by an underscore. The bulk of the code in GNU Radio belongs to the `gr' package, hence names look like gr_open_file (...).
Class data members (instance variables): All class data members shall begin with the prefix `d_'.
File names
Each significant class shall be contained in its own files. For example, the declaration of the class gr_foo shall be in gr_foo.h and the definition in gr_foo.cc.
Suffixes
By convention, we encode the input and output types of signal processing blocks in their name using suffixes. The suffix is typically one or two characters long. Sources and sinks have single character suffixes. Regular blocks that have both inputs and outputs have two character suffixes. The first character indicates the type of the input streams, while the second indicates the type of the output streams.
The SWIG file: how.i
SWIG, the Simplified Wrapper and Interface Generator, is used to generate the glue that allows our code to be used from Python.The SWIG .i file tells SWIG the gluing guidelines.
A .i file can been treated as a pared-down version of the .h file, plus a bit of magic that has Python work with the boost::shared_ptr. To reduce the code bloat,declare methods that are required to access from Python.
GR_SWIG_BLOCK_MAGIC does some `magics' so that we can access howto_square_ff from Python as howto.square_ff(). From Python's point of view, howto is a package, and square_ff() becomes a function defined in howto. Calling this function will return a smart pointer howto_square_ff_sptr pointing to a new instance of howto_square_ff.

1 comment:

  1. hi i want write new block in windows version can you help me?
    spring_20000@yahoo.com

    ReplyDelete