diff options
23 files changed, 1331 insertions, 1008 deletions
diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am index b15e651dd..346f23b6a 100644 --- a/gnuradio-core/src/lib/runtime/Makefile.am +++ b/gnuradio-core/src/lib/runtime/Makefile.am @@ -31,8 +31,8 @@ libruntime_la_LIBADD = \ libruntime_la_SOURCES = \ gr_basic_block.cc \ - gr_simple_flowgraph.cc \ - gr_simple_flowgraph_detail.cc \ + gr_flowgraph.cc \ + gr_flat_flowgraph.cc \ gr_block.cc \ gr_block_detail.cc \ gr_hier_block2.cc \ @@ -66,14 +66,15 @@ libruntime_qa_la_SOURCES = \ qa_gr_block.cc \ qa_gr_hier_block2.cc \ qa_gr_buffer.cc \ + qa_gr_flowgraph.cc \ qa_gr_io_signature.cc \ qa_gr_vmcircbuf.cc \ qa_runtime.cc grinclude_HEADERS = \ gr_basic_block.h \ - gr_simple_flowgraph.h \ - gr_simple_flowgraph_detail.h \ + gr_flowgraph.h \ + gr_flat_flowgraph.h \ gr_block.h \ gr_block_detail.h \ gr_hier_block2.h \ @@ -109,6 +110,7 @@ noinst_HEADERS = \ gr_vmcircbuf_sysv_shm.h \ gr_vmcircbuf_createfilemapping.h \ qa_gr_block.h \ + qa_gr_flowgraph.h \ qa_gr_hier_block2.h \ qa_gr_buffer.h \ qa_gr_io_signature.h \ @@ -135,3 +137,5 @@ swiginclude_HEADERS = \ gr_sync_interpolator.i \ gr_swig_block_magic.i \ runtime.i + +MOSTLYCLEANFILES = *~ *.loT diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.cc b/gnuradio-core/src/lib/runtime/gr_basic_block.cc index 33cc3c2e9..e94e089e2 100644 --- a/gnuradio-core/src/lib/runtime/gr_basic_block.cc +++ b/gnuradio-core/src/lib/runtime/gr_basic_block.cc @@ -42,7 +42,8 @@ gr_basic_block::gr_basic_block(const std::string &name, : d_name(name), d_input_signature(input_signature), d_output_signature(output_signature), - d_unique_id(s_next_id++) + d_unique_id(s_next_id++), + d_color(WHITE) { s_ncurrently_allocated++; } diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.h b/gnuradio-core/src/lib/runtime/gr_basic_block.h index c47430e12..b2b8b42a3 100644 --- a/gnuradio-core/src/lib/runtime/gr_basic_block.h +++ b/gnuradio-core/src/lib/runtime/gr_basic_block.h @@ -41,10 +41,16 @@ class gr_basic_block : public boost::enable_shared_from_this<gr_basic_block> { protected: + friend class gr_flowgraph; + friend class gr_flat_flowgraph; // TODO: will be redundant + + enum vcolor { WHITE, GREY, BLACK }; + std::string d_name; gr_io_signature_sptr d_input_signature; gr_io_signature_sptr d_output_signature; long d_unique_id; + vcolor d_color; //! Protected constructor prevents instantiation by non-derived classes gr_basic_block(const std::string &name, @@ -61,6 +67,12 @@ protected: d_output_signature = iosig; } + /*! + * \brief Allow the flowgraph to set for sorting and partitioning + */ + void set_color(vcolor color) { d_color = color; } + vcolor color() const { return d_color; } + public: virtual ~gr_basic_block(); long unique_id() const { return d_unique_id; } diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h index aa2b0bde9..ce58ca9ac 100644 --- a/gnuradio-core/src/lib/runtime/gr_block.h +++ b/gnuradio-core/src/lib/runtime/gr_block.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -214,4 +214,9 @@ class gr_block : public gr_basic_block { typedef std::vector<gr_block_sptr> gr_block_vector_t; typedef std::vector<gr_block_sptr>::iterator gr_block_viter_t; +inline gr_block_sptr make_gr_block_sptr(gr_basic_block_sptr p) +{ + return boost::dynamic_pointer_cast<gr_block, gr_basic_block>(p); +} + #endif /* INCLUDED_GR_BLOCK_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc index e545d833d..ae1ea2562 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc @@ -38,8 +38,7 @@ gr_block_detail_ncurrently_allocated () gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs) : d_ninputs (ninputs), d_noutputs (noutputs), d_input (ninputs), d_output (noutputs), - d_done (false), - d_color (gr_block_detail::WHITE) + d_done (false) { s_ncurrently_allocated++; } diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h index 78b1019eb..a3b7731c0 100644 --- a/gnuradio-core/src/lib/runtime/gr_block_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h @@ -75,13 +75,6 @@ class gr_block_detail { void produce_each (int how_many_items); - /*! - * \brief Allow the flowgraph to set for sorting and partitioning - */ - enum vcolor { WHITE, GREY, BLACK }; - void set_color(vcolor color) { d_color = color; } - vcolor color() const { return d_color; } - // ---------------------------------------------------------------------------- private: @@ -90,7 +83,6 @@ class gr_block_detail { std::vector<gr_buffer_reader_sptr> d_input; std::vector<gr_buffer_sptr> d_output; bool d_done; - vcolor d_color; gr_block_detail (unsigned int ninputs, unsigned int noutputs); diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc new file mode 100644 index 000000000..d7f3ffb51 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc @@ -0,0 +1,223 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_flat_flowgraph.h> +#include <gr_block_detail.h> +#include <gr_io_signature.h> +#include <gr_buffer.h> +#include <iostream> +#include <map> + +#define GR_FLAT_FLOWGRAPH_DEBUG 0 + +gr_flat_flowgraph_sptr +gr_make_flat_flowgraph() +{ + return gr_flat_flowgraph_sptr(new gr_flat_flowgraph()); +} + +gr_flat_flowgraph::gr_flat_flowgraph() +{ +} + +gr_flat_flowgraph::~gr_flat_flowgraph() +{ +} + +void +gr_flat_flowgraph::setup_connections() +{ + gr_basic_block_vector_t blocks = calc_used_blocks(); + + // Assign block details to blocks + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + make_gr_block_sptr(*p)->set_detail(allocate_block_detail(*p)); + + // Connect inputs to outputs for each block + for(gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + connect_block_inputs(*p); +} + +gr_block_detail_sptr +gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block, gr_block_detail_sptr old_detail) +{ + int ninputs = calc_used_ports(block, true).size(); + int noutputs = calc_used_ports(block, false).size(); + gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Creating block detail for " << block << std::endl; + + // Re-use or allocate output buffers + for (int i = 0; i < noutputs; i++) { + gr_buffer_sptr buffer; + + if (!old_detail || i >= old_detail->noutputs()) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Allocating new buffer for output " << i << std::endl; + buffer = allocate_buffer(block, i); + } + else { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Reusing old buffer for output " << i << std::endl; + buffer = old_detail->output(i); + } + + detail->set_output(i, buffer); + } + + return detail; +} + +gr_buffer_sptr +gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port) +{ + gr_block_sptr grblock = make_gr_block_sptr(block); + if (!grblock) + throw std::runtime_error("allocate_buffer found non-gr_block"); + int item_size = block->output_signature()->sizeof_stream_item(port); + int nitems = s_fixed_buffer_size/item_size; + + // Make sure there are at least twice the output_multiple no. of items + if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple() + nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically + + // If any downstream blocks are decimators and/or have a large output_multiple, + // ensure we have a buffer at least twice their decimation factor*output_multiple + gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port); + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + gr_block_sptr dgrblock = make_gr_block_sptr(*p); + if (!dgrblock) + throw std::runtime_error("allocate_buffer found non-gr_block"); + + double decimation = (1.0/dgrblock->relative_rate()); + int multiple = dgrblock->output_multiple(); + int history = dgrblock->history(); + nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history))); + } + + return gr_make_buffer(nitems, item_size); +} + +void +gr_flat_flowgraph::connect_block_inputs(gr_basic_block_sptr block) +{ + gr_block_sptr grblock = make_gr_block_sptr(block); + if (!grblock) + throw std::runtime_error("found non-gr_block"); + + // Get its detail and edges that feed into it + gr_block_detail_sptr detail = grblock->detail(); + gr_edge_vector_t in_edges = calc_upstream_edges(block); + + // For each edge that feeds into it + for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) { + // Set the buffer reader on the destination port to the output + // buffer on the source port + int dst_port = e->dst().port(); + int src_port = e->src().port(); + gr_basic_block_sptr src_block = e->src().block(); + gr_block_sptr src_grblock = make_gr_block_sptr(src_block); + if (!src_grblock) + throw std::runtime_error("found non-gr_block"); + gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl; + + detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1)); + } +} + +void +gr_flat_flowgraph::merge_connections(gr_flat_flowgraph_sptr old_ffg) +{ + std::map<gr_block_sptr, gr_block_detail_sptr> old_details; + + // Allocate or reuse output buffers + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + gr_block_sptr block = make_gr_block_sptr(*p); + + gr_block_detail_sptr old_detail = block->detail(); + block->set_detail(allocate_block_detail(block, old_detail)); + + // Save old detail for use in next step + old_details[block] = old_detail; + } + + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + gr_block_sptr block = make_gr_block_sptr(*p); + + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: testing " << (*p) << "..."; + + if (old_ffg->has_block_p(*p)) { + // Block exists in old flow graph + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "used in old flow graph" << std::endl; + gr_block_detail_sptr detail = block->detail(); + + // Iterate through the inputs and see what needs to be done + for (int i = 0; i < detail->ninputs(); i++) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "Checking input " << i << "..."; + gr_edge edge = calc_upstream_edge(*p, i); + + // Fish out old buffer reader and see if it matches correct buffer from edge list + gr_block_sptr src_block = make_gr_block_sptr(edge.src().block()); + gr_block_detail_sptr src_detail = src_block->detail(); + gr_buffer_sptr src_buffer = src_detail->output(edge.src().port()); + gr_buffer_reader_sptr old_reader; + gr_block_detail_sptr old_detail = old_details[block]; + if (old_detail && i < old_detail->ninputs()) + old_reader = old_detail->input(i); + + // If there's a match, use it + if (old_reader && (src_buffer == old_reader->buffer())) { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "matched" << std::endl; + detail->set_input(i, old_reader); + + } + else { + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "needs a new reader" << std::endl; + + // Create new buffer reader and assign + detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1)); + } + } + } + else { + // Block is new, it just needs buffer readers at this point + if (GR_FLAT_FLOWGRAPH_DEBUG) + std::cout << "new block" << std::endl; + connect_block_inputs(block); + } + } +} + diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h new file mode 100644 index 000000000..0f4928064 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_FLAT_FLOWGRAPH_H +#define INCLUDED_GR_FLAT_FLOWGRAPH_H + +#include <gr_flowgraph.h> +#include <gr_block.h> + +// 32Kbyte buffer size between blocks +#define GR_FIXED_BUFFER_SIZE (32*(1L<<10)) + +// Create a shared pointer to a heap allocated gr_flat_flowgraph +// (types defined in gr_runtime_types.h) +gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); + +/*! + *\brief Class specializing gr_flat_flowgraph that has all nodes + * as gr_blocks, with no hierarchy + * + */ +class gr_flat_flowgraph : public gr_flowgraph +{ +public: + friend gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); + + // Destruct an arbitrary gr_flat_flowgraph + ~gr_flat_flowgraph(); + + // Wire gr_blocks together in new flat_flowgraph + void setup_connections(); + + // Merge applicable connections from existing flat flowgraph + void merge_connections(gr_flat_flowgraph_sptr sfg); + +private: + gr_flat_flowgraph(); + + static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE; + gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block, + gr_block_detail_sptr old_detail=gr_block_detail_sptr()); + gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port); + void connect_block_inputs(gr_basic_block_sptr block); +}; + +#endif /* INCLUDED_GR_FLAT_FLOWGRAPH_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flowgraph.cc new file mode 100644 index 000000000..8e96dba75 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_flowgraph.cc @@ -0,0 +1,436 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_flowgraph.h> +#include <gr_io_signature.h> +#include <stdexcept> +#include <iostream> + +#define GR_FLOWGRAPH_DEBUG 0 + +gr_edge::~gr_edge() +{ +} + +gr_flowgraph_sptr gr_make_flowgraph() +{ + return gr_flowgraph_sptr(new gr_flowgraph()); +} + +gr_flowgraph::gr_flowgraph() +{ +} + +gr_flowgraph::~gr_flowgraph() +{ +} + +void +gr_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst) +{ + check_valid_port(src.block()->output_signature(), src.port()); + check_valid_port(dst.block()->input_signature(), dst.port()); + check_dst_not_used(dst); + check_type_match(src, dst); + + // All ist klar, Herr Kommisar + d_edges.push_back(gr_edge(src,dst)); +} + +void +gr_flowgraph::disconnect(const gr_endpoint &src, const gr_endpoint &dst) +{ + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (src == p->src() && dst == p->dst()) { + d_edges.erase(p); + return; + } + } + + throw std::invalid_argument("edge to disconnect not found"); +} + +void +gr_flowgraph::validate() +{ + d_blocks = calc_used_blocks(); + + for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + std::vector<int> used_ports; + int ninputs, noutputs; + + if (GR_FLOWGRAPH_DEBUG) + std::cout << "Validating block: " << (*p) << std::endl; + + used_ports = calc_used_ports(*p, true); // inputs + ninputs = used_ports.size(); + check_contiguity(*p, used_ports, true); // inputs + + used_ports = calc_used_ports(*p, false); // outputs + noutputs = used_ports.size(); + check_contiguity(*p, used_ports, false); // outputs + + if (!((*p)->check_topology(ninputs, noutputs))) + throw std::runtime_error("check topology failed"); + } +} + +void +gr_flowgraph::clear() +{ + // Boost shared pointers will deallocate as needed + d_blocks.clear(); + d_edges.clear(); +} + +void +gr_flowgraph::check_valid_port(gr_io_signature_sptr sig, int port) +{ + if (port < 0) + throw std::invalid_argument("negative port number"); + if (sig->max_streams() >= 0 && port >= sig->max_streams()) + throw std::invalid_argument("port number exceeds max"); +} + +void +gr_flowgraph::check_dst_not_used(const gr_endpoint &dst) +{ + // A destination is in use if it is already on the edge list + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->dst() == dst) + throw std::invalid_argument("dst already in use"); +} + +void +gr_flowgraph::check_type_match(const gr_endpoint &src, const gr_endpoint &dst) +{ + int src_size = src.block()->output_signature()->sizeof_stream_item(src.port()); + int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port()); + + if (src_size != dst_size) + throw std::invalid_argument("itemsize mismatch between src and dst"); +} + +gr_basic_block_vector_t +gr_flowgraph::calc_used_blocks() +{ + gr_basic_block_vector_t tmp, result; + std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); + + // Collect all blocks in the edge list + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + tmp.push_back(p->src().block()); + tmp.push_back(p->dst().block()); + } + + // Return vector of unique blocks + sort(tmp.begin(), tmp.end()); + unique_copy(tmp.begin(), tmp.end(), inserter); + return result; +} + +std::vector<int> +gr_flowgraph::calc_used_ports(gr_basic_block_sptr block, bool check_inputs) +{ + std::vector<int> tmp, result; + std::insert_iterator<std::vector<int> > inserter(result, result.begin()); + + // Collect all seen ports + gr_edge_vector_t edges = calc_connections(block, check_inputs); + for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { + if (check_inputs == true) + tmp.push_back(p->dst().port()); + else + tmp.push_back(p->src().port()); + } + + // Return vector of unique values + std::sort(tmp.begin(), tmp.end()); + std::unique_copy(tmp.begin(), tmp.end(), inserter); + return result; +} + +gr_edge_vector_t +gr_flowgraph::calc_connections(gr_basic_block_sptr block, bool check_inputs) +{ + gr_edge_vector_t result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (check_inputs) { + if (p->dst().block() == block) + result.push_back(*p); + } + else { + if (p->src().block() == block) + result.push_back(*p); + } + } + + return result; // assumes no duplicates +} + +void +gr_flowgraph::check_contiguity(gr_basic_block_sptr block, + const std::vector<int> &used_ports, + bool check_inputs) +{ + gr_io_signature_sptr sig = + check_inputs ? block->input_signature() : block->output_signature(); + + int nports = used_ports.size(); + int min_ports = sig->min_streams(); + + if (nports == 0) { + if (min_ports == 0) + return; + else + throw std::runtime_error("insufficient ports"); + } + + if (used_ports[nports-1]+1 != nports) { + for (int i = 0; i < nports; i++) + if (used_ports[i] != i) + throw std::runtime_error("missing input assignment"); + } +} + +gr_basic_block_vector_t +gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block, int port) +{ + gr_basic_block_vector_t tmp, result; + std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->src() == gr_endpoint(block, port)) + tmp.push_back(p->dst().block()); + + // Remove duplicates + sort(tmp.begin(), tmp.end()); + unique_copy(tmp.begin(), tmp.end(), inserter); + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block) +{ + gr_basic_block_vector_t tmp, result; + std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->src().block() == block) + tmp.push_back(p->dst().block()); + + // Remove duplicates + sort(tmp.begin(), tmp.end()); + unique_copy(tmp.begin(), tmp.end(), inserter); + return result; +} + +gr_edge_vector_t +gr_flowgraph::calc_upstream_edges(gr_basic_block_sptr block) +{ + gr_edge_vector_t result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if (p->dst().block() == block) + result.push_back(*p); + + return result; // Assume no duplicates +} + +bool +gr_flowgraph::has_block_p(gr_basic_block_sptr block) +{ + gr_basic_block_viter_t result; + result = std::find(d_blocks.begin(), d_blocks.end(), block); + return (result != d_blocks.end()); +} + +gr_edge +gr_flowgraph::calc_upstream_edge(gr_basic_block_sptr block, int port) +{ + gr_edge result; + + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if (p->dst() == gr_endpoint(block, port)) { + result = (*p); + break; + } + } + + return result; +} + +std::vector<gr_basic_block_vector_t> +gr_flowgraph::partition() +{ + std::vector<gr_basic_block_vector_t> result; + gr_basic_block_vector_t blocks = calc_used_blocks(); + gr_basic_block_vector_t graph; + + while (blocks.size() > 0) { + graph = calc_reachable_blocks(blocks[0], blocks); + assert(graph.size()); + result.push_back(topological_sort(graph)); + + for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++) + blocks.erase(find(blocks.begin(), blocks.end(), *p)); + } + + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t result; + + // Mark all blocks as unvisited + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + (*p)->set_color(gr_basic_block::WHITE); + + // Recursively mark all reachable blocks + reachable_dfs_visit(block, blocks); + + // Collect all the blocks that have been visited + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + if ((*p)->color() == gr_basic_block::BLACK) + result.push_back(*p); + + return result; +} + +// Recursively mark all reachable blocks from given block and block list +void +gr_flowgraph::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + // Mark the current one as visited + block->set_color(gr_basic_block::BLACK); + + // Recurse into adjacent vertices + gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks); + + for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++) + if ((*p)->color() == gr_basic_block::WHITE) + reachable_dfs_visit(*p, blocks); +} + +// Return a list of block adjacent to a given block along any edge +gr_basic_block_vector_t +gr_flowgraph::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t tmp, result; + std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); + + // Find any blocks that are inputs or outputs + for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + + if (p->src().block() == block) + tmp.push_back(p->dst().block()); + if (p->dst().block() == block) + tmp.push_back(p->src().block()); + } + + // Remove duplicates + sort(tmp.begin(), tmp.end()); + unique_copy(tmp.begin(), tmp.end(), inserter); + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::topological_sort(gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t tmp; + gr_basic_block_vector_t result; + tmp = sort_sources_first(blocks); + + // Start 'em all white + for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) + (*p)->set_color(gr_basic_block::WHITE); + + for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { + if ((*p)->color() == gr_basic_block::WHITE) + topological_dfs_visit(*p, result); + } + + reverse(result.begin(), result.end()); + return result; +} + +gr_basic_block_vector_t +gr_flowgraph::sort_sources_first(gr_basic_block_vector_t &blocks) +{ + gr_basic_block_vector_t sources, nonsources, result; + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + if (source_p(*p)) + sources.push_back(*p); + else + nonsources.push_back(*p); + } + + for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++) + result.push_back(*p); + + for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++) + result.push_back(*p); + + return result; +} + +bool +gr_flowgraph::source_p(gr_basic_block_sptr block) +{ + return (calc_upstream_edges(block).size() == 0); +} + +void +gr_flowgraph::topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output) +{ + block->set_color(gr_basic_block::GREY); + gr_basic_block_vector_t blocks(calc_downstream_blocks(block)); + + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + switch ((*p)->color()) { + case gr_basic_block::WHITE: + topological_dfs_visit(*p, output); + break; + + case gr_basic_block::GREY: + throw std::runtime_error("flow graph has loops!"); + + case gr_basic_block::BLACK: + continue; + + default: + throw std::runtime_error("invalid color on block!"); + } + } + + block->set_color(gr_basic_block::BLACK); + output.push_back(block); +} + diff --git a/gnuradio-core/src/lib/runtime/gr_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_flowgraph.h new file mode 100644 index 000000000..131e41bb9 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_flowgraph.h @@ -0,0 +1,188 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_FLOWGRAPH_H +#define INCLUDED_GR_FLOWGRAPH_H + +#include <gr_basic_block.h> +#include <iostream> + +/*! + *\brief Class representing a specific input or output graph endpoint + * + */ +class gr_endpoint +{ +private: + gr_basic_block_sptr d_basic_block; + int d_port; + +public: + gr_endpoint() : d_basic_block(), d_port(0) { } + gr_endpoint(gr_basic_block_sptr block, int port) { d_basic_block = block; d_port = port; } + gr_basic_block_sptr block() const { return d_basic_block; } + int port() const { return d_port; } + + bool operator==(const gr_endpoint &other) const; +}; + +inline bool gr_endpoint::operator==(const gr_endpoint &other) const +{ + return (d_basic_block == other.d_basic_block && + d_port == other.d_port); +} + +// Hold vectors of gr_endpoint objects +typedef std::vector<gr_endpoint> gr_endpoint_vector_t; +typedef std::vector<gr_endpoint>::iterator gr_endpoint_viter_t; + +/*! + *\brief Class representing a connection between to graph endpoints + * + */ +class gr_edge +{ +public: + gr_edge() : d_src(), d_dst() { }; + gr_edge(const gr_endpoint &src, const gr_endpoint &dst) : d_src(src), d_dst(dst) { } + ~gr_edge(); + + const gr_endpoint &src() const { return d_src; } + const gr_endpoint &dst() const { return d_dst; } + +private: + gr_endpoint d_src; + gr_endpoint d_dst; +}; + +// Hold vectors of gr_edge objects +typedef std::vector<gr_edge> gr_edge_vector_t; +typedef std::vector<gr_edge>::iterator gr_edge_viter_t; + + +// Create a shared pointer to a heap allocated flowgraph +// (types defined in gr_runtime_types.h) +gr_flowgraph_sptr gr_make_flowgraph(); + +/*! + *\brief Class representing a directed, acyclic graph of basic blocks + * + */ +class gr_flowgraph +{ +public: + friend gr_flowgraph_sptr gr_make_flowgraph(); + + // Destruct an arbitrary flowgraph + ~gr_flowgraph(); + + // Connect two endpoints + void connect(const gr_endpoint &src, const gr_endpoint &dst); + + // Disconnect two endpoints + void disconnect(const gr_endpoint &src, const gr_endpoint &dst); + + // Connect an output port to an input port (convenience) + void connect(gr_basic_block_sptr src_block, int src_port, + gr_basic_block_sptr dst_block, int dst_port); + + // Disconnect an input port from an output port (convenience) + void disconnect(gr_basic_block_sptr src_block, int src_port, + gr_basic_block_sptr dst_block, int dst_port); + + // Validate connectivity, raise exception if invalid + void validate(); + + // Clear existing flowgraph + void clear(); + + // Return vector of edges + const gr_edge_vector_t &edges() const { return d_edges; } + + // Return vector of connected blocks + gr_basic_block_vector_t calc_used_blocks(); + + // Return vector of vectors of disjointly connected blocks, topologically + // sorted. + std::vector<gr_basic_block_vector_t> partition(); + +protected: + gr_basic_block_vector_t d_blocks; + gr_edge_vector_t d_edges; + + gr_flowgraph(); + std::vector<int> calc_used_ports(gr_basic_block_sptr block, bool check_inputs); + gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block, int port); + gr_edge_vector_t calc_upstream_edges(gr_basic_block_sptr block); + bool has_block_p(gr_basic_block_sptr block); + gr_edge calc_upstream_edge(gr_basic_block_sptr block, int port); + +private: + + void check_valid_port(gr_io_signature_sptr sig, int port); + void check_dst_not_used(const gr_endpoint &dst); + void check_type_match(const gr_endpoint &src, const gr_endpoint &dst); + gr_edge_vector_t calc_connections(gr_basic_block_sptr block, bool check_inputs); // false=use outputs + void check_contiguity(gr_basic_block_sptr block, const std::vector<int> &used_ports, bool check_inputs); + + gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block); + gr_basic_block_vector_t calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); + void reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); + gr_basic_block_vector_t calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); + gr_basic_block_vector_t topological_sort(gr_basic_block_vector_t &blocks); + gr_basic_block_vector_t sort_sources_first(gr_basic_block_vector_t &blocks); + bool source_p(gr_basic_block_sptr block); + void topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output); +}; + +// Convenience functions +inline +void gr_flowgraph::connect(gr_basic_block_sptr src_block, int src_port, + gr_basic_block_sptr dst_block, int dst_port) +{ + connect(gr_endpoint(src_block, src_port), + gr_endpoint(dst_block, dst_port)); +} + +inline +void gr_flowgraph::disconnect(gr_basic_block_sptr src_block, int src_port, + gr_basic_block_sptr dst_block, int dst_port) +{ + disconnect(gr_endpoint(src_block, src_port), + gr_endpoint(dst_block, dst_port)); +} + +inline std::ostream& +operator <<(std::ostream &os, const gr_endpoint endp) +{ + os << endp.block() << ":" << endp.port(); + return os; +} + +inline std::ostream& +operator <<(std::ostream &os, const gr_edge edge) +{ + os << edge.src() << "->" << edge.dst(); + return os; +} + +#endif /* INCLUDED_GR_FLOWGRAPH_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc index 46656360e..99131afb6 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc @@ -24,7 +24,6 @@ #endif #include <gr_hier_block2_detail.h> -#include <gr_simple_flowgraph.h> #include <gr_io_signature.h> #include <gr_runtime.h> #include <stdexcept> @@ -35,7 +34,7 @@ gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) : d_owner(owner), d_parent_detail(0), - d_fg(gr_make_simple_flowgraph()), + d_fg(gr_make_flowgraph()), d_inputs(owner->input_signature()->max_streams()), d_outputs(owner->output_signature()->max_streams()), d_runtime() @@ -228,22 +227,24 @@ gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) } void -gr_hier_block2_detail::flatten(gr_simple_flowgraph_sptr sfg) +gr_hier_block2_detail::flatten(gr_flat_flowgraph_sptr sfg) { if (GR_HIER_BLOCK2_DETAIL_DEBUG) std::cout << "flattening " << d_owner->name() << std::endl; // Add my edges to the flow graph, resolving references to actual endpoints - for (gr_edge_viter_t p = d_fg->d_detail->d_edges.begin(); p != d_fg->d_detail->d_edges.end(); p++) { + gr_edge_vector_t edges = d_fg->edges(); + + for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { if (GR_HIER_BLOCK2_DETAIL_DEBUG) std::cout << "Flattening edge " << (*p) << std::endl; - gr_endpoint src_endp = resolve_endpoint((*p)->src(), false); - gr_endpoint dst_endp = resolve_endpoint((*p)->dst(), true); + gr_endpoint src_endp = resolve_endpoint(p->src(), false); + gr_endpoint dst_endp = resolve_endpoint(p->dst(), true); sfg->connect(src_endp, dst_endp); } - gr_basic_block_vector_t blocks = d_fg->d_detail->calc_used_blocks(); + gr_basic_block_vector_t blocks = d_fg->calc_used_blocks(); // Recurse hierarchical children for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h index 9002dde1d..b315061be 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h @@ -22,7 +22,7 @@ #define INCLUDED_GR_HIER_BLOCK2_DETAIL_H #include <gr_hier_block2.h> -#include <gr_simple_flowgraph_detail.h> +#include <gr_flat_flowgraph.h> #include <boost/utility.hpp> class gr_hier_block2_detail : boost::noncopyable @@ -37,7 +37,7 @@ private: // Private implementation data gr_hier_block2 *d_owner; gr_hier_block2_detail *d_parent_detail; - gr_simple_flowgraph_sptr d_fg; + gr_flowgraph_sptr d_fg; gr_endpoint_vector_t d_inputs; gr_endpoint_vector_t d_outputs; gr_runtime *d_runtime; @@ -51,7 +51,7 @@ private: void connect_output(int my_port, int port, gr_basic_block_sptr block); void disconnect_input(int my_port, int port, gr_basic_block_sptr block); void disconnect_output(int my_port, int port, gr_basic_block_sptr block); - void flatten(gr_simple_flowgraph_sptr sfg); + void flatten(gr_flat_flowgraph_sptr sfg); gr_endpoint resolve_port(int port, bool is_input); gr_endpoint resolve_endpoint(const gr_endpoint &endp, bool is_input); void set_runtime(gr_runtime *runtime) { d_runtime = runtime; } diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc b/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc index 134690a1a..30a39f1d8 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc +++ b/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc @@ -26,7 +26,7 @@ #include <gr_runtime.h> #include <gr_runtime_impl.h> -#include <gr_simple_flowgraph.h> +#include <gr_flat_flowgraph.h> #include <gr_hier_block2.h> #include <gr_hier_block2_detail.h> #include <gr_local_sighandler.h> @@ -42,6 +42,19 @@ static gr_runtime_impl *s_runtime = 0; +// Make a vector of gr_block from a vector of gr_basic_block +static +gr_block_vector_t +make_gr_block_vector(gr_basic_block_vector_t &blocks) +{ + gr_block_vector_t result; + for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + result.push_back(make_gr_block_sptr(*p)); + } + + return result; +} + // FIXME: This prevents using more than one gr_runtime instance void runtime_sigint_handler(int signum) @@ -56,7 +69,7 @@ runtime_sigint_handler(int signum) gr_runtime_impl::gr_runtime_impl(gr_hier_block2_sptr top_block, gr_runtime *owner) : d_running(false), d_top_block(top_block), - d_sfg(gr_make_simple_flowgraph()), + d_ffg(gr_make_flat_flowgraph()), d_owner(owner) { s_runtime = this; @@ -79,12 +92,12 @@ gr_runtime_impl::start() throw std::runtime_error("already running"); // Create new simple flow graph by flattening hierarchical block - d_sfg->d_detail->reset(); - d_top_block->d_detail->flatten(d_sfg); + d_ffg->clear(); + d_top_block->d_detail->flatten(d_ffg); // Validate new simple flow graph and wire it up - d_sfg->d_detail->validate(); - d_sfg->d_detail->setup_connections(); + d_ffg->validate(); + d_ffg->setup_connections(); // Execute scheduler threads start_threads(); @@ -96,10 +109,10 @@ gr_runtime_impl::start_threads() if (GR_RUNTIME_IMPL_DEBUG) std::cout << "start_threads: entered" << std::endl; - d_graphs = d_sfg->d_detail->partition(); - for (std::vector<gr_block_vector_t>::iterator p = d_graphs.begin(); + d_graphs = d_ffg->partition(); + for (std::vector<gr_basic_block_vector_t>::iterator p = d_graphs.begin(); p != d_graphs.end(); p++) { - gr_scheduler_thread *thread = new gr_scheduler_thread(*p); + gr_scheduler_thread *thread = new gr_scheduler_thread(make_gr_block_vector(*p)); d_threads.push_back(thread); if (GR_RUNTIME_IMPL_DEBUG) std::cout << "start_threads: starting " << thread << std::endl; @@ -188,14 +201,14 @@ gr_runtime_impl::restart() std::cout << "restart: threads stopped" << std::endl; // Create new simple flow graph - gr_simple_flowgraph_sptr new_sfg = gr_make_simple_flowgraph(); - d_top_block->d_detail->flatten(new_sfg); - new_sfg->validate(); - new_sfg->d_detail->merge_connections(d_sfg); + gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph(); + d_top_block->d_detail->flatten(new_ffg); + new_ffg->validate(); + new_ffg->merge_connections(d_ffg); if (GR_RUNTIME_IMPL_DEBUG) std::cout << "restart: replacing old flow graph with new" << std::endl; - d_sfg = new_sfg; + d_ffg = new_ffg; start_threads(); } diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.h b/gnuradio-core/src/lib/runtime/gr_runtime_impl.h index 17a8a985c..f6230018a 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_impl.h +++ b/gnuradio-core/src/lib/runtime/gr_runtime_impl.h @@ -72,8 +72,8 @@ private: bool d_running; gr_hier_block2_sptr d_top_block; - gr_simple_flowgraph_sptr d_sfg; - std::vector<gr_block_vector_t> d_graphs; + gr_flat_flowgraph_sptr d_ffg; + std::vector<gr_basic_block_vector_t> d_graphs; gr_scheduler_thread_vector_t d_threads; gr_runtime *d_owner; int d_lock_count; diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_types.h b/gnuradio-core/src/lib/runtime/gr_runtime_types.h index 6ab1ac8f7..8af663cdf 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_types.h +++ b/gnuradio-core/src/lib/runtime/gr_runtime_types.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -36,17 +36,19 @@ class gr_hier_block2; class gr_io_signature; class gr_buffer; class gr_buffer_reader; -class gr_simple_flowgraph; +class gr_flowgraph; +class gr_flat_flowgraph; class gr_runtime; typedef boost::shared_ptr<gr_basic_block> gr_basic_block_sptr; typedef boost::shared_ptr<gr_block> gr_block_sptr; -typedef boost::shared_ptr<gr_block_detail> gr_block_detail_sptr; -typedef boost::shared_ptr<gr_hier_block2> gr_hier_block2_sptr; +typedef boost::shared_ptr<gr_block_detail> gr_block_detail_sptr; +typedef boost::shared_ptr<gr_hier_block2> gr_hier_block2_sptr; typedef boost::shared_ptr<gr_io_signature> gr_io_signature_sptr; -typedef boost::shared_ptr<gr_buffer> gr_buffer_sptr; -typedef boost::shared_ptr<gr_buffer_reader> gr_buffer_reader_sptr; -typedef boost::shared_ptr<gr_runtime> gr_runtime_sptr; -typedef boost::shared_ptr<gr_simple_flowgraph> gr_simple_flowgraph_sptr; +typedef boost::shared_ptr<gr_buffer> gr_buffer_sptr; +typedef boost::shared_ptr<gr_buffer_reader> gr_buffer_reader_sptr; +typedef boost::shared_ptr<gr_runtime> gr_runtime_sptr; +typedef boost::shared_ptr<gr_flowgraph> gr_flowgraph_sptr; +typedef boost::shared_ptr<gr_flat_flowgraph> gr_flat_flowgraph_sptr; #endif /* INCLUDED_GR_RUNTIME_TYPES_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc deleted file mode 100644 index be74cec40..000000000 --- a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_simple_flowgraph.h> -#include <gr_simple_flowgraph_detail.h> -#include <iostream> - -gr_simple_flowgraph_sptr gr_make_simple_flowgraph() -{ - return gr_simple_flowgraph_sptr(new gr_simple_flowgraph()); -} - -gr_simple_flowgraph::gr_simple_flowgraph() : -d_detail(new gr_simple_flowgraph_detail()) -{ -} - -gr_simple_flowgraph::~gr_simple_flowgraph() -{ - delete d_detail; -} - -void -gr_simple_flowgraph::connect(gr_basic_block_sptr src_block, int src_port, - gr_basic_block_sptr dst_block, int dst_port) -{ - d_detail->connect(gr_endpoint(src_block, src_port), gr_endpoint(dst_block, dst_port)); -} - -void -gr_simple_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst) -{ - d_detail->connect(src, dst); -} - -void -gr_simple_flowgraph::disconnect(gr_basic_block_sptr src_block, int src_port, - gr_basic_block_sptr dst_block, int dst_port) -{ - d_detail->disconnect(gr_endpoint(src_block, src_port), gr_endpoint(dst_block, dst_port)); -} - -void -gr_simple_flowgraph::validate() -{ - d_detail->validate(); -} diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h deleted file mode 100644 index 998bcb64f..000000000 --- a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GR_SIMPLE_FLOWGRAPH_H -#define INCLUDED_GR_SIMPLE_FLOWGRAPH_H - -#include <gr_block.h> -#include <boost/shared_ptr.hpp> -#include <string> - -gr_simple_flowgraph_sptr gr_make_simple_flowgraph(); - -class gr_simple_flowgraph_detail; - -class gr_endpoint -{ -private: - friend class gr_hier_block2_detail; - gr_basic_block_sptr d_block; - int d_port; - -public: - gr_endpoint() : d_block(), d_port(0) { } // Internal use only - gr_endpoint(gr_basic_block_sptr block, int port) { d_block = block; d_port = port; } - gr_basic_block_sptr block() const { return d_block; } - int port() const { return d_port; } -}; - -typedef std::vector<gr_endpoint> gr_endpoint_vector_t; - -/*! - *\brief Class representing a low-level, "flattened" flow graph - * - * This class holds the results of the call to gr.hier_block2.flatten(), - * which is a graph that has only the connected blocks and edges of - * the original hier_block2, with all the hierarchy removed. - * - * While this class is exported to Python via SWIG for ease of QA - * testing, it is not used by application developers, and there is - * no way to feed this to a gr.runtime() instance. - */ -class gr_simple_flowgraph -{ -private: - friend class gr_runtime_impl; - friend class gr_simple_flowgraph_detail; - friend class gr_hier_block2_detail; - friend gr_simple_flowgraph_sptr gr_make_simple_flowgraph(); - gr_simple_flowgraph(); - - gr_simple_flowgraph_detail *d_detail; - -public: - ~gr_simple_flowgraph(); - - void connect(gr_basic_block_sptr src_block, int src_port, - gr_basic_block_sptr dst_block, int dst_port); - void connect(const gr_endpoint &src, const gr_endpoint &dst); - void disconnect(gr_basic_block_sptr src_block, int src_port, - gr_basic_block_sptr dst_block, int dst_port); - void validate(); -}; - -#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc deleted file mode 100644 index 2da2dad52..000000000 --- a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc +++ /dev/null @@ -1,609 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_simple_flowgraph.h> -#include <gr_simple_flowgraph_detail.h> -#include <gr_io_signature.h> -#include <gr_block_detail.h> -#include <gr_buffer.h> -#include <iostream> -#include <stdexcept> -#include <map> - -#define GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG 0 - -gr_edge_sptr -gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst) -{ - return gr_edge_sptr(new gr_edge(src, dst)); -} - -gr_edge::~gr_edge() -{ -} - -gr_simple_flowgraph_detail::~gr_simple_flowgraph_detail() -{ -} - -void -gr_simple_flowgraph_detail::reset() -{ - // Boost shared pointers will deallocate as needed - d_edges.clear(); - d_blocks.clear(); -} - -void -gr_simple_flowgraph_detail::connect(const gr_endpoint &src, const gr_endpoint &dst) -{ - check_valid_port(src.block()->output_signature(), src.port()); - check_valid_port(dst.block()->input_signature(), dst.port()); - check_dst_not_used(dst); - check_type_match(src, dst); - d_edges.push_back(gr_make_edge(src,dst)); -} - -void -gr_simple_flowgraph_detail::disconnect(const gr_endpoint &src, const gr_endpoint &dst) -{ - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (src.block() == (*p)->src().block() && src.port() == (*p)->src().port() && - dst.block() == (*p)->dst().block() && dst.port() == (*p)->dst().port()) { - d_edges.erase(p); - return; - } - } - - throw std::invalid_argument("edge to disconnect not found"); -} - -void -gr_simple_flowgraph_detail::check_valid_port(gr_io_signature_sptr sig, int port) -{ - if (port < 0) - throw std::invalid_argument("negative port number"); - if (sig->max_streams() >= 0 && port >= sig->max_streams()) - throw std::invalid_argument("port number exceeds max"); -} - -void -gr_simple_flowgraph_detail::check_dst_not_used(const gr_endpoint &dst) -{ - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if ((*p)->dst().block() == dst.block() && - (*p)->dst().port() == dst.port()) - throw std::invalid_argument("dst already in use"); -} - -void -gr_simple_flowgraph_detail::check_type_match(const gr_endpoint &src, const gr_endpoint &dst) -{ - int src_size = src.block()->output_signature()->sizeof_stream_item(src.port()); - int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port()); - - if (src_size != dst_size) - throw std::invalid_argument("type size mismatch while attempting to connect"); -} - -void -gr_simple_flowgraph_detail::validate() -{ - d_blocks = calc_used_blocks(); - - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - std::vector<int> used_ports; - int ninputs, noutputs; - - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Validating block: " << (*p) << std::endl; - - used_ports = calc_used_ports(*p, true); // inputs - ninputs = used_ports.size(); - check_contiguity(*p, used_ports, true); // inputs - - used_ports = calc_used_ports(*p, false); // outputs - noutputs = used_ports.size(); - check_contiguity(*p, used_ports, false); // outputs - - if (!((*p)->check_topology(ninputs, noutputs))) - throw std::runtime_error("check topology failed"); - } -} - -std::vector<int> -gr_simple_flowgraph_detail::calc_used_ports(gr_basic_block_sptr block, bool check_inputs) -{ - std::vector<int> tmp, result; - std::insert_iterator<std::vector<int> > inserter(result, result.begin()); - - gr_edge_vector_t edges = calc_connections(block, check_inputs); - for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { - if (check_inputs == true) - tmp.push_back((*p)->dst().port()); - else - tmp.push_back((*p)->src().port()); - } - - // remove duplicates - std::sort(tmp.begin(), tmp.end()); - std::unique_copy(tmp.begin(), tmp.end(), inserter); - return result; -} - -gr_edge_vector_t -gr_simple_flowgraph_detail::calc_connections(gr_basic_block_sptr block, bool check_inputs) -{ - gr_edge_vector_t result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (check_inputs) { - if ((*p)->dst().block() == block) - result.push_back(*p); - } - else { - if ((*p)->src().block() == block) - result.push_back(*p); - } - } - - return result; // assumes no duplicates -} - -void -gr_simple_flowgraph_detail::check_contiguity(gr_basic_block_sptr block, - const std::vector<int> &used_ports, - bool check_inputs) -{ - gr_io_signature_sptr sig = - check_inputs ? block->input_signature() : block->output_signature(); - - int nports = used_ports.size(); - int min_ports = sig->min_streams(); - - if (nports == 0) { - if (min_ports == 0) - return; - else - throw std::runtime_error("insufficient ports"); - } - - if (used_ports[nports-1]+1 != nports) { - for (int i = 0; i < nports; i++) - if (used_ports[i] != i) - throw std::runtime_error("missing input assignment"); - } -} - -gr_basic_block_vector_t -gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block, int port) -{ - gr_basic_block_vector_t tmp, result; - std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if ((*p)->src().block() == block && (*p)->src().port() == port) - tmp.push_back((*p)->dst().block()); - - // Remove duplicates - sort(tmp.begin(), tmp.end()); - unique_copy(tmp.begin(), tmp.end(), inserter); - return result; -} - -gr_basic_block_vector_t -gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block) -{ - gr_basic_block_vector_t tmp, result; - std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if ((*p)->src().block() == block) - tmp.push_back((*p)->dst().block()); - - // Remove duplicates - sort(tmp.begin(), tmp.end()); - unique_copy(tmp.begin(), tmp.end(), inserter); - return result; -} - -gr_edge_vector_t -gr_simple_flowgraph_detail::calc_upstream_edges(gr_basic_block_sptr block) -{ - gr_edge_vector_t result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if ((*p)->dst().block() == block) - result.push_back(*p); - - return result; // Assume no duplicates -} - -gr_basic_block_vector_t -gr_simple_flowgraph_detail::calc_used_blocks() -{ - gr_basic_block_vector_t tmp, result; - std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - tmp.push_back((*p)->src().block()); - tmp.push_back((*p)->dst().block()); - } - - sort(tmp.begin(), tmp.end()); - unique_copy(tmp.begin(), tmp.end(), inserter); - return result; -} - -std::vector<gr_block_vector_t> -gr_simple_flowgraph_detail::partition() -{ - std::vector<gr_block_vector_t> result; - gr_basic_block_vector_t blocks = calc_used_blocks(); - gr_basic_block_vector_t graph; - - while (blocks.size() > 0) { - graph = calc_reachable_blocks(blocks[0], blocks); - assert(graph.size()); - result.push_back(topological_sort(graph)); - - for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++) - blocks.erase(find(blocks.begin(), blocks.end(), *p)); - } - - return result; -} - -gr_basic_block_vector_t -gr_simple_flowgraph_detail::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t result; - - // Mark all blocks as unvisited - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) - boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE); - - // Recursively mark all reachable blocks - reachable_dfs_visit(block, blocks); - - // Collect all the blocks that have been visited - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) - if ((boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p))->detail()->color() == gr_block_detail::BLACK) - result.push_back(*p); - - return result; -} - -// Recursively mark all reachable blocks from given block and block list -void -gr_simple_flowgraph_detail::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - // Mark the current one as visited - boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::BLACK); - - // Recurse into adjacent vertices - gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks); - - for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++) - if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE) - reachable_dfs_visit(*p, blocks); -} - -// Return a list of block adjacent to a given block along any edge -gr_basic_block_vector_t -gr_simple_flowgraph_detail::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t tmp, result; - std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin()); - - // Find any blocks that are inputs or outputs - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - - if ((*p)->src().block() == block) - tmp.push_back((*p)->dst().block()); - if ((*p)->dst().block() == block) - tmp.push_back((*p)->src().block()); - } - - // Remove duplicates - sort(tmp.begin(), tmp.end()); - unique_copy(tmp.begin(), tmp.end(), inserter); - return result; -} - -gr_block_vector_t -gr_simple_flowgraph_detail::topological_sort(gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t tmp; - gr_block_vector_t result; - tmp = sort_sources_first(blocks); - - // Start 'em all white - for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) - boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE); - - for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { - if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE) - topological_dfs_visit(*p, result); - } - - reverse(result.begin(), result.end()); - - return result; -} - -bool -gr_simple_flowgraph_detail::source_p(gr_basic_block_sptr block) -{ - return (calc_upstream_edges(block).size() == 0); -} - -gr_basic_block_vector_t -gr_simple_flowgraph_detail::sort_sources_first(gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t sources, nonsources, result; - - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - if (source_p(*p)) - sources.push_back(*p); - else - nonsources.push_back(*p); - } - - for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++) - result.push_back(*p); - - for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++) - result.push_back(*p); - - return result; -} - -void -gr_simple_flowgraph_detail::topological_dfs_visit(gr_basic_block_sptr block, gr_block_vector_t &output) -{ - boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::GREY); - - gr_basic_block_vector_t blocks(calc_downstream_blocks(block)); - - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - switch (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color()) { - case gr_block_detail::WHITE: - topological_dfs_visit(*p, output); - break; - - case gr_block_detail::GREY: - throw std::runtime_error("flow graph has loops!"); - - case gr_block_detail::BLACK: - continue; - - default: - throw std::runtime_error("invalid color on block!"); - } - } - - gr_block_sptr result_block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)); - - result_block->detail()->set_color(gr_block_detail::BLACK); - output.push_back(result_block); -} - -bool -gr_simple_flowgraph_detail::has_block_p(gr_basic_block_sptr block) -{ - gr_basic_block_viter_t result; - result = std::find(d_blocks.begin(), d_blocks.end(), block); - return (result != d_blocks.end()); -} - -gr_edge_sptr -gr_simple_flowgraph_detail::calc_upstream_edge(gr_basic_block_sptr block, int port) -{ - gr_edge_sptr result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if ((*p)->dst().block() == block && (*p)->dst().port() == port) { - result = (*p); - break; - } - } - - return result; -} - -gr_block_detail_sptr -gr_simple_flowgraph_detail::allocate_block_detail(gr_basic_block_sptr block, gr_block_detail_sptr old_detail) -{ - int ninputs = calc_used_ports(block, true).size(); - int noutputs = calc_used_ports(block, false).size(); - gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs); - - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Creating block detail for " << block << std::endl; - - // Re-use or allocate output buffers - for (int i = 0; i < noutputs; i++) { - gr_buffer_sptr buffer; - - if (!old_detail || i >= old_detail->noutputs()) { - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Allocating new buffer for output " << i << std::endl; - buffer = allocate_buffer(block, i); - } - else { - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Reusing old buffer for output " << i << std::endl; - buffer = old_detail->output(i); - } - - detail->set_output(i, buffer); - } - - return detail; -} - -void -gr_simple_flowgraph_detail::connect_block_inputs(gr_basic_block_sptr block) -{ - gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)); - if (!grblock) - throw std::runtime_error("found non-gr_block"); - - // Get its detail and edges that feed into it - gr_block_detail_sptr detail = grblock->detail(); - gr_edge_vector_t in_edges = calc_upstream_edges(block); - - // For each edge that feeds into it - for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) { - // Set the buffer reader on the destination port to the output - // buffer on the source port - int dst_port = (*e)->dst().port(); - int src_port = (*e)->src().port(); - gr_basic_block_sptr src_block = (*e)->src().block(); - gr_block_sptr src_grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(src_block)); - if (!grblock) - throw std::runtime_error("found non-gr_block"); - gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port); - - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl; - - detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1)); - } -} - -gr_buffer_sptr -gr_simple_flowgraph_detail::allocate_buffer(gr_basic_block_sptr block, int port) -{ - gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)); - if (!grblock) - throw std::runtime_error("allocate_buffer found non-gr_block"); - int item_size = block->output_signature()->sizeof_stream_item(port); - int nitems = s_fixed_buffer_size/item_size; - - // Make sure there are at least twice the output_multiple no. of items - if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple() - nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically - - // If any downstream blocks are decimators and/or have a large output_multiple, - // ensure we have a buffer at least twice their decimation factor*output_multiple - gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port); - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - gr_block_sptr dgrblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)); - if (!dgrblock) - throw std::runtime_error("allocate_buffer found non-gr_block"); - int decimation = (int)(1.0/dgrblock->relative_rate()); - int multiple = dgrblock->output_multiple(); - int history = dgrblock->history(); - nitems = std::max(nitems, 2*(decimation*multiple+history)); - } - - return gr_make_buffer(nitems, item_size); -} - -void -gr_simple_flowgraph_detail::setup_connections() -{ - // Assign block details to blocks - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) - boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->set_detail(allocate_block_detail(*p)); - - // Connect inputs to outputs for each block - for(gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) - connect_block_inputs(*p); -} - -void -gr_simple_flowgraph_detail::merge_connections(gr_simple_flowgraph_sptr old_sfg) -{ - std::map<gr_block_sptr, gr_block_detail_sptr> old_details; - - // Allocate or reuse output buffers - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)); - - gr_block_detail_sptr old_detail = block->detail(); - block->set_detail(allocate_block_detail(block, old_detail)); - - // Save old detail for use in next step - old_details[block] = old_detail; - } - - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)); - - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "merge: testing " << (*p) << "..."; - - if (old_sfg->d_detail->has_block_p(*p)) { - // Block exists in old flow graph - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "used in old flow graph" << std::endl; - gr_block_detail_sptr detail = block->detail(); - - // Iterate through the inputs and see what needs to be done - for (int i = 0; i < detail->ninputs(); i++) { - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "Checking input " << i << "..."; - - gr_edge_sptr edge = calc_upstream_edge(*p, i); - if (!edge) - throw std::runtime_error("merge: missing input edge"); - - // Fish out old buffer reader and see if it matches correct buffer from edge list - gr_block_sptr src_block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(edge->src().block())); - gr_block_detail_sptr src_detail = src_block->detail(); - gr_buffer_sptr src_buffer = src_detail->output(edge->src().port()); - gr_buffer_reader_sptr old_reader; - gr_block_detail_sptr old_detail = old_details[block]; - if (old_detail && i < old_detail->ninputs()) - old_reader = old_detail->input(i); - - // If there's a match, use it - if (old_reader && (src_buffer == old_reader->buffer())) { - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "matched" << std::endl; - detail->set_input(i, old_reader); - - } - else { - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "needs a new reader" << std::endl; - - // Create new buffer reader and assign - detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1)); - } - } - } - else { - // Block is new, it just needs buffer readers at this point - if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG) - std::cout << "new block" << std::endl; - connect_block_inputs(block); - } - } -} diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h deleted file mode 100644 index 53b620350..000000000 --- a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GR_SIMPLE_FLOWGRAPH_DETAIL_H -#define INCLUDED_GR_SIMPLE_FLOWGRAPH_DETAIL_H - -#include <gr_basic_block.h> -#include <gr_simple_flowgraph.h> -#include <iostream> - -#define GR_FIXED_BUFFER_SIZE (32*(1L<<10)) - -class gr_edge; -typedef boost::shared_ptr<gr_edge> gr_edge_sptr; -gr_edge_sptr gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst); - -class gr_edge -{ -private: - friend gr_edge_sptr gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst); - gr_edge(const gr_endpoint &src, const gr_endpoint &dst) : d_src(src), d_dst(dst) { } - - gr_endpoint d_src; - gr_endpoint d_dst; - -public: - ~gr_edge(); - - const gr_endpoint &src() const { return d_src; } - const gr_endpoint &dst() const { return d_dst; } -}; - -typedef std::vector<gr_edge_sptr> gr_edge_vector_t; -typedef std::vector<gr_edge_sptr>::iterator gr_edge_viter_t; - -class gr_simple_flowgraph_detail -{ -private: - friend class gr_simple_flowgraph; - friend class gr_runtime_impl; - friend class gr_hier_block2_detail; - friend class topo_block_cmp; - - gr_simple_flowgraph_detail() : d_blocks(), d_edges() { } - - gr_basic_block_vector_t d_blocks; - gr_edge_vector_t d_edges; - static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE; - - void reset(); - void connect(const gr_endpoint &src, const gr_endpoint &dst); - void disconnect(const gr_endpoint &src, const gr_endpoint &dst); - void check_valid_port(gr_io_signature_sptr sig, int port); - void check_dst_not_used(const gr_endpoint &dst); - void check_type_match(const gr_endpoint &src, const gr_endpoint &dst); - void validate(); - gr_edge_vector_t calc_connections(gr_basic_block_sptr block, bool check_inputs); // false=use outputs - std::vector<int> calc_used_ports(gr_basic_block_sptr block, bool check_inputs); - void check_contiguity(gr_basic_block_sptr block, const std::vector<int> &used_ports, bool check_inputs); - void setup_connections(); - void merge_connections(gr_simple_flowgraph_sptr sfg); - - void connect_block_inputs(gr_basic_block_sptr block); - gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block, - gr_block_detail_sptr old_detail=gr_block_detail_sptr()); - gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port); - gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block, int port); - gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block); - gr_edge_sptr calc_upstream_edge(gr_basic_block_sptr block, int port); - gr_edge_vector_t calc_upstream_edges(gr_basic_block_sptr block); - gr_basic_block_vector_t calc_used_blocks(); - std::vector<gr_block_vector_t> partition(); - gr_basic_block_vector_t calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); - gr_block_vector_t topological_sort(gr_basic_block_vector_t &blocks); - void reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); - gr_basic_block_vector_t calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks); - bool source_p(gr_basic_block_sptr block); - gr_basic_block_vector_t sort_sources_first(gr_basic_block_vector_t &blocks); - void topological_dfs_visit(gr_basic_block_sptr block, gr_block_vector_t &output); - bool has_block_p(gr_basic_block_sptr block); - -public: - ~gr_simple_flowgraph_detail(); -}; - -inline std::ostream& -operator <<(std::ostream &os, const gr_endpoint endp) -{ - os << endp.block() << ":" << endp.port(); - return os; -} - -inline std::ostream& -operator <<(std::ostream &os, const gr_edge_sptr edge) -{ - os << edge->src() << "->" << edge->dst(); - return os; -} - -inline void -enumerate_edges(gr_edge_vector_t &edges) -{ - std::cout << "Edge list has " << edges.size() << " elements" << std::endl; - for(gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) - std::cout << *p << std::endl; -} - -#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */ diff --git a/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc new file mode 100644 index 000000000..c883c1678 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc @@ -0,0 +1,245 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qa_gr_flowgraph.h> +#include <gr_flowgraph.h> +#include <gr_nop.h> +#include <gr_null_source.h> +#include <gr_null_sink.h> + +void qa_gr_flowgraph::t0() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + CPPUNIT_ASSERT(fg); +} + +void qa_gr_flowgraph::t1_connect() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); +} + +void qa_gr_flowgraph::t2_connect_invalid_src_port_neg() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + CPPUNIT_ASSERT_THROW(fg->connect(nop1, -1, nop2, 0), std::invalid_argument); +} + +void qa_gr_flowgraph::t3_connect_src_port_exceeds() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr src = gr_make_null_source(sizeof(int)); + gr_block_sptr dst = gr_make_null_sink(sizeof(int)); + + CPPUNIT_ASSERT_THROW(fg->connect(src, 1, dst, 0), std::invalid_argument); +} + +void qa_gr_flowgraph::t4_connect_invalid_dst_port_neg() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + CPPUNIT_ASSERT_THROW(fg->connect(nop1, 0, nop2, -1), std::invalid_argument); +} + +void qa_gr_flowgraph::t5_connect_dst_port_exceeds() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr src = gr_make_null_source(sizeof(int)); + gr_block_sptr dst = gr_make_null_sink(sizeof(int)); + + CPPUNIT_ASSERT_THROW(fg->connect(src, 0, dst, 1), std::invalid_argument); +} + +void qa_gr_flowgraph::t6_connect_dst_in_use() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr src1 = gr_make_null_source(sizeof(int)); + gr_block_sptr src2 = gr_make_null_source(sizeof(int)); + gr_block_sptr dst = gr_make_null_sink(sizeof(int)); + + fg->connect(src1, 0, dst, 0); + CPPUNIT_ASSERT_THROW(fg->connect(src2, 0, dst, 0), std::invalid_argument); +} + +void qa_gr_flowgraph::t7_connect_one_src_two_dst() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr src = gr_make_null_source(sizeof(int)); + gr_block_sptr dst1 = gr_make_null_sink(sizeof(int)); + gr_block_sptr dst2 = gr_make_null_sink(sizeof(int)); + + fg->connect(src, 0, dst1, 0); + fg->connect(src, 0, dst2, 0); +} + +void qa_gr_flowgraph::t8_connect_type_mismatch() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(char)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + CPPUNIT_ASSERT_THROW(fg->connect(nop1, 0, nop2, 0), std::invalid_argument); +} + +void qa_gr_flowgraph::t9_disconnect() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + fg->disconnect(nop1, 0, nop2, 0); +} + +void qa_gr_flowgraph::t10_disconnect_unconnected_block() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + gr_block_sptr nop3 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + CPPUNIT_ASSERT_THROW(fg->disconnect(nop1, 0, nop3, 0), std::invalid_argument); +} + +void qa_gr_flowgraph::t11_disconnect_unconnected_port() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + CPPUNIT_ASSERT_THROW(fg->disconnect(nop1, 0, nop2, 1), std::invalid_argument); +} + +void qa_gr_flowgraph::t12_validate() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + fg->validate(); +} + +void qa_gr_flowgraph::t13_validate_missing_input_assignment() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + fg->connect(nop1, 0, nop2, 2); + CPPUNIT_ASSERT_THROW(fg->validate(), std::runtime_error); +} + +void qa_gr_flowgraph::t14_validate_missing_output_assignment() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + fg->connect(nop1, 2, nop2, 1); + CPPUNIT_ASSERT_THROW(fg->validate(), std::runtime_error); +} + +void qa_gr_flowgraph::t15_clear() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop1 = gr_make_nop(sizeof(int)); + gr_block_sptr nop2 = gr_make_nop(sizeof(int)); + + fg->connect(nop1, 0, nop2, 0); + + CPPUNIT_ASSERT(fg->edges().size() == 1); + CPPUNIT_ASSERT(fg->calc_used_blocks().size() == 2); + + fg->clear(); + + CPPUNIT_ASSERT(fg->edges().size() == 0); + CPPUNIT_ASSERT(fg->calc_used_blocks().size() == 0); +} + +void qa_gr_flowgraph::t16_partition() +{ + gr_flowgraph_sptr fg = gr_make_flowgraph(); + + gr_block_sptr nop11 = gr_make_nop(sizeof(int)); + gr_block_sptr nop12 = gr_make_nop(sizeof(int)); + gr_block_sptr nop13 = gr_make_nop(sizeof(int)); + gr_block_sptr nop14 = gr_make_nop(sizeof(int)); + + gr_block_sptr nop21 = gr_make_nop(sizeof(int)); + gr_block_sptr nop22 = gr_make_nop(sizeof(int)); + gr_block_sptr nop23 = gr_make_nop(sizeof(int)); + + gr_block_sptr nop31 = gr_make_nop(sizeof(int)); + gr_block_sptr nop32 = gr_make_nop(sizeof(int)); + + // Build disjoint graph #1 + fg->connect(nop11, 0, nop12, 0); + fg->connect(nop12, 0, nop13, 0); + fg->connect(nop13, 0, nop14, 0); + + // Build disjoint graph #2 + fg->connect(nop21, 0, nop22, 0); + fg->connect(nop22, 0, nop23, 0); + + // Build disjoint graph #3 + fg->connect(nop31, 0, nop32, 0); + + std::vector<gr_basic_block_vector_t> graphs = fg->partition(); + + CPPUNIT_ASSERT(graphs.size() == 3); + CPPUNIT_ASSERT(graphs[0].size() == 4); + CPPUNIT_ASSERT(graphs[1].size() == 3); + CPPUNIT_ASSERT(graphs[2].size() == 2); +} diff --git a/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h new file mode 100644 index 000000000..2253afccd --- /dev/null +++ b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QA_GR_FLOWGRAPH_H +#define INCLUDED_QA_GR_FLOWGRAPH_H + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> +#include <stdexcept> + +class qa_gr_flowgraph : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_gr_flowgraph); + + CPPUNIT_TEST(t0); + CPPUNIT_TEST(t1_connect); + CPPUNIT_TEST(t2_connect_invalid_src_port_neg); + CPPUNIT_TEST(t3_connect_src_port_exceeds); + CPPUNIT_TEST(t4_connect_invalid_dst_port_neg); + CPPUNIT_TEST(t5_connect_dst_port_exceeds); + CPPUNIT_TEST(t6_connect_dst_in_use); + CPPUNIT_TEST(t7_connect_one_src_two_dst); + CPPUNIT_TEST(t8_connect_type_mismatch); + CPPUNIT_TEST(t9_disconnect); + CPPUNIT_TEST(t10_disconnect_unconnected_block); + CPPUNIT_TEST(t11_disconnect_unconnected_port); + CPPUNIT_TEST(t12_validate); + CPPUNIT_TEST(t13_validate_missing_input_assignment); + CPPUNIT_TEST(t14_validate_missing_output_assignment); + CPPUNIT_TEST(t15_clear); + CPPUNIT_TEST(t16_partition); + + CPPUNIT_TEST_SUITE_END(); + +private: + + void t0(); + void t1_connect(); + void t2_connect_invalid_src_port_neg(); + void t3_connect_src_port_exceeds(); + void t4_connect_invalid_dst_port_neg(); + void t5_connect_dst_port_exceeds(); + void t6_connect_dst_in_use(); + void t7_connect_one_src_two_dst(); + void t8_connect_type_mismatch(); + void t9_disconnect(); + void t10_disconnect_unconnected_block(); + void t11_disconnect_unconnected_port(); + void t12_validate(); + void t13_validate_missing_input_assignment(); + void t14_validate_missing_output_assignment(); + void t15_clear(); + void t16_partition(); +}; + +#endif /* INCLUDED_QA_GR_FLOWGRAPH_H */ diff --git a/gnuradio-core/src/lib/runtime/qa_runtime.cc b/gnuradio-core/src/lib/runtime/qa_runtime.cc index 2abdc36b3..5c00a4fbe 100644 --- a/gnuradio-core/src/lib/runtime/qa_runtime.cc +++ b/gnuradio-core/src/lib/runtime/qa_runtime.cc @@ -1,5 +1,5 @@ /* - * Copyright 2002 Free Software Foundation, Inc. + * Copyright 2002,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -33,6 +33,7 @@ #include <qa_gr_vmcircbuf.h> #include <qa_gr_io_signature.h> #include <qa_gr_block.h> +#include <qa_gr_flowgraph.h> #include <qa_gr_hier_block2.h> #include <qa_gr_buffer.h> @@ -44,6 +45,7 @@ qa_runtime::suite () s->addTest (qa_gr_vmcircbuf::suite ()); s->addTest (qa_gr_io_signature::suite ()); s->addTest (qa_gr_block::suite ()); + s->addTest (qa_gr_flowgraph::suite ()); s->addTest (qa_gr_hier_block2::suite ()); s->addTest (qa_gr_buffer::suite ()); diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py index 1e12a5d73..9fa002501 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py @@ -20,14 +20,6 @@ class test_hier_block2(gr_unittest.TestCase): self.assertEqual(1, hblock.output_signature().max_streams()) self.assertEqual(gr.sizeof_int, hblock.output_signature().sizeof_stream_item(0)) - def test_001_connect_internal(self): - hblock = gr.hier_block2("test_block", - gr.io_signature(1,1,gr.sizeof_int), - gr.io_signature(1,1,gr.sizeof_int)) - nop1 = gr.nop(gr.sizeof_int) - nop2 = gr.nop(gr.sizeof_int) - hblock.connect(nop1, nop2) - def test_002_connect_input(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), @@ -35,7 +27,7 @@ class test_hier_block2(gr_unittest.TestCase): nop1 = gr.nop(gr.sizeof_int) hblock.connect(hblock, nop1) - def test_002a_connect_input_in_use(self): + def test_003_connect_input_in_use(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -45,14 +37,14 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.connect(hblock, nop2)) - def test_003_connect_output(self): + def test_004_connect_output(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) nop1 = gr.nop(gr.sizeof_int) hblock.connect(nop1, hblock) - def test_003a_connect_output_in_use(self): + def test_005_connect_output_in_use(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -62,7 +54,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.connect(nop2, hblock)) - def test_004_connect_invalid_src_port_neg(self): + def test_006_connect_invalid_src_port_neg(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -78,7 +70,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.connect((hblock, 1), nop1)) - def test_006_connect_invalid_dst_port_neg(self): + def test_007_connect_invalid_dst_port_neg(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -87,7 +79,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.connect(nop1, (nop2, -1))) - def test_007_connect_invalid_dst_port_exceeds(self): + def test_008_connect_invalid_dst_port_exceeds(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -96,54 +88,11 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.connect(nop1, (nop2, 1))) - def test_008_connect_dst_port_in_use(self): - hblock = gr.hier_block2("test_block", - gr.io_signature(1,1,gr.sizeof_int), - gr.io_signature(1,1,gr.sizeof_int)) - nop1 = gr.nop(gr.sizeof_int) - nop2 = gr.nop(gr.sizeof_int) - hblock.connect(nop1, nop2); - self.assertRaises(ValueError, - lambda: hblock.connect(nop1, nop2)) - - def test_009_connect_one_src_two_dst(self): - hblock = gr.top_block("test_block") - src = gr.null_source(gr.sizeof_int) - dst1 = gr.null_sink(gr.sizeof_int) - dst2 = gr.null_sink(gr.sizeof_int) - hblock.connect(src, dst1) - hblock.connect(src, dst2) - - def test_010_connect_type_mismatch(self): - hblock = gr.top_block("test_block") - nop1 = gr.nop(gr.sizeof_char) - nop2 = gr.nop(gr.sizeof_int) - self.assertRaises(ValueError, - lambda: hblock.connect(nop1, nop2)) - - def test_011_check_topology(self): + def test_009_check_topology(self): hblock = gr.top_block("test_block") hblock.check_topology(0, 0) - def test_012_disconnect(self): - hblock = gr.top_block("test_block") - nop1 = gr.nop(gr.sizeof_int) - nop2 = gr.nop(gr.sizeof_int) - hblock.connect(nop1, nop2) - hblock.disconnect(nop1, nop2) - - def test_013_disconnect_not_connected(self): - hblock = gr.hier_block2("test_block", - gr.io_signature(1,1,gr.sizeof_int), - gr.io_signature(1,1,gr.sizeof_int)) - nop1 = gr.nop(gr.sizeof_int) - nop2 = gr.nop(gr.sizeof_int) - nop3 = gr.nop(gr.sizeof_int) - hblock.connect(nop1, nop2) - self.assertRaises(ValueError, - lambda: hblock.disconnect(nop1, nop3)) - - def test_014_run(self): + def test_010_run(self): expected = (1.0, 2.0, 3.0, 4.0) hblock = gr.top_block("test_block") src = gr.vector_source_f(expected, False) @@ -158,7 +107,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertEquals(expected, actual1) self.assertEquals(expected, actual2) - def test_015_disconnect_input(self): + def test_012_disconnect_input(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -166,7 +115,7 @@ class test_hier_block2(gr_unittest.TestCase): hblock.connect(hblock, nop1) hblock.disconnect(hblock, nop1) - def test_016_disconnect_input_not_connected(self): + def test_013_disconnect_input_not_connected(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -176,7 +125,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect(hblock, nop2)) - def test_017_disconnect_input_neg(self): + def test_014_disconnect_input_neg(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -185,7 +134,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect((hblock, -1), nop1)) - def test_018_disconnect_input_exceeds(self): + def test_015_disconnect_input_exceeds(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -194,7 +143,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect((hblock, 1), nop1)) - def test_019_disconnect_output(self): + def test_016_disconnect_output(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -202,7 +151,7 @@ class test_hier_block2(gr_unittest.TestCase): hblock.connect(nop1, hblock) hblock.disconnect(nop1, hblock) - def test_020_disconnect_output_not_connected(self): + def test_017_disconnect_output_not_connected(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -212,7 +161,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect(nop2, hblock)) - def test_021_disconnect_output_neg(self): + def test_018_disconnect_output_neg(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -221,7 +170,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect(nop1, (hblock, -1))) - def test_022_disconnect_output_exceeds(self): + def test_019_disconnect_output_exceeds(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) @@ -230,7 +179,7 @@ class test_hier_block2(gr_unittest.TestCase): self.assertRaises(ValueError, lambda: hblock.disconnect(nop1, (hblock, 1))) - def test_023_run(self): + def test_020_run(self): hblock = gr.top_block("test_block") data = (1.0, 2.0, 3.0, 4.0) src = gr.vector_source_f(data, False) |