3 * Copyright 2006,2007 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
27 #include <gr_simple_flowgraph.h>
28 #include <gr_simple_flowgraph_detail.h>
29 #include <gr_io_signature.h>
30 #include <gr_block_detail.h>
31 #include <gr_buffer.h>
36 gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst)
38 return gr_edge_sptr(new gr_edge(src, dst));
45 gr_simple_flowgraph_detail::~gr_simple_flowgraph_detail()
50 gr_simple_flowgraph_detail::reset()
52 // Boost shared pointers will deallocate as needed
58 gr_simple_flowgraph_detail::connect(const gr_endpoint &src, const gr_endpoint &dst)
60 check_valid_port(src.block()->output_signature(), src.port());
61 check_valid_port(dst.block()->input_signature(), dst.port());
62 check_dst_not_used(dst);
63 check_type_match(src, dst);
64 d_edges.push_back(gr_make_edge(src,dst));
68 gr_simple_flowgraph_detail::disconnect(const gr_endpoint &src, const gr_endpoint &dst)
70 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
71 if (src.block() == (*p)->src().block() && src.port() == (*p)->src().port() &&
72 dst.block() == (*p)->dst().block() && dst.port() == (*p)->dst().port()) {
78 throw std::invalid_argument("edge to disconnect not found");
82 gr_simple_flowgraph_detail::check_valid_port(gr_io_signature_sptr sig, int port)
85 throw std::invalid_argument("negative port number");
86 if (sig->max_streams() >= 0 && port >= sig->max_streams())
87 throw std::invalid_argument("port number exceeds max");
91 gr_simple_flowgraph_detail::check_dst_not_used(const gr_endpoint &dst)
93 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
94 if ((*p)->dst().block() == dst.block() &&
95 (*p)->dst().port() == dst.port())
96 throw std::invalid_argument("dst already in use");
100 gr_simple_flowgraph_detail::check_type_match(const gr_endpoint &src, const gr_endpoint &dst)
102 int src_size = src.block()->output_signature()->sizeof_stream_item(src.port());
103 int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port());
105 if (src_size != dst_size)
106 throw std::invalid_argument("type size mismatch while attempting to connect");
110 gr_simple_flowgraph_detail::validate()
112 d_blocks = calc_used_blocks();
114 for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
115 std::vector<int> used_ports;
116 int ninputs, noutputs;
118 used_ports = calc_used_ports(*p, true); // inputs
119 ninputs = used_ports.size();
120 check_contiguity(*p, used_ports, true); // inputs
122 used_ports = calc_used_ports(*p, false); // outputs
123 noutputs = used_ports.size();
124 check_contiguity(*p, used_ports, false); // outputs
126 if (!((*p)->check_topology(ninputs, noutputs)))
127 throw std::runtime_error("check topology failed");
132 gr_simple_flowgraph_detail::calc_used_ports(gr_basic_block_sptr block, bool check_inputs)
134 std::vector<int> tmp, result;
135 std::insert_iterator<std::vector<int> > inserter(result, result.begin());
137 gr_edge_vector_t edges = calc_connections(block, check_inputs);
138 for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
139 if (check_inputs == true)
140 tmp.push_back((*p)->dst().port());
142 tmp.push_back((*p)->src().port());
146 std::sort(tmp.begin(), tmp.end());
147 std::unique_copy(tmp.begin(), tmp.end(), inserter);
152 gr_simple_flowgraph_detail::calc_connections(gr_basic_block_sptr block, bool check_inputs)
154 gr_edge_vector_t result;
156 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
158 if ((*p)->dst().block() == block)
159 result.push_back(*p);
162 if ((*p)->src().block() == block)
163 result.push_back(*p);
167 return result; // assumes no duplicates
171 gr_simple_flowgraph_detail::check_contiguity(gr_basic_block_sptr block,
172 const std::vector<int> &used_ports,
175 gr_io_signature_sptr sig =
176 check_inputs ? block->input_signature() : block->output_signature();
178 int nports = used_ports.size();
179 int min_ports = sig->min_streams();
185 throw std::runtime_error("insufficient ports");
188 if (used_ports[nports-1]+1 != nports) {
189 for (int i = 0; i < nports; i++)
190 if (used_ports[i] != i)
191 throw std::runtime_error("missing input assignment");
196 gr_simple_flowgraph_detail::setup_connections()
198 // Assign block details to blocks
199 for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
200 int ninputs = calc_used_ports(*p, true).size();
201 int noutputs = calc_used_ports(*p, false).size();
202 gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
203 for (int i = 0; i < noutputs; i++)
204 detail->set_output(i, allocate_buffer(*p, i));
206 boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->set_detail(detail);
209 // Connect inputs to outputs for each block
210 for(gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
211 gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p));
213 throw std::runtime_error("setup_connections found non-gr_block");
215 // Get its detail and edges that feed into it
216 gr_block_detail_sptr detail = grblock->detail();
217 gr_edge_vector_t in_edges = calc_upstream_edges(*p);
219 // For each edge that feeds into it
220 for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
221 // Set the input reader on the destination port to the output
222 // buffer on the source port
223 int dst_port = (*e)->dst().port();
224 int src_port = (*e)->src().port();
225 gr_basic_block_sptr src_block = (*e)->src().block();
226 gr_block_sptr src_grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(src_block));
228 throw std::runtime_error("setup_connections found non-gr_block");
229 gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port);
231 detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1));
237 gr_simple_flowgraph_detail::allocate_buffer(gr_basic_block_sptr block, int port)
239 gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block));
241 throw std::runtime_error("allocate_buffer found non-gr_block");
242 int item_size = block->output_signature()->sizeof_stream_item(port);
243 int nitems = s_fixed_buffer_size/item_size;
245 // Make sure there are at least twice the output_multiple no. of items
246 if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple()
247 nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically
249 // If any downstream blocks are decimators and/or have a large output_multiple,
250 // ensure we have a buffer at least twice their decimation factor*output_multiple
251 gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port);
252 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
253 gr_block_sptr dgrblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p));
255 throw std::runtime_error("allocate_buffer found non-gr_block");
256 int decimation = (int)(1.0/dgrblock->relative_rate());
257 int multiple = dgrblock->output_multiple();
258 int history = dgrblock->history();
259 nitems = std::max(nitems, 2*(decimation*multiple+history));
262 return gr_make_buffer(nitems, item_size);
265 gr_basic_block_vector_t
266 gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block, int port)
268 gr_basic_block_vector_t tmp, result;
269 std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
271 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
272 if ((*p)->src().block() == block && (*p)->src().port() == port)
273 tmp.push_back((*p)->dst().block());
276 sort(tmp.begin(), tmp.end());
277 unique_copy(tmp.begin(), tmp.end(), inserter);
281 gr_basic_block_vector_t
282 gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block)
284 gr_basic_block_vector_t tmp, result;
285 std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
287 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
288 if ((*p)->src().block() == block)
289 tmp.push_back((*p)->dst().block());
292 sort(tmp.begin(), tmp.end());
293 unique_copy(tmp.begin(), tmp.end(), inserter);
298 gr_simple_flowgraph_detail::calc_upstream_edges(gr_basic_block_sptr block)
300 gr_edge_vector_t result;
302 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
303 if ((*p)->dst().block() == block)
304 result.push_back(*p);
306 return result; // Assume no duplicates
309 gr_basic_block_vector_t
310 gr_simple_flowgraph_detail::calc_used_blocks()
312 gr_basic_block_vector_t tmp, result;
313 std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
315 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
316 tmp.push_back((*p)->src().block());
317 tmp.push_back((*p)->dst().block());
320 sort(tmp.begin(), tmp.end());
321 unique_copy(tmp.begin(), tmp.end(), inserter);
325 std::vector<gr_block_vector_t>
326 gr_simple_flowgraph_detail::partition()
328 std::vector<gr_block_vector_t> result;
329 gr_basic_block_vector_t blocks = calc_used_blocks();
330 gr_basic_block_vector_t graph;
332 while (blocks.size() > 0) {
333 graph = calc_reachable_blocks(blocks[0], blocks);
334 assert(graph.size());
335 result.push_back(topological_sort(graph));
337 for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++)
338 blocks.erase(find(blocks.begin(), blocks.end(), *p));
344 gr_basic_block_vector_t
345 gr_simple_flowgraph_detail::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
347 gr_basic_block_vector_t result;
349 // Mark all blocks as unvisited
350 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
351 boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE);
353 // Recursively mark all reachable blocks
354 reachable_dfs_visit(block, blocks);
356 // Collect all the blocks that have been visited
357 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
358 if ((boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p))->detail()->color() == gr_block_detail::BLACK)
359 result.push_back(*p);
364 // Recursively mark all reachable blocks from given block and block list
366 gr_simple_flowgraph_detail::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
368 // Mark the current one as visited
369 boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::BLACK);
371 // Recurse into adjacent vertices
372 gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks);
374 for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++)
375 if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE)
376 reachable_dfs_visit(*p, blocks);
379 // Return a list of block adjacent to a given block along any edge
380 gr_basic_block_vector_t
381 gr_simple_flowgraph_detail::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
383 gr_basic_block_vector_t tmp, result;
384 std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
386 // Find any blocks that are inputs or outputs
387 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
389 if ((*p)->src().block() == block)
390 tmp.push_back((*p)->dst().block());
391 if ((*p)->dst().block() == block)
392 tmp.push_back((*p)->src().block());
396 sort(tmp.begin(), tmp.end());
397 unique_copy(tmp.begin(), tmp.end(), inserter);
402 gr_simple_flowgraph_detail::topological_sort(gr_basic_block_vector_t &blocks)
404 gr_basic_block_vector_t tmp;
405 gr_block_vector_t result;
406 tmp = sort_sources_first(blocks);
408 // Start 'em all white
409 for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++)
410 boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE);
412 for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
413 if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE)
414 topological_dfs_visit(*p, result);
417 reverse(result.begin(), result.end());
423 gr_simple_flowgraph_detail::source_p(gr_basic_block_sptr block)
425 return (calc_upstream_edges(block).size() == 0);
428 gr_basic_block_vector_t
429 gr_simple_flowgraph_detail::sort_sources_first(gr_basic_block_vector_t &blocks)
431 gr_basic_block_vector_t sources, nonsources, result;
433 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
435 sources.push_back(*p);
437 nonsources.push_back(*p);
440 for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++)
441 result.push_back(*p);
443 for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++)
444 result.push_back(*p);
450 gr_simple_flowgraph_detail::topological_dfs_visit(gr_basic_block_sptr block, gr_block_vector_t &output)
452 boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::GREY);
454 gr_basic_block_vector_t blocks(calc_downstream_blocks(block));
456 for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
457 switch (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color()) {
458 case gr_block_detail::WHITE:
459 topological_dfs_visit(*p, output);
462 case gr_block_detail::GREY:
463 throw std::runtime_error("flow graph has loops!");
465 case gr_block_detail::BLACK:
469 throw std::runtime_error("invalid color on block!");
473 gr_block_sptr result_block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block));
475 result_block->detail()->set_color(gr_block_detail::BLACK);
476 output.push_back(result_block);
480 gr_simple_flowgraph_detail::merge_connections(gr_simple_flowgraph_sptr sfg)