diff options
author | Tom Rondeau <trondeau@vt.edu> | 2012-10-03 12:26:59 -0400 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2012-10-03 12:26:59 -0400 |
commit | 3a50fdf70947dea210242b6f5647435fc0117845 (patch) | |
tree | 3bf0b2ab450f290688e0272173499dd619db8106 | |
parent | ef86dbf72f97a7a9a3b25b1ea94eb32bf609db53 (diff) | |
parent | d7b57e43f186097f147534ad49c6337edc4fdc88 (diff) |
Merge branch 'master' into next
-rw-r--r-- | docs/doxygen/other/group_defs.dox | 1 | ||||
-rw-r--r-- | docs/doxygen/other/main_page.dox | 275 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_basic_block.cc | 4 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_basic_block.h | 74 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_basic_block.i | 6 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_block.cc | 31 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_block.h | 39 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_block.i | 6 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_block_executor.cc | 4 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc | 30 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_scheduler_tpb.cc | 5 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/qa_gr_top_block.cc | 143 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/qa_gr_top_block.h | 8 | ||||
-rw-r--r-- | gr-uhd/examples/grc/uhd_fft.grc | 707 | ||||
-rw-r--r-- | grc/gui/ActionHandler.py | 130 | ||||
-rw-r--r-- | grc/gui/Actions.py | 6 | ||||
-rw-r--r-- | grc/gui/FlowGraph.py | 3 |
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 ########################################################################### |