diff --git a/grc/foo_selector.xml b/grc/foo_selector.xml
new file mode 100644
index 0000000..fdddccd
--- /dev/null
+++ b/grc/foo_selector.xml
@@ -0,0 +1,92 @@
+
+
+ Selector
+ foo_selector
+ [Foo]
+ import foo
+ foo.selector(
+ item_size=$type.size*$vlen,
+ num_inputs=$num_inputs,
+ num_outputs=$num_outputs,
+ input_index=$input_index,
+ output_index=$output_index,
+)
+ set_input_index(int($input_index))
+ set_output_index(int($output_index))
+
+ Type
+ type
+ enum
+
+
+
+
+
+
+
+ Num Inputs
+ num_inputs
+ 2
+ int
+
+
+ Num Outputs
+ num_outputs
+ 2
+ int
+
+
+ Input Index
+ input_index
+ 0
+ int
+
+
+ Output Index
+ output_index
+ 0
+ int
+
+
+ Vec Length
+ vlen
+ 1
+ int
+
+ $vlen > 0
+
+ in
+ $type
+ $vlen
+ $num_inputs
+
+
+ out
+ $type
+ $vlen
+ $num_outputs
+
+
+Connect the sink at input index to the source at output index. Leave all other ports disconnected.
+
+
diff --git a/grc/foo_valve.xml b/grc/foo_valve.xml
new file mode 100644
index 0000000..c1c94e7
--- /dev/null
+++ b/grc/foo_valve.xml
@@ -0,0 +1,67 @@
+
+
+ Valve
+ foo_valve
+ [Foo]
+ import foo
+ foo.valve(item_size=$type.size*$vlen, open=bool($open))
+ set_open(bool($open))
+
+ Type
+ type
+ enum
+
+
+
+
+
+
+
+ Open
+ open
+ 0
+ raw
+
+
+ Vec Length
+ vlen
+ 1
+ int
+
+ $vlen > 0
+
+ in
+ $type
+ $vlen
+ $num_inputs
+
+
+ out
+ $type
+ $vlen
+ $num_outputs
+
+
+Connect output to input when valve is closed (not open).
+
+
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 0e4f1b3..a14a510 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -31,6 +31,7 @@ endif()
GR_PYTHON_INSTALL(
FILES
__init__.py
+ selector.py
DESTINATION ${GR_PYTHON_DIR}/foo
)
diff --git a/python/__init__.py b/python/__init__.py
index 1be5feb..1ce4a83 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -43,6 +43,7 @@ if _RTLD_GLOBAL != 0:
# import swig generated symbols into the foo namespace
from foo_swig import *
+from selector import *
# import any pure python here
#
diff --git a/python/selector.py b/python/selector.py
new file mode 100644
index 0000000..fd175e8
--- /dev/null
+++ b/python/selector.py
@@ -0,0 +1,144 @@
+#
+# Copyright 2017 Bastian Bloessl
+#
+# 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.
+
+from gnuradio import gr
+from gnuradio import blocks
+
+class selector(gr.hier_block2):
+ """A hier2 block with N inputs and M outputs, where data is only forwarded through input n to output m."""
+ def __init__(self, item_size, num_inputs, num_outputs, input_index, output_index):
+ """
+ Selector constructor.
+
+ Args:
+ item_size: the size of the gr data stream in bytes
+ num_inputs: the number of inputs (integer)
+ num_outputs: the number of outputs (integer)
+ input_index: the index for the source data
+ output_index: the index for the destination data
+ """
+ gr.hier_block2.__init__(
+ self, 'selector',
+ gr.io_signature(num_inputs, num_inputs, item_size),
+ gr.io_signature(num_outputs, num_outputs, item_size),
+ )
+
+ print "Warning: the blks2.selector block is deprecated."
+
+ #terminator blocks for unused inputs and outputs
+ self.input_terminators = [blocks.null_sink(item_size) for i in range(num_inputs)]
+ self.output_terminators = [blocks.head(item_size, 0) for i in range(num_outputs)]
+ self.copy = blocks.copy(item_size)
+ #connections
+ for i in range(num_inputs): self.connect((self, i), self.input_terminators[i])
+ for i in range(num_outputs): self.connect(blocks.null_source(item_size),
+ self.output_terminators[i], (self, i))
+ self.item_size = item_size
+ self.input_index = input_index
+ self.output_index = output_index
+ self.num_inputs = num_inputs
+ self.num_outputs = num_outputs
+ self._connect_current()
+
+ def _indexes_valid(self):
+ """
+ Are the input and output indexes within range of the number of inputs and outputs?
+
+ Returns:
+ true if input index and output index are in range
+ """
+ return self.input_index in range(self.num_inputs) and self.output_index in range(self.num_outputs)
+
+ def _connect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from their terminators,
+ and connect them to one another. Then connect the terminators to one another."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index), self.input_terminators[self.input_index])
+ self.disconnect(self.output_terminators[self.output_index], (self, self.output_index))
+ self.connect((self, self.input_index), self.copy)
+ self.connect(self.copy, (self, self.output_index))
+ self.connect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
+
+ def _disconnect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from one another,
+ and the terminators at the input and output index from one another.
+ Reconnect the blocks to the terminators."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index), self.copy)
+ self.disconnect(self.copy, (self, self.output_index))
+ self.disconnect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
+ self.connect((self, self.input_index), self.input_terminators[self.input_index])
+ self.connect(self.output_terminators[self.output_index], (self, self.output_index))
+
+ def set_input_index(self, input_index):
+ """
+ Change the block to the new input index if the index changed.
+
+ Args:
+ input_index: the new input index
+ """
+ if self.input_index != input_index:
+ self.lock()
+ self._disconnect_current()
+ self.input_index = input_index
+ self._connect_current()
+ self.unlock()
+
+ def set_output_index(self, output_index):
+ """
+ Change the block to the new output index if the index changed.
+
+ Args:
+ output_index: the new output index
+ """
+ if self.output_index != output_index:
+ self.lock()
+ self._disconnect_current()
+ self.output_index = output_index
+ self._connect_current()
+ self.unlock()
+
+class valve(selector):
+ """Wrapper for selector with 1 input and 1 output."""
+
+ def __init__(self, item_size, open):
+ """
+ Constructor for valve.
+
+ Args:
+ item_size: the size of the gr data stream in bytes
+ open: true if initial valve state is open
+ """
+ if open: output_index = -1
+ else: output_index = 0
+ selector.__init__(self, item_size, 1, 1, 0, output_index)
+
+ print "Warning: the blks2.valve block is deprecated."
+
+ def set_open(self, open):
+ """
+ Callback to set open state.
+
+ Args:
+ open: true to set valve state to open
+ """
+ if open: output_index = -1
+ else: output_index = 0
+ self.set_output_index(output_index)