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>
31 #define GR_HIER_BLOCK2_DETAIL_DEBUG 0
33 gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
36 d_fg(gr_make_flowgraph()),
37 d_inputs(owner->input_signature()->max_streams()),
38 d_outputs(owner->output_signature()->max_streams())
42 gr_hier_block2_detail::~gr_hier_block2_detail()
44 d_owner = 0; // Don't use delete, we didn't allocate
48 gr_hier_block2_detail::connect(gr_basic_block_sptr block)
50 std::stringstream msg;
53 if (std::find(d_blocks.begin(), d_blocks.end(), block) != d_blocks.end()) {
54 msg << "Block " << block << " already connected.";
55 throw std::invalid_argument(msg.str());
58 // Check if has inputs or outputs
59 if (block->input_signature()->max_streams() != 0 ||
60 block->output_signature()->max_streams() != 0) {
61 msg << "Block " << block << " must not have any input or output ports";
62 throw std::invalid_argument(msg.str());
65 d_blocks.push_back(block);
69 gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port,
70 gr_basic_block_sptr dst, int dst_port)
72 std::stringstream msg;
74 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
75 std::cout << "connecting: " << gr_endpoint(src, src_port)
76 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
78 if (src.get() == dst.get())
79 throw std::invalid_argument("connect: src and destination blocks cannot be the same");
81 gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src));
82 gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst));
84 if (src_block && src.get() != d_owner) {
85 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
86 std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl;
87 src_block->d_detail->d_parent_detail = this;
90 if (dst_block && dst.get() != d_owner) {
91 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
92 std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl;
93 dst_block->d_detail->d_parent_detail = this;
96 // Connections to block inputs or outputs
98 if (src.get() == d_owner) {
99 max_port = src->input_signature()->max_streams();
100 if ((max_port != -1 && (src_port >= max_port)) || src_port < 0) {
101 msg << "source port " << src_port << " out of range for " << src;
102 throw std::invalid_argument(msg.str());
105 return connect_input(src_port, dst_port, dst);
108 if (dst.get() == d_owner) {
109 max_port = dst->output_signature()->max_streams();
110 if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0) {
111 msg << "destination port " << dst_port << " out of range for " << dst;
112 throw std::invalid_argument(msg.str());
115 return connect_output(dst_port, src_port, src);
118 // Internal connections
119 d_fg->connect(src, src_port, dst, dst_port);
121 // TODO: connects to NC
125 gr_hier_block2_detail::disconnect(gr_basic_block_sptr block)
127 for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
134 std::stringstream msg;
135 msg << "cannot disconnect block " << block << ", not found";
136 throw std::invalid_argument(msg.str());
140 gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port,
141 gr_basic_block_sptr dst, int dst_port)
143 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
144 std::cout << "disconnecting: " << gr_endpoint(src, src_port)
145 << " -> " << gr_endpoint(dst, dst_port) << std::endl;
147 if (src.get() == dst.get())
148 throw std::invalid_argument("disconnect: source and destination blocks cannot be the same");
150 gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src));
151 gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst));
153 if (src_block && src.get() != d_owner) {
154 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
155 std::cout << "connect: src is hierarchical, clearing parent" << std::endl;
156 src_block->d_detail->d_parent_detail = 0;
159 if (dst_block && dst.get() != d_owner) {
160 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
161 std::cout << "connect: dst is hierarchical, clearing parent" << std::endl;
162 dst_block->d_detail->d_parent_detail = 0;
165 if (src.get() == d_owner)
166 return disconnect_input(src_port, dst_port, dst);
168 if (dst.get() == d_owner)
169 return disconnect_output(dst_port, src_port, src);
171 // Internal connections
172 d_fg->disconnect(src, src_port, dst, dst_port);
175 // FIXME: ticket:161 will be implemented here
177 gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block)
179 std::stringstream msg;
181 if (my_port < 0 || my_port >= (signed)d_inputs.size()) {
182 msg << "input port " << my_port << " out of range for " << block;
183 throw std::invalid_argument(msg.str());
186 if (d_inputs[my_port].block()) {
187 msg << "external input port " << my_port << " already wired to "
188 << d_inputs[my_port];
189 throw std::invalid_argument(msg.str());
192 d_inputs[my_port] = gr_endpoint(block, port);
196 gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block)
198 std::stringstream msg;
200 if (my_port < 0 || my_port >= (signed)d_outputs.size()) {
201 msg << "output port " << my_port << " out of range for " << block;
202 throw std::invalid_argument(msg.str());
205 if (d_outputs[my_port].block()) {
206 msg << "external output port " << my_port << " already connected from "
207 << d_outputs[my_port];
208 throw std::invalid_argument(msg.str());
211 d_outputs[my_port] = gr_endpoint(block, port);
215 gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block)
217 std::stringstream msg;
219 if (my_port < 0 || my_port >= (signed)d_inputs.size()) {
220 msg << "input port number " << my_port << " out of range for " << block;
221 throw std::invalid_argument(msg.str());
224 if (d_inputs[my_port].block() != block) {
225 msg << "block " << block << " not assigned to input "
226 << my_port << ", can't disconnect";
227 throw std::invalid_argument(msg.str());
230 d_inputs[my_port] = gr_endpoint();
234 gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block)
236 std::stringstream msg;
238 if (my_port < 0 || my_port >= (signed)d_outputs.size()) {
239 msg << "output port number " << my_port << " out of range for " << block;
240 throw std::invalid_argument(msg.str());
243 if (d_outputs[my_port].block() != block) {
244 msg << "block " << block << " not assigned to output "
245 << my_port << ", can't disconnect";
246 throw std::invalid_argument(msg.str());
249 d_outputs[my_port] = gr_endpoint();
253 gr_hier_block2_detail::resolve_port(int port, bool is_input)
255 std::stringstream msg;
257 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
258 std::cout << "Resolving port " << port << " as an "
259 << (is_input ? "input" : "output")
260 << " of " << d_owner->name() << std::endl;
265 if (port < 0 || port >= (signed)d_inputs.size()) {
266 msg << "resolve_port: input " << port << " is out of range";
267 throw std::runtime_error(msg.str());
270 result = resolve_endpoint(d_inputs[port], true);
273 if (port < 0 || port >= (signed)d_outputs.size()) {
274 msg << "resolve_port: output " << port << " is out of range";
275 throw std::runtime_error(msg.str());
278 result = resolve_endpoint(d_outputs[port], false);
281 if (!result.block()) {
282 msg << "unable to resolve "
283 << (is_input ? "input port " : "output port ")
285 throw std::runtime_error(msg.str());
292 gr_hier_block2_detail::disconnect_all()
301 gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) const
303 std::stringstream msg;
305 // Check if endpoint is a leaf node
306 if (cast_to_block_sptr(endp.block()))
309 // Check if endpoint is a hierarchical block
310 gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(endp.block()));
312 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
313 std::cout << "Resolving endpoint " << endp << " as an "
314 << (is_input ? "input" : "output")
315 << ", recursing" << std::endl;
316 return hier_block2->d_detail->resolve_port(endp.port(), is_input);
319 msg << "unable to resolve" << (is_input ? " input " : " output ")
320 << "endpoint " << endp;
321 throw std::runtime_error(msg.str());
325 gr_hier_block2_detail::flatten_aux(gr_flat_flowgraph_sptr sfg) const
327 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
328 std::cout << "flattening " << d_owner->name() << std::endl;
330 // Add my edges to the flow graph, resolving references to actual endpoints
331 gr_edge_vector_t edges = d_fg->edges();
333 for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
334 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
335 std::cout << "Flattening edge " << (*p) << std::endl;
337 gr_endpoint src_endp = resolve_endpoint(p->src(), false);
338 gr_endpoint dst_endp = resolve_endpoint(p->dst(), true);
339 sfg->connect(src_endp, dst_endp);
342 // Construct unique list of blocks used either in edges or
343 // by themselves. I hate STL.
344 gr_basic_block_vector_t blocks, tmp = d_fg->calc_used_blocks();
345 std::insert_iterator<gr_basic_block_vector_t> inserter(blocks, blocks.begin());
346 std::vector<gr_basic_block_sptr>::const_iterator p; // Because flatten_aux is const
347 for (p = d_blocks.begin(); p != d_blocks.end(); p++)
349 sort(tmp.begin(), tmp.end());
350 unique_copy(tmp.begin(), tmp.end(), inserter);
352 // Recurse hierarchical children
353 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
354 gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(*p));
356 hier_block2->d_detail->flatten_aux(sfg);
361 gr_hier_block2_detail::lock()
363 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
364 std::cout << "lock: entered in " << this << std::endl;
367 d_parent_detail->lock();
373 gr_hier_block2_detail::unlock()
375 if (GR_HIER_BLOCK2_DETAIL_DEBUG)
376 std::cout << "unlock: entered in " << this << std::endl;
379 d_parent_detail->unlock();