summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Morman <jmorman@perspectalabs.com>2019-05-13 14:24:47 -0400
committerMartin Braun <martin.braun@ettus.com>2019-06-15 16:55:58 -0700
commit3ad584916c9fe2c1404dcd634d02eb85afd98337 (patch)
tree54480012d5a168bd3cf8d1db812d95b728d046f4
parent25b01217d191a419ff686bd9c59a11f4a3b7437d (diff)
blocks: replace blks2_selector with new implementation
blks2_selector was deprecated and finally removed This block implements the same functionality but in a way more similar to the Copy block fixes #2460
-rw-r--r--gr-blocks/examples/selector.grc369
-rw-r--r--gr-blocks/grc/blocks.tree.yml1
-rw-r--r--gr-blocks/grc/blocks_selector.block.yml93
-rw-r--r--gr-blocks/include/gnuradio/blocks/CMakeLists.txt1
-rw-r--r--gr-blocks/include/gnuradio/blocks/selector.h65
-rw-r--r--gr-blocks/lib/CMakeLists.txt1
-rw-r--r--gr-blocks/lib/selector_impl.cc143
-rw-r--r--gr-blocks/lib/selector_impl.h73
-rw-r--r--gr-blocks/python/blocks/qa_selector.py223
-rw-r--r--gr-blocks/swig/blocks_swig7.i3
10 files changed, 972 insertions, 0 deletions
diff --git a/gr-blocks/examples/selector.grc b/gr-blocks/examples/selector.grc
new file mode 100644
index 0000000000..99cc7b91ef
--- /dev/null
+++ b/gr-blocks/examples/selector.grc
@@ -0,0 +1,369 @@
+options:
+ parameters:
+ author: ''
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: top_block
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: top_block
+ window_size: ''
+ states:
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: freq
+ id: variable_qtgui_range
+ parameters:
+ comment: ''
+ gui_hint: (2,0,1,2)
+ label: ''
+ min_len: '200'
+ orient: Qt.Horizontal
+ rangeType: float
+ start: '0'
+ step: '1'
+ stop: samp_rate/4
+ value: '200'
+ widget: counter_slider
+ states:
+ coordinate: [448, 12.0]
+ rotation: 0
+ state: true
+- name: input_index
+ id: variable_qtgui_range
+ parameters:
+ comment: ''
+ gui_hint: (3,0,1,2)
+ label: ''
+ min_len: '200'
+ orient: Qt.Horizontal
+ rangeType: int
+ start: '0'
+ step: '1'
+ stop: '2'
+ value: '0'
+ widget: counter_slider
+ states:
+ coordinate: [584, 12.0]
+ rotation: 0
+ state: true
+- name: output_index
+ id: variable_qtgui_range
+ parameters:
+ comment: ''
+ gui_hint: (4,0,1,2)
+ label: ''
+ min_len: '200'
+ orient: Qt.Horizontal
+ rangeType: int
+ start: '0'
+ step: '1'
+ stop: '1'
+ value: '0'
+ widget: counter_slider
+ states:
+ coordinate: [696, 12.0]
+ rotation: 0
+ state: true
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: '32000'
+ states:
+ coordinate: [184, 12]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: freq
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ coordinate: [280, 84.0]
+ rotation: 0
+ state: true
+- name: analog_sig_source_x_1
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: freq
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_TRI_WAVE
+ states:
+ coordinate: [280, 204.0]
+ rotation: 0
+ state: true
+- name: analog_sig_source_x_2
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: freq
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_SAW_WAVE
+ states:
+ coordinate: [280, 324.0]
+ rotation: 0
+ state: true
+- name: blocks_selector_0
+ id: blocks_selector
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: "The Selector block passes \nsamples from the input selected\n by input_index\
+ \ to the output \nselected by output_index.\n\nOutputs != output_index \ndo\
+ \ not produce samples\n\nWhen Enabled is set to Off, \nno output samples are\
+ \ produced"
+ enabled: 'True'
+ input_index: input_index
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_inputs: '3'
+ num_outputs: '2'
+ output_index: output_index
+ showports: 'True'
+ type: complex
+ vlen: '1'
+ states:
+ coordinate: [560, 196.0]
+ rotation: 0
+ state: true
+- name: qtgui_time_sink_x_0
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ axislabels: 'True'
+ color1: blue
+ color10: blue
+ color2: green
+ color3: black
+ color4: cyan
+ color5: magenta
+ color6: yellow
+ color7: dark red
+ color8: dark green
+ color9: Dark Blue
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: (0,0,1,1)
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '1'
+ marker10: '1'
+ marker2: '1'
+ marker3: '1'
+ marker4: '1'
+ marker5: '1'
+ marker6: '1'
+ marker7: '1'
+ marker8: '1'
+ marker9: '1'
+ name: '"Output 0"'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: Amplitude
+ ymax: '1'
+ ymin: '-1'
+ yunit: '""'
+ states:
+ coordinate: [856, 108.0]
+ rotation: 0
+ state: true
+- name: qtgui_time_sink_x_1
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ axislabels: 'True'
+ color1: blue
+ color10: blue
+ color2: green
+ color3: black
+ color4: cyan
+ color5: magenta
+ color6: yellow
+ color7: dark red
+ color8: dark green
+ color9: Dark Blue
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'True'
+ gui_hint: (0,1,1,1)
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '1'
+ marker10: '1'
+ marker2: '1'
+ marker3: '1'
+ marker4: '1'
+ marker5: '1'
+ marker6: '1'
+ marker7: '1'
+ marker8: '1'
+ marker9: '1'
+ name: '"Output 1"'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: Amplitude
+ ymax: '1'
+ ymin: '-1'
+ yunit: '""'
+ states:
+ coordinate: [856, 252.0]
+ rotation: 0
+ state: true
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_selector_0, '0']
+- [analog_sig_source_x_1, '0', blocks_selector_0, '1']
+- [analog_sig_source_x_2, '0', blocks_selector_0, '2']
+- [blocks_selector_0, '0', qtgui_time_sink_x_0, '0']
+- [blocks_selector_0, '1', qtgui_time_sink_x_1, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-blocks/grc/blocks.tree.yml b/gr-blocks/grc/blocks.tree.yml
index ebe509ddc4..40108372c2 100644
--- a/gr-blocks/grc/blocks.tree.yml
+++ b/gr-blocks/grc/blocks.tree.yml
@@ -94,6 +94,7 @@
- blocks_null_source
- blocks_null_sink
- blocks_copy
+ - blocks_selector
- blocks_nop
- xmlrpc_server
- xmlrpc_client
diff --git a/gr-blocks/grc/blocks_selector.block.yml b/gr-blocks/grc/blocks_selector.block.yml
new file mode 100644
index 0000000000..5470c7d150
--- /dev/null
+++ b/gr-blocks/grc/blocks_selector.block.yml
@@ -0,0 +1,93 @@
+id: blocks_selector
+label: Selector
+flags: [ python, cpp ]
+
+parameters:
+- id: type
+ label: Type
+ dtype: enum
+ options: [complex, float, int, short, byte]
+ option_attributes:
+ size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short,
+ gr.sizeof_char]
+ hide: part
+- id: enabled
+ label: Enabled
+ dtype: bool
+ default: 'True'
+ options: ['True', 'False']
+ option_labels: [Enabled, Disabled]
+- id: num_inputs
+ label: Number of Inputs
+ dtype: int
+ default: 2
+- id: num_outputs
+ label: Number of Outputs
+ dtype: int
+ default: 2
+- id: input_index
+ label: Input Index
+ dtype: int
+ default: 0
+- id: output_index
+ label: Output Index
+ dtype: int
+ default: 0
+- id: vlen
+ label: Vec Length
+ dtype: int
+ default: '1'
+ hide: ${ 'part' if vlen == 1 else 'none' }
+- id: showports
+ label: Show Msg Ports
+ dtype: bool
+ default: 'True'
+ options: ['False', 'True']
+ option_labels: ['Yes', 'No']
+ hide: part
+
+inputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+ multiplicity: ${ num_inputs }
+- domain: message
+ id: en
+ optional: true
+ hide: ${ showports }
+
+outputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+ multiplicity: ${ num_outputs }
+
+asserts:
+- ${ vlen > 0 }
+
+templates:
+ imports: from gnuradio import blocks
+ make: |-
+ blocks.selector(${type.size}*${vlen},${input_index},${output_index})
+ self.${id}.set_enabled(${enabled})
+ callbacks:
+ - set_enabled(${enabled})
+ - set_input_index(${input_index})
+ - set_output_index(${output_index})
+
+cpp_templates:
+ includes: ['#include <gnuradio/blocks/copy.h>']
+ declarations: 'blocks::selector::sptr ${id};'
+ make: |-
+ this->${id} = blocks::selector::make(${type.size}*${vlen},${input_index},${output_index});
+ self->${id}.set_enabled(${enabled});
+ callbacks:
+ - set_enabled(${enabled})
+ - set_input_index(${input_index})
+ - set_output_index(${output_index})
+ translations:
+ gr.sizeof_: 'sizeof('
+ 'True': 'true'
+ 'False': 'false'
+
+file_format: 1
diff --git a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
index 4ea763b105..04d7a81af9 100644
--- a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
+++ b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
@@ -51,6 +51,7 @@ install(FILES
probe_signal_v.h
rotator.h
sample_and_hold.h
+ selector.h
sub.h
tsb_vector_sink.h
unpack_k_bits.h
diff --git a/gr-blocks/include/gnuradio/blocks/selector.h b/gr-blocks/include/gnuradio/blocks/selector.h
new file mode 100644
index 0000000000..6d347a21a6
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/selector.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 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.
+ */
+
+#ifndef INCLUDED_GR_SELECTOR_H
+#define INCLUDED_GR_SELECTOR_H
+
+#include <gnuradio/block.h>
+#include <gnuradio/blocks/api.h>
+
+namespace gr {
+namespace blocks {
+
+/*!
+ * \brief output[output_index][i] = input[input_index][i]
+ * \ingroup misc_blk
+ *
+ * \details
+ * Connect the sink at input index to the source at output index
+ * Samples from other input ports are consumed and dumped
+ * Other output ports produce no samples
+ *
+ */
+class BLOCKS_API selector : virtual public block
+{
+public:
+ typedef boost::shared_ptr<selector> sptr;
+
+ static sptr
+ make(size_t itemsize, unsigned int input_index, unsigned int output_index);
+
+ // When enabled is set to false, no output samples are produced
+ // Otherwise samples are copied to the selected output port
+ virtual void set_enabled(bool enable) = 0;
+ virtual bool enabled() const = 0;
+
+ virtual void set_input_index(unsigned int input_index) = 0;
+ virtual int input_index() const = 0;
+
+ virtual void set_output_index(unsigned int output_index) = 0;
+ virtual int output_index() const = 0;
+};
+
+} /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_SELECTOR_H */
diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt
index 7ee527d2fb..5ff174a8a8 100644
--- a/gr-blocks/lib/CMakeLists.txt
+++ b/gr-blocks/lib/CMakeLists.txt
@@ -46,6 +46,7 @@ add_library(gnuradio-blocks
probe_signal_impl.cc
probe_signal_v_impl.cc
sample_and_hold_impl.cc
+ selector_impl.cc
sub_impl.cc
tsb_vector_sink_impl.cc
unpacked_to_packed_impl.cc
diff --git a/gr-blocks/lib/selector_impl.cc b/gr-blocks/lib/selector_impl.cc
new file mode 100644
index 0000000000..dafb5f9096
--- /dev/null
+++ b/gr-blocks/lib/selector_impl.cc
@@ -0,0 +1,143 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "selector_impl.h"
+#include <gnuradio/io_signature.h>
+#include <string.h>
+#include <stdexcept>
+
+namespace gr {
+namespace blocks {
+
+selector::sptr
+selector::make(size_t itemsize, unsigned int input_index, unsigned int output_index)
+{
+ return gnuradio::get_initial_sptr(
+ new selector_impl(itemsize, input_index, output_index));
+}
+
+selector_impl::selector_impl(size_t itemsize,
+ unsigned int input_index,
+ unsigned int output_index)
+ : block("selector",
+ io_signature::make(1, -1, itemsize),
+ io_signature::make(1, -1, itemsize)),
+ d_itemsize(itemsize),
+ d_enabled(true),
+ d_input_index(input_index),
+ d_output_index(output_index),
+ d_num_inputs(0),
+ d_num_outputs(0)
+{
+ message_port_register_in(pmt::mp("en"));
+ set_msg_handler(pmt::mp("en"), [this](pmt::pmt_t msg) { this->handle_enable(msg); });
+
+ // TODO: add message ports for input_index and output_index
+}
+
+selector_impl::~selector_impl() {}
+
+void selector_impl::set_input_index(unsigned int input_index)
+{
+ gr::thread::scoped_lock l(d_mutex);
+ if (input_index < d_num_inputs)
+ d_input_index = input_index;
+ else
+ throw std::out_of_range("input_index must be < ninputs");
+}
+
+void selector_impl::set_output_index(unsigned int output_index)
+{
+ gr::thread::scoped_lock l(d_mutex);
+ if (output_index < d_num_outputs)
+ d_output_index = output_index;
+ else
+ throw std::out_of_range("output_index must be < noutputs");
+}
+
+void selector_impl::handle_enable(pmt::pmt_t msg)
+{
+ if (pmt::is_bool(msg)) {
+ bool en = pmt::to_bool(msg);
+ gr::thread::scoped_lock l(d_mutex);
+ d_enabled = en;
+ } else {
+ GR_LOG_WARN(d_logger,
+ "handle_enable: Non-PMT type received, expecting Boolean PMT");
+ }
+}
+
+void selector_impl::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;
+ }
+}
+
+bool selector_impl::check_topology(int ninputs, int noutputs)
+{
+ if ((int)d_input_index < ninputs && (int)d_output_index < noutputs) {
+ d_num_inputs = (unsigned int)ninputs;
+ d_num_outputs = (unsigned int)noutputs;
+ return true;
+ } else {
+ GR_LOG_WARN(d_logger,
+ "check_topology: Input or Output index greater than number of ports");
+ return false;
+ }
+}
+
+int selector_impl::general_work(int noutput_items,
+ gr_vector_int& ninput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ const uint8_t** in = (const uint8_t**)&input_items[0];
+ uint8_t** out = (uint8_t**)&output_items[0];
+
+ gr::thread::scoped_lock l(d_mutex);
+ if (d_enabled) {
+ std::copy(in[d_input_index],
+ in[d_input_index] + noutput_items * d_itemsize,
+ out[d_output_index]);
+ produce(d_output_index, noutput_items);
+ }
+
+ consume_each(noutput_items);
+ return WORK_CALLED_PRODUCE;
+}
+
+void selector_impl::setup_rpc()
+{
+#ifdef GR_CTRLPORT
+ add_rpc_variable(rpcbasic_sptr(new rpcbasic_register_handler<selector>(
+ alias(), "en", "", "Enable", RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+}
+
+} /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/selector_impl.h b/gr-blocks/lib/selector_impl.h
new file mode 100644
index 0000000000..e11068d805
--- /dev/null
+++ b/gr-blocks/lib/selector_impl.h
@@ -0,0 +1,73 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2019 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.
+ */
+
+#ifndef INCLUDED_GR_SELECTOR_IMPL_H
+#define INCLUDED_GR_SELECTOR_IMPL_H
+
+#include <gnuradio/blocks/selector.h>
+#include <gnuradio/thread/thread.h>
+
+namespace gr {
+namespace blocks {
+
+class selector_impl : public selector
+{
+private:
+ size_t d_itemsize;
+ bool d_enabled;
+ unsigned int d_input_index, d_output_index;
+ unsigned int d_num_inputs, d_num_outputs; // keep track of the topology
+
+ gr::thread::mutex d_mutex;
+
+
+public:
+ selector_impl(size_t itemsize, unsigned int input_index, unsigned int output_index);
+ ~selector_impl();
+
+ void forecast(int noutput_items, gr_vector_int& ninput_items_required);
+ bool check_topology(int ninputs, int noutputs);
+ void setup_rpc();
+ void handle_enable(pmt::pmt_t msg);
+ void set_enabled(bool enable)
+ {
+ gr::thread::scoped_lock l(d_mutex);
+ d_enabled = enable;
+ }
+ bool enabled() const { return d_enabled; }
+
+ void set_input_index(unsigned int input_index);
+ int input_index() const { return d_input_index; }
+
+ void set_output_index(unsigned int output_index);
+ int output_index() const { return d_output_index; }
+
+ int general_work(int noutput_items,
+ gr_vector_int& ninput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items);
+};
+
+} /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_SELECTOR_IMPL_H */
diff --git a/gr-blocks/python/blocks/qa_selector.py b/gr-blocks/python/blocks/qa_selector.py
new file mode 100644
index 0000000000..5bf01b593f
--- /dev/null
+++ b/gr-blocks/python/blocks/qa_selector.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 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.
+#
+
+
+from gnuradio import gr, gr_unittest, blocks
+
+
+class test_selector(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_select_same(self):
+ src_data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ expected_result = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ expected_drop = ()
+
+ num_inputs = 4; num_outputs = 4
+ input_index = 1; output_index = 2
+
+ op = blocks.selector(gr.sizeof_char, input_index, output_index)
+
+ src = []
+ dst = []
+ for ii in range(num_inputs):
+ src.append( blocks.vector_source_b(src_data))
+ self.tb.connect(src[ii], (op,ii))
+ for jj in range(num_outputs):
+ dst.append(blocks.vector_sink_b())
+ self.tb.connect((op,jj),dst[jj])
+
+
+ self.tb.run()
+
+ dst_data = dst[output_index].data()
+
+ self.assertEqual(expected_result, dst_data)
+
+
+ def test_select_input(self):
+
+ num_inputs = 4; num_outputs = 4
+ input_index = 1; output_index = 2
+
+ op = blocks.selector(gr.sizeof_char, input_index, output_index)
+
+ src = []
+ dst = []
+ for ii in range(num_inputs):
+ src_data = [ii+1]*10
+ src.append( blocks.vector_source_b(src_data))
+ self.tb.connect(src[ii], (op,ii))
+ for jj in range(num_outputs):
+ dst.append(blocks.vector_sink_b())
+ self.tb.connect((op,jj),dst[jj])
+
+
+ self.tb.run()
+
+ expected_result = [input_index+1]*10
+ dst_data = list(dst[output_index].data())
+
+ self.assertEqual(expected_result, dst_data)
+
+ def test_dump(self):
+
+ num_inputs = 4; num_outputs = 4
+ input_index = 1; output_index = 2
+ output_not_selected = 3
+
+ op = blocks.selector(gr.sizeof_char, input_index, output_index)
+
+ src = []
+ dst = []
+ for ii in range(num_inputs):
+ src_data = [ii+1]*10
+ src.append( blocks.vector_source_b(src_data))
+ self.tb.connect(src[ii], (op,ii))
+ for jj in range(num_outputs):
+ dst.append(blocks.vector_sink_b())
+ self.tb.connect((op,jj),dst[jj])
+
+
+ self.tb.run()
+
+ expected_result = []
+ dst_data = list(dst[output_not_selected].data())
+
+ self.assertEqual(expected_result, dst_data)
+
+ def test_not_enabled (self):
+ src_data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ expected_result = ()
+
+ num_inputs = 4; num_outputs = 4
+ input_index = 1; output_index = 2
+
+ op = blocks.selector(gr.sizeof_char, input_index, output_index)
+ op.set_enabled(False)
+
+ src = []
+ dst = []
+ for ii in range(num_inputs):
+ src.append( blocks.vector_source_b(src_data))
+ self.tb.connect(src[ii], (op,ii))
+ for jj in range(num_outputs):
+ dst.append(blocks.vector_sink_b())
+ self.tb.connect((op,jj),dst[jj])
+
+
+ self.tb.run()
+
+ dst_data = dst[output_index].data()
+ self.assertEqual(expected_result, dst_data)
+
+
+ # These tests cannot be run as set_index can only be called after check_topology is called
+ # def test_set_indices(self):
+
+ # num_inputs = 4; num_outputs = 4
+ # input_index = 1; output_index = 2
+
+ # op = blocks.selector(gr.sizeof_char, 0, 0)
+
+
+ # src = []
+ # dst = []
+ # for ii in range(num_inputs):
+ # src_data = [ii+1]*10
+ # src.append( blocks.vector_source_b(src_data))
+ # self.tb.connect(src[ii], (op,ii))
+ # for jj in range(num_outputs):
+ # dst.append(blocks.vector_sink_b())
+ # self.tb.connect((op,jj),dst[jj])
+
+ # op.set_input_index(input_index)
+ # op.set_output_index(output_index)
+
+ # self.tb.run()
+
+ # expected_result = [input_index+1]*10
+ # dst_data = list(dst[output_index].data())
+
+ # self.assertEqual(expected_result, dst_data)
+
+ # def test_dont_set_indices(self):
+
+ # num_inputs = 4; num_outputs = 4
+ # input_index = 1; output_index = 2
+
+ # op = blocks.selector(gr.sizeof_char, 0, 0)
+ # #op.set_input_index(input_index)
+ # #op.set_output_index(output_index)
+
+ # src = []
+ # dst = []
+ # for ii in range(num_inputs):
+ # src_data = [ii+1]*10
+ # src.append( blocks.vector_source_b(src_data))
+ # self.tb.connect(src[ii], (op,ii))
+ # for jj in range(num_outputs):
+ # dst.append(blocks.vector_sink_b())
+ # self.tb.connect((op,jj),dst[jj])
+
+
+ # self.tb.run()
+
+ # expected_result = [input_index+1]*10
+ # dst_data = list(dst[output_index].data())
+
+ # self.assertNotEqual(expected_result, dst_data)
+
+ def test_float_vector(self):
+
+ num_inputs = 4; num_outputs = 4
+ input_index = 1; output_index = 2
+
+ veclen = 3
+
+ op = blocks.selector(gr.sizeof_float*veclen, input_index, output_index)
+
+ src = []
+ dst = []
+ for ii in range(num_inputs):
+ src_data = [float(ii)+1]*10*veclen
+ src.append( blocks.vector_source_f(src_data, repeat=False, vlen=veclen))
+ self.tb.connect(src[ii], (op,ii))
+ for jj in range(num_outputs):
+ dst.append(blocks.vector_sink_f(vlen=veclen))
+ self.tb.connect((op,jj),dst[jj])
+
+
+ self.tb.run()
+
+ expected_result = [float(input_index)+1]*10*veclen
+ dst_data = list(dst[output_index].data())
+
+ self.assertEqual(expected_result, dst_data)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_selector)
diff --git a/gr-blocks/swig/blocks_swig7.i b/gr-blocks/swig/blocks_swig7.i
index 6314873b71..bb888dfbb2 100644
--- a/gr-blocks/swig/blocks_swig7.i
+++ b/gr-blocks/swig/blocks_swig7.i
@@ -34,6 +34,7 @@
#include "gnuradio/blocks/deinterleave.h"
#include "gnuradio/blocks/divide.h"
#include "gnuradio/blocks/exponentiate_const_cci.h"
+#include "gnuradio/blocks/selector.h"
#include "gnuradio/blocks/skiphead.h"
#include "gnuradio/blocks/stream_mux.h"
#include "gnuradio/blocks/stream_to_streams.h"
@@ -50,6 +51,7 @@
%include "gnuradio/blocks/deinterleave.h"
%include "gnuradio/blocks/divide.h"
%include "gnuradio/blocks/exponentiate_const_cci.h"
+%include "gnuradio/blocks/selector.h"
%include "gnuradio/blocks/skiphead.h"
%include "gnuradio/blocks/stream_mux.h"
%include "gnuradio/blocks/stream_to_streams.h"
@@ -68,6 +70,7 @@ GR_SWIG_BLOCK_MAGIC2_TMPL(blocks, divide_ss, divide<std::int16_t>);
GR_SWIG_BLOCK_MAGIC2_TMPL(blocks, divide_ii, divide<std::int32_t>);
GR_SWIG_BLOCK_MAGIC2_TMPL(blocks, divide_cc, divide<gr_complex>);
GR_SWIG_BLOCK_MAGIC2(blocks, exponentiate_const_cci);
+GR_SWIG_BLOCK_MAGIC2(blocks, selector);
GR_SWIG_BLOCK_MAGIC2(blocks, skiphead);
GR_SWIG_BLOCK_MAGIC2(blocks, stream_mux);
GR_SWIG_BLOCK_MAGIC2(blocks, stream_to_streams);