summaryrefslogtreecommitdiff
path: root/gnuradio-runtime/python/gnuradio/gr/gateway.py
diff options
context:
space:
mode:
authorJeff Long <willcode4@gmail.com>2018-02-11 21:00:51 -0500
committerMarcus Müller <mueller@kit.edu>2018-02-21 19:42:46 +0100
commitba63bd46e3a79d4312a16d9d35f918aa4cfa67db (patch)
tree654ef222a4e3f097145708d666dcd95027dd3e8a /gnuradio-runtime/python/gnuradio/gr/gateway.py
parent76f8abeb0e88ff4063909f0f502cf7cfe22e5640 (diff)
python gateway: permit a variable number of ports
C++ block in/out ports are described by io_signature, which holds the min number of ports, max number of ports, and a list of type lengths. If len(type lengths) < max number of ports, the last type is assumed to apply to the remaining ports. When a flowgraph is built, a variable number of ports can be connected. Python block ports are specified using a list of numpy types. The number of ports is fixed in the block specification, and the flowgraph must connect exactly that number of ports. This patch changes the Python behavior (while maintaining backward compatibility) to match the C++ behavior. A new py_io_signature class is used to specify port number limits, along with a list of numpy types, like this: in_sig = gr.py_io_signature(2, -1, ['float32', 'float32']) where in_sig is passed to the block super's __init__ as before.
Diffstat (limited to 'gnuradio-runtime/python/gnuradio/gr/gateway.py')
-rw-r--r--gnuradio-runtime/python/gnuradio/gr/gateway.py89
1 files changed, 63 insertions, 26 deletions
diff --git a/gnuradio-runtime/python/gnuradio/gr/gateway.py b/gnuradio-runtime/python/gnuradio/gr/gateway.py
index 8403421dd5..fe9a77bcc4 100644
--- a/gnuradio-runtime/python/gnuradio/gr/gateway.py
+++ b/gnuradio-runtime/python/gnuradio/gr/gateway.py
@@ -1,5 +1,5 @@
#
-# Copyright 2011-2012 Free Software Foundation, Inc.
+# Copyright 2011-2012, 2018 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -78,35 +78,61 @@ class msg_handler(gr.feval_p):
return 0
########################################################################
+# io_signature for Python
+########################################################################
+class py_io_signature(object):
+
+ # Minimum and maximum number of ports, and a list of numpy types.
+ def __init__(self, min_ports, max_ports, type_list):
+ self.__min_ports = min_ports
+ self.__max_ports = max_ports
+ self.__types = map(numpy.dtype, type_list)
+
+ # Make/return a gr.io_signature. A non-empty list of sizes is
+ # required, even if there are no ports.
+ def gr_io_signature(self):
+ return io_signaturev(self.__min_ports, self.__max_ports,
+ [t.itemsize for t in self.__types] or [0])
+
+ # Return data types for the first nports ports. If nports is
+ # smaller than the provided type list, return a truncated list. If
+ # larger, fill with the last type.
+ def port_types(self, nports):
+ ntypes = len(self.__types)
+ if ntypes == 0:
+ return []
+ if nports <= ntypes:
+ return self.__types[:nports]
+ return self.__types + [self.__types[-1]]*(nports-ntypes)
+
+########################################################################
# The guts that make this into a gr block
########################################################################
class gateway_block(object):
def __init__(self, name, in_sig, out_sig, work_type, factor):
- #ensure that the sigs are iterable dtypes
- def sig_to_dtype_sig(sig):
- if sig is None: sig = ()
- return map(numpy.dtype, sig)
- self.__in_sig = sig_to_dtype_sig(in_sig)
- self.__out_sig = sig_to_dtype_sig(out_sig)
+ # Normalize the many Python ways of saying 'nothing' to '[]'
+ in_sig = in_sig or []
+ out_sig = out_sig or []
- #cache the ranges to iterate when dispatching work
- self.__in_indexes = range(len(self.__in_sig))
- self.__out_indexes = range(len(self.__out_sig))
-
- #convert the signatures into gr.io_signatures
- def sig_to_gr_io_sigv(sig):
- if not len(sig): return io_signature(0, 0, 0)
- return io_signaturev(len(sig), len(sig), [s.itemsize for s in sig])
- gr_in_sig = sig_to_gr_io_sigv(self.__in_sig)
- gr_out_sig = sig_to_gr_io_sigv(self.__out_sig)
+ # Backward compatibility: array of type strings -> py_io_signature
+ if type(in_sig) is py_io_signature:
+ self.__in_sig = in_sig
+ else:
+ self.__in_sig = py_io_signature(len(in_sig), len(in_sig), in_sig)
+ if type(out_sig) is py_io_signature:
+ self.__out_sig = out_sig
+ else:
+ self.__out_sig = py_io_signature(len(out_sig), len(out_sig), out_sig)
#create internal gateway block
self.__handler = gateway_handler()
self.__handler.init(self.__gr_block_handle)
self.__gateway = block_gateway(
- self.__handler, name, gr_in_sig, gr_out_sig, work_type, factor)
+ self.__handler, name,
+ self.__in_sig.gr_io_signature(), self.__out_sig.gr_io_signature(),
+ work_type, factor)
self.__message = self.__gateway.block_message()
#dict to keep references to all message handlers
@@ -128,36 +154,47 @@ class gateway_block(object):
"""
Dispatch tasks according to the action type specified in the message.
"""
+
if self.__message.action == gr.block_gw_message_type.ACTION_GENERAL_WORK:
+ # Actual number of inputs/output from scheduler
+ ninputs = len(self.__message.general_work_args_input_items)
+ noutputs = len(self.__message.general_work_args_output_items)
+ in_types = self.__in_sig.port_types(ninputs)
+ out_types = self.__out_sig.port_types(noutputs)
self.__message.general_work_args_return_value = self.general_work(
input_items=[pointer_to_ndarray(
self.__message.general_work_args_input_items[i],
- self.__in_sig[i],
+ in_types[i],
self.__message.general_work_args_ninput_items[i]
- ) for i in self.__in_indexes],
+ ) for i in xrange(ninputs)],
output_items=[pointer_to_ndarray(
self.__message.general_work_args_output_items[i],
- self.__out_sig[i],
+ out_types[i],
self.__message.general_work_args_noutput_items
- ) for i in self.__out_indexes],
+ ) for i in xrange(noutputs)],
)
elif self.__message.action == gr.block_gw_message_type.ACTION_WORK:
+ # Actual number of inputs/output from scheduler
+ ninputs = len(self.__message.work_args_input_items)
+ noutputs = len(self.__message.work_args_output_items)
+ in_types = self.__in_sig.port_types(ninputs)
+ out_types = self.__out_sig.port_types(noutputs)
self.__message.work_args_return_value = self.work(
input_items=[pointer_to_ndarray(
self.__message.work_args_input_items[i],
- self.__in_sig[i],
+ in_types[i],
self.__message.work_args_ninput_items
- ) for i in self.__in_indexes],
+ ) for i in xrange(ninputs)],
output_items=[pointer_to_ndarray(
self.__message.work_args_output_items[i],
- self.__out_sig[i],
+ out_types[i],
self.__message.work_args_noutput_items
- ) for i in self.__out_indexes],
+ ) for i in xrange(noutputs)],
)
elif self.__message.action == gr.block_gw_message_type.ACTION_FORECAST: