summaryrefslogtreecommitdiff
path: root/gnuradio-runtime/python/gnuradio/gr/top_block.py
diff options
context:
space:
mode:
authorSebastian Koslowski <koslowski@kit.edu>2014-12-10 15:42:46 +0100
committerSebastian Koslowski <koslowski@kit.edu>2014-12-10 16:10:19 +0100
commit94a93636ea33685a22e673934006f96cff0c29aa (patch)
treedfd73a4deff3baed2a2486f1b68c73dd9b0c3b11 /gnuradio-runtime/python/gnuradio/gr/top_block.py
parent57728315c8d49457006e1a6fce5cc213b97de61b (diff)
runtime: refactor top/hier block python wrappers
Diffstat (limited to 'gnuradio-runtime/python/gnuradio/gr/top_block.py')
-rw-r--r--gnuradio-runtime/python/gnuradio/gr/top_block.py149
1 files changed, 52 insertions, 97 deletions
diff --git a/gnuradio-runtime/python/gnuradio/gr/top_block.py b/gnuradio-runtime/python/gnuradio/gr/top_block.py
index 51d0ad5d55..8d810652aa 100644
--- a/gnuradio-runtime/python/gnuradio/gr/top_block.py
+++ b/gnuradio-runtime/python/gnuradio/gr/top_block.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2014 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-
from runtime_swig import top_block_swig, \
top_block_wait_unlocked, top_block_run_unlocked, \
top_block_start_unlocked, top_block_stop_unlocked, \
@@ -26,32 +25,31 @@ from runtime_swig import top_block_swig, \
#import gnuradio.gr.gr_threading as _threading
import gr_threading as _threading
-#
-# There is no problem that can't be solved with an additional
-# level of indirection...
-#
-# This kludge allows ^C to interrupt top_block.run and top_block.wait
-#
-# The problem that we are working around is that Python only services
-# signals (e.g., KeyboardInterrupt) in its main thread. If the main
-# thread is blocked in our C++ version of wait, even though Python's
-# SIGINT handler fires, and even though there may be other python
-# threads running, no one will know. Thus instead of directly waiting
-# in the thread that calls wait (which is likely to be the Python main
-# thread), we create a separate thread that does the blocking wait,
-# and then use the thread that called wait to do a slow poll of an
-# event queue. That thread, which is executing "wait" below is
-# interruptable, and if it sees a KeyboardInterrupt, executes a stop
-# on the top_block, then goes back to waiting for it to complete.
-# This ensures that the unlocked wait that was in progress (in the
-# _top_block_waiter thread) can complete, release its mutex and back
-# out. If we don't do that, we are never able to clean up, and nasty
-# things occur like leaving the USRP transmitter sending a carrier.
-#
-# See also top_block.wait (below), which uses this class to implement
-# the interruptable wait.
-#
+from hier_block2 import hier_block2
+
class _top_block_waiter(_threading.Thread):
+ """
+ This kludge allows ^C to interrupt top_block.run and top_block.wait
+
+ The problem that we are working around is that Python only services
+ signals (e.g., KeyboardInterrupt) in its main thread. If the main
+ thread is blocked in our C++ version of wait, even though Python's
+ SIGINT handler fires, and even though there may be other python
+ threads running, no one will know. Thus instead of directly waiting
+ in the thread that calls wait (which is likely to be the Python main
+ thread), we create a separate thread that does the blocking wait,
+ and then use the thread that called wait to do a slow poll of an
+ event queue. That thread, which is executing "wait" below is
+ interruptable, and if it sees a KeyboardInterrupt, executes a stop
+ on the top_block, then goes back to waiting for it to complete.
+ This ensures that the unlocked wait that was in progress (in the
+ _top_block_waiter thread) can complete, release its mutex and back
+ out. If we don't do that, we are never able to clean up, and nasty
+ things occur like leaving the USRP transmitter sending a carrier.
+
+ See also top_block.wait (below), which uses this class to implement
+ the interruptable wait.
+ """
def __init__(self, tb):
_threading.Thread.__init__(self)
self.setDaemon(1)
@@ -73,7 +71,7 @@ class _top_block_waiter(_threading.Thread):
#
-# This hack forces a 'has-a' relationship to look like an 'is-a' one.
+# This makes a 'has-a' relationship to look like an 'is-a' one.
#
# It allows Python classes to subclass this one, while passing through
# method calls to the C++ class shared pointer from SWIG.
@@ -84,91 +82,48 @@ class _top_block_waiter(_threading.Thread):
# to release the Python global interpreter lock before calling the actual
# method in gr_top_block
#
-class top_block(object):
+class top_block(hier_block2):
"""
Top-level hierarchical block representing a flow-graph.
This is a python wrapper around the C++ implementation to allow
python subclassing.
"""
- def __init__(self, name="top_block"):
- self._tb = top_block_swig(name)
- def __getattr__(self, name):
- if not hasattr(self, "_tb"):
- raise RuntimeError("top_block: invalid state--did you forget to call gr.top_block.__init__ in a derived class?")
- return getattr(self._tb, name)
+ def __init__(self, name="top_block"):
+ """
+ Create a top block with a given name.
+ """
+ # not calling hier_block2.__init__, we set our own _impl
+ self._impl = top_block_swig(name)
def start(self, max_noutput_items=10000000):
- top_block_start_unlocked(self._tb, max_noutput_items)
+ """
+ Start the flowgraph with the given number of output items and return.
+ """
+ top_block_start_unlocked(self._impl, max_noutput_items)
def stop(self):
- top_block_stop_unlocked(self._tb)
+ """
+ Stop the flowgraph
+ """
+ top_block_stop_unlocked(self._impl)
def run(self, max_noutput_items=10000000):
+ """
+ Start the flowgraph with the given number of output items and wait.
+ """
self.start(max_noutput_items)
self.wait()
def wait(self):
- _top_block_waiter(self._tb).wait()
-
-
- # FIXME: these are duplicated from hier_block2.py; they should really be implemented
- # in the original C++ class (gr_hier_block2), then they would all be inherited here
-
- def connect(self, *points):
- '''connect requires one or more arguments that can be coerced to endpoints.
- If more than two arguments are provided, they are connected together successively.
- '''
- if len (points) < 1:
- raise ValueError, ("connect requires at least one endpoint; %d provided." % (len (points),))
- else:
- if len(points) == 1:
- self._tb.primitive_connect(points[0].to_basic_block())
- else:
- for i in range (1, len (points)):
- self._connect(points[i-1], points[i])
-
- def msg_connect(self, src, srcport, dst, dstport):
- self.primitive_msg_connect(src.to_basic_block(), srcport, dst.to_basic_block(), dstport);
-
- def msg_disconnect(self, src, srcport, dst, dstport):
- self.primitive_msg_disconnect(src.to_basic_block(), srcport, dst.to_basic_block(), dstport);
-
- def _connect(self, src, dst):
- (src_block, src_port) = self._coerce_endpoint(src)
- (dst_block, dst_port) = self._coerce_endpoint(dst)
- self._tb.primitive_connect(src_block.to_basic_block(), src_port,
- dst_block.to_basic_block(), dst_port)
-
- def _coerce_endpoint(self, endp):
- if hasattr(endp, 'to_basic_block'):
- return (endp, 0)
- else:
- if hasattr(endp, "__getitem__") and len(endp) == 2:
- return endp # Assume user put (block, port)
- else:
- raise ValueError("unable to coerce endpoint")
-
- def disconnect(self, *points):
- '''disconnect requires one or more arguments that can be coerced to endpoints.
- If more than two arguments are provided, they are disconnected successively.
- '''
- if len (points) < 1:
- raise ValueError, ("disconnect requires at least one endpoint; %d provided." % (len (points),))
- else:
- if len(points) == 1:
- self._tb.primitive_disconnect(points[0].to_basic_block())
- else:
- for i in range (1, len (points)):
- self._disconnect(points[i-1], points[i])
-
- def _disconnect(self, src, dst):
- (src_block, src_port) = self._coerce_endpoint(src)
- (dst_block, dst_port) = self._coerce_endpoint(dst)
- self._tb.primitive_disconnect(src_block.to_basic_block(), src_port,
- dst_block.to_basic_block(), dst_port)
+ """
+ Wait for the flowgraph to finish running
+ """
+ _top_block_waiter(self._impl).wait()
def dot_graph(self):
- '''Return graph representation in dot language'''
- return dot_graph_tb(self._tb)
+ """
+ Return graph representation in dot language
+ """
+ return dot_graph_tb(self._impl)