From b3858bfe3b559722bd788e7c32159d4963422c01 Mon Sep 17 00:00:00 2001
From: Johnathan Corgan
Date: Thu, 12 Nov 2009 10:50:03 -0800
Subject: howto: move limbo'd docs into toplevel doc dir for preservation
---
docs/howto-write-a-block/.gitignore | 17 +
docs/howto-write-a-block/Makefile.am | 81 ++
docs/howto-write-a-block/README | 4 +-
docs/howto-write-a-block/howto-write-a-block.xml | 959 ++++++++++++++++++++++
docs/howto-write-a-block/howto_1.i | 29 +
docs/howto-write-a-block/make_numbered_listing.py | 45 +
docs/howto-write-a-block/qa_howto_1.py | 27 +
docs/howto-write-a-block/src_lib_Makefile_1.am | 25 +
docs/howto-write-a-block/src_lib_Makefile_2.am | 86 ++
9 files changed, 1270 insertions(+), 3 deletions(-)
create mode 100644 docs/howto-write-a-block/Makefile.am
create mode 100644 docs/howto-write-a-block/howto-write-a-block.xml
create mode 100644 docs/howto-write-a-block/howto_1.i
create mode 100755 docs/howto-write-a-block/make_numbered_listing.py
create mode 100755 docs/howto-write-a-block/qa_howto_1.py
create mode 100644 docs/howto-write-a-block/src_lib_Makefile_1.am
create mode 100644 docs/howto-write-a-block/src_lib_Makefile_2.am
(limited to 'docs')
diff --git a/docs/howto-write-a-block/.gitignore b/docs/howto-write-a-block/.gitignore
index 719ea5d4f..f65ab6cf7 100644
--- a/docs/howto-write-a-block/.gitignore
+++ b/docs/howto-write-a-block/.gitignore
@@ -1 +1,18 @@
+/Makefile
+/Makefile.in
+/.deps
+/.libs
+/*.la
+/*.lo
+/autom4te.cache
+/*.cache
/howto-write-a-block.html
+/gr_block.h.xml
+/howto_1.i.xml
+/howto_square_ff.cc.xml
+/howto_square_ff.h.xml
+/qa_howto_1.py.xml
+/src_lib_Makefile_1.am.xml
+/src_lib_Makefile_2.am.xml
+/howto_square2_ff.cc.xml
+/howto_square2_ff.h.xml
diff --git a/docs/howto-write-a-block/Makefile.am b/docs/howto-write-a-block/Makefile.am
new file mode 100644
index 000000000..5f58a21e9
--- /dev/null
+++ b/docs/howto-write-a-block/Makefile.am
@@ -0,0 +1,81 @@
+#
+# Copyright 2004,2005,2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+TARGETS = howto-write-a-block.html
+
+# To avoid build problems for folks who don't have xmlto installed, we
+# don't build the docs by default.
+
+# html: $(TARGETS)
+all: $(TARGETS)
+
+
+EXTRA_DIST = \
+ README \
+ howto-write-a-block.xml \
+ howto_1.i \
+ make_numbered_listing.py \
+ qa_howto_1.py \
+ src_lib_Makefile_1.am \
+ src_lib_Makefile_2.am
+
+
+BUILT_XML_FILES = \
+ gr_block.h.xml \
+ howto_1.i.xml \
+ howto_square_ff.cc.xml \
+ howto_square_ff.h.xml \
+ howto_square2_ff.cc.xml \
+ howto_square2_ff.h.xml \
+ qa_howto_1.py.xml \
+ src_lib_Makefile_1.am.xml \
+ src_lib_Makefile_2.am.xml
+
+
+howto-write-a-block.html : howto-write-a-block.xml $(BUILT_XML_FILES)
+
+
+gr_block.h.xml: $(GNURADIO_CORE_INCLUDEDIR)/gr_block.h make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $(GNURADIO_CORE_INCLUDEDIR)/gr_block.h
+
+howto_square_ff.cc.xml: $(top_srcdir)/src/lib/howto_square_ff.cc make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $(top_srcdir)/src/lib/howto_square_ff.cc
+
+howto_square_ff.h.xml: $(top_srcdir)/src/lib/howto_square_ff.h make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $(top_srcdir)/src/lib/howto_square_ff.h
+
+howto_square2_ff.cc.xml: $(top_srcdir)/src/lib/howto_square2_ff.cc make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $(top_srcdir)/src/lib/howto_square2_ff.cc
+
+howto_square2_ff.h.xml: $(top_srcdir)/src/lib/howto_square2_ff.h make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $(top_srcdir)/src/lib/howto_square2_ff.h
+
+
+# ----------------------------------------------------------------
+
+clean:
+ -${RM} -f $(TARGETS) $(BUILT_XML_FILES)
+
+%.html : %.xml
+ xmlto html-nochunks $<
+
+%.xml : % make_numbered_listing.py
+ $(PYTHON) ./make_numbered_listing.py $<
diff --git a/docs/howto-write-a-block/README b/docs/howto-write-a-block/README
index 73b8e6028..ff3b75e57 100644
--- a/docs/howto-write-a-block/README
+++ b/docs/howto-write-a-block/README
@@ -1,3 +1 @@
-If you're looking for howto-write-a-block, it was moved into it's own
-tarball: gr-howto-write-a-block. It includes the document source
-and a full build tree, Makefiles, examples, etc.
+The contents of this directory are obsolete.
diff --git a/docs/howto-write-a-block/howto-write-a-block.xml b/docs/howto-write-a-block/howto-write-a-block.xml
new file mode 100644
index 000000000..f8027b456
--- /dev/null
+++ b/docs/howto-write-a-block/howto-write-a-block.xml
@@ -0,0 +1,959 @@
+
+GNU Radio">
+ SWIG">
+ gr_block">
+ howto_square_ff">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]>
+
+
+
+
+How to Write a Signal Processing Block
+
+ Eric
+ Blossom
+
+
+ eb@comsec.com
+
+
+
+
+
+
+ 0.1
+ 2005-01-20
+
+
+ 0.2
+ 2005-02-02
+ Updated for SWIG 1.3.24
+
+
+ 0.3
+ 2006-07-21
+ Clarification of 1:1 fixed rate vs item size
+
+
+
+
+ 2004
+ 2005
+ Free Software Foundation, Inc.
+
+
+This article explains how to write signal
+processing blocks for GNU Radio.
+
+
+
+
+Prerequisites
+This article assumes that the reader has basic familiarity with
+GNU Radio and has read and understood
+
+Exploring GNU Radio.
+
+
+There is a tarball of files that accompany this article. It
+includes the examples, DocBook source for the article and all the
+Makefiles etc it takes to make it work. Grab it at
+ftp://ftp.gnu.org/gnu/gnuradio or one of the mirrors. The
+file you want is
+gr-howto-write-a-block-X.Y.tar.gz. Pick the one
+with the highest version number.
+See
+http://comsec.com/wiki?CvsAccess for CVS Access.
+
+
+
+
+
+Introduction
+&gnuradio; provides a framework for building software radios.
+Waveforms -- signal processing applications -- are built using a
+combination of Python code for high level organization, policy, GUI and
+other non performance-critical functions, while performance critical
+signal processing blocks are written in C++.
+
+From the Python point of view, &gnuradio; provides a data flow
+abstraction. The fundamental concepts are signal processing
+blocks and the connections between them. This abstraction is
+implemented by the Python gr.flow_graph class.
+Each block has a set of input ports and output ports. Each port has
+an associated data type. The most common port types are
+float and gr_complex
+(equivalent to std::complex<float>), though other types are used,
+including those representing structures, arrays or other types of
+packetized data.
+
+From the high level point-of-view, infinite streams of data flow
+through the ports. At the C++ level, streams are dealt with in
+convenient sized pieces, represented as contiguous arrays of the
+underlying type.
+
+
+
+The View from 30,000 Feet
+
+This article will walk through the construction of several
+simple signal processing blocks, and explain the techniques and idioms
+used. Later sections cover debugging signal processing blocks in the
+mixed Python/C++ environment and performance measurement and
+optimization.
+
+The example blocks will be built in the style of all &gnuradio;
+extensions. That is, they are built outside of the gnuradio-core build
+tree, and are constructed 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.
+
+
+
+
+
+
+The C++ class &gr_block; is the base of all signal processing
+blocks in &gnuradio;. Writing a new signal processing block involves
+creating 3 files: The .h and .cc files that define the new 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.
+
+Our first examples will derive directly from &gr_block;. Later
+we will look at some other subclasses that simplify the process for
+common cases.
+
+
+
+
+
+
+
+Autotools, Makefiles, and Directory Layout
+
+Before we dive into the code, &lets; talk a bit about the
+overall build environment and the directory structure that &well;
+be using.
+
+To reduce the amount of Makefile hacking that we have to do, and
+to facilitate portability across a variety of systems, we use the GNU
+autoconf,
+automake, and
+libtool tools. These are collectively
+referred to as the autotools, and once you get over the initial
+shock, they will become your friends. (The good news is that we
+provide boilerplate that can be used pretty much as-is.)
+
+
+
+automake
+
+automake and configure work together to generate GNU
+compliant Makefiles from a much higher level description contained in
+the corresponding Makefile.am file. Makefile.am
+specifies the libraries and programs to build and the source files
+that compose each. Automake reads Makefile.am
+and produces Makefile.in. Configure reads
+Makefile.in and produces
+Makefile. The resulting Makefile contains a
+zillion rules that do the right right thing to build, check and
+install your code. It is not uncommon for the the resulting
+Makefile to be 5 or 6 times larger than
+Makefile.am.
+
+
+
+
+autoconf
+autoconf reads configure.ac
+and produces the configure shell
+script. configure automatically tests for
+features of the underlying system and sets a bunch of variables and
+defines that can be used in the Makefiles and your C++ code to
+conditionalize the build. If features are required but not found,
+configure will output an error message and stop.
+
+
+
+libtool
+libtool works behind the scenes and provides the magic
+to construct shared libraries on a wide variety of systems.
+
+
+
+
+
+ shows the directory layout and
+common files &well; be using. After renaming the
+topdir directory, use it in your projects
+too. We'll talk about particular files as they come up later.
+
+
+Directory Layout
+
+
+
+File/Dir Name
+Comment
+
+
+
+
+
+
+topdir/Makefile.am
+Top level Makefile.am
+
+
+topdir/Makefile.common
+Common fragment included in sub-Makefiles
+
+
+topdir/bootstrap
+Runs autoconf, automake, libtool first time through
+
+
+topdir/config
+Directory of m4 macros used by configure.ac
+
+
+topdir/configure.ac
+Input to autoconf
+
+
+topdir/src
+
+
+topdir/src/lib
+C++ code goes here
+
+
+topdir/src/lib/Makefile.am
+
+
+topdir/src/python
+Python code goes here
+
+
+topdir/src/python/Makefile.am
+
+
+topdir/src/python/run_tests
+Script to run tests in the build tree
+
+
+
+
+
+
+
+
+
+
+Naming Conventions
+
+&gnuradio; uses a set of naming conventions to assist in
+comprehending the code base and gluing C++ and Python together.
+Please follow them.
+
+Death to CamelCaseNames!
+
+We've returned to a kinder, gentler era. We're now using the
+"STL style" naming convention with a couple of modifications
+since we're not using namespaces.
+
+With the exception of macros and other constant values, all
+identifiers shall be lower case with words_separated_like_this.
+
+Macros and constant values (e.g., enumerated values,
+static const int FOO = 23) shall be in UPPER_CASE.
+
+
+
+Global Names
+
+All globally visible names (types, functions, variables, consts, 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 (...).
+
+Large coherent bodies of code may use other package prefixes, but
+let's try to keep them to a well thought out list. See the list
+below.
+
+
+
+Package Prefixes
+
+These are the current package prefixes:
+
+
+
+gr_
+Almost everything.
+
+
+gri_
+
+Implementation primitives. Sometimes we
+have both a gr_foo and a gri_foo. In that case,
+gr_foo would be derived from gr_block and gri_foo
+would be the low level guts of the function.
+
+
+atsc_
+Code related to the Advanced Television Standards Committee HDTV implementation
+
+
+
+usrp_
+Universal Software Radio Peripheral.
+
+
+qa_
+Quality Assurance (Test code.)
+
+
+
+
+
+
+
+Class Data Members (instance variables)
+
+All class data members shall begin with d_foo.
+
+The big win is when you're staring at a block of code it's obvious
+which of the things being assigned to persist outside of the block.
+This also keeps you from having to be creative with parameter names
+for methods and constructors. You just use the same name as the
+instance variable, without the d_.
+
+
+class gr_wonderfulness {
+ std::string d_name;
+ double d_wonderfulness_factor;
+
+public:
+ gr_wonderfulness (std::string name, double wonderfulness_factor)
+ : d_name (name), d_wonderfulness_factor (wonderfulness_factor)
+ {
+ ...
+ }
+ ...
+};
+
+
+
+
+Class Static Data Members (class variables)
+
+
+All class static data members shall begin with s_foo.
+
+
+
+
+File Names
+
+Each significant class shall be contained in its own file. The
+declaration of 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. Source 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, the second indicates the type of the output
+streams. FIR filter blocks have a three character suffix, indicating
+the type of the inputs, outputs and taps, respectively.
+
+These are the suffix characters and their interpretations:
+
+f - single precision floating point
+c - complex<float>
+s - short (16-bit integer)
+i - integer (32-bit integer)
+
+
+
+In addition, for those cases where the block deals with streams
+of vectors, we use the character 'v' as the first character of the
+suffix. An example of this usage is
+gr_fft_vcc. The FFT block takes a vector of
+complex numbers on its input and produces a vector of complex
+numbers on its output.
+
+
+
+
+
+
+
+
+First Block: □
+
+For our first example &well; create a block that computes
+the square of its single float input. This block will accept a single
+float input stream and produce a single float output stream.
+
+Following the naming conventions, &well; use
+howto as our package prefix, and the block will
+be called howto_square_ff.
+
+We are going to arrange that this block, as well as the others
+that we write in this article, end up in the
+gnuradio.howto Python module. This will allow us
+to access it from Python like this:
+
+from gnuradio import howto
+sqr = howto.square_ff ()
+
+
+
+
+Test Driven Programming
+
+We could just start banging out the C++ code, but being highly
+evolved modern programmers, &were; going to write the test code first.
+After all, we do have a good spec for the behavior: take a single
+stream of floats as the input and produce a single stream of floats as
+the output. The output should be the square of the input.
+
+How hard could this be? Turns out that this is easy! Check out
+.
+
+
+qa_howto.py (first version)
+&qa_howto_1_listing;
+
+
+
+gr_unittest is an extension to the standard
+python module unittest.
+gr_unittest adds support for checking
+approximate equality of tuples of float and complex numbers.
+Unittest uses Python's reflection mechanism to find all methods that start with
+test_ and runs them. Unittest wraps each call
+to test_* with matching calls to
+setUp and tearDown.
+See the python
+unittest documentation for details.
+
+
+When we run the test,
+gr_unittest.main is going to invoke
+setUp,
+test_001_square_ff, and
+tearDown.
+
+test_001_square_ff builds a small graph that
+contains three nodes. gr.vector_source_f(src_data) will source the
+elements of src_data and then say that &its; finished. howto.square_ff is the block
+&were; testing. gr.vector_sink_f gathers the output of
+howto.square_ff.
+
+The run method runs the graph until all
+the blocks indicate they are finished. Finally, we check that the
+result of executing square_ff on src_data matches what we expect.
+
+
+
+
+Build Tree vs. Install Tree
+
+The build tree is everything from topdir
+(the one containing configure.ac) down. The path to the install tree is
+
+prefix/lib/pythonversion/site-packages,
+where prefix is the --prefix
+argument to configure (default /usr/local) and
+version is the installed version of
+python. A typical value is
+/usr/local/lib/python2.3/site-packages.
+
+
+We normally set our PYTHONPATH environment variable to point at
+the install tree, and do this in ~/.bash_profile
+or ~/.profile.
+This allows our python apps to access all the standard python
+libraries, plus our locally installed stuff like GNU Radio.
+
+We write our applications such that they access the code and
+libraries in the install tree. On the other hand, we want our test
+code to run on the build tree, where we can detect problems before
+installation.
+
+
+
+make check
+
+
+We use make check to run our tests.
+Make check invokes the run_tests shell script which
+sets up the PYTHONPATH environment variable so that
+our tests use the build tree versions of our code and libraries.
+It then runs all files
+which have names of the form qa_*.py and reports
+the overall success or failure.
+
+There is quite a bit of behind-the-scenes action required to use
+the non-installed versions of our code (look at
+runtest for a cheap thrill.)
+
+Finally, running make check in the python
+directory produces this result:
+
+ [eb@bufo python]$ make check
+ make check-TESTS
+ make[1]: Entering directory `/home/eb/gr-build/gr-howto-write-a-block/src/python'
+ Traceback (most recent call last):
+ File "./qa_howto.py", line 24, in ?
+ import howto
+ ImportError: No module named howto
+ Traceback (most recent call last):
+ File "./qa_howto_1.py", line 24, in ?
+ import howto
+ ImportError: No module named howto
+ FAIL: run_tests
+ ===================
+ 1 of 1 tests failed
+ ===================
+ make[1]: *** [check-TESTS] Error 1
+ make[1]: Leaving directory `/home/eb/gr-build/gr-howto-write-a-block/src/python'
+ make: *** [check-am] Error 2
+ [eb@bufo python]$
+
+Excellent! Our test failed, just as we expected. The ImportError
+indicates that it can't find the module named
+howto. No surprise, since we haven't written it yet.
+
+
+
+
+The C++ code
+Now that we've got a test case written that successfully fails,
+let's write the C++ code. As we mentioned earlier, all signal
+processing blocks are derived from gr_block or
+one of its subclasses. Let's take a look at
+.
+
+
+gr_block.h
+&gr_block_listing;
+
+
+A quick scan of gr_block.h reveals that
+since general_work is pure virtual, we
+definitely need to override that.
+general_work is the method that does the
+actual signal processing. For our squaring example we'll
+need to override general_work and provide a
+constructor and destructor and a bit of stuff to take advantage of
+the boost
+
+shared_ptrs.
+
+
+
+
+
+and are the header and c++
+source.
+
+
+howto_square_ff.h
+&howto_square_ff_h_listing;
+
+
+
+howto_square_ff.cc
+&howto_square_ff_cc_listing;
+
+
+Now we need a Makefile.am to get all this to build.
+
+is enough to build a shared library from our source file. We'll be
+adding additional rules to use &SWIG; in just a bit. If you haven't
+already, this is a good time to browse all the Makefile.am's in
+the build tree and get an idea for how it all hangs together.
+
+
+src/lib/Makefile.am (no &SWIG;)
+&src_lib_Makefile_1_am_listing;
+
+
+
+
+
+
+
+
+The &SWIG; .i file
+
+Now that we've got something that will compile, we need to write
+the &SWIG; .i file. This is a pared-down version of the .h file, plus
+a bit of magic that has python work with the boost shared_ptr's.
+To reduce code bloat, we only declare methods that &well; want to
+access from Python.
+
+We're going to call the .i file
+howto.i, and use it to hold the &SWIG;
+declarations for all classes from howto that will
+be accessible from python. It's quite small:
+&howto_1_i_listing;
+
+
+
+
+Putting it all together
+
+Now we need to modify src/lib/Makefile.am
+to run &SWIG; and to add the glue it generates to the shared library.
+
+
+src/lib/Makefile.am (with &SWIG;)
+&src_lib_Makefile_2_am_listing;
+
+
+make now builds everything successfully. We get a
+few warnings, but &thats; OK.
+
+Changing directories back to the python directory we try
+make check again:
+
+ [eb@bufo python]$ make check
+ make check-TESTS
+ make[1]: Entering directory `/home/eb/gr-build/gr-howto-write-a-block/src/python'
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.004s
+
+ OK
+ PASS: run_tests
+ ==================
+ All 1 tests passed
+ ==================
+ make[1]: Leaving directory `/home/eb/gr-build/gr-howto-write-a-block/src/python'
+ [eb@bufo python]$
+
+Victory! Our new block works!
+
+
+
+
+
+
+Additional gr_block methods
+
+In our howto_square_ff example above, we only
+had to override the general_work method to
+accomplish our goal. gr_block provides a few other
+methods that are sometimes useful.
+
+forecast
+
+Looking at general_work you may
+have wondered how the system knows how much data it needs to
+ensure is valid in each of the input arrays. The
+forecast method provides this
+information.
+
+The default implementation of forecast
+says there is a 1:1 relationship between noutput_items and the
+requirements for each input stream. The size of the items is defined by
+gr_io_signatures in the constructor of
+gr_block. The sizes of the input and output items
+can of course differ; this still qualifies as a 1:1 relationship.
+
+ // default implementation: 1:1
+
+ void
+ gr_block::forecast (int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ unsigned ninputs = ninput_items_required.size ();
+ for (unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = noutput_items;
+ }
+
+
+
+Although the 1:1 implementation worked for howto_square_ff, it
+wouldn't be appropriate for interpolators, decimators, or blocks
+with a more complicated relationship between noutput_items and the
+input requirements. That said, by deriving your classes from
+gr_sync_block,
+gr_sync_interpolator or
+gr_sync_decimator instead of
+gr_block, you can often avoid
+implementing forecast.
+
+
+
+set_output_multiple
+
+When implementing your general_work
+routine, &its; occasionally convenient to have the run time system
+ensure that you are only asked to produce a number of output items
+that is a multiple of some particular value. This might occur if your
+algorithm naturally applies to a fixed sized block of data.
+Call set_output_multiple in your constructor
+to specify this requirement. The default output multiple is 1.
+
+
+
+
+
+
+
+Subclasses for common patterns
+
+gr_block allows tremendous flexibility
+with regard to the consumption of input streams and the production of
+output streams. Adroit use of forecast and
+consume allows variable rate blocks to be
+built. It is possible to construct blocks that consume data at
+different rates on each input, and produce output at a rate that
+is a function of the contents of the input data.
+
+On the other hand, it is very common for signal processing
+blocks to have a fixed relationship between the input rate and the
+output rate. Many are 1:1, while others have 1:N or N:1
+relationships.
+
+Another common requirement is the need to examine more than one
+input sample to produce a single output sample. This is orthogonal to
+the relationship between input and output rate. For example, a
+non-decimating, non-interpolating FIR filter needs to examine N input
+samples for each output sample it produces, where N is the number of
+taps in the filter. However, it only consumes a single input sample
+to produce a single output. We call this concept "history", but you
+could also think of it as "look-ahead".
+
+gr_sync_block
+
+
+
+gr_sync_block
+is derived from
+
+gr_block
+and implements a 1:1 block with
+optional history. Given that we know the input to output rate,
+certain simplifications are possible. From the implementor's
+point-of-view, the primary change is that we define a
+work method instead of
+general_work. work
+has a slightly different calling sequence;
+It omits the unnecessary ninput_items parameter, and arranges for
+consume_each to be called on our
+behalf.
+
+ /*!
+ * \brief Just like gr_block::general_work, only this arranges to
+ * call consume_each for you.
+ *
+ * The user must override work to define the signal processing code
+ */
+ virtual int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items) = 0;
+
+
+This gives us fewer things to worry about, and less code to
+write. If the block requires history greater than 1, call
+set_history in the constructor, or any time
+the requirement changes.
+
+gr_sync_block provides a
+version of forecast that handles the
+history requirement.
+
+
+
+gr_sync_decimator
+
+
+
+gr_sync_decimator
+is derived from
+
+gr_sync_block
+and implements a N:1 block with optional history.
+
+
+
+
+gr_sync_interpolator
+
+
+
+gr_sync_interpolator
+is derived from
+
+gr_sync_block
+and implements a 1:N block with optional history.
+
+
+
+
+
+
+
+
+Second Block: howto_square2_ff
+
+Given that we now know about
+gr_sync_block, the way
+howto_square_ff should really be implemented is
+by subclassing gr_sync_block.
+
+Here are the revised sources: ,
+.
+The accompanying files contain the additional test code.
+
+
+
+howto_square2_ff.h
+&howto_square2_ff_h_listing;
+
+
+
+howto_square2_ff.cc
+&howto_square2_ff_cc_listing;
+
+
+
+
+Where to from Here?
+
+At this point, we've got a basic overview of how the system
+goes together. For more insight, I suggest that you look at the code
+of the system. The doxygen generated class
+hierarchy is a useful way to find things that might interest
+you.
+
+
+
+
+Miscellaneous Tips
+
+Sources and Sinks
+
+Sources and sinks are derived from
+gr_sync_block. The only thing different about
+them is that sources have no inputs and sinks have no outputs. This
+is reflected in the gr_io_signatures that are
+passed to the gr_sync_block constructor.
+Take a look at gr_file_source.{h,cc} and
+gr_file_sink.{h,cc} for some very straight-forward examples.
+
+
+
+
+
+Debugging with gdb
+
+If your block isn't working, and you can't sort it
+out through python test cases or a few printfs in the code, you may want to
+use gdb to debug it. The trick of course
+is that all of &gnuradio;, including your new block, is dynamically
+loaded into python for execution.
+
+Try this: In your python test code, after the relevant imports,
+print out the process id and wait for a keystroke. In another
+window run gdb and tell it to attach to the python process with the
+given process id. At this point you can set breakpoints or whatever
+in your code. Go back to the python window and hit Enter so
+it'll continue.
+
+
+ #!/usr/bin/env python
+ from gnuradio import gr
+ from gnuradio import my_buggy_module
+
+ # insert this in your test code...
+ import os
+ print 'Blocked waiting for GDB attach (pid = %d)' % (os.getpid(),)
+ raw_input ('Press Enter to continue: ')
+ # remainder of your test code follows...
+
+
+Another SNAFU you might run into is that gdb 6.2 isn't
+able to set breakpoints in the constructors or destructors generated
+by g++ 3.4. In this case, insert a call to the nop function
+gri_debugger_hook in the constructor and recompile. Load the code as
+before and set a break point on gri_debugger_hook.
+
+
+
+
+Performance Measurement with oprofile
+Oprofile is your friend.
+See http://oprofile.sourceforge.net.
+
+
+
+
+
+Coming Attractions
+
+
+Improved Type System
+
+
+
+Hierarchical Blocks
+
+
+
+
+
+
diff --git a/docs/howto-write-a-block/howto_1.i b/docs/howto-write-a-block/howto_1.i
new file mode 100644
index 000000000..640d0897b
--- /dev/null
+++ b/docs/howto-write-a-block/howto_1.i
@@ -0,0 +1,29 @@
+/* -*- c++ -*- */
+
+%include "exception.i"
+%import "gnuradio.i" // the common stuff
+
+%{
+#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
+#include "howto_square_ff.h"
+#include
+%}
+
+// ----------------------------------------------------------------
+
+/*
+ * First arg is the package prefix.
+ * Second arg is the name of the class minus the prefix.
+ *
+ * This does some behind-the-scenes magic so we can
+ * access howto_square_ff from python as howto.square_ff
+ */
+GR_SWIG_BLOCK_MAGIC(howto,square_ff);
+
+howto_square_ff_sptr howto_make_square_ff ();
+
+class howto_square_ff : public gr_block
+{
+private:
+ howto_square_ff ();
+};
diff --git a/docs/howto-write-a-block/make_numbered_listing.py b/docs/howto-write-a-block/make_numbered_listing.py
new file mode 100755
index 000000000..889c2d78d
--- /dev/null
+++ b/docs/howto-write-a-block/make_numbered_listing.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+import sys
+import os, os.path
+from optparse import OptionParser
+
+def quote_line (line):
+ line = line.replace ('&', '&')
+ line = line.replace ('<', '<')
+ line = line.replace ('>', '>')
+ line = line.replace ("'", ''')
+ line = line.replace ('"', '"')
+ return line
+
+def generate_listing (input_filename, title=None):
+ inf = open (input_filename, "r")
+ output_filename = os.path.basename (input_filename) + '.xml'
+ outf = open (output_filename, "w")
+ outf.write ('\n')
+ # outf.write ('\n' % (input_filename,))
+ # if not title:
+ # title = input_filename
+ # outf.write ('')
+ # outf.write (title)
+ # outf.write ('\n')
+ outf.write ('\n');
+
+ lineno = 0
+ for line in inf:
+ line = line.expandtabs (8)
+ line = quote_line (line)
+ lineno = lineno + 1
+ outf.write ('%3d %s' % (lineno, line))
+
+ outf.write ('\n')
+ # outf.write ('\n')
+
+
+def main ():
+ for file in sys.argv[1:]:
+ generate_listing (file)
+
+if __name__ == '__main__':
+ main ()
+
diff --git a/docs/howto-write-a-block/qa_howto_1.py b/docs/howto-write-a-block/qa_howto_1.py
new file mode 100755
index 000000000..3173110f8
--- /dev/null
+++ b/docs/howto-write-a-block/qa_howto_1.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gr_unittest
+import howto
+
+class qa_howto (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_001_square_ff (self):
+ src_data = (-3, 4, -5.5, 2, 3)
+ expected_result = (9, 16, 30.25, 4, 9)
+ src = gr.vector_source_f (src_data)
+ sqr = howto.square_ff ()
+ dst = gr.vector_sink_f ()
+ self.tb.connect (src, sqr)
+ self.tb.connect (sqr, dst)
+ self.tb.run ()
+ result_data = dst.data ()
+ self.assertFloatTuplesAlmostEqual (expected_result, result_data, 6)
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/docs/howto-write-a-block/src_lib_Makefile_1.am b/docs/howto-write-a-block/src_lib_Makefile_1.am
new file mode 100644
index 000000000..e97d70d1c
--- /dev/null
+++ b/docs/howto-write-a-block/src_lib_Makefile_1.am
@@ -0,0 +1,25 @@
+include $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the gnuradio.howto module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
+
+ourlib_LTLIBRARIES = _howto.la
+
+# These are the source files that go into the shared library
+_howto_la_SOURCES = \
+ howto_square_ff.cc
+
+# magic flags
+_howto_la_LDFLAGS = -module -avoid-version
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ howto_square_ff.h
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc
diff --git a/docs/howto-write-a-block/src_lib_Makefile_2.am b/docs/howto-write-a-block/src_lib_Makefile_2.am
new file mode 100644
index 000000000..dca236e20
--- /dev/null
+++ b/docs/howto-write-a-block/src_lib_Makefile_2.am
@@ -0,0 +1,86 @@
+#
+# Copyright 2004,2008 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the gnuradio.howto module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
+
+SWIGCPPPYTHONARGS = -noruntime -c++ -python $(PYTHON_CPPFLAGS) \
+ -I$(swigincludedir) -I$(grincludedir) $(WITH_SWIG_INCLUDES)
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+
+LOCAL_IFILES = \
+ howto.i
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _howto shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES = \
+ howto.cc \
+ howto.py
+
+# This gets howto.py installed in the right place
+ourpython_PYTHON = \
+ howto.py
+
+ourlib_LTLIBRARIES = _howto.la
+
+# These are the source files that go into the shared library
+_howto_la_SOURCES = \
+ howto.cc \
+ howto_square_ff.cc
+
+# magic flags
+_howto_la_LDFLAGS = -module -avoid-version
+
+# link the library against some comon swig runtime code and the
+# c++ standard library
+_howto_la_LIBADD = \
+ -lgrswigrunpy \
+ -lstdc++
+
+howto.cc howto.py: howto.i $(ALL_IFILES)
+ $(SWIG) $(SWIGCPPPYTHONARGS) -module howto -o howto.cc $<
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ howto_square_ff.h
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc
--
cgit