summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/doxygen/other/group_defs.dox1
-rw-r--r--docs/doxygen/other/main_page.dox275
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.cc4
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.h74
-rw-r--r--gnuradio-core/src/lib/runtime/gr_basic_block.i6
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.cc31
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.h39
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.i6
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.cc4
-rw-r--r--gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc30
-rw-r--r--gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc5
-rw-r--r--gnuradio-core/src/lib/runtime/qa_gr_top_block.cc143
-rw-r--r--gnuradio-core/src/lib/runtime/qa_gr_top_block.h8
-rw-r--r--gr-uhd/examples/grc/uhd_fft.grc707
-rw-r--r--grc/gui/ActionHandler.py130
-rw-r--r--grc/gui/Actions.py6
-rw-r--r--grc/gui/FlowGraph.py3
17 files changed, 1362 insertions, 110 deletions
diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox
index 213486b7a1..4aee49ec85 100644
--- a/docs/doxygen/other/group_defs.dox
+++ b/docs/doxygen/other/group_defs.dox
@@ -28,6 +28,7 @@
/*! \defgroup slicedice_blk Slicing and Dicing Streams */
/*! \defgroup vocoder_blk Voice Encoders and Decoders */
/*! \defgroup digital Digital Modulation Blocks */
+/*! \defgroup analog Analog Communications Blocks */
/*! \defgroup qtgui_blk QT Graphical Interfaces */
/*! \defgroup uhd_blk UHD Interface */
/*! \defgroup audio_blk Audio Interface */
diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox
index 8f69a97373..2826824647 100644
--- a/docs/doxygen/other/main_page.dox
+++ b/docs/doxygen/other/main_page.dox
@@ -39,6 +39,280 @@ More details on packages in GNU Radio:
\li \ref page_vocoder
\li \ref page_pfb
+
+\section flowgraph Operating a Flowgraph
+
+The basic data structure in GNU Radio is the flowgraph, which
+represents the connections of the blocks through which a continuous
+stream of samples flows. The concept of a flowgraph is an acyclic
+directional graph with one or more source blocks (to insert samples
+into the flowgraph), one or more sink blocks (to terminate or export
+samples from the flowgraph), and any signal processing blocks in
+between.
+
+A program must at least create a GNU Radio 'top_block', which
+represents the top-most structure of the flowgraph. The top blocks
+provide the overall control and hold methods such as 'start,' 'stop,'
+and 'wait.'
+
+The general construction of a GNU Radio application is to create a
+gr_top_block, instantiate the blocks, connect the blocks together, and
+then start the gr_top_block. The following program shows how this is
+done. A single source and sink are used with a FIR filter between
+them.
+
+\code
+ from gnuradio import gr, filter
+
+ class my_topblock(gr.top_block):
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ amp = 1
+ taps = filter.firdes.low_pass(1, 1, 0.1, 0.01)
+
+ self.src = gr.noise_source_c(gr.GR_GAUSSIAN, amp)
+ self.flt = filter.fir_filter_ccf(1, taps)
+ self.snk = gr.null_sink(gr.sizeof_gr_complex)
+
+ self.connect(self.src, self.flt, self.snk)
+
+ if __name__ == "__main__":
+ tb = my_topblock()
+ tb.start()
+ tb.wait()
+\endcode
+
+The 'tb.start()' starts the data flowing through the flowgraph while
+the 'tb.wait()' is the equivalent of a thread's 'join' operation and
+blocks until the gr_top_block is done.
+
+An alternative to using the 'start' and 'wait' methods, a 'run' method is
+also provided for convenience that is a blocking start call;
+equivalent to the above 'start' followed by a 'wait.'
+
+
+\subsection latency Latency and Throughput
+
+By default, GNU Radio runs a scheduler that attempts to optimize
+throughput. Using a dynamic scheduler, blocks in a flowgraph pass
+chunks of items from sources to sinks. The sizes of these chunks will
+vary depending on the speed of processing. For each block, the number
+of items is can process is dependent on how much space it has in its
+output buffer(s) and how many items are available on the input
+buffer(s).
+
+The consequence of this is that often a block may be called with a very
+large number of items to process (several thousand). In terms of
+speed, this is efficient since now the majority of the processing time
+is taken up with processing samples. Smaller chunks mean more calls
+into the scheduler to retrieve more data. The downside to this is that
+it can lead to large latency while a block is processing a large chunk
+of data.
+
+To combat this problem, the gr_top_block can be passed a limit on the
+number of output items a block will ever receive. A block may get less
+than this number, but never more, and so it serves as an upper limit
+to the latency any block will exhibit. By limiting the number of items
+per call to a block, though, we increase the overhead of the
+scheduler, and so reduce the overall efficiency of the application.
+
+To set the maximum number of output items, we pass a value into the
+'start' or 'run' method of the gr_top_block:
+
+\code
+ tb.start(1000)
+ tb.wait()
+or
+ tb.run(1000)
+\endcode
+
+Using this method, we place a global restriction on the size of items
+to all blocks. Each block, though, has the ability to overwrite this
+with its own limit. Using the 'set_max_noutput_items(m)' method for an
+individual block will overwrite the global setting. For example, in
+the following code, the global setting is 1000 items max, except for
+the FIR filter, which can receive up to 2000 items.
+
+\code
+ tb.flt.set_max_noutput_items(2000)
+ tb.run(1000)
+\endcode
+
+In some situations, you might actually want to restrict the size of
+the buffer itself. This can help to prevent a buffer who is blocked
+for data from just increasing the amount of items in its buffer, which
+will then cause an increased latency for new samples. You can set the
+size of an output buffer for each output port for every block.
+
+WARNING: This is an advanced feature in GNU Radio and should not be
+used without a full understanding of this concept as explained below.
+
+To set the output buffer size of a block, you simply call:
+
+\code
+ tb.blk0.set_max_output_buffer(2000)
+ tb.blk1.set_max_output_buffer(1, 2000)
+ tb.start()
+ print tb.blk1.max_output_buffer(0)
+ print tb.blk1.max_output_buffer(1)
+\endcode
+
+In the above example, all ports of blk0 are set to a buffer size of
+2000 in _items_ (not bytes), and blk1 only sets the size for output
+port 1, any and all other ports use the default. The third and fourth
+lines just print out the buffer sizes for ports 0 and 1 of blk1. This
+is done after start() is called because the values are updated based
+on what is actually allocated to the block's buffers.
+
+NOTES:
+
+1. Buffer length assignment is done once at runtime (i.e., when run()
+or start() is called). So to set the max buffer lengths, the
+set_max_output_buffer calls must be done before this.
+
+2. Once the flowgraph is started, the buffer lengths for a block are
+set and cannot be dynamically changed, even during a
+lock()/unlock(). If you need to change the buffer size, you will have
+to delete the block and rebuild it, and therefore must disconnect and
+reconnect the blocks.
+
+3. This can affect throughput. Large buffers are designed to improve
+the efficiency and speed of the program at the expense of
+latency. Limiting the size of the buffer may decrease performance.
+
+4. The real buffer size is actually based on a minimum granularity of
+the system. Typically, this is a page size, which is typically 4096
+bytes. This means that any buffer size that is specified with this
+command will get rounded up to the nearest granularity (e.g., page)
+size. When calling max_output_buffer(port) after the flowgraph is
+started, you will get how many items were actually allocated in the
+buffer, which may be different than what was initially specified.
+
+
+\section reconfigure Reconfiguring Flowgraphs
+
+It is possible to reconfigure the flowgraph at runtime. The
+reconfiguration is meant for changes in the flowgraph structure, not
+individual parameter settings of the blocks. For example, changing the
+constant in a gr_add_const_cc block can be done while the flowgraph is
+running using the 'set_k(k)' method.
+
+Reconfiguration is done by locking the flowgraph, which stops it from
+running and processing data, performing the reconfiguration, and then
+restarting the graph by unlocking it.
+
+The following example code shows a graph that first adds two
+gr_noise_source_c blocks and then replaces the gr_add_cc block with a
+gr_sub_cc block to then subtract the sources.
+
+\code
+from gnuradio import gr
+import time
+
+class mytb(gr.top_block):
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.add = gr.add_cc()
+ self.sub = gr.sub_cc()
+ self.head = gr.head(gr.sizeof_gr_complex, 1000000)
+ self.snk = gr.file_sink(gr.sizeof_gr_complex, "output.32fc")
+
+ self.connect(self.src0, (self.add,0))
+ self.connect(self.src1, (self.add,1))
+ self.connect(self.add, self.head)
+ self.connect(self.head, self.snk)
+
+def main():
+ tb = mytb()
+ tb.start()
+ time.sleep(0.01)
+
+ # Stop flowgraph and disconnect the add block
+ tb.lock()
+ tb.disconnect(tb.add, tb.head)
+ tb.disconnect(tb.src0, (tb.add,0))
+ tb.disconnect(tb.src1, (tb.add,1))
+
+ # Connect the sub block and restart
+ tb.connect(tb.sub, tb.head)
+ tb.connect(tb.src0, (tb.sub,0))
+ tb.connect(tb.src1, (tb.sub,1))
+ tb.unlock()
+
+ tb.wait()
+
+if __name__ == "__main__":
+ main()
+\endcode
+
+During reconfiguration, the maximum noutput_items value can be changed
+either globally using the 'set_max_noutput_items(m)' on the gr_top_block
+object or locally using the 'set_max_noutput_items(m)' on any given
+block object.
+
+A block also has a 'unset_max_noutput_items()' method that unsets the
+local max noutput_items value so that block reverts back to using the
+global value.
+
+The following example expands the previous example but sets and resets
+the max noutput_items both locally and globally.
+
+\code
+from gnuradio import gr
+import time
+
+class mytb(gr.top_block):
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.add = gr.add_cc()
+ self.sub = gr.sub_cc()
+ self.head = gr.head(gr.sizeof_gr_complex, 1000000)
+ self.snk = gr.file_sink(gr.sizeof_gr_complex, "output.32fc")
+
+ self.connect(self.src0, (self.add,0))
+ self.connect(self.src1, (self.add,1))
+ self.connect(self.add, self.head)
+ self.connect(self.head, self.snk)
+
+def main():
+ # Start the gr_top_block after setting some max noutput_items.
+ tb = mytb()
+ tb.src1.set_max_noutput_items(2000)
+ tb.start(100)
+ time.sleep(0.01)
+
+ # Stop flowgraph and disconnect the add block
+ tb.lock()
+
+ tb.disconnect(tb.add, tb.head)
+ tb.disconnect(tb.src0, (tb.add,0))
+ tb.disconnect(tb.src1, (tb.add,1))
+
+ # Connect the sub block
+ tb.connect(tb.sub, tb.head)
+ tb.connect(tb.src0, (tb.sub,0))
+ tb.connect(tb.src1, (tb.sub,1))
+
+ # Set new max_noutput_items for the gr_top_block
+ # and unset the local value for src1
+ tb.set_max_noutput_items(1000)
+ tb.src1.unset_max_noutput_items()
+ tb.unlock()
+
+ tb.wait()
+
+if __name__ == "__main__":
+ main()
+\endcode
+
+
\section volk_main Using Volk in GNU Radio
The \ref volk_guide page provides an overview of how to incorporate
@@ -48,4 +322,5 @@ Many blocks have already been converted to use Volk in their calls, so
they can also serve as examples. See the gr_complex_to_xxx.h file for
examples of various blocks that make use of Volk.
+
*/
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.cc b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
index d7263b92d0..3d809aa8b7 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
@@ -45,7 +45,9 @@ gr_basic_block::gr_basic_block(const std::string &name,
d_input_signature(input_signature),
d_output_signature(output_signature),
d_unique_id(s_next_id++),
- d_color(WHITE)
+ d_color(WHITE),
+ d_max_output_buffer(std::max(output_signature->max_streams(),1), -1),
+ d_min_output_buffer(std::max(output_signature->max_streams(),1), -1)
{
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 4d03b878e7..b8e8148b23 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.h
@@ -29,7 +29,9 @@
#include <boost/enable_shared_from_this.hpp>
#include <boost/function.hpp>
#include <gr_msg_accepter.h>
+#include <gr_io_signature.h>
#include <string>
+#include <iostream>
/*!
* \brief The abstract base class for all signal processing blocks.
@@ -61,6 +63,20 @@ private:
msg_handler_t d_msg_handler;
+ /*
+ * Used to expand the vectors that hold the min/max buffer sizes.
+ *
+ * Specifically, when -1 is used, the vectors are just initialized
+ * with 1 value; this is used by the flat_flowgraph to expand when
+ * required to add a new value for new ports on these blocks.
+ */
+ void expand_minmax_buffer(int port) {
+ if((size_t)port >= d_max_output_buffer.size())
+ set_max_output_buffer(port, -1);
+ if((size_t)port >= d_min_output_buffer.size())
+ set_min_output_buffer(port, -1);
+ }
+
protected:
friend class gr_flowgraph;
friend class gr_flat_flowgraph; // TODO: will be redundant
@@ -73,6 +89,8 @@ protected:
gr_io_signature_sptr d_output_signature;
long d_unique_id;
vcolor d_color;
+ std::vector<long> d_max_output_buffer;
+ std::vector<long> d_min_output_buffer;
gr_basic_block(void){} //allows pure virtual interface sub-classes
@@ -106,6 +124,62 @@ public:
gr_basic_block_sptr to_basic_block(); // Needed for Python type coercion
/*!
+ * \brief Returns max buffer size on output port \p i.
+ */
+ long max_output_buffer(size_t i) {
+ if(i >= d_max_output_buffer.size())
+ throw std::invalid_argument("gr_basic_block::max_output_buffer: port out of range.");
+ return d_max_output_buffer[i];
+ }
+
+ /*!
+ * \brief Sets max buffer size on all output ports.
+ */
+ void set_max_output_buffer(long max_output_buffer) {
+ for(int i=0; i<output_signature()->max_streams(); i++) {
+ set_max_output_buffer(i, max_output_buffer);
+ }
+ }
+
+ /*!
+ * \brief Sets max buffer size on output port \p port.
+ */
+ void set_max_output_buffer(int port, long max_output_buffer) {
+ if((size_t)port >= d_max_output_buffer.size())
+ d_max_output_buffer.push_back(max_output_buffer);
+ else
+ d_max_output_buffer[port] = max_output_buffer;
+ }
+
+ /*!
+ * \brief Returns min buffer size on output port \p i.
+ */
+ long min_output_buffer(size_t i) {
+ if(i >= d_min_output_buffer.size())
+ throw std::invalid_argument("gr_basic_block::min_output_buffer: port out of range.");
+ return d_min_output_buffer[i];
+ }
+
+ /*!
+ * \brief Sets min buffer size on all output ports.
+ */
+ void set_min_output_buffer(long min_output_buffer) {
+ for(int i=0; i<output_signature()->max_streams(); i++) {
+ set_min_output_buffer(i, min_output_buffer);
+ }
+ }
+
+ /*!
+ * \brief Sets min buffer size on output port \p port.
+ */
+ void set_min_output_buffer(int port, long min_output_buffer) {
+ if((size_t)port >= d_min_output_buffer.size())
+ d_min_output_buffer.push_back(min_output_buffer);
+ else
+ d_min_output_buffer[port] = min_output_buffer;
+ }
+
+ /*!
* \brief Confirm that ninputs and noutputs is an acceptable combination.
*
* \param ninputs number of input streams connected
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.i b/gnuradio-core/src/lib/runtime/gr_basic_block.i
index e43cc114c9..7713f2fe15 100644
--- a/gnuradio-core/src/lib/runtime/gr_basic_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.i
@@ -42,6 +42,12 @@ public:
long unique_id() const;
gr_basic_block_sptr to_basic_block();
bool check_topology (int ninputs, int noutputs);
+ long max_output_buffer(int i);
+ void set_max_output_buffer(long max_output_buffer);
+ void set_max_output_buffer(int port, long max_output_buffer);
+ long min_output_buffer(int i);
+ void set_min_output_buffer(long min_output_buffer);
+ void set_min_output_buffer(int port, long min_output_buffer);
};
%rename(block_ncurrently_allocated) gr_basic_block_ncurrently_allocated;
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
index 9a5255a933..7e01c0ba89 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -40,6 +40,8 @@ gr_block::gr_block (const std::string &name,
d_relative_rate (1.0),
d_history(1),
d_fixed_rate(false),
+ d_max_noutput_items_set(false),
+ d_max_noutput_items(0),
d_tag_propagation_policy(TPP_ALL_TO_ALL)
{
}
@@ -208,6 +210,35 @@ gr_block::set_tag_propagation_policy(tag_propagation_policy_t p)
d_tag_propagation_policy = p;
}
+
+int
+gr_block::max_noutput_items()
+{
+ return d_max_noutput_items;
+}
+
+void
+gr_block::set_max_noutput_items(int m)
+{
+ if(m <= 0)
+ throw std::runtime_error("gr_block::set_max_noutput_items: value for max_noutput_items must be greater than 0.\n");
+
+ d_max_noutput_items = m;
+ d_max_noutput_items_set = true;
+}
+
+void
+gr_block::unset_max_noutput_items()
+{
+ d_max_noutput_items_set = false;
+}
+
+bool
+gr_block::is_set_max_noutput_items()
+{
+ return d_max_noutput_items_set;
+}
+
std::ostream&
operator << (std::ostream& os, const gr_block *m)
{
diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h
index 71ac8eee66..c89138bb34 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_block.h
@@ -251,6 +251,43 @@ class GR_CORE_API gr_block : public gr_basic_block {
*/
void set_tag_propagation_policy(tag_propagation_policy_t p);
+ /*!
+ * \brief Return the maximum number of output items this block will
+ * handle during a call to work.
+ */
+ int max_noutput_items();
+
+ /*!
+ * \brief Set the maximum number of ouput items htis block will
+ * handle during a call to work.
+ *
+ * \param m the maximum noutput_items this block will handle.
+ */
+ void set_max_noutput_items(int m);
+
+ /*!
+ * \brief Clear the switch for using the max_noutput_items value of this block.
+ *
+ * When is_set_max_noutput_items() returns 'true', the scheduler
+ * will use the value returned by max_noutput_items() to limit the
+ * size of the number of items possible for this block's work
+ * function. If is_set_max_notput_items() returns 'false', then the
+ * scheduler ignores the internal value and uses the value set
+ * globally in the top_block.
+ *
+ * Use this value to clear the 'is_set' flag so the scheduler will
+ * ignore this. Use the set_max_noutput_items(m) call to both set a
+ * new value for max_noutput_items and to reenable its use in the
+ * scheduler.
+ */
+ void unset_max_noutput_items();
+
+ /*!
+ * \brief Ask the block if the flag is or is not set to use the
+ * internal value of max_noutput_items during a call to work.
+ */
+ bool is_set_max_noutput_items();
+
// ----------------------------------------------------------------------------
private:
@@ -263,6 +300,8 @@ class GR_CORE_API gr_block : public gr_basic_block {
gr_block_detail_sptr d_detail; // implementation details
unsigned d_history;
bool d_fixed_rate;
+ bool d_max_noutput_items_set; // if d_max_noutput_items is valid
+ int d_max_noutput_items; // value of max_noutput_items for this block
tag_propagation_policy_t d_tag_propagation_policy; // policy for moving tags downstream
protected:
diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i
index 4cc260bfe4..e9341e8cbf 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -52,6 +52,12 @@ class gr_block : public gr_basic_block {
uint64_t nitems_read(unsigned int which_input);
uint64_t nitems_written(unsigned int which_output);
+ // Methods to manage the block's max_noutput_items size.
+ int max_noutput_items();
+ void set_max_noutput_items(int m);
+ void unset_max_noutput_items();
+ bool is_set_max_noutput_items();
+
// internal use
gr_block_detail_sptr detail () const { return d_detail; }
void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.cc b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
index c085344757..375b58f563 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_executor.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
@@ -206,7 +206,7 @@ gr_block_executor::run_one_iteration()
// determine the minimum available output space
noutput_items = min_available_space (d, m->output_multiple ());
- noutput_items = std::min(noutput_items, d_max_noutput_items);
+ noutput_items = std::min(noutput_items, max_noutput_items);
LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl);
if (noutput_items == -1) // we're done
goto were_done;
@@ -251,7 +251,7 @@ gr_block_executor::run_one_iteration()
// take a swag at how much output we can sink
noutput_items = (int) (max_items_avail * m->relative_rate ());
noutput_items = round_down (noutput_items, m->output_multiple ());
- noutput_items = std::min(noutput_items, d_max_noutput_items);
+ noutput_items = std::min(noutput_items, max_noutput_items);
LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl);
LOG(*d_log << " noutput_items = " << noutput_items << std::endl);
diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
index 030e2d97de..b70135b854 100644
--- a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
+++ b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
@@ -84,10 +84,14 @@ gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block)
std::cout << "Creating block detail for " << block << std::endl;
for (int i = 0; i < noutputs; i++) {
+ block->expand_minmax_buffer(i);
gr_buffer_sptr buffer = allocate_buffer(block, i);
if (GR_FLAT_FLOWGRAPH_DEBUG)
std::cout << "Allocated buffer for output " << block << ":" << i << std::endl;
detail->set_output(i, buffer);
+
+ // Update the block's max_output_buffer based on what was actually allocated.
+ block->set_max_output_buffer(i, buffer->bufsize());
}
return detail;
@@ -114,6 +118,21 @@ gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port)
// ensure we have a buffer at least twice their decimation factor*output_multiple
gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port);
+ // limit buffer size if indicated
+ if(block->max_output_buffer(port) > 0) {
+// std::cout << "constraining output items to " << block->max_output_buffer(port) << "\n";
+ nitems = std::min((long)nitems, (long)block->max_output_buffer(port));
+ nitems -= nitems%grblock->output_multiple();
+ if( nitems < 1 )
+ throw std::runtime_error("problems allocating a buffer with the given max output buffer constraint!");
+ }
+ else if(block->min_output_buffer(port) > 0) {
+ nitems = std::max((long)nitems, (long)block->min_output_buffer(port));
+ nitems -= nitems%grblock->output_multiple();
+ if( nitems < 1 )
+ throw std::runtime_error("problems allocating a buffer with the given min output buffer constraint!");
+ }
+
for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
gr_block_sptr dgrblock = cast_to_block_sptr(*p);
if (!dgrblock)
@@ -125,6 +144,7 @@ gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port)
nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history)));
}
+// std::cout << "gr_make_buffer(" << nitems << ", " << item_size << ", " << grblock << "\n";
return gr_make_buffer(nitems, item_size, grblock);
}
@@ -267,10 +287,10 @@ gr_flat_flowgraph::setup_buffer_alignment(gr_block_sptr block)
for(int i = 0; i < block->detail()->ninputs(); i++) {
void *r = (void*)block->detail()->input(i)->read_pointer();
unsigned long int ri = (unsigned long int)r % alignment;
- //std::cout << "reader: " << r << " alignment: " << ri << std::endl;
+ //std::cerr << "reader: " << r << " alignment: " << ri << std::endl;
if(ri != 0) {
size_t itemsize = block->detail()->input(i)->get_sizeof_item();
- block->detail()->input(i)->update_read_pointer(ri/itemsize);
+ block->detail()->input(i)->update_read_pointer(alignment-ri/itemsize);
}
block->set_unaligned(0);
block->set_is_unaligned(false);
@@ -279,10 +299,10 @@ gr_flat_flowgraph::setup_buffer_alignment(gr_block_sptr block)
for(int i = 0; i < block->detail()->noutputs(); i++) {
void *w = (void*)block->detail()->output(i)->write_pointer();
unsigned long int wi = (unsigned long int)w % alignment;
- size_t itemsize = block->detail()->output(i)->get_sizeof_item();
- //std::cout << "writer: " << w << " alignment: " << wi << std::endl;
+ //std::cerr << "writer: " << w << " alignment: " << wi << std::endl;
if(wi != 0) {
- block->detail()->output(i)->update_write_pointer(wi/itemsize);
+ size_t itemsize = block->detail()->output(i)->get_sizeof_item();
+ block->detail()->output(i)->update_write_pointer(alignment-wi/itemsize);
}
block->set_unaligned(0);
block->set_is_unaligned(false);
diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc
index 131ddd19cd..2824eb1b3b 100644
--- a/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc
+++ b/gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc
@@ -74,6 +74,11 @@ gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_i
for (size_t i = 0; i < blocks.size(); i++){
std::stringstream name;
name << "thread-per-block[" << i << "]: " << blocks[i];
+
+ // If set, use internal value instead of global value
+ if(blocks[i]->is_set_max_noutput_items())
+ max_noutput_items = blocks[i]->max_noutput_items();
+
d_threads.create_thread(
gruel::thread_body_wrapper<tpb_container>(tpb_container(blocks[i], max_noutput_items),
name.str()));
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc
index cc7b7c7205..a0b4755a80 100644
--- a/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc
+++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc
@@ -27,6 +27,7 @@
#include <qa_gr_top_block.h>
#include <gr_top_block.h>
#include <gr_head.h>
+#include <gr_nop.h>
#include <gr_null_source.h>
#include <gr_null_sink.h>
#include <iostream>
@@ -119,3 +120,145 @@ void qa_gr_top_block::t4_reconfigure()
// Wait for flowgraph to end on its own
tb->wait();
}
+
+
+void qa_gr_top_block::t5_max_noutputs()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t5()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->start(100);
+ tb->wait();
+}
+
+void qa_gr_top_block::t6_reconfig_max_noutputs()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t6()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, dst, 0);
+ tb->start(100);
+
+ // Reconfigure with gr_head in the middle
+ tb->lock();
+ tb->disconnect(src, 0, dst, 0);
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->set_max_noutput_items(1000);
+ head->set_max_noutput_items(500);
+ tb->unlock();
+
+ // Wait for flowgraph to end on its own
+ tb->wait();
+}
+
+void qa_gr_top_block::t7_max_noutputs_per_block()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t7()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ head->set_max_noutput_items(100);
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->start();
+ tb->wait();
+}
+
+void qa_gr_top_block::t8_reconfig_max_noutputs_per_block()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t8()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ head->set_max_noutput_items(99);
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, dst, 0);
+ tb->start(201);
+
+ // Reconfigure with gr_head in the middle
+ tb->lock();
+ tb->disconnect(src, 0, dst, 0);
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->set_max_noutput_items(1023);
+ head->set_max_noutput_items(513);
+ tb->unlock();
+
+ // Wait for flowgraph to end on its own
+ tb->wait();
+}
+
+void qa_gr_top_block::t9_max_output_buffer()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t9()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ head->set_max_output_buffer(1024);
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->start();
+ tb->wait();
+}
+
+void qa_gr_top_block::t10_reconfig_max_output_buffer()
+{
+ if (VERBOSE) std::cout << "qa_gr_top_block::t10()\n";
+
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 100000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ head->set_max_output_buffer(1000);
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, dst, 0);
+ tb->start(201);
+
+ // Reconfigure with gr_head in the middle
+ tb->lock();
+ gr_block_sptr nop = gr_make_nop(sizeof(int));
+ nop->set_max_output_buffer(4000);
+ tb->disconnect(src, 0, dst, 0);
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, nop, 0);
+ tb->connect(nop, 0, dst, 0);
+ tb->unlock();
+
+ // Wait for flowgraph to end on its own
+ tb->wait();
+}
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.h b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h
index b223633e56..bb891abca6 100644
--- a/gnuradio-core/src/lib/runtime/qa_gr_top_block.h
+++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h
@@ -36,6 +36,8 @@ class qa_gr_top_block : public CppUnit::TestCase
CPPUNIT_TEST(t2_start_stop_wait);
CPPUNIT_TEST(t3_lock_unlock);
CPPUNIT_TEST(t4_reconfigure); // triggers 'join never returns' bug
+ CPPUNIT_TEST(t5_max_noutputs);
+ CPPUNIT_TEST(t6_reconfig_max_noutputs);
CPPUNIT_TEST_SUITE_END();
@@ -46,6 +48,12 @@ private:
void t2_start_stop_wait();
void t3_lock_unlock();
void t4_reconfigure();
+ void t5_max_noutputs();
+ void t6_reconfig_max_noutputs();
+ void t7_max_noutputs_per_block();
+ void t8_reconfig_max_noutputs_per_block();
+ void t9_max_output_buffer();
+ void t10_reconfig_max_output_buffer();
};
#endif /* INCLUDED_QA_GR_TOP_BLOCK_H */
diff --git a/gr-uhd/examples/grc/uhd_fft.grc b/gr-uhd/examples/grc/uhd_fft.grc
index 29c3750657..2582b5e3b1 100644
--- a/gr-uhd/examples/grc/uhd_fft.grc
+++ b/gr-uhd/examples/grc/uhd_fft.grc
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='ASCII'?>
<flow_graph>
- <timestamp>Sat Oct 8 10:26:30 2011</timestamp>
+ <timestamp>Mon Jun 18 14:20:11 2012</timestamp>
<block>
<key>options</key>
<param>
@@ -13,7 +13,7 @@
</param>
<param>
<key>title</key>
- <value>UHD FFT Plotter</value>
+ <value>UHD FFT</value>
</param>
<param>
<key>author</key>
@@ -21,7 +21,7 @@
</param>
<param>
<key>description</key>
- <value>FFT waveform plot</value>
+ <value>UHD FFT Waveform Plotter</value>
</param>
<param>
<key>window_size</key>
@@ -44,12 +44,16 @@
<value>True</value>
</param>
<param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>_coordinate</key>
- <value>(10, 10)</value>
+ <value>(15, 15)</value>
</param>
<param>
<key>_rotation</key>
@@ -57,34 +61,22 @@
</param>
</block>
<block>
- <key>parameter</key>
+ <key>import</key>
<param>
<key>id</key>
- <value>gain</value>
+ <value>import_0</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
- <key>label</key>
- <value>Default Gain</value>
- </param>
- <param>
- <key>value</key>
- <value>0</value>
- </param>
- <param>
- <key>type</key>
- <value>eng_float</value>
- </param>
- <param>
- <key>short_id</key>
- <value>g</value>
+ <key>import</key>
+ <value>import numpy</value>
</param>
<param>
<key>_coordinate</key>
- <value>(633, 17)</value>
+ <value>(15, 121)</value>
</param>
<param>
<key>_rotation</key>
@@ -95,7 +87,7 @@
<key>parameter</key>
<param>
<key>id</key>
- <value>freq</value>
+ <value>param_samp_rate</value>
</param>
<param>
<key>_enabled</key>
@@ -103,11 +95,11 @@
</param>
<param>
<key>label</key>
- <value>Default Frequency</value>
+ <value>Sample Rate</value>
</param>
<param>
<key>value</key>
- <value>2.45e9</value>
+ <value>1e6</value>
</param>
<param>
<key>type</key>
@@ -115,11 +107,11 @@
</param>
<param>
<key>short_id</key>
- <value>f</value>
+ <value>s</value>
</param>
<param>
<key>_coordinate</key>
- <value>(485, 18)</value>
+ <value>(358, 14)</value>
</param>
<param>
<key>_rotation</key>
@@ -130,7 +122,7 @@
<key>parameter</key>
<param>
<key>id</key>
- <value>address</value>
+ <value>param_freq</value>
</param>
<param>
<key>_enabled</key>
@@ -138,23 +130,23 @@
</param>
<param>
<key>label</key>
- <value>IP Address</value>
+ <value>Default Frequency</value>
</param>
<param>
<key>value</key>
- <value>addr=192.168.11.2</value>
+ <value>2.45e9</value>
</param>
<param>
<key>type</key>
- <value>string</value>
+ <value>eng_float</value>
</param>
<param>
<key>short_id</key>
- <value>a</value>
+ <value>f</value>
</param>
<param>
<key>_coordinate</key>
- <value>(205, 16)</value>
+ <value>(508, 14)</value>
</param>
<param>
<key>_rotation</key>
@@ -165,7 +157,7 @@
<key>parameter</key>
<param>
<key>id</key>
- <value>samp_rate</value>
+ <value>param_gain</value>
</param>
<param>
<key>_enabled</key>
@@ -173,11 +165,11 @@
</param>
<param>
<key>label</key>
- <value>Sample Rate</value>
+ <value>Default Gain</value>
</param>
<param>
<key>value</key>
- <value>1e6</value>
+ <value>0</value>
</param>
<param>
<key>type</key>
@@ -185,11 +177,11 @@
</param>
<param>
<key>short_id</key>
- <value>s</value>
+ <value>g</value>
</param>
<param>
<key>_coordinate</key>
- <value>(359, 18)</value>
+ <value>(672, 13)</value>
</param>
<param>
<key>_rotation</key>
@@ -197,10 +189,10 @@
</param>
</block>
<block>
- <key>wxgui_fftsink2</key>
+ <key>wxgui_scopesink2</key>
<param>
<key>id</key>
- <value>wxgui_fftsink2_0</value>
+ <value>wxgui_scopesink2_0</value>
</param>
<param>
<key>_enabled</key>
@@ -212,55 +204,35 @@
</param>
<param>
<key>title</key>
- <value>FFT Plot</value>
+ <value>Scope Plot</value>
</param>
<param>
<key>samp_rate</key>
<value>samp_rate</value>
</param>
<param>
- <key>baseband_freq</key>
- <value>tun_freq</value>
- </param>
- <param>
- <key>y_per_div</key>
- <value>10</value>
- </param>
- <param>
- <key>y_divs</key>
- <value>10</value>
- </param>
- <param>
- <key>ref_level</key>
- <value>10</value>
- </param>
- <param>
- <key>ref_scale</key>
- <value>2.0</value>
+ <key>v_scale</key>
+ <value>0</value>
</param>
<param>
- <key>fft_size</key>
- <value>1024</value>
+ <key>v_offset</key>
+ <value>0</value>
</param>
<param>
- <key>fft_rate</key>
- <value>30</value>
+ <key>t_scale</key>
+ <value>0</value>
</param>
<param>
- <key>peak_hold</key>
+ <key>ac_couple</key>
<value>False</value>
</param>
<param>
- <key>average</key>
+ <key>xy_mode</key>
<value>False</value>
</param>
<param>
- <key>avg_alpha</key>
- <value>0</value>
- </param>
- <param>
- <key>win</key>
- <value>None</value>
+ <key>num_inputs</key>
+ <value>1</value>
</param>
<param>
<key>win_size</key>
@@ -272,11 +244,19 @@
</param>
<param>
<key>notebook</key>
- <value></value>
+ <value>nb0, 2</value>
+ </param>
+ <param>
+ <key>trig_mode</key>
+ <value>gr.gr_TRIG_MODE_AUTO</value>
+ </param>
+ <param>
+ <key>y_axis_label</key>
+ <value>Counts</value>
</param>
<param>
<key>_coordinate</key>
- <value>(479, 176)</value>
+ <value>(314, 250)</value>
</param>
<param>
<key>_rotation</key>
@@ -295,7 +275,15 @@
</param>
<param>
<key>type</key>
- <value>complex</value>
+ <value>fc32</value>
+ </param>
+ <param>
+ <key>otw</key>
+ <value></value>
+ </param>
+ <param>
+ <key>stream_args</key>
+ <value></value>
</param>
<param>
<key>dev_addr</key>
@@ -314,7 +302,11 @@
<value>1</value>
</param>
<param>
- <key>ref_source0</key>
+ <key>clock_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source0</key>
<value></value>
</param>
<param>
@@ -322,7 +314,11 @@
<value></value>
</param>
<param>
- <key>ref_source1</key>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
<value></value>
</param>
<param>
@@ -330,7 +326,11 @@
<value></value>
</param>
<param>
- <key>ref_source2</key>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
<value></value>
</param>
<param>
@@ -338,7 +338,11 @@
<value></value>
</param>
<param>
- <key>ref_source3</key>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
<value></value>
</param>
<param>
@@ -346,7 +350,11 @@
<value></value>
</param>
<param>
- <key>ref_source4</key>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
<value></value>
</param>
<param>
@@ -354,7 +362,11 @@
<value></value>
</param>
<param>
- <key>ref_source5</key>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
<value></value>
</param>
<param>
@@ -362,7 +374,11 @@
<value></value>
</param>
<param>
- <key>ref_source6</key>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
<value></value>
</param>
<param>
@@ -370,7 +386,11 @@
<value></value>
</param>
<param>
- <key>ref_source7</key>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
<value></value>
</param>
<param>
@@ -387,19 +407,19 @@
</param>
<param>
<key>center_freq0</key>
- <value>tun_freq</value>
+ <value>freq</value>
</param>
<param>
<key>gain0</key>
- <value>tun_gain</value>
+ <value>gain</value>
</param>
<param>
<key>ant0</key>
- <value></value>
+ <value>ant</value>
</param>
<param>
<key>bw0</key>
- <value>0</value>
+ <value>samp_rate</value>
</param>
<param>
<key>center_freq1</key>
@@ -899,7 +919,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(212, 216)</value>
+ <value>(37, 394)</value>
</param>
<param>
<key>_rotation</key>
@@ -907,34 +927,505 @@
</param>
</block>
<block>
- <key>variable_slider</key>
+ <key>variable_function_probe</key>
<param>
<key>id</key>
- <value>tun_freq</value>
+ <value>chan0_lo_locked</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
+ <key>value</key>
+ <value>uhd.sensor_value("", False, "")</value>
+ </param>
+ <param>
+ <key>block_id</key>
+ <value>uhd_usrp_source_0</value>
+ </param>
+ <param>
+ <key>function_name</key>
+ <value>get_sensor</value>
+ </param>
+ <param>
+ <key>function_args</key>
+ <value>"'lo_locked'"</value>
+ </param>
+ <param>
+ <key>poll_rate</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(583, 432)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>notebook</key>
+ <param>
+ <key>id</key>
+ <value>nb0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.NB_TOP</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>['FFT', 'Waterfall', 'Scope']</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>0, 0, 1, 8</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(15, 172)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_chooser</key>
+ <param>
+ <key>id</key>
+ <value>ant_xcvr</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
<key>label</key>
- <value>UHD Freq (Hz)</value>
+ <value>Antenna</value>
</param>
<param>
<key>value</key>
+ <value>"J2"</value>
+ </param>
+ <param>
+ <key>choices</key>
+ <value>["J2","J1"]</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>["J2","J1"]</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>radio_buttons</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.RA_HORIZONTAL</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(830, 278)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_static_text</key>
+ <param>
+ <key>id</key>
+ <value>lo_locked_probe</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>LO Locked</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>chan0_lo_locked.to_bool()</value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>str_converter</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>lambda x: x and "True" or "False"</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>1, 7, 1, 1</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(583, 314)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_chooser</key>
+ <param>
+ <key>id</key>
+ <value>ant</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Antenna</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>"RX2"</value>
+ </param>
+ <param>
+ <key>choices</key>
+ <value>["RX2","TX/RX"]</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>["RX2","TX/RX"]</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>radio_buttons</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.RA_HORIZONTAL</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>1, 4, 1, 2</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(830, 130)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>parameter</key>
+ <param>
+ <key>id</key>
+ <value>address</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IP Address</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value></value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>string</value>
+ </param>
+ <param>
+ <key>short_id</key>
+ <value>a</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(190, 15)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_fftsink2</key>
+ <param>
+ <key>id</key>
+ <value>fft</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>FFT Plot</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>baseband_freq</key>
+ <value>freq</value>
+ </param>
+ <param>
+ <key>y_per_div</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>y_divs</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>avg_alpha</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value>(-1, 400)</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value>nb0, 0</value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(314, 359)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_waterfallsink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_waterfallsink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Waterfall Plot</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>baseband_freq</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>dynamic_range</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>512</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>avg_alpha</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value>(-1, 400)</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value>nb0, 1</value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(313, 573)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_text_box</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Sample Rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>param_samp_rate</value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>float_converter</value>
+ </param>
+ <param>
+ <key>formatter</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value>1, 0, 1, 3</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(358, 129)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_slider</key>
+ <param>
+ <key>id</key>
<value>freq</value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>RX Tune Frequency</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>param_freq</value>
+ </param>
+ <param>
<key>min</key>
- <value>2.4e9</value>
+ <value>50e6</value>
</param>
<param>
<key>max</key>
- <value>2.5e9</value>
+ <value>6e9</value>
</param>
<param>
<key>num_steps</key>
- <value>100</value>
+ <value>1000</value>
</param>
<param>
<key>style</key>
@@ -946,7 +1437,7 @@
</param>
<param>
<key>grid_pos</key>
- <value></value>
+ <value>3, 0, 1, 8</value>
</param>
<param>
<key>notebook</key>
@@ -954,7 +1445,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(36, 376)</value>
+ <value>(510, 128)</value>
</param>
<param>
<key>_rotation</key>
@@ -965,7 +1456,7 @@
<key>variable_slider</key>
<param>
<key>id</key>
- <value>tun_gain</value>
+ <value>gain</value>
</param>
<param>
<key>_enabled</key>
@@ -973,11 +1464,11 @@
</param>
<param>
<key>label</key>
- <value>UHD Gain</value>
+ <value>RX Gain</value>
</param>
<param>
<key>value</key>
- <value>gain</value>
+ <value>param_gain</value>
</param>
<param>
<key>min</key>
@@ -985,11 +1476,11 @@
</param>
<param>
<key>max</key>
- <value>20</value>
+ <value>31.5</value>
</param>
<param>
<key>num_steps</key>
- <value>100</value>
+ <value>63</value>
</param>
<param>
<key>style</key>
@@ -1001,7 +1492,7 @@
</param>
<param>
<key>grid_pos</key>
- <value></value>
+ <value>2, 0, 1, 8</value>
</param>
<param>
<key>notebook</key>
@@ -1009,7 +1500,7 @@
</param>
<param>
<key>_coordinate</key>
- <value>(177, 377)</value>
+ <value>(679, 130)</value>
</param>
<param>
<key>_rotation</key>
@@ -1018,7 +1509,19 @@
</block>
<connection>
<source_block_id>uhd_usrp_source_0</source_block_id>
- <sink_block_id>wxgui_fftsink2_0</sink_block_id>
+ <sink_block_id>wxgui_scopesink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>uhd_usrp_source_0</source_block_id>
+ <sink_block_id>wxgui_waterfallsink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>uhd_usrp_source_0</source_block_id>
+ <sink_block_id>fft</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 17c49adea8..add32dbdac 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -159,6 +159,134 @@ class ActionHandler:
self.get_flow_graph().update()
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
+ ##################################################
+ # Create heir block
+ ##################################################
+ elif action == Actions.BLOCK_CREATE_HIER:
+
+ # keeping track of coordinates for pasting later
+ coords = self.get_flow_graph().get_selected_blocks()[0].get_coordinate()
+ x,y = coords
+ x_min = x
+ y_min = y
+
+ pads = [];
+ params = [];
+
+ # Save the state of the leaf blocks
+ for block in self.get_flow_graph().get_selected_blocks():
+
+ # Check for string variables within the blocks
+ for param in block.get_params():
+ for variable in self.get_flow_graph().get_variables():
+ # If a block parameter exists that is a variable, create a parameter for it
+ if param.get_value() == variable.get_id():
+ params.append(param.get_value())
+ for flow_param in self.get_flow_graph().get_parameters():
+ # If a block parameter exists that is a parameter, create a parameter for it
+ if param.get_value() == flow_param.get_id():
+ params.append(param.get_value())
+
+
+ # keep track of x,y mins for pasting later
+ (x,y) = block.get_coordinate()
+ if x < x_min:
+ x_min = x
+ if y < y_min:
+ y_min = y
+
+ for connection in block.get_connections():
+
+ # Get id of connected blocks
+ source_id = connection.get_source().get_parent().get_id()
+ sink_id = connection.get_sink().get_parent().get_id()
+
+ # If connected block is not in the list of selected blocks create a pad for it
+ if self.get_flow_graph().get_block(source_id) not in self.get_flow_graph().get_selected_blocks():
+ pads.append({'key': connection.get_sink().get_key(), 'coord': connection.get_source().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'source'})
+
+ if self.get_flow_graph().get_block(sink_id) not in self.get_flow_graph().get_selected_blocks():
+ pads.append({'key': connection.get_source().get_key(), 'coord': connection.get_sink().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'sink'})
+
+
+ # Copy the selected blocks and paste them into a new page
+ # then move the flowgraph to a reasonable position
+ Actions.BLOCK_COPY()
+ self.main_window.new_page()
+ Actions.BLOCK_PASTE()
+ coords = (x_min,y_min)
+ self.get_flow_graph().move_selected(coords)
+
+
+ # Set flow graph to heir block type
+ top_block = self.get_flow_graph().get_block("top_block")
+ top_block.get_param('generate_options').set_value('hb')
+
+ # this needs to be a unique name
+ top_block.get_param('id').set_value('new_heir')
+
+ # Remove the default samp_rate variable block that is created
+ remove_me = self.get_flow_graph().get_block("samp_rate")
+ self.get_flow_graph().remove_element(remove_me)
+
+
+ # Add the param blocks along the top of the window
+ x_pos = 150
+ for param in params:
+ param_id = self.get_flow_graph().add_new_block('parameter',(x_pos,10))
+ param_block = self.get_flow_graph().get_block(param_id)
+ param_block.get_param('id').set_value(param)
+ x_pos = x_pos + 100
+
+ for pad in pads:
+ # Add the pad sources and sinks within the new heir block
+ if pad['direction'] == 'sink':
+
+ # Add new PAD_SINK block to the canvas
+ pad_id = self.get_flow_graph().add_new_block('pad_sink', pad['coord'])
+
+ # setup the references to the sink and source
+ pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_sink = pad_block.get_sinks()[0]
+
+ source_block = self.get_flow_graph().get_block(pad['block_id'])
+ source = source_block.get_source(pad['key'])
+
+ # Ensure the port types match
+ while pad_sink.get_type() != source.get_type():
+
+ # Special case for some blocks that have non-standard type names, e.g. uhd
+ if pad_sink.get_type() == 'complex' and source.get_type() == 'fc32':
+ break;
+ pad_block.type_controller_modify(1)
+
+ # Connect the pad to the proper sinks
+ new_connection = self.get_flow_graph().connect(source,pad_sink)
+
+ elif pad['direction'] == 'source':
+ pad_id = self.get_flow_graph().add_new_block('pad_source', pad['coord'])
+
+ # setup the references to the sink and source
+ pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_source = pad_block.get_sources()[0]
+
+ sink_block = self.get_flow_graph().get_block(pad['block_id'])
+ sink = sink_block.get_sink(pad['key'])
+
+ # Ensure the port types match
+ while sink.get_type() != pad_source.get_type():
+ # Special case for some blocks that have non-standard type names, e.g. uhd
+ if pad_source.get_type() == 'complex' and sink.get_type() == 'fc32':
+ break;
+ pad_block.type_controller_modify(1)
+
+ # Connect the pad to the proper sinks
+ new_connection = self.get_flow_graph().connect(pad_source,sink)
+
+ # update the new heir block flow graph
+ self.get_flow_graph().update()
+
+
##################################################
# Move/Rotate/Delete/Create
##################################################
@@ -270,6 +398,7 @@ class ActionHandler:
else:
try:
ParseXML.to_file(self.get_flow_graph().export_data(), self.get_page().get_file_path())
+ self.get_flow_graph().grc_file_path = self.get_page().get_file_path()
self.get_page().set_saved(True)
except IOError:
Messages.send_fail_save(self.get_page().get_file_path())
@@ -335,6 +464,7 @@ class ActionHandler:
#update enable/disable
Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BLOCK_CREATE_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
Actions.OPEN_HIER.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
Actions.RELOAD_BLOCKS.set_sensitive(True)
#set the exec and stop buttons
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 9d321f98bc..36fbd4c423 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -204,6 +204,12 @@ BLOCK_DISABLE = Action(
stock_id=gtk.STOCK_DISCONNECT,
keypresses=(gtk.keysyms.d, NO_MODS_MASK),
)
+BLOCK_CREATE_HIER = Action(
+ label='C_reate Hier',
+ tooltip='Create hier block from selected blocks',
+ stock_id=gtk.STOCK_CONNECT,
+ keypresses=(gtk.keysyms.c, NO_MODS_MASK),
+)
BLOCK_CUT = Action(
label='Cu_t',
tooltip='Cut',
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index e3ff4fb37d..8573e87b18 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -63,6 +63,7 @@ class FlowGraph(Element):
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
Actions.BLOCK_PARAM_MODIFY,
+ Actions.BLOCK_CREATE_HIER,
Actions.OPEN_HIER,
]: self._context_menu.append(action.create_menu_item())
@@ -100,6 +101,8 @@ class FlowGraph(Element):
block.get_param('id').set_value(id)
Actions.ELEMENT_CREATE()
+ return id
+
###########################################################################
# Copy Paste
###########################################################################