diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2014-12-10 15:42:46 +0100 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2014-12-10 16:10:19 +0100 |
commit | 94a93636ea33685a22e673934006f96cff0c29aa (patch) | |
tree | dfd73a4deff3baed2a2486f1b68c73dd9b0c3b11 /gnuradio-runtime/python/gnuradio/gr/top_block.py | |
parent | 57728315c8d49457006e1a6fce5cc213b97de61b (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.py | 149 |
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) |