2 * Copyright 2006,2007 Free Software Foundation, Inc.
4 * This file is part of GNU Radio
6 * GNU Radio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
11 * GNU Radio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Radio; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street,
19 * Boston, MA 02110-1301, USA.
26 #include <gr_hier_block2_detail.h>
27 #include <gr_simple_flowgraph.h>
28 #include <gr_io_signature.h>
29 #include <gr_runtime.h>
33 #define GR_HIER_BLOCK2_DETAIL_DEBUG 0
35 gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
38 d_fg(gr_make_simple_flowgraph()),
39 d_inputs(owner->input_signature()->max_streams()),
40 d_outputs(owner->output_signature()->max_streams()),
45 gr_hier_block2_detail::~gr_hier_block2_detail()
47 d_owner = 0; // Don't use delete, we didn't allocate
51 gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port,
52 gr_basic_block_sptr dst, int dst_port)
54 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
55 std::cout << "connecting: " << gr_endpoint(src, src_port)
56 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
58 if (src.get() == dst.get())
59 throw std::invalid_argument("src and destination blocks cannot be the same");
61 gr_hier_block2_sptr src_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(src));
62 gr_hier_block2_sptr dst_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(dst));
64 if (src_block && src.get() != d_owner) {
65 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
66 std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl;
67 src_block->d_detail->d_parent_detail = this;
70 if (dst_block && dst.get() != d_owner) {
71 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
72 std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl;
73 dst_block->d_detail->d_parent_detail = this;
76 // Connections to block inputs or outputs
78 if (src.get() == d_owner) {
79 max_port = src->input_signature()->max_streams();
80 if ((max_port != -1 && (src_port >= max_port)) || src_port < 0)
81 throw std::invalid_argument("source port out of range");
82 return connect_input(src_port, dst_port, dst);
85 if (dst.get() == d_owner) {
86 max_port = dst->output_signature()->max_streams();
87 if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0)
88 throw std::invalid_argument("source port out of range");
89 return connect_output(dst_port, src_port, src);
92 // Internal connections
93 d_fg->connect(src, src_port, dst, dst_port);
95 // TODO: connects to NC
99 gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port,
100 gr_basic_block_sptr dst, int dst_port)
102 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
103 std::cout << "disconnecting: " << gr_endpoint(src, src_port)
104 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
106 if (src.get() == dst.get())
107 throw std::invalid_argument("src and destination blocks cannot be the same");
109 gr_hier_block2_sptr src_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(src));
110 gr_hier_block2_sptr dst_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(dst));
112 if (src_block && src.get() != d_owner) {
113 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
114 std::cout << "connect: src is hierarchical, clearing parent" << std::endl;
115 src_block->d_detail->d_parent_detail = 0;
118 if (dst_block && dst.get() != d_owner) {
119 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
120 std::cout << "connect: dst is hierarchical, clearing parent" << std::endl;
121 dst_block->d_detail->d_parent_detail = 0;
124 if (src.get() == d_owner)
125 return disconnect_input(src_port, dst_port, dst);
127 if (dst.get() == d_owner)
128 return disconnect_output(dst_port, src_port, src);
130 // Internal connections
131 d_fg->disconnect(src, src_port, dst, dst_port);
135 gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block)
137 if (my_port < 0 || my_port >= (signed)d_inputs.size())
138 throw std::invalid_argument("input port number out of range");
140 if (d_inputs[my_port].block())
141 throw std::invalid_argument("input port in use");
143 d_inputs[my_port] = gr_endpoint(block, port);
147 gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block)
149 if (my_port < 0 || my_port >= (signed)d_outputs.size())
150 throw std::invalid_argument("output port number out of range");
152 if (d_outputs[my_port].block())
153 throw std::invalid_argument("output port in use");
155 d_outputs[my_port] = gr_endpoint(block, port);
159 gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block)
161 if (my_port < 0 || my_port >= (signed)d_inputs.size())
162 throw std::invalid_argument("input port number out of range");
164 if (d_inputs[my_port].block() != block)
165 throw std::invalid_argument("block not assigned to given input, can't disconnect");
167 d_inputs[my_port] = gr_endpoint();
171 gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block)
173 if (my_port < 0 || my_port >= (signed)d_outputs.size())
174 throw std::invalid_argument("input port number out of range");
176 if (d_outputs[my_port].block() != block)
177 throw std::invalid_argument("block not assigned to given output, can't disconnect");
179 d_outputs[my_port] = gr_endpoint();
183 gr_hier_block2_detail::resolve_port(int port, bool is_input)
185 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
186 std::cout << "Resolving port " << port << " as an "
187 << (is_input ? "input" : "output")
188 << " of " << d_owner->name() << std::endl;
193 if (port < 0 || port >= (signed)d_inputs.size())
194 throw std::runtime_error("input port number out of range");
195 result = resolve_endpoint(d_inputs[port], true);
198 if (port < 0 || port >= (signed)d_outputs.size())
199 throw std::runtime_error("output port number out of range");
200 result = resolve_endpoint(d_outputs[port], false);
204 throw std::runtime_error("unable to resolve port");
210 gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input)
212 // Check if endpoint is a leaf node
213 if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(endp.block()))
216 // Check if endpoint is a hierarchical block
217 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(endp.block()));
219 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
220 std::cout << "Resolving endpoint " << endp << " as an "
221 << (is_input ? "input" : "output")
222 << ", recursing" << std::endl;
223 return hier_block2->d_detail->resolve_port(endp.port(), is_input);
226 // Shouldn't ever get here
227 throw std::runtime_error("block is not a valid gr_block or gr_hier_block2!");
231 gr_hier_block2_detail::flatten(gr_simple_flowgraph_sptr sfg)
233 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
234 std::cout << "flattening " << d_owner->name() << std::endl;
236 // Add my edges to the flow graph, resolving references to actual endpoints
237 for (gr_edge_viter_t p = d_fg->d_detail->d_edges.begin(); p != d_fg->d_detail->d_edges.end(); p++) {
238 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
239 std::cout << "Flattening edge " << (*p) << std::endl;
241 gr_endpoint src_endp = resolve_endpoint((*p)->src(), false);
242 gr_endpoint dst_endp = resolve_endpoint((*p)->dst(), true);
243 sfg->connect(src_endp, dst_endp);
246 gr_basic_block_vector_t blocks = d_fg->d_detail->calc_used_blocks();
248 // Recurse hierarchical children
249 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
250 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(*p));
252 hier_block2->d_detail->flatten(sfg);
257 gr_hier_block2_detail::lock()
259 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
260 std::cout << "lock: entered in " << this << std::endl;
263 d_parent_detail->lock();
270 gr_hier_block2_detail::unlock()
272 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
273 std::cout << "unlock: entered in " << this << std::endl;
276 d_parent_detail->unlock();