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_io_signature.h>
28 #include <gr_runtime.h>
32 #define GR_HIER_BLOCK2_DETAIL_DEBUG 0
34 gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
37 d_fg(gr_make_flowgraph()),
38 d_inputs(owner->input_signature()->max_streams()),
39 d_outputs(owner->output_signature()->max_streams()),
44 gr_hier_block2_detail::~gr_hier_block2_detail()
46 d_owner = 0; // Don't use delete, we didn't allocate
50 gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port,
51 gr_basic_block_sptr dst, int dst_port)
53 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
54 std::cout << "connecting: " << gr_endpoint(src, src_port)
55 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
57 if (src.get() == dst.get())
58 throw std::invalid_argument("src and destination blocks cannot be the same");
60 gr_hier_block2_sptr src_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(src));
61 gr_hier_block2_sptr dst_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(dst));
63 if (src_block && src.get() != d_owner) {
64 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
65 std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl;
66 src_block->d_detail->d_parent_detail = this;
69 if (dst_block && dst.get() != d_owner) {
70 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
71 std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl;
72 dst_block->d_detail->d_parent_detail = this;
75 // Connections to block inputs or outputs
77 if (src.get() == d_owner) {
78 max_port = src->input_signature()->max_streams();
79 if ((max_port != -1 && (src_port >= max_port)) || src_port < 0)
80 throw std::invalid_argument("source port out of range");
81 return connect_input(src_port, dst_port, dst);
84 if (dst.get() == d_owner) {
85 max_port = dst->output_signature()->max_streams();
86 if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0)
87 throw std::invalid_argument("source port out of range");
88 return connect_output(dst_port, src_port, src);
91 // Internal connections
92 d_fg->connect(src, src_port, dst, dst_port);
94 // TODO: connects to NC
98 gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port,
99 gr_basic_block_sptr dst, int dst_port)
101 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
102 std::cout << "disconnecting: " << gr_endpoint(src, src_port)
103 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
105 if (src.get() == dst.get())
106 throw std::invalid_argument("src and destination blocks cannot be the same");
108 gr_hier_block2_sptr src_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(src));
109 gr_hier_block2_sptr dst_block(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(dst));
111 if (src_block && src.get() != d_owner) {
112 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
113 std::cout << "connect: src is hierarchical, clearing parent" << std::endl;
114 src_block->d_detail->d_parent_detail = 0;
117 if (dst_block && dst.get() != d_owner) {
118 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
119 std::cout << "connect: dst is hierarchical, clearing parent" << std::endl;
120 dst_block->d_detail->d_parent_detail = 0;
123 if (src.get() == d_owner)
124 return disconnect_input(src_port, dst_port, dst);
126 if (dst.get() == d_owner)
127 return disconnect_output(dst_port, src_port, src);
129 // Internal connections
130 d_fg->disconnect(src, src_port, dst, dst_port);
134 gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block)
136 if (my_port < 0 || my_port >= (signed)d_inputs.size())
137 throw std::invalid_argument("input port number out of range");
139 if (d_inputs[my_port].block())
140 throw std::invalid_argument("input port in use");
142 d_inputs[my_port] = gr_endpoint(block, port);
146 gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block)
148 if (my_port < 0 || my_port >= (signed)d_outputs.size())
149 throw std::invalid_argument("output port number out of range");
151 if (d_outputs[my_port].block())
152 throw std::invalid_argument("output port in use");
154 d_outputs[my_port] = gr_endpoint(block, port);
158 gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block)
160 if (my_port < 0 || my_port >= (signed)d_inputs.size())
161 throw std::invalid_argument("input port number out of range");
163 if (d_inputs[my_port].block() != block)
164 throw std::invalid_argument("block not assigned to given input, can't disconnect");
166 d_inputs[my_port] = gr_endpoint();
170 gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block)
172 if (my_port < 0 || my_port >= (signed)d_outputs.size())
173 throw std::invalid_argument("input port number out of range");
175 if (d_outputs[my_port].block() != block)
176 throw std::invalid_argument("block not assigned to given output, can't disconnect");
178 d_outputs[my_port] = gr_endpoint();
182 gr_hier_block2_detail::resolve_port(int port, bool is_input)
184 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
185 std::cout << "Resolving port " << port << " as an "
186 << (is_input ? "input" : "output")
187 << " of " << d_owner->name() << std::endl;
192 if (port < 0 || port >= (signed)d_inputs.size())
193 throw std::runtime_error("input port number out of range");
194 result = resolve_endpoint(d_inputs[port], true);
197 if (port < 0 || port >= (signed)d_outputs.size())
198 throw std::runtime_error("output port number out of range");
199 result = resolve_endpoint(d_outputs[port], false);
203 throw std::runtime_error("unable to resolve port");
209 gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input)
211 // Check if endpoint is a leaf node
212 if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(endp.block()))
215 // Check if endpoint is a hierarchical block
216 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(endp.block()));
218 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
219 std::cout << "Resolving endpoint " << endp << " as an "
220 << (is_input ? "input" : "output")
221 << ", recursing" << std::endl;
222 return hier_block2->d_detail->resolve_port(endp.port(), is_input);
225 // Shouldn't ever get here
226 throw std::runtime_error("block is not a valid gr_block or gr_hier_block2!");
230 gr_hier_block2_detail::flatten(gr_flat_flowgraph_sptr sfg)
232 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
233 std::cout << "flattening " << d_owner->name() << std::endl;
235 // Add my edges to the flow graph, resolving references to actual endpoints
236 gr_edge_vector_t edges = d_fg->edges();
238 for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
239 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
240 std::cout << "Flattening edge " << (*p) << std::endl;
242 gr_endpoint src_endp = resolve_endpoint(p->src(), false);
243 gr_endpoint dst_endp = resolve_endpoint(p->dst(), true);
244 sfg->connect(src_endp, dst_endp);
247 gr_basic_block_vector_t blocks = d_fg->calc_used_blocks();
249 // Recurse hierarchical children
250 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
251 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(*p));
253 hier_block2->d_detail->flatten(sfg);
258 gr_hier_block2_detail::lock()
260 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
261 std::cout << "lock: entered in " << this << std::endl;
264 d_parent_detail->lock();
271 gr_hier_block2_detail::unlock()
273 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
274 std::cout << "unlock: entered in " << this << std::endl;
277 d_parent_detail->unlock();