Tutorial: Writing a Python Function
GNU Radio uses Python as a scripting language. As opposed to writing our own domain-specific language, we use Python because it's easy to learn, easy to use, and has a huge community of users and developers. The pool of information and tools (or Python modules) available is really pretty astounding. Because we use Python a lot in GNU Radio, we inherit all of that.
Often, we can solve a lot of our control and setup problems simply by writing a new Python function or class. You can always do this yourself, but then the question becomes how you manage that function and how do you make it easy to pull in for any Python GNU Radio program, including within the GNU Radio Companion?
This tutorial goes over the steps to add a Python file to an OOT project, which helps with code management and installation issues. This tutorial is designed to help you use Python within GNU Radio, but it cannot explain Python itself to you,
Using the GNU Radio Modtool to Build the Project
If you already have an OOT module, you can skip step one. If you don't let's make one:
1. Create a new OOT project. Let's just call it testpy. Note that anything surrounded by asterisks is what you as the user file in.
$ gr_modtool nm Name of the new module: *testpy* Creating out-of-tree module in ./gr-testpy... Done. Use 'gr_modtool add' to add a new block to this currently empty module.
2. Add the Python file to the project. This is a 'noblock' so it will just be an empty Python file, not a GNU Radio block. In this example, we will create a very simply function that returns the square of a value passed to it. We will call the function squareme as a noblock type using the language python.
$ gr_modtool add GNU Radio module name identified: testpy ('sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock') Enter block type: *noblock* Language (python/cpp): *python* Language: Python Enter name of block/code (without module name prefix): *squareme* Block/code identifier: squareme Enter valid argument list, including default arguments: *x* Adding file 'python/squareme.py'...
3. We set the argument x above, but this is actually meaningless. All the above has done is created a file called gr-testpy/python/squareme.py that has the standard GPL header already in it but is blank otherwise. Let's edit that and add the function squareme:
#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright 2015 <+YOU OR YOUR COMPANY+>. # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this software; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # def squareme(x): return x*x
4. That's really it. You can now build and install your project, and it will install the squareme.py file into the Python package for the testpy module. But first, take a quick look at the gr-testpy/python/_init_.py file (I've skipped the header). Our gr_modtool has already added the squareme function from the squareme.py file to be loaded into the module space. Just keep this line in mind if you ever add more functions to squareme.py, you'll want to add them here or change that line to
from squareme import * if appropriate.
# The presence of this file turns this directory into a Python package ''' This is the GNU Radio TESTPY module. Place your Python package description here (python/__init__.py). ''' # import swig generated symbols into the testpy namespace try: # this might fail if the module is python-only from testpy_swig import * except ImportError: pass # import any pure python here from squareme import squareme #
5. Build and install:
$ mkdir build $ cd build $ cmake ../ $ make $ make install
6. Use the new function from GRC. We might have to import the module if this is all that we are using from it; it might already be pulled in if you are using a block from this module in the flowgraph already. We'll use it as a stand-alone function, though, to be clear how to import it. In the image below, we put an "Import" block that calls import testpy, which loads that into the Python module space. We then use the squareme function from testpy to square a value. The Properties box is open so we can see both the calling convention and the results (12*12 = 144).
7. Do something that's actually interesting with Python. This tutorial just shows the how, not the what. There are plenty of more advanced things we can do because of the nature and power of Python. But that's now up to you.