From 77bfe4faccd79741b49e0dee3bb0a21bd21da53f Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sun, 19 Apr 2009 20:45:40 +0000 Subject: [PATCH] Merged r10875:10880 from jcorgan/t161 into trunk. Implements ticket:161, allowing multiple internal blocks to be connected to a hier_block2 external input. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10881 221aa14e-8319-0410-a670-987f0aec2ac5 --- .../src/lib/runtime/gr_hier_block2_detail.cc | 86 ++++++++++++------- .../src/lib/runtime/gr_hier_block2_detail.h | 12 +-- .../src/python/gnuradio/gr/qa_hier_block2.py | 54 +++++++++--- gr-wxgui/src/python/fftsink_gl.py | 3 +- gr-wxgui/src/python/scopesink_gl.py | 5 +- gr-wxgui/src/python/waterfallsink_gl.py | 3 +- 6 files changed, 108 insertions(+), 55 deletions(-) diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc index d85d2674..fa52b742 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc @@ -49,7 +49,7 @@ gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) : throw std::runtime_error(msg.str()); } - d_inputs = gr_endpoint_vector_t(max_inputs); + d_inputs = std::vector(max_inputs); d_outputs = gr_endpoint_vector_t(max_outputs); } @@ -222,7 +222,6 @@ gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port, d_fg->disconnect(src, src_port, dst, dst_port); } -// FIXME: ticket:161 will be implemented here void gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block) { @@ -233,13 +232,16 @@ gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr throw std::invalid_argument(msg.str()); } - if (d_inputs[my_port].block()) { - msg << "external input port " << my_port << " already wired to " - << d_inputs[my_port]; + gr_endpoint_vector_t &endps = d_inputs[my_port]; + gr_endpoint endp(block, port); + + gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if (p != endps.end()) { + msg << "external input port " << my_port << " already wired to " << endp; throw std::invalid_argument(msg.str()); } - - d_inputs[my_port] = gr_endpoint(block, port); + + endps.push_back(endp); } void @@ -271,13 +273,16 @@ gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sp throw std::invalid_argument(msg.str()); } - if (d_inputs[my_port].block() != block) { - msg << "block " << block << " not assigned to input " - << my_port << ", can't disconnect"; + gr_endpoint_vector_t &endps = d_inputs[my_port]; + gr_endpoint endp(block, port); + + gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if (p == endps.end()) { + msg << "external input port " << my_port << " not connected to " << endp; throw std::invalid_argument(msg.str()); } - - d_inputs[my_port] = gr_endpoint(); + + endps.erase(p); } void @@ -299,7 +304,7 @@ gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_s d_outputs[my_port] = gr_endpoint(); } -gr_endpoint +gr_endpoint_vector_t gr_hier_block2_detail::resolve_port(int port, bool is_input) { std::stringstream msg; @@ -309,7 +314,7 @@ gr_hier_block2_detail::resolve_port(int port, bool is_input) << (is_input ? "input" : "output") << " of " << d_owner->name() << std::endl; - gr_endpoint result; + gr_endpoint_vector_t result; if (is_input) { if (port < 0 || port >= (signed)d_inputs.size()) { @@ -317,13 +322,18 @@ gr_hier_block2_detail::resolve_port(int port, bool is_input) throw std::runtime_error(msg.str()); } - if (d_inputs[port] == gr_endpoint()) { + if (d_inputs[port].empty()) { msg << "hierarchical block '" << d_owner->name() << "' input " << port << " is not connected internally"; throw std::runtime_error(msg.str()); } - result = resolve_endpoint(d_inputs[port], true); + gr_endpoint_vector_t &endps = d_inputs[port]; + gr_endpoint_viter_t p; + for (p = endps.begin(); p != endps.end(); p++) { + gr_endpoint_vector_t tmp = resolve_endpoint(*p, true); + std::copy(tmp.begin(), tmp.end(), back_inserter(result)); + } } else { if (port < 0 || port >= (signed)d_outputs.size()) { @@ -340,7 +350,7 @@ gr_hier_block2_detail::resolve_port(int port, bool is_input) result = resolve_endpoint(d_outputs[port], false); } - if (!result.block()) { + if (result.empty()) { msg << "unable to resolve " << (is_input ? "input port " : "output port ") << port; @@ -359,16 +369,18 @@ gr_hier_block2_detail::disconnect_all() d_outputs.clear(); } -gr_endpoint +gr_endpoint_vector_t gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) const { std::stringstream msg; + gr_endpoint_vector_t result; // Check if endpoint is a leaf node if (cast_to_block_sptr(endp.block())) { if (GR_HIER_BLOCK2_DETAIL_DEBUG) std::cout << "Block " << endp.block() << " is a leaf node, returning." << std::endl; - return endp; + result.push_back(endp); + return result; } // Check if endpoint is a hierarchical block @@ -394,33 +406,41 @@ gr_hier_block2_detail::flatten_aux(gr_flat_flowgraph_sptr sfg) const // Add my edges to the flow graph, resolving references to actual endpoints gr_edge_vector_t edges = d_fg->edges(); - - for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { + gr_edge_viter_t p; + + for (p = edges.begin(); p != edges.end(); p++) { if (GR_HIER_BLOCK2_DETAIL_DEBUG) std::cout << "Flattening edge " << (*p) << std::endl; - gr_endpoint src_endp = resolve_endpoint(p->src(), false); - gr_endpoint dst_endp = resolve_endpoint(p->dst(), true); + gr_endpoint_vector_t src_endps = resolve_endpoint(p->src(), false); + gr_endpoint_vector_t dst_endps = resolve_endpoint(p->dst(), true); - if (GR_HIER_BLOCK2_DETAIL_DEBUG) { - std::cout << "src_endp = " << src_endp - << ", dst_endp = " << dst_endp << std::endl; + gr_endpoint_viter_t s, d; + for (s = src_endps.begin(); s != src_endps.end(); s++) { + for (d = dst_endps.begin(); d != dst_endps.end(); d++) { + if (GR_HIER_BLOCK2_DETAIL_DEBUG) + std::cout << (*s) << "->" << (*d) << std::endl; + sfg->connect(*s, *d); + } } - sfg->connect(src_endp, dst_endp); } // Construct unique list of blocks used either in edges, inputs, // outputs, or by themselves. I still hate STL. gr_basic_block_vector_t blocks, tmp = d_fg->calc_used_blocks(); - std::vector::const_iterator p; // Because flatten_aux is const - for (p = d_blocks.begin(); p != d_blocks.end(); p++) - tmp.push_back(*p); + std::vector::const_iterator b; // Because flatten_aux is const + for (b = d_blocks.begin(); b != d_blocks.end(); b++) + tmp.push_back(*b); + + std::vector::const_iterator ep; // Because flatten_aux is const + std::vector::const_iterator e; // Because flatten_aux is const + + for (ep = d_inputs.begin(); ep != d_inputs.end(); ep++) + for (e = (*ep).begin(); e != (*ep).end(); e++) + tmp.push_back((*e).block()); - std::vector::const_iterator e; // Because flatten_aux is const - for (e = d_inputs.begin(); e != d_inputs.end(); e++) - tmp.push_back((*e).block()); for (e = d_outputs.begin(); e != d_outputs.end(); e++) tmp.push_back((*e).block()); diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h index d31ae93e..0e1f89fb 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h @@ -1,5 +1,6 @@ +/* -*- c++ -*- */ /* - * Copyright 2006,2007 Free Software Foundation, Inc. + * Copyright 2006,2007,2009 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -48,16 +49,17 @@ private: gr_hier_block2 *d_owner; gr_hier_block2_detail *d_parent_detail; gr_flowgraph_sptr d_fg; - gr_endpoint_vector_t d_inputs; - gr_endpoint_vector_t d_outputs; + std::vector d_inputs; // Multiple internal endpoints per external input + gr_endpoint_vector_t d_outputs; // Single internal endpoint per external output gr_basic_block_vector_t d_blocks; void connect_input(int my_port, int port, gr_basic_block_sptr block); void connect_output(int my_port, int port, gr_basic_block_sptr block); void disconnect_input(int my_port, int port, gr_basic_block_sptr block); void disconnect_output(int my_port, int port, gr_basic_block_sptr block); - gr_endpoint resolve_port(int port, bool is_input); - gr_endpoint resolve_endpoint(const gr_endpoint &endp, bool is_input) const; + + gr_endpoint_vector_t resolve_port(int port, bool is_input); + gr_endpoint_vector_t resolve_endpoint(const gr_endpoint &endp, bool is_input) const; }; #endif /* INCLUDED_GR_HIER_BLOCK2_DETAIL_H */ diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py index 36739961..8fa3d4af 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py @@ -27,16 +27,6 @@ class test_hier_block2(gr_unittest.TestCase): nop1 = gr.nop(gr.sizeof_int) hblock.connect(hblock, nop1) - def test_003_connect_input_in_use(self): - hblock = gr.hier_block2("test_block", - gr.io_signature(1,1,gr.sizeof_int), - gr.io_signature(1,1,gr.sizeof_int)) - nop1 = gr.nop(gr.sizeof_int) - nop2 = gr.nop(gr.sizeof_int) - hblock.connect(hblock, nop1) - self.assertRaises(ValueError, - lambda: hblock.connect(hblock, nop2)) - def test_004_connect_output(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), @@ -289,6 +279,50 @@ class test_hier_block2(gr_unittest.TestCase): hb2.connect(hb2, gr.kludge_copy(gr.sizeof_char), dst) tb.run() self.assertEquals(dst.data(), (1,)) + + def test_031_multiple_internal_inputs(self): + tb = gr.top_block() + src = gr.vector_source_f([1.0,]) + hb = gr.hier_block2("hb", + gr.io_signature(1, 1, gr.sizeof_float), + gr.io_signature(1, 1, gr.sizeof_float)) + m1 = gr.multiply_const_ff(1.0) + m2 = gr.multiply_const_ff(2.0) + add = gr.add_ff() + hb.connect(hb, m1) # m1 is connected to hb external input #0 + hb.connect(hb, m2) # m2 is also connected to hb external input #0 + hb.connect(m1, (add, 0)) + hb.connect(m2, (add, 1)) + hb.connect(add, hb) # add is connected to hb external output #0 + dst = gr.vector_sink_f() + tb.connect(src, hb, dst) + tb.run() + self.assertEquals(dst.data(), (3.0,)) + + def test_032_nested_multiple_internal_inputs(self): + tb = gr.top_block() + src = gr.vector_source_f([1.0,]) + hb = gr.hier_block2("hb", + gr.io_signature(1, 1, gr.sizeof_float), + gr.io_signature(1, 1, gr.sizeof_float)) + hb2 = gr.hier_block2("hb", + gr.io_signature(1, 1, gr.sizeof_float), + gr.io_signature(1, 1, gr.sizeof_float)) + + m1 = gr.multiply_const_ff(1.0) + m2 = gr.multiply_const_ff(2.0) + add = gr.add_ff() + hb2.connect(hb2, m1) # m1 is connected to hb2 external input #0 + hb2.connect(hb2, m2) # m2 is also connected to hb2 external input #0 + hb2.connect(m1, (add, 0)) + hb2.connect(m2, (add, 1)) + hb2.connect(add, hb2) # add is connected to hb2 external output #0 + hb.connect(hb, hb2, hb) # hb as hb2 as nested internal block + dst = gr.vector_sink_f() + tb.connect(src, hb, dst) + tb.run() + self.assertEquals(dst.data(), (3.0,)) + if __name__ == "__main__": gr_unittest.main() diff --git a/gr-wxgui/src/python/fftsink_gl.py b/gr-wxgui/src/python/fftsink_gl.py index 30ebd3fd..3f0a93fc 100644 --- a/gr-wxgui/src/python/fftsink_gl.py +++ b/gr-wxgui/src/python/fftsink_gl.py @@ -63,7 +63,6 @@ class _fft_sink_base(gr.hier_block2): gr.io_signature(0, 0, 0), ) #blocks - copy = gr.kludge_copy(self._item_size) fft = self._fft_chain( sample_rate=sample_rate, fft_size=fft_size, @@ -75,7 +74,7 @@ class _fft_sink_base(gr.hier_block2): msgq = gr.msg_queue(2) sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True) #connect - self.connect(self, copy, fft, sink) + self.connect(self, fft, sink) #controller self.controller = pubsub() self.controller.subscribe(AVERAGE_KEY, fft.set_average) diff --git a/gr-wxgui/src/python/scopesink_gl.py b/gr-wxgui/src/python/scopesink_gl.py index 6e9ff832..b4ae0f33 100644 --- a/gr-wxgui/src/python/scopesink_gl.py +++ b/gr-wxgui/src/python/scopesink_gl.py @@ -42,13 +42,12 @@ class ac_couple_block(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_float), ) #blocks - copy = gr.kludge_copy(gr.sizeof_float) lpf = gr.single_pole_iir_filter_ff(0.0) sub = gr.sub_ff() mute = gr.mute_ff() #connect - self.connect(self, copy, sub, self) - self.connect(copy, lpf, mute, (sub, 1)) + self.connect(self, sub, self) + self.connect(self, lpf, mute, (sub, 1)) #subscribe controller.subscribe(ac_couple_key, lambda x: mute.set_mute(not x)) controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(2.0/x)) diff --git a/gr-wxgui/src/python/waterfallsink_gl.py b/gr-wxgui/src/python/waterfallsink_gl.py index 344640af..91c1c7eb 100644 --- a/gr-wxgui/src/python/waterfallsink_gl.py +++ b/gr-wxgui/src/python/waterfallsink_gl.py @@ -63,7 +63,6 @@ class _waterfall_sink_base(gr.hier_block2): gr.io_signature(0, 0, 0), ) #blocks - copy = gr.kludge_copy(self._item_size) fft = self._fft_chain( sample_rate=sample_rate, fft_size=fft_size, @@ -75,7 +74,7 @@ class _waterfall_sink_base(gr.hier_block2): msgq = gr.msg_queue(2) sink = gr.message_sink(gr.sizeof_float*fft_size, msgq, True) #connect - self.connect(self, copy, fft, sink) + self.connect(self, fft, sink) #controller self.controller = pubsub() self.controller.subscribe(AVERAGE_KEY, fft.set_average) -- 2.30.2