2 * Copyright 2006 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 2, 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>
32 gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
37 gr_hier_block2_detail::~gr_hier_block2_detail()
39 d_owner = 0; // Don't use delete, we didn't allocate
43 gr_hier_block2_detail::lookup_block(const std::string &name)
45 gr_hier_component_miter_t p = d_components.find(name);
46 if (p != d_components.end())
49 return gr_basic_block_sptr();
53 gr_hier_block2_detail::define_component(const std::string &name, gr_basic_block_sptr block)
56 throw std::invalid_argument("null block passed");
59 throw std::invalid_argument("name is reserved");
61 // TODO: reject names with '.' inside
63 if (!lookup_block(name))
64 d_components[name] = block;
66 throw std::invalid_argument("name already in use");
70 gr_hier_block2_detail::connect(const std::string &src_name, int src_port,
71 const std::string &dst_name, int dst_port)
73 gr_io_signature_sptr src_io_signature;
74 gr_io_signature_sptr dst_io_signature;
76 // Check against our *input_signature* if we're wiring from one of our external inputs
77 if (src_name == "self")
78 src_io_signature = d_owner->input_signature();
80 gr_basic_block_sptr src_block = lookup_block(src_name);
82 throw std::invalid_argument("undefined src name");
83 src_io_signature = src_block->output_signature();
86 // Check against our *output_signature* if we're wiring to one of our external outputs
87 if (dst_name == "self")
88 dst_io_signature = d_owner->output_signature();
90 gr_basic_block_sptr dst_block = lookup_block(dst_name);
92 throw std::invalid_argument("undefined dst name");
93 dst_io_signature = dst_block->input_signature();
96 // Check port numbers are valid
97 check_valid_port(src_io_signature, src_port);
98 check_valid_port(dst_io_signature, dst_port);
100 // Check destination port not already in use
101 check_dst_not_used(dst_name, dst_port);
103 // Check endpoint types match
104 check_type_match(src_io_signature, src_port, dst_io_signature, dst_port);
106 d_edges.push_back(gr_make_edge(src_name, src_port, dst_name, dst_port));
110 gr_hier_block2_detail::check_valid_port(gr_io_signature_sptr sig, int port)
113 throw std::invalid_argument("port number must not be negative");
115 if (sig->max_streams() >= 0 && port >= sig->max_streams())
116 throw std::invalid_argument("port number exceeds max streams");
120 gr_hier_block2_detail::check_dst_not_used(const std::string name, int port)
122 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
123 if ((*p)->dst_name() == name && (*p)->dst_port() == port)
124 throw std::invalid_argument("destination port in use");
128 gr_hier_block2_detail::check_type_match(gr_io_signature_sptr src_sig, int src_port,
129 gr_io_signature_sptr dst_sig, int dst_port)
131 if (src_sig->sizeof_stream_item(src_port) != dst_sig->sizeof_stream_item(dst_port))
132 throw std::invalid_argument("type mismatch");
136 gr_hier_block2_detail::prepend_prefix(const std::string &prefix, const std::string &str)
138 return prefix + ((prefix == "") ? "" : ".") + str;
142 gr_hier_block2_detail::match_endpoint(const std::string &name, int port, bool is_input)
144 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
146 if ((*p)->src_name() == name && (*p)->src_port() == port)
147 return resolve_endpoint((*p)->dst_name(), (*p)->dst_port(), "", !is_input);
150 if ((*p)->dst_name() == name && (*p)->dst_port() == port)
151 return resolve_endpoint((*p)->src_name(), (*p)->src_port(), "", !is_input);
155 // Should never get here
156 throw std::runtime_error("unable to match endpoint");
160 gr_hier_block2_detail::resolve_endpoint(const std::string &name, int port,
161 const std::string &prefix, bool is_input)
163 gr_basic_block_sptr basic_block = lookup_block(name);
165 // Check if 'name' points to gr_block (leaf node)
166 gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(basic_block));
168 return gr_endpoint(prepend_prefix(prefix, name), port);
170 // Check if 'name' points to hierarchical block
171 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(basic_block));
173 std::string child_prefix = prepend_prefix(prefix, name);
174 gr_endpoint match(hier_block2->d_detail->match_endpoint("self", port, !is_input));
175 return gr_endpoint(prepend_prefix(child_prefix, match.name()), match.port());
178 // Shouldn't ever get here
179 throw std::runtime_error("unable to resolve endpoint");
183 gr_hier_block2_detail::flatten(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
185 flatten_components(sfg, prefix);
186 flatten_edges(sfg, prefix);
190 gr_hier_block2_detail::flatten_components(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
192 // Add my non-hierarchical components to the simple flowgraph, then recurse
193 for (gr_hier_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
194 std::string name = prepend_prefix(prefix, p->first);
196 gr_basic_block_sptr basic_block = p->second;
197 gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(basic_block));
199 sfg->define_component(name, block);
201 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(basic_block));
203 hier_block2->d_detail->flatten_components(sfg, name);
208 gr_hier_block2_detail::flatten_edges(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
210 // Add my edges to the flow graph, resolving references to actual endpoints
211 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
212 // Connections to self get resolved/added by parent if actually connected
213 if ((*p)->src_name() == "self" || (*p)->dst_name() == "self")
216 gr_endpoint src_endp = resolve_endpoint((*p)->src_name(), (*p)->src_port(), prefix, true);
217 gr_endpoint dst_endp = resolve_endpoint((*p)->dst_name(), (*p)->dst_port(), prefix, false);
218 sfg->connect(src_endp.name(), src_endp.port(), dst_endp.name(), dst_endp.port());
221 // Recurse hierarchical children
222 for (gr_hier_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
223 gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(p->second));
225 hier_block2->d_detail->flatten_edges(sfg, prepend_prefix(prefix, p->first));