summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--cmake/Modules/GrPackage.cmake5
-rw-r--r--docs/doxygen/other/thread_affinity.dox50
-rw-r--r--gnuradio-runtime/include/gnuradio/basic_block.h9
-rw-r--r--gnuradio-runtime/include/gnuradio/block_gateway.h6
-rw-r--r--gnuradio-runtime/include/gnuradio/fxpt_vco.h11
-rw-r--r--gnuradio-runtime/include/gnuradio/hier_block2.h23
-rw-r--r--gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h76
-rw-r--r--gnuradio-runtime/lib/controlport/gnuradio.ice6
-rw-r--r--gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc14
-rw-r--r--gnuradio-runtime/lib/hier_block2.cc18
-rw-r--r--gnuradio-runtime/lib/hier_block2_detail.cc25
-rw-r--r--gnuradio-runtime/lib/hier_block2_detail.h4
-rw-r--r--gnuradio-runtime/lib/math/qa_fxpt_vco.cc20
-rw-r--r--gnuradio-runtime/lib/math/vco.h14
-rw-r--r--gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py82
-rwxr-xr-xgnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor76
-rw-r--r--gnuradio-runtime/python/gnuradio/ctrlport/monitor.py2
-rw-r--r--gnuradio-runtime/swig/hier_block2.i4
-rw-r--r--gr-atsc/include/gnuradio/atsc/field_sync_mux.h11
-rw-r--r--gr-atsc/lib/atsc_field_sync_mux.cc18
-rw-r--r--gr-atsc/python/atsc/CMakeLists.txt6
-rw-r--r--gr-atsc/python/atsc/README25
-rw-r--r--gr-atsc/python/atsc/all_atsc.py142
-rwxr-xr-xgr-atsc/python/atsc/atsc_rx.py134
-rwxr-xr-xgr-atsc/python/atsc/btl-fsd.py48
-rwxr-xr-xgr-atsc/python/atsc/fpll.py88
-rwxr-xr-xgr-atsc/python/atsc/interp.py66
-rwxr-xr-xgr-atsc/python/atsc/interp_short.py78
-rwxr-xr-xgr-atsc/python/atsc/viterbi-out.py58
-rwxr-xr-xgr-atsc/python/atsc/xlate.py58
-rw-r--r--gr-blocks/grc/blocks_block_tree.xml3
-rw-r--r--gr-blocks/grc/blocks_ctrlport_probe2_c.xml41
-rw-r--r--gr-blocks/grc/blocks_ctrlport_probe2_x.xml123
-rw-r--r--gr-blocks/grc/blocks_interleaved_char_to_complex.xml37
-rw-r--r--gr-blocks/grc/blocks_tag_debug.xml2
-rw-r--r--gr-blocks/grc/blocks_tags_strobe.xml69
-rw-r--r--gr-blocks/grc/blocks_vco_c.xml35
-rw-r--r--gr-blocks/include/gnuradio/blocks/CMakeLists.txt7
-rw-r--r--gr-blocks/include/gnuradio/blocks/ctrlport_probe2_b.h69
-rw-r--r--gr-blocks/include/gnuradio/blocks/ctrlport_probe2_c.h4
-rw-r--r--gr-blocks/include/gnuradio/blocks/ctrlport_probe2_f.h69
-rw-r--r--gr-blocks/include/gnuradio/blocks/ctrlport_probe2_i.h69
-rw-r--r--gr-blocks/include/gnuradio/blocks/ctrlport_probe2_s.h69
-rw-r--r--gr-blocks/include/gnuradio/blocks/interleaved_char_to_complex.h51
-rw-r--r--gr-blocks/include/gnuradio/blocks/tag_debug.h5
-rw-r--r--gr-blocks/include/gnuradio/blocks/tags_strobe.h87
-rw-r--r--gr-blocks/include/gnuradio/blocks/vco_c.h59
-rw-r--r--gr-blocks/lib/CMakeLists.txt7
-rw-r--r--gr-blocks/lib/ctrlport_probe2_b_impl.cc162
-rw-r--r--gr-blocks/lib/ctrlport_probe2_b_impl.h69
-rw-r--r--gr-blocks/lib/ctrlport_probe2_c_impl.cc16
-rw-r--r--gr-blocks/lib/ctrlport_probe2_c_impl.h4
-rw-r--r--gr-blocks/lib/ctrlport_probe2_f_impl.cc164
-rw-r--r--gr-blocks/lib/ctrlport_probe2_f_impl.h69
-rw-r--r--gr-blocks/lib/ctrlport_probe2_i_impl.cc163
-rw-r--r--gr-blocks/lib/ctrlport_probe2_i_impl.h69
-rw-r--r--gr-blocks/lib/ctrlport_probe2_s_impl.cc163
-rw-r--r--gr-blocks/lib/ctrlport_probe2_s_impl.h69
-rw-r--r--gr-blocks/lib/interleaved_char_to_complex_impl.cc65
-rw-r--r--gr-blocks/lib/interleaved_char_to_complex_impl.h47
-rw-r--r--gr-blocks/lib/tag_debug_impl.cc23
-rw-r--r--gr-blocks/lib/tag_debug_impl.h3
-rw-r--r--gr-blocks/lib/tags_strobe_impl.cc99
-rw-r--r--gr-blocks/lib/tags_strobe_impl.h59
-rw-r--r--gr-blocks/lib/vco_c_impl.cc68
-rw-r--r--gr-blocks/lib/vco_c_impl.h53
-rw-r--r--gr-blocks/python/blocks/CMakeLists.txt1
-rw-r--r--gr-blocks/python/blocks/qa_ctrlport_probes.py229
-rwxr-xr-xgr-blocks/python/blocks/qa_hier_block2.py33
-rw-r--r--gr-blocks/python/blocks/qa_tags_strobe.py96
-rw-r--r--gr-blocks/python/blocks/qa_vco.py23
-rw-r--r--gr-blocks/swig/blocks_swig0.i12
-rw-r--r--gr-blocks/swig/blocks_swig3.i3
-rw-r--r--gr-blocks/swig/blocks_swig5.i6
-rw-r--r--gr-channels/CMakeLists.txt4
-rw-r--r--gr-channels/doc/channels.dox110
-rw-r--r--gr-channels/examples/CMakeLists.txt33
-rw-r--r--gr-channels/examples/demo_gmsk.grc894
-rw-r--r--gr-channels/examples/demo_ofdm.grc1410
-rw-r--r--gr-channels/examples/demo_qam.grc1048
-rw-r--r--gr-channels/examples/demo_quantization.grc958
-rw-r--r--gr-channels/examples/demo_spec_an.grc1087
-rw-r--r--gr-channels/examples/demo_two_tone.grc1190
-rw-r--r--gr-channels/grc/CMakeLists.txt12
-rw-r--r--gr-channels/grc/channels_amp_bal.xml27
-rw-r--r--gr-channels/grc/channels_block_tree.xml11
-rw-r--r--gr-channels/grc/channels_channel_model2.xml61
-rw-r--r--gr-channels/grc/channels_conj_fs_iqcorr.xml34
-rw-r--r--gr-channels/grc/channels_distortion_2_gen.xml27
-rw-r--r--gr-channels/grc/channels_distortion_3_gen.xml27
-rw-r--r--gr-channels/grc/channels_impairments.xml76
-rw-r--r--gr-channels/grc/channels_iqbal_gen.xml34
-rw-r--r--gr-channels/grc/channels_phase_bal.xml27
-rw-r--r--gr-channels/grc/channels_phase_noise_gen.xml34
-rw-r--r--gr-channels/grc/channels_quantizer.xml27
-rw-r--r--gr-channels/include/gnuradio/channels/CMakeLists.txt1
-rw-r--r--gr-channels/include/gnuradio/channels/channel_model2.h102
-rw-r--r--gr-channels/include/gnuradio/channels/fading_model.h10
-rw-r--r--gr-channels/include/gnuradio/channels/selective_fading_model.h16
-rw-r--r--gr-channels/lib/CMakeLists.txt1
-rw-r--r--gr-channels/lib/channel_model2_impl.cc176
-rw-r--r--gr-channels/lib/channel_model2_impl.h76
-rw-r--r--gr-channels/python/channels/CMakeLists.txt11
-rw-r--r--gr-channels/python/channels/__init__.py13
-rw-r--r--gr-channels/python/channels/amp_bal.py63
-rw-r--r--gr-channels/python/channels/conj_fs_iqcorr.py65
-rw-r--r--gr-channels/python/channels/distortion_2_gen.py63
-rw-r--r--gr-channels/python/channels/distortion_3_gen.py61
-rw-r--r--gr-channels/python/channels/impairments.py129
-rw-r--r--gr-channels/python/channels/iqbal_gen.py67
-rw-r--r--gr-channels/python/channels/phase_bal.py76
-rw-r--r--gr-channels/python/channels/phase_noise_gen.py69
-rw-r--r--gr-channels/python/channels/quantizer.py54
-rw-r--r--gr-channels/swig/channels_swig.i3
-rwxr-xr-xgr-digital/examples/narrowband/benchmark_rx.py6
-rwxr-xr-xgr-digital/examples/narrowband/benchmark_tx.py6
-rw-r--r--gr-digital/examples/narrowband/uhd_interface.py57
-rwxr-xr-xgr-digital/examples/ofdm/benchmark_rx.py6
-rwxr-xr-xgr-digital/examples/ofdm/benchmark_tx.py9
-rw-r--r--gr-digital/examples/ofdm/uhd_interface.py66
-rw-r--r--gr-digital/include/gnuradio/digital/constellation.h23
-rw-r--r--gr-filter/grc/filter_fractional_resampler_xx.xml5
-rw-r--r--gr-filter/lib/fractional_resampler_cc_impl.cc43
-rw-r--r--gr-filter/lib/fractional_resampler_ff_impl.cc44
-rw-r--r--gr-filter/python/filter/qa_fractional_resampler.py61
-rw-r--r--gr-qtgui/grc/qtgui_block_tree.xml3
-rw-r--r--gr-qtgui/grc/qtgui_histogram_sink_x.xml91
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h29
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h74
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/displayform.h2
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h108
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h80
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h28
-rw-r--r--gr-qtgui/lib/CMakeLists.txt5
-rw-r--r--gr-qtgui/lib/ConstellationDisplayPlot.cc3
-rw-r--r--gr-qtgui/lib/HistogramDisplayPlot.cc440
-rw-r--r--gr-qtgui/lib/displayform.cc5
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.cc391
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.h113
-rw-r--r--gr-qtgui/lib/histogramdisplayform.cc174
-rw-r--r--gr-qtgui/lib/spectrumUpdateEvents.cc43
-rwxr-xr-xgr-qtgui/python/qtgui/qa_qtgui.py3
-rw-r--r--gr-qtgui/swig/qtgui_swig.i3
-rw-r--r--gr-uhd/grc/gen_uhd_usrp_blocks.py17
-rw-r--r--gr-uhd/lib/gr_uhd_common.h15
-rw-r--r--gr-uhd/lib/usrp_sink_impl.cc35
-rw-r--r--gr-uhd/lib/usrp_source_impl.cc52
-rw-r--r--gr-utils/python/modtool/gr-newmod/cmake/Modules/FindGnuradioRuntime.cmake3
-rw-r--r--gr-utils/python/modtool/modtool_base.py3
-rw-r--r--gr-utils/python/modtool/templates.py8
-rw-r--r--grc/base/Block.py631
-rw-r--r--grc/base/Connection.py165
-rw-r--r--grc/base/Element.py132
-rw-r--r--grc/base/FlowGraph.py511
-rw-r--r--grc/base/Param.py314
-rw-r--r--grc/base/ParseXML.py167
-rw-r--r--grc/base/Platform.py310
-rw-r--r--grc/base/Port.py147
-rw-r--r--grc/base/block_tree.dtd6
-rw-r--r--grc/base/flow_graph.dtd10
-rw-r--r--grc/base/odict.py146
-rw-r--r--grc/blocks/bus_sink.xml27
-rw-r--r--grc/blocks/bus_source.xml27
-rw-r--r--grc/blocks/bus_structure_sink.xml18
-rw-r--r--grc/blocks/bus_structure_source.xml18
-rw-r--r--grc/blocks/pad_sink.xml9
-rw-r--r--grc/blocks/pad_source.xml10
-rw-r--r--grc/blocks/variable_constellation.xml51
-rw-r--r--grc/blocks/variable_constellation_rect.xml69
-rw-r--r--grc/examples/xmlrpc/xmlrpc_client_script.py22
-rw-r--r--grc/grc_gnuradio/blks2/__init__.py4
-rw-r--r--grc/grc_gnuradio/blks2/error_rate.py204
-rw-r--r--grc/grc_gnuradio/blks2/packet.py350
-rw-r--r--grc/grc_gnuradio/blks2/selector.py214
-rw-r--r--grc/grc_gnuradio/blks2/tcp.py80
-rw-r--r--grc/gui/ActionHandler.py763
-rw-r--r--grc/gui/Actions.py368
-rw-r--r--grc/gui/Bars.py207
-rw-r--r--grc/gui/Block.py346
-rw-r--r--grc/gui/BlockTreeWindow.py339
-rw-r--r--grc/gui/Connection.py246
-rw-r--r--grc/gui/Dialogs.py130
-rw-r--r--grc/gui/DrawingArea.py202
-rw-r--r--grc/gui/Element.py444
-rw-r--r--grc/gui/FileDialogs.py244
-rw-r--r--grc/gui/FlowGraph.py1067
-rw-r--r--grc/gui/MainWindow.py542
-rw-r--r--grc/gui/Messages.py84
-rw-r--r--grc/gui/NotebookPage.py364
-rw-r--r--grc/gui/Param.py262
-rw-r--r--grc/gui/Platform.py2
-rw-r--r--grc/gui/Port.py371
-rw-r--r--grc/gui/Preferences.py84
-rw-r--r--grc/gui/PropsDialog.py294
-rw-r--r--grc/gui/StateCache.py146
-rw-r--r--grc/gui/Utils.py148
-rw-r--r--grc/python/Block.py351
-rw-r--r--grc/python/Connection.py43
-rw-r--r--grc/python/Constants.py59
-rw-r--r--grc/python/FlowGraph.py375
-rw-r--r--grc/python/Generator.py236
-rw-r--r--grc/python/Param.py810
-rw-r--r--grc/python/Platform.py66
-rw-r--r--grc/python/Port.py382
-rw-r--r--grc/python/block.dtd22
-rw-r--r--grc/python/convert_hier.py160
-rw-r--r--grc/python/default_flow_graph.grc70
-rw-r--r--grc/python/expr_utils.py264
-rw-r--r--grc/python/extract_docs.py94
-rw-r--r--grc/python/flow_graph.tmpl386
-rwxr-xr-xgrc/scripts/gnuradio-companion54
213 files changed, 20356 insertions, 7315 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e1e68a05c..625d83def4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,8 +41,8 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
# Set the version information here
set(VERSION_INFO_MAJOR_VERSION 3)
set(VERSION_INFO_API_COMPAT 7)
-set(VERSION_INFO_MINOR_VERSION 0)
-set(VERSION_INFO_MAINT_VERSION 0)
+set(VERSION_INFO_MINOR_VERSION 1)
+set(VERSION_INFO_MAINT_VERSION git)
include(GrVersion) #setup version info
# Append -O2 optimization flag for Debug builds
@@ -315,8 +315,11 @@ if(NOT CMAKE_MODULES_DIR)
set(CMAKE_MODULES_DIR lib/cmake/gnuradio)
endif(NOT CMAKE_MODULES_DIR)
+# Install all other cmake files into same directory
+file(GLOB cmake_others "cmake/Modules/*.cmake")
+
install(
- FILES ${cmake_configs}
+ FILES ${cmake_configs} ${cmake_others}
DESTINATION ${CMAKE_MODULES_DIR}
COMPONENT "runtime_devel"
)
diff --git a/cmake/Modules/GrPackage.cmake b/cmake/Modules/GrPackage.cmake
index d1b0b33205..54a752661d 100644
--- a/cmake/Modules/GrPackage.cmake
+++ b/cmake/Modules/GrPackage.cmake
@@ -175,3 +175,8 @@ endforeach(filename)
set(CPACK_NSIS_MODIFY_PATH ON)
set(HLKM_ENV "\\\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Session Manager\\\\Environment\\\"")
+
+IF(WIN32)
+ #Install necessary runtime DLL's
+ INCLUDE(InstallRequiredSystemLibraries)
+ENDIF(WIN32)
diff --git a/docs/doxygen/other/thread_affinity.dox b/docs/doxygen/other/thread_affinity.dox
index 2f31d9ce53..86634ffdf5 100644
--- a/docs/doxygen/other/thread_affinity.dox
+++ b/docs/doxygen/other/thread_affinity.dox
@@ -10,13 +10,13 @@ The implementation is done by adding new functions to the threading
section of the gnuradio-runtime library:
\code
- gr_thread_t get_current_thread_id();
+ gr::thread::gr_thread_t get_current_thread_id();
void thread_bind_to_processor(unsigned int n);
void thread_bind_to_processor(const std::vector<unsigned int> &mask);
- void thread_bind_to_processor(gr_thread_t thread, unsigned int n);
- void thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask);
+ void thread_bind_to_processor(gr::thread::gr_thread_t thread, unsigned int n);
+ void thread_bind_to_processor(gr::thread::gr_thread_t thread, const std::vector<unsigned int> &mask);
void thread_unbind();
- void thread_unbind(gr_thread_t thread);
+ void thread_unbind(gr::thread::gr_thread_t thread);
\endcode
The ability to set a thread's affinity to a core or groups of cores is
@@ -45,21 +45,55 @@ Each block has two new data members:
thread.
- thread: a gr::thread::gr_thread_t handle to the block's thread.
-A block can set and unset it's affinity at any time using the
+A block can set and unset its affinity at any time using the
following member functions:
-- gr_block::set_processor_affinity(const std::vector<unsigned int> &mask)
-- gr_block::unset_processor_affinity()
+- gr::block::set_processor_affinity(const std::vector<int> &mask)
+- gr::block::unset_processor_affinity()
Where \p mask is a vector of core numbers to set the thread's affinity
to.
The current core affinity can be retrieved using the member function:
-- gr_block::processor_affinity()
+- gr::block::processor_affinity()
When set before the flowgraph is started, the scheduler will set the
thread's affinity when it is started. When already running, the
block's affinity will be immediately set.
+
+\subsection affinity_api_hier Setting Affinity for a gr::hier_block2
+
+A hierarchical block (gr::hier_block2) also has a concept of setting
+the block thread affinity. Because the hierarchical block itself does
+no work and just encapsulates a set of blocks, setting the
+hierarchical block's affinity individually sets all blocks inside it
+to that affinity setting.
+
+The gr::hier_block2 class supports the same API interface to the block
+thread affinity:
+
+- gr::hier_block2::set_processor_affinity(const std::vector<int> &mask)
+- gr::hier_block2::unset_processor_affinity()
+- gr::hier_block2::processor_affinity()
+
+Setting and unsetting the affinity does so recursively for every block
+in the hierarchical block. It is of course possible to individually set
+the affinity to any block underneath the hierarchical block. However,
+in this case, note that when asking for the current affinity value
+using 'processor_affinity()', the code returns the current processor
+affinity value of only the first block.
+
+
+\subsection affinity_api_grc GRC Access
+
+GRC supports the setting of the thread core affinity in a block's
+options. Each block now has a field 'Core Affinity' that accepts a
+vector (list) of integers and sets the affinity after the block is
+constructed.
+
+Note that GRC does not provide a callback function for changing the
+thread core affinity while the flowgraph is running.
+
*/
diff --git a/gnuradio-runtime/include/gnuradio/basic_block.h b/gnuradio-runtime/include/gnuradio/basic_block.h
index 30ae2ca0f0..4a2d550fb3 100644
--- a/gnuradio-runtime/include/gnuradio/basic_block.h
+++ b/gnuradio-runtime/include/gnuradio/basic_block.h
@@ -342,6 +342,15 @@ namespace gr {
}
d_msg_handlers[which_port] = msg_handler_t(msg_handler);
}
+
+ virtual void set_processor_affinity(const std::vector<int> &mask)
+ { throw std::runtime_error("set_processor_affinity not overloaded in child class."); }
+
+ virtual void unset_processor_affinity()
+ { throw std::runtime_error("unset_processor_affinity not overloaded in child class."); }
+
+ virtual std::vector<int> processor_affinity()
+ { throw std::runtime_error("processor_affinity not overloaded in child class."); }
};
inline bool operator<(basic_block_sptr lhs, basic_block_sptr rhs)
diff --git a/gnuradio-runtime/include/gnuradio/block_gateway.h b/gnuradio-runtime/include/gnuradio/block_gateway.h
index c2d09de00d..09e372163d 100644
--- a/gnuradio-runtime/include/gnuradio/block_gateway.h
+++ b/gnuradio-runtime/include/gnuradio/block_gateway.h
@@ -41,6 +41,12 @@ namespace gr {
GR_BLOCK_GW_WORK_INTERP,
};
+ enum tag_propagation_policy_t {
+ TPP_DONT = 0,
+ TPP_ALL_TO_ALL = 1,
+ TPP_ONE_TO_ONE = 2
+ };
+
/*!
* Shared message structure between python and gateway.
* Each action type represents a scheduler-called function.
diff --git a/gnuradio-runtime/include/gnuradio/fxpt_vco.h b/gnuradio-runtime/include/gnuradio/fxpt_vco.h
index 77d58677ce..cbc204c1b8 100644
--- a/gnuradio-runtime/include/gnuradio/fxpt_vco.h
+++ b/gnuradio-runtime/include/gnuradio/fxpt_vco.h
@@ -61,6 +61,17 @@ namespace gr {
*cosx = fxpt::cos(d_phase);
}
+ // compute complex sine a block at a time
+ void sincos(gr_complex *output, const float *input, int noutput_items,
+ float k, float ampl = 1.0)
+ {
+ for(int i = 0; i < noutput_items; i++) {
+ output[i] = gr_complex((float)(fxpt::cos(d_phase) * ampl),
+ (float)(fxpt::sin(d_phase) * ampl));
+ adjust_phase(input[i] * k);
+ }
+ }
+
// compute a block at a time
void cos(float *output, const float *input, int noutput_items, float k, float ampl = 1.0)
{
diff --git a/gnuradio-runtime/include/gnuradio/hier_block2.h b/gnuradio-runtime/include/gnuradio/hier_block2.h
index ff09f9139d..0d7b138e4d 100644
--- a/gnuradio-runtime/include/gnuradio/hier_block2.h
+++ b/gnuradio-runtime/include/gnuradio/hier_block2.h
@@ -210,6 +210,29 @@ namespace gr {
throw std::invalid_argument("block already has a primitive output port by this name");
hier_message_ports_out = pmt::list_add(hier_message_ports_out, port_id);
}
+
+ /*!
+ * \brief Set the affinity of all blocks in hier_block2 to processor core \p n.
+ *
+ * \param mask a vector of ints of the core numbers available to this block.
+ */
+ void set_processor_affinity(const std::vector<int> &mask);
+
+ /*!
+ * \brief Remove processor affinity for all blocks in hier_block2.
+ */
+ void unset_processor_affinity();
+
+ /*!
+ * \brief Get the current processor affinity.
+ *
+ * \details This returns the processor affinity value for the first
+ * block in the hier_block2's list of blocks with the assumption
+ * that they have always only been set through the hier_block2's
+ * interface. If any block has been individually set, then this
+ * call could be misleading.
+ */
+ std::vector<int> processor_affinity();
};
inline hier_block2_sptr cast_to_hier_block2_sptr(basic_block_sptr block) {
diff --git a/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h b/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h
index 4431d15bd8..92adc0b768 100644
--- a/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h
+++ b/gnuradio-runtime/include/gnuradio/rpcregisterhelpers.h
@@ -95,6 +95,36 @@ public:
// Specialized Extractor Templates
template<typename T>
+class rpcbasic_extractor<T,char> : public virtual rpcextractor_base<T,char>
+{
+public:
+ rpcbasic_extractor(T* source, void (T::*func)(char))
+ : rpcextractor_base<T,char>(source, func)
+ {;}
+
+ void post(pmt::pmt_t which_port, pmt::pmt_t msg)
+ {
+ (rpcextractor_base<T,char>::_source->*rpcextractor_base<T,char>::_func)
+ (static_cast<char>(pmt::to_long(msg)));
+ }
+};
+
+template<typename T>
+class rpcbasic_extractor<T,short> : public virtual rpcextractor_base<T,short>
+{
+public:
+ rpcbasic_extractor(T* source, void (T::*func)(short))
+ : rpcextractor_base<T,short>(source, func)
+ {;}
+
+ void post(pmt::pmt_t which_port, pmt::pmt_t msg)
+ {
+ (rpcextractor_base<T,short>::_source->*rpcextractor_base<T,char>::_func)
+ (static_cast<short>(pmt::to_long(msg)));
+ }
+};
+
+template<typename T>
class rpcbasic_extractor<T,double> : public virtual rpcextractor_base<T,double>
{
public:
@@ -238,6 +268,50 @@ public:
};
template<typename T>
+class rpcbasic_inserter<T,std::vector< signed char > >
+ : public virtual rpcinserter_base<T,std::vector< signed char > >
+{
+public:
+ rpcbasic_inserter(T* source, std::vector< signed char > (T::*func)() const)
+ : rpcinserter_base<T,std::vector< signed char > >(source, func)
+ {;}
+
+ rpcbasic_inserter(T* source, std::vector< signed char > (T::*func)())
+ : rpcinserter_base<T,std::vector< signed char > >(source, func)
+ {;}
+
+ pmt::pmt_t retrieve()
+ {
+ std::vector< signed char >
+ vec((rpcinserter_base<T,std::vector< signed char > >::
+ _source->*rpcinserter_base<T,std::vector< signed char > >::_func)());
+ return pmt::init_s8vector(vec.size(), &vec[0]);
+ }
+};
+
+template<typename T>
+class rpcbasic_inserter<T,std::vector< short > >
+ : public virtual rpcinserter_base<T,std::vector< short > >
+{
+public:
+ rpcbasic_inserter(T* source, std::vector< short > (T::*func)() const)
+ : rpcinserter_base<T,std::vector< short > >(source, func)
+ {;}
+
+ rpcbasic_inserter(T* source, std::vector< short > (T::*func)())
+ : rpcinserter_base<T,std::vector< short > >(source, func)
+ {;}
+
+ pmt::pmt_t retrieve()
+ {
+ std::vector< short >
+ vec((rpcinserter_base<T,std::vector< short > >::
+ _source->*rpcinserter_base<T,std::vector< short > >::_func)());
+ return pmt::init_s16vector(vec.size(), &vec[0]);
+ }
+};
+
+template<typename T>
class rpcbasic_inserter<T,std::vector< int > >
: public virtual rpcinserter_base<T,std::vector< int > >
{
@@ -354,7 +428,7 @@ public:
: rpcinserter_base<T,std::complex<double> >(source, func)
{;}
- pmt::pmt_t retrieve()
+ pmt::pmt_t retrieve()
{
std::complex<double > k((rpcinserter_base<T,std::complex<double> >::
_source->*rpcinserter_base<T,std::complex<double> >::_func)());
diff --git a/gnuradio-runtime/lib/controlport/gnuradio.ice b/gnuradio-runtime/lib/controlport/gnuradio.ice
index 8318875926..3d6101087a 100644
--- a/gnuradio-runtime/lib/controlport/gnuradio.ice
+++ b/gnuradio-runtime/lib/controlport/gnuradio.ice
@@ -35,6 +35,7 @@ class Knob {};
class KnobB extends Knob { bool value; };
class KnobC extends Knob { byte value; };
class KnobI extends Knob { int value; };
+class KnobT extends Knob { short value; };
class KnobF extends Knob { float value; };
class KnobD extends Knob { double value; };
class KnobL extends Knob { long value; };
@@ -44,11 +45,12 @@ class KnobZ extends Knob { complex value; };
sequence<bool> VectorB; sequence<byte> VectorC;
sequence<int> VectorI; sequence<float> VectorF;
sequence<double> VectorD; sequence<string> VectorS;
-sequence<long> VectorL;
+sequence<long> VectorL; sequence<short> VectorT;
class KnobVecB extends Knob { VectorB value; };
class KnobVecC extends Knob { VectorC value; };
class KnobVecI extends Knob { VectorI value; };
+class KnobVecT extends Knob { VectorT value; };
class KnobVecF extends Knob { VectorF value; };
class KnobVecD extends Knob { VectorD value; };
class KnobVecL extends Knob { VectorL value; };
@@ -57,7 +59,7 @@ class KnobVecS extends Knob { VectorS value; };
enum KnobType { KNOBBOOL, KNOBCHAR, KNOBINT, KNOBFLOAT,
KNOBDOUBLE, KNOBSTRING, KNOBLONG, KNOBVECBOOL,
KNOBVECCHAR, KNOBVECINT, KNOBVECFLOAT, KNOBVECDOUBLE,
- KNOBVECSTRING, KNOBVECLONG };
+ KNOBVECSTRING, KNOBVECLONG, KNOBSHORT};
const int DISPNULL = 0x0000;
const int DISPTIME = 0x0001;
diff --git a/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc b/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc
index ca6a769f48..efd2a5599c 100644
--- a/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc
+++ b/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc
@@ -60,6 +60,11 @@ rpcpmtconverter::from_pmt(const pmt::pmt_t& knob, const Ice::Current& c)
const int* start((const int*) pmt::s32vector_elements(knob,size));
return new GNURadio::KnobVecI(std::vector<int>(start,start+size));
}
+ else if (pmt::is_s16vector(knob)) {
+ size_t size(pmt::length(knob));
+ const short* start((const short*) pmt::s16vector_elements(knob,size));
+ return new GNURadio::KnobVecT(std::vector<short>(start,start+size));
+ }
else if(pmt::is_f32vector(knob)) {
size_t size(pmt::length(knob));
const float* start((const float*) pmt::f32vector_elements(knob,size));
@@ -70,6 +75,11 @@ rpcpmtconverter::from_pmt(const pmt::pmt_t& knob, const Ice::Current& c)
const uint8_t* start((const uint8_t*) pmt::u8vector_elements(knob,size));
return new GNURadio::KnobVecC(std::vector<Ice::Byte>(start,start+size));
}
+ else if (pmt::is_s8vector(knob)) {
+ size_t size(pmt::length(knob));
+ const int8_t* start((const int8_t*) pmt::s8vector_elements(knob,size));
+ return new GNURadio::KnobVecC(std::vector<Ice::Byte>(start,start+size));
+ }
else {
std::cerr << "Error: Don't know how to handle Knob Type (from): " << std::endl; assert(0);}
//TODO: VECTORS!!!
@@ -92,6 +102,10 @@ rpcpmtconverter::to_pmt(const GNURadio::KnobPtr& knob, const Ice::Current& c)
GNURadio::KnobIPtr k(GNURadio::KnobIPtr::dynamicCast(knob));
return pmt::mp(k->value);
}
+ else if(id == "KnobT") {
+ GNURadio::KnobTPtr k(GNURadio::KnobTPtr::dynamicCast(knob));
+ return pmt::mp(k->value);
+ }
else if(id == "KnobS") {
GNURadio::KnobSPtr k(GNURadio::KnobSPtr::dynamicCast(knob));
return pmt::string_to_symbol(k->value);
diff --git a/gnuradio-runtime/lib/hier_block2.cc b/gnuradio-runtime/lib/hier_block2.cc
index f26da18e54..e0acba30a0 100644
--- a/gnuradio-runtime/lib/hier_block2.cc
+++ b/gnuradio-runtime/lib/hier_block2.cc
@@ -157,4 +157,22 @@ namespace gr {
return new_ffg;
}
+ void
+ hier_block2::set_processor_affinity(const std::vector<int> &mask)
+ {
+ d_detail->set_processor_affinity(mask);
+ }
+
+ void
+ hier_block2::unset_processor_affinity()
+ {
+ d_detail->unset_processor_affinity();
+ }
+
+ std::vector<int>
+ hier_block2::processor_affinity()
+ {
+ return d_detail->processor_affinity();
+ }
+
} /* namespace gr */
diff --git a/gnuradio-runtime/lib/hier_block2_detail.cc b/gnuradio-runtime/lib/hier_block2_detail.cc
index 704e92599e..ebfaa6fa69 100644
--- a/gnuradio-runtime/lib/hier_block2_detail.cc
+++ b/gnuradio-runtime/lib/hier_block2_detail.cc
@@ -657,4 +657,29 @@ namespace gr {
d_owner->unlock();
}
+ void
+ hier_block2_detail::set_processor_affinity(const std::vector<int> &mask)
+ {
+ basic_block_vector_t tmp = d_fg->calc_used_blocks();
+ for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
+ (*p)->set_processor_affinity(mask);
+ }
+ }
+
+ void
+ hier_block2_detail::unset_processor_affinity()
+ {
+ basic_block_vector_t tmp = d_fg->calc_used_blocks();
+ for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
+ (*p)->unset_processor_affinity();
+ }
+ }
+
+ std::vector<int>
+ hier_block2_detail::processor_affinity()
+ {
+ basic_block_vector_t tmp = d_fg->calc_used_blocks();
+ return tmp[0]->processor_affinity();
+ }
+
} /* namespace gr */
diff --git a/gnuradio-runtime/lib/hier_block2_detail.h b/gnuradio-runtime/lib/hier_block2_detail.h
index 99bf6e8ef1..806738360f 100644
--- a/gnuradio-runtime/lib/hier_block2_detail.h
+++ b/gnuradio-runtime/lib/hier_block2_detail.h
@@ -54,6 +54,10 @@ namespace gr {
void unlock();
void flatten_aux(flat_flowgraph_sptr sfg) const;
+ void set_processor_affinity(const std::vector<int> &mask);
+ void unset_processor_affinity();
+ std::vector<int> processor_affinity();
+
private:
// Private implementation data
hier_block2 *d_owner;
diff --git a/gnuradio-runtime/lib/math/qa_fxpt_vco.cc b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc
index ee9865e926..8ee402fdc1 100644
--- a/gnuradio-runtime/lib/math/qa_fxpt_vco.cc
+++ b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc
@@ -102,6 +102,26 @@ qa_fxpt_vco::t1()
void
qa_fxpt_vco::t2()
{
+ gr::vco<gr_complex,float> ref_vco;
+ gr::fxpt_vco new_vco;
+ gr_complex ref_block[SIN_COS_BLOCK_SIZE];
+ gr_complex new_block[SIN_COS_BLOCK_SIZE];
+ float input[SIN_COS_BLOCK_SIZE];
+ double max_error = 0;
+
+ for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) {
+ input[i] = sin(double(i));
+ }
+
+ ref_vco.sincos(ref_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL);
+ new_vco.sincos(new_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL);
+
+ for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) {
+ CPPUNIT_ASSERT_COMPLEXES_EQUAL(ref_block[i], new_block[i], SIN_COS_TOLERANCE);
+ max_error = max_d(max_error, abs(ref_block[i]-new_block[i]));
+ }
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE);
+ // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, ref_vco.get_phase()-new_vco.get_phase());
}
void
diff --git a/gnuradio-runtime/lib/math/vco.h b/gnuradio-runtime/lib/math/vco.h
index fa11732c1f..d8a6fbb415 100644
--- a/gnuradio-runtime/lib/math/vco.h
+++ b/gnuradio-runtime/lib/math/vco.h
@@ -64,6 +64,9 @@ namespace gr {
// compute sin and cos for current phase angle
void sincos(float *sinx, float *cosx) const;
+ void sincos(gr_complex *output, const float *input,
+ int noutput_items, double k, double ampl = 1.0);
+
// compute cos or sin for current phase angle
float cos() const { return std::cos(d_phase); }
float sin() const { return std::sin(d_phase); }
@@ -85,6 +88,17 @@ namespace gr {
template<class o_type, class i_type>
void
+ vco<o_type,i_type>::sincos(gr_complex *output, const float *input,
+ int noutput_items, double k, double ampl)
+ {
+ for(int i = 0; i < noutput_items; i++) {
+ output[i] = gr_complex(cos() * ampl, sin() * ampl);
+ adjust_phase(input[i] * k);
+ }
+ }
+
+ template<class o_type, class i_type>
+ void
vco<o_type,i_type>::cos(float *output, const float *input,
int noutput_items, double k, double ampl)
{
diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py b/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py
index 4e9ef13133..78b83c2411 100644
--- a/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py
+++ b/gnuradio-runtime/python/gnuradio/ctrlport/GrDataPlotter.py
@@ -24,7 +24,7 @@ from gnuradio import gr
from gnuradio import blocks
from gnuradio import filter
from gnuradio.ctrlport import GNURadio
-import sys, time
+import sys, time, struct
try:
from gnuradio import qtgui
@@ -420,14 +420,72 @@ class GrDataPlotterValueTable:
self.treeWidget.resizeColumnToContents(0)
def updateItems(self, knobs, knobprops):
- items = [];
- self.treeWidget.clear()
- for k, v in knobs.iteritems():
- val = v.value
- if(type(val) == GNURadio.complex):
- val = val.re + val.im*1j
-
- items.append(QtGui.QTreeWidgetItem([str(k), str(val),
- knobprops[k].units,
- knobprops[k].description]))
- self.treeWidget.insertTopLevelItems(0, items)
+ items = []
+ foundKeys = []
+ deleteKeys = []
+ numItems = self.treeWidget.topLevelItemCount()
+
+ # The input knobs variable is a dict of stats to display in the tree.
+
+ # Update tree stat values with new values found in knobs.
+ # Track found keys and track keys in tree that are not in input knobs.
+ for i in range(0, numItems):
+ item = self.treeWidget.topLevelItem(i)
+
+ # itemKey is the text in the first column of a QTreeWidgetItem
+ itemKey = str(item.text(0))
+ if itemKey in knobs.keys():
+
+ # This key was found in the tree, update its values.
+ foundKeys.append(itemKey)
+ v = knobs[itemKey].value
+ units = str(knobprops[itemKey].units)
+ descr = str(knobprops[itemKey].description)
+
+ if(type(v) == GNURadio.complex):
+ v = v.re + v.im*1j
+ # If it's a byte stream, Python thinks it's a string.
+ # Unpack and convert to floats for plotting.
+ # Ignore the edge list knob if it's being exported
+ elif(type(v) == str and itemKey.find('probe2_b') == 0):
+ v = struct.unpack(len(v)*'b', v)
+
+ # Convert the final value to a string for displaying
+ v = str(v)
+
+ if (item.text(1) != v or
+ item.text(2) != units or
+ item.text(3) != descr):
+
+ item.setText(1, v)
+ item.setText(2, units)
+ item.setText(3, descr)
+ else:
+ # This item is not in the knobs list...track it for removal.
+ deleteKeys.append(itemKey)
+
+ # Add items to tree that are not currently in the tree.
+ for k in knobs.keys():
+ if k not in foundKeys:
+ v = knobs[k].value
+ if(type(v) == GNURadio.complex):
+ v = v.re + v.im*1j
+ # If it's a byte stream, Python thinks it's a string.
+ # Unpack and convert to floats for plotting.
+ # Ignore the edge list knob if it's being exported
+ elif(type(v) == str and k.find('probe2_b') == 0):
+ v = struct.unpack(len(v)*'b', v)
+
+ item = QtGui.QTreeWidgetItem([k, str(v),
+ knobprops[k].units, knobprops[k].description])
+ self.treeWidget.addTopLevelItem(item)
+
+ # Remove items currently in tree that are not in the knob list.
+ for itemKey in deleteKeys:
+ qtwiList = self.treeWidget.findItems(itemKey, Qt.Qt.MatchFixedString)
+ if (len(qtwiList) > 1):
+ raise Exception('More than one item with key %s in tree' %
+ itemKey)
+ elif (len(qtwiList) == 1):
+ i = self.treeWidget.indexOfTopLevelItem(qtwiList[0])
+ self.treeWidget.takeTopLevelItem(i)
diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor b/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor
index ac6e6a4675..b087ad5c71 100755
--- a/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor
+++ b/gnuradio-runtime/python/gnuradio/ctrlport/gr-ctrlport-monitor
@@ -24,7 +24,7 @@ from gnuradio import gr, ctrlport
from PyQt4 import QtCore,Qt
import PyQt4.QtGui as QtGui
-import os, sys, time
+import os, sys, time, struct
import Ice
from gnuradio.ctrlport.IceRadioClient import *
@@ -109,23 +109,8 @@ class MAINWindow(QtGui.QMainWindow):
title = "{0}:{1}".format(r[3], r[5])
props = radio.properties([key])
- pmin = props[key].min.value
- pmax = props[key].max.value
- # Convert from GNURadio::complex to Python complex
- if(type(pmin) == GNURadio.complex):
- pmin = pmin.re + pmin.im*1j
- if(type(pmax) == GNURadio.complex):
- pmax = pmax.re + pmax.im*1j
-
- if pmin == []:
- pmin = None
- else:
- pmin = 1.1*abs(pmin)
- if pmax == []:
- pmax = None
- else:
- pmax = 1.1*abs(pmax)
+ pmin,pmax = get_minmax(props[key])
# Use display option mask of item to set up available plot
# types and default options.
@@ -197,22 +182,7 @@ class MAINWindow(QtGui.QMainWindow):
r = str(tree.radio).split(" ")
title = "{0}:{1}".format(r[3], r[5])
- pmin = knobprop.min.value
- pmax = knobprop.max.value
-
- if(type(pmin) == GNURadio.complex):
- pmin = pmin.re + pmin.im*1j
- if(type(pmax) == GNURadio.complex):
- pmax = pmax.re + pmax.im*1j
-
- if pmin == []:
- pmin = None
- else:
- pmin = 1.1*pmin
- if pmax == []:
- pmax = None
- else:
- pmax = 1.1*pmax
+ pmin,pmax = get_minmax(knobprop)
disp = knobprop.display
if(disp & gr.DISPTIME):
@@ -337,6 +307,13 @@ class MAINWindow(QtGui.QMainWindow):
d = knobs[n].value
if(type(d) == GNURadio.complex):
d = [d.re, d.im]
+
+ # If it's a byte stream, Python thinks it's a string.
+ # Unpack and convert to floats for plotting.
+ if(type(d) == str and n.find('probe2_b') == 0):
+ d = struct.unpack(len(d)*'b', d)
+ d = [float(di) for di in d]
+
data.append(d)
plot.update(data)
plot.stop()
@@ -352,10 +329,6 @@ class MAINWindow(QtGui.QMainWindow):
self.newConAct = QtGui.QAction("&New Connection",
self, shortcut=QtGui.QKeySequence.New,
statusTip="Create a new file", triggered=self.newCon)
- #self.newAct = QtGui.QAction(QtGui.QIcon(':/images/new.png'), "&New Plot",
- self.newPlotAct = QtGui.QAction("&New Plot",
- self,
- statusTip="Create a new file", triggered=self.newPlotF)
self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q",
statusTip="Exit the application",
@@ -408,7 +381,6 @@ class MAINWindow(QtGui.QMainWindow):
def createMenus(self):
self.fileMenu = self.menuBar().addMenu("&File")
self.fileMenu.addAction(self.newConAct)
- self.fileMenu.addAction(self.newPlotAct)
self.fileMenu.addAction(self.urAct)
self.fileMenu.addSeparator()
self.fileMenu.addAction(self.exitAct)
@@ -435,7 +407,6 @@ class MAINWindow(QtGui.QMainWindow):
def createToolBars(self):
self.fileToolBar = self.addToolBar("File")
self.fileToolBar.addAction(self.newConAct)
- self.fileToolBar.addAction(self.newPlotAct)
self.fileToolBar.addAction(self.urAct)
self.fileToolBar = self.addToolBar("Window")
@@ -744,6 +715,33 @@ class MForm(QtGui.QWidget):
self.parent.propertiesMenu(itemname, self.radio, self.uid)
+def get_minmax(p):
+ pmin = p.min.value
+ pmax = p.max.value
+
+ # Find min/max or real or imag for GNURadio::complex
+ if(type(pmin) == GNURadio.complex):
+ pmin = min(pmin.re, pmin.im)
+ if(type(pmax) == GNURadio.complex):
+ pmax = max(pmax.re, pmax.im)
+
+ # If it's a byte stream, Python thinks it's a string.
+ if(type(pmin) == str):
+ pmin = struct.unpack('b', pmin)[0]
+ if(type(pmax) == str):
+ pmax = struct.unpack('b', pmax)[0]
+
+ if pmin == []:
+ pmin = None
+ else:
+ pmin = 1.1*float(pmin)
+ if pmax == []:
+ pmax = None
+ else:
+ pmax = 1.1*float(pmax)
+
+ return pmin, pmax
+
class MyClient(IceRadioClient):
def __init__(self):
IceRadioClient.__init__(self, MAINWindow)
diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py b/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py
index e067b9b0a6..8bb26d93a1 100644
--- a/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py
+++ b/gnuradio-runtime/python/gnuradio/ctrlport/monitor.py
@@ -33,7 +33,7 @@ class monitor:
try:
# setup export prefs
gr.prefs().singleton().set_bool("ControlPort","on",True);
- if(tool == "gr-ctrlport-monitor"):
+ if(tool == "gr-perf-monitorx"):
gr.prefs().singleton().set_bool("ControlPort","edges_list",True);
gr.prefs().singleton().set_bool("PerfCounters","on",True);
gr.prefs().singleton().set_bool("PerfCounters","export",True);
diff --git a/gnuradio-runtime/swig/hier_block2.i b/gnuradio-runtime/swig/hier_block2.i
index b455e02a7e..87c936544a 100644
--- a/gnuradio-runtime/swig/hier_block2.i
+++ b/gnuradio-runtime/swig/hier_block2.i
@@ -87,6 +87,10 @@ namespace gr {
void message_port_register_hier_in(pmt::pmt_t port_id);
void message_port_register_hier_out(pmt::pmt_t port_id);
+ void set_processor_affinity(const std::vector<int> &mask);
+ void unset_processor_affinity();
+ std::vector<int> processor_affinity();
+
gr::hier_block2_sptr to_hier_block2(); // Needed for Python type coercion
};
}
diff --git a/gr-atsc/include/gnuradio/atsc/field_sync_mux.h b/gr-atsc/include/gnuradio/atsc/field_sync_mux.h
index dbf08c5132..2cccb52aec 100644
--- a/gr-atsc/include/gnuradio/atsc/field_sync_mux.h
+++ b/gr-atsc/include/gnuradio/atsc/field_sync_mux.h
@@ -38,7 +38,7 @@ ATSC_API atsc_field_sync_mux_sptr atsc_make_field_sync_mux();
*
* input: atsc_data_segment; output: atsc_data_segment
*/
-class ATSC_API atsc_field_sync_mux : public gr::sync_block
+class ATSC_API atsc_field_sync_mux : public gr::block
{
friend ATSC_API atsc_field_sync_mux_sptr atsc_make_field_sync_mux();
@@ -46,17 +46,20 @@ class ATSC_API atsc_field_sync_mux : public gr::sync_block
public:
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
- int work (int noutput_items,
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
static const int N_SAVED_SYMBOLS = 12;
- void reset() { /* nop */ }
+ void reset()
+ {
+ d_already_output_field_sync = false;
+ }
protected:
- gr_uint64 d_current_index;
bool d_already_output_field_sync;
unsigned char d_saved_symbols[N_SAVED_SYMBOLS];
};
diff --git a/gr-atsc/lib/atsc_field_sync_mux.cc b/gr-atsc/lib/atsc_field_sync_mux.cc
index 5520a74877..6b0586dbfc 100644
--- a/gr-atsc/lib/atsc_field_sync_mux.cc
+++ b/gr-atsc/lib/atsc_field_sync_mux.cc
@@ -37,7 +37,7 @@ atsc_make_field_sync_mux()
}
atsc_field_sync_mux::atsc_field_sync_mux()
- : gr::sync_block("atsc_field_sync_mux",
+ : gr::block("atsc_field_sync_mux",
gr::io_signature::make(1, 1, sizeof(atsc_data_segment)),
gr::io_signature::make(1, 1, sizeof(atsc_data_segment)))
{
@@ -148,21 +148,24 @@ atsc_field_sync_mux::forecast (int noutput_items, gr_vector_int &ninput_items_re
{
unsigned ninputs = ninput_items_required.size();
for (unsigned i = 0; i < ninputs; i++)
- ninput_items_required[i] = fixed_rate_noutput_to_ninput (noutput_items);
+ ninput_items_required[i] = noutput_items;
}
int
-atsc_field_sync_mux::work (int noutput_items,
+atsc_field_sync_mux::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
+ int in_length = ninput_items[0];
const atsc_data_segment *in = (const atsc_data_segment *) input_items[0];
atsc_data_segment *out = (atsc_data_segment *) output_items[0];
- unsigned int index = 0;
- for (int outdex = 0; outdex < noutput_items; outdex++){
+ int index = 0;
+ int outdex = 0;
+ for (outdex = 0; outdex < noutput_items && index < in_length; outdex++){
assert (in[index].pli.regular_seg_p ());
@@ -197,7 +200,6 @@ atsc_field_sync_mux::work (int noutput_items,
}
}
- d_current_index += index;
-
- return noutput_items;
+ this->consume_each(index);
+ return outdex;
}
diff --git a/gr-atsc/python/atsc/CMakeLists.txt b/gr-atsc/python/atsc/CMakeLists.txt
index 881a3bb9fc..ab19b13e2d 100644
--- a/gr-atsc/python/atsc/CMakeLists.txt
+++ b/gr-atsc/python/atsc/CMakeLists.txt
@@ -32,11 +32,7 @@ GR_PYTHON_INSTALL(
GR_PYTHON_INSTALL(
PROGRAMS
- btl-fsd.py
- fpll.py
- interp.py
- xlate.py
- viterbi-out.py
+ atsc_rx.py
DESTINATION ${GR_PKG_DATA_DIR}/examples/atsc
COMPONENT "atsc_examples"
)
diff --git a/gr-atsc/python/atsc/README b/gr-atsc/python/atsc/README
index 74d6ba134c..38772c2f10 100644
--- a/gr-atsc/python/atsc/README
+++ b/gr-atsc/python/atsc/README
@@ -1,11 +1,11 @@
-Decoding ATSC using 19.2MSps rate over 5 processes
---------------------------------------------------
+Decoding ATSC using 6.4MSps rate
+---------------------------------
1) Verify signal, adjust antenna and find best gain setting using uhd_fft.py,
station frequency from the fcc video database, and sample rate to 6.4e6.
2) Capture data - adjust gain (-g) frequency (-f) and which side
-the tvrx is on to fit your local setup:
+the daughterboard is on to fit your local setup:
uhd_rx_cfile.py -s --samp-rate=6.4e6 -g 65 -f 503e6 atsc_data_6-4m_complex
@@ -14,21 +14,6 @@ striped sata drives. Make sure there are no or very few Ou overruns. Saving
the raw usrp data in 'short' form halves the disk space/bus bandwidth that
the usual complex form uses.
-3) Make pipes:
-
-mkfifo /tmp/atsc_pipe_1
-mkfifo /tmp/atsc_pipe_2
-mkfifo /tmp/atsc_pipe_3
-mkfifo /tmp/atsc_pipe_4
-mkfifo /tmp/atsc_pipe_5
-
-4) In seperate windows run processes:
-
-./interp_short.py <input rf data at 6.4Msps>
-./xlate.py
-./fpll.py
-./btl-fsd.py
-./viterbi-out.py <output mpeg transport stream>
-
-
+3) Run atsc_rx.py:
+./atsc_rx.py atsc_data_6-4m_complex outfile.ts \ No newline at end of file
diff --git a/gr-atsc/python/atsc/all_atsc.py b/gr-atsc/python/atsc/all_atsc.py
deleted file mode 100644
index 7cac785149..0000000000
--- a/gr-atsc/python/atsc/all_atsc.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env /usr/bin/python
-#
-# Copyright 2004 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-# This module starts the atsc processing chain taking the captured
-# off-air signal created with:
-#
-# uhd_rx_cfile.py --samp-rate=6.4e6
-# -f <center of tv signal channel freq>
-# -g <appropriate gain for best signal / noise>
-# -s output shorts
-#
-# All this module does is multiply the sample rate by 3, from 6.4e6 to
-# 19.2e6 complex samples / sec, then lowpass filter with a cutoff of 3.2MHz
-# and a transition band width of .5MHz. Center of the tv channels is
-# then at 0 with edges at -3.2MHz and 3.2MHz.
-
-from gnuradio import gr, atsc
-from gnuradio import filter
-from gnuradio import blocks
-import sys, os, math
-
-def graph (args):
-
- nargs = len(args)
- if nargs == 2:
- infile = args[0]
- outfile = args[1]
- else:
- raise ValueError('usage: interp.py input_file output_file\n')
-
- tb = gr.top_block ()
-
- # Convert to a from shorts to a stream of complex numbers.
- srcf = blocks.file_source (gr.sizeof_short,infile)
- s2ss = blocks.stream_to_streams(gr.sizeof_short,2)
- s2f1 = blocks.short_to_float()
- s2f2 = blocks.short_to_float()
- src0 = blocks.float_to_complex()
- tb.connect(srcf, s2ss)
- tb.connect((s2ss, 0), s2f1, (src0, 0))
- tb.connect((s2ss, 1), s2f2, (src0, 1))
-
- # Low pass filter it and increase sample rate by a factor of 3.
- lp_coeffs = filter.firdes.low_pass ( 3, 19.2e6, 3.2e6, .5e6, filter.firdes.WIN_HAMMING )
- lp = filter.interp_fir_filter_ccf ( 3, lp_coeffs )
- tb.connect(src0, lp)
-
- # Upconvert it.
- duc_coeffs = filter.firdes.low_pass ( 1, 19.2e6, 9e6, 1e6, filter.firdes.WIN_HAMMING )
- duc = filter.freq_xlating_fir_filter_ccf ( 1, duc_coeffs, 5.75e6, 19.2e6 )
- # Discard the imaginary component.
- c2f = blocks.complex_to_float()
- tb.connect(lp, duc, c2f)
-
- # Frequency Phase Lock Loop
- input_rate = 19.2e6
- IF_freq = 5.75e6
- # 1/2 as wide because we're designing lp filter
- symbol_rate = atsc.ATSC_SYMBOL_RATE/2.
- NTAPS = 279
- tt = filter.firdes.root_raised_cosine (1.0, input_rate, symbol_rate, .115, NTAPS)
- # heterodyne the low pass coefficients up to the specified bandpass
- # center frequency. Note that when we do this, the filter bandwidth
- # is effectively twice the low pass (2.69 * 2 = 5.38) and hence
- # matches the diagram in the ATSC spec.
- arg = 2. * math.pi * IF_freq / input_rate
- t=[]
- for i in range(len(tt)):
- t += [tt[i] * 2. * math.cos(arg * i)]
- rrc = filter.fir_filter_fff(1, t)
-
- fpll = atsc.fpll()
-
- pilot_freq = IF_freq - 3e6 + 0.31e6
- lower_edge = 6e6 - 0.31e6
- upper_edge = IF_freq - 3e6 + pilot_freq
- transition_width = upper_edge - lower_edge
- lp_coeffs = filter.firdes.low_pass(1.0,
- input_rate,
- (lower_edge + upper_edge) * 0.5,
- transition_width,
- filter.firdes.WIN_HAMMING);
-
- lp_filter = filter.fir_filter_fff(1,lp_coeffs)
-
- alpha = 1e-5
- iir = filter.single_pole_iir_filter_ff(alpha)
- remove_dc = blocks.sub_ff()
-
- tb.connect(c2f, fpll, lp_filter)
- tb.connect(lp_filter, iir)
- tb.connect(lp_filter, (remove_dc,0))
- tb.connect(iir, (remove_dc,1))
-
- # Bit Timing Loop, Field Sync Checker and Equalizer
-
- btl = atsc.bit_timing_loop()
- fsc = atsc.fs_checker()
- eq = atsc.equalizer()
- fsd = atsc.field_sync_demux()
-
- tb.connect(remove_dc, btl)
- tb.connect((btl, 0),(fsc, 0),(eq, 0),(fsd, 0))
- tb.connect((btl, 1),(fsc, 1),(eq, 1),(fsd, 1))
-
- # Viterbi
-
- viterbi = atsc.viterbi_decoder()
- deinter = atsc.deinterleaver()
- rs_dec = atsc.rs_decoder()
- derand = atsc.derandomizer()
- depad = atsc.depad()
- dst = blocks.file_sink(gr.sizeof_char, outfile)
- tb.connect(fsd, viterbi, deinter, rs_dec, derand, depad, dst)
-
- dst2 = blocks.file_sink(gr.sizeof_gr_complex, "atsc_complex.data")
- tb.connect(src0, dst2)
-
- tb.run ()
-
-if __name__ == '__main__':
- graph (sys.argv[1:])
-
-
diff --git a/gr-atsc/python/atsc/atsc_rx.py b/gr-atsc/python/atsc/atsc_rx.py
new file mode 100755
index 0000000000..377c4daa29
--- /dev/null
+++ b/gr-atsc/python/atsc/atsc_rx.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env /usr/bin/python
+#
+# Copyright 2004, 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# This module starts the atsc processing chain taking the captured
+# off-air signal created with:
+#
+# uhd_rx_cfile.py --samp-rate=6.4e6
+# -f <center of tv signal channel freq>
+# -g <appropriate gain for best signal / noise>
+# -s output shorts
+#
+# This python script converts from interleaved shorts to the complex data type,
+# then multiplies the sample rate by 3, from 6.4e6 to 19.2e6
+# complex samples / sec, then lowpass filters with a cutoff of 3.2MHz
+# and a transition band width of .5MHz. Center of the tv channels is
+# now at 0 with edges at -3.2MHz and 3.2MHz. This puts the pilot at
+# -3MHz + 309KHz. Next a root raised cosine filter is aplied to match the one
+# in the transmitter and thus reduce ISI. The phased locked loop then locks to
+# the pilot and outputs just the real part of the signal ( as information is
+# not stored in the phase with atsc ), this is then feed to the bit lock
+# loop, this looks for the bit sync marker put at the beginning of every segment
+# field, this then adjusts the timing so the amplitude will be sampled at the
+# correct sample ( sub-sample is used in this case ).
+#
+# Output is float.
+
+from gnuradio import gr, analog, atsc
+from gnuradio import blocks
+from gnuradio import filter
+import sys, math, os
+
+def graph (args):
+
+ print os.getpid()
+
+ nargs = len(args)
+ if nargs == 2:
+ infile = args[0]
+ outfile = args[1]
+ else:
+ raise ValueError('usage: interp.py input_file output_file.ts\n')
+
+ input_rate = 19.2e6
+ IF_freq = 5.75e6
+
+ tb = gr.top_block()
+
+ # Read from input file
+ srcf = blocks.file_source(gr.sizeof_short, infile)
+
+ # Convert interleaved shorts (I,Q,I,Q) to complex
+ is2c = blocks.interleaved_short_to_complex()
+
+ # 1/2 as wide because we're designing lp filter
+ symbol_rate = atsc.ATSC_SYMBOL_RATE/2.
+ NTAPS = 279
+ tt = filter.firdes.root_raised_cosine (1.0, input_rate / 3, symbol_rate, .1152, NTAPS)
+ rrc = filter.fir_filter_ccf(1, tt)
+
+ # Interpolate Filter our 6MHz wide signal centered at 0
+ ilp_coeffs = filter.firdes.low_pass(1, input_rate, 3.2e6, .5e6, filter.firdes.WIN_HAMMING)
+ ilp = filter.interp_fir_filter_ccf(3, ilp_coeffs)
+
+ # Move the center frequency to 5.75MHz ( this wont be needed soon )
+ duc_coeffs = filter.firdes.low_pass ( 1, 19.2e6, 9e6, 1e6, filter.firdes.WIN_HAMMING )
+ duc = filter.freq_xlating_fir_filter_ccf ( 1, duc_coeffs, -5.75e6, 19.2e6 )
+
+ # fpll input is float
+ c2f = blocks.complex_to_float()
+
+ # Phase locked loop
+ fpll = atsc.fpll()
+
+ # Clean fpll output
+ lp_coeffs2 = filter.firdes.low_pass (1.0,
+ input_rate,
+ 5.75e6,
+ 120e3,
+ filter.firdes.WIN_HAMMING);
+ lp_filter = filter.fir_filter_fff (1, lp_coeffs2)
+
+ # Remove pilot ( at DC now )
+ iir = filter.single_pole_iir_filter_ff(1e-5)
+ remove_dc = blocks.sub_ff()
+
+ # Bit Timing Loop, Field Sync Checker and Equalizer
+ btl = atsc.bit_timing_loop()
+ fsc = atsc.fs_checker()
+ eq = atsc.equalizer()
+ fsd = atsc.field_sync_demux()
+
+ # Viterbi
+ viterbi = atsc.viterbi_decoder()
+ deinter = atsc.deinterleaver()
+ rs_dec = atsc.rs_decoder()
+ derand = atsc.derandomizer()
+ depad = atsc.depad()
+
+ # Write to output file
+ outf = blocks.file_sink(gr.sizeof_char,outfile)
+
+ # Connect it all together
+ tb.connect( srcf, is2c, rrc, ilp, duc, c2f, fpll, lp_filter)
+ tb.connect( lp_filter, iir )
+ tb.connect( lp_filter, (remove_dc, 0) )
+ tb.connect( iir, (remove_dc, 1) )
+ tb.connect( remove_dc, btl )
+ tb.connect( (btl, 0), (fsc, 0), (eq, 0), (fsd,0) )
+ tb.connect( (btl, 1), (fsc, 1), (eq, 1), (fsd,1) )
+ tb.connect( fsd, viterbi, deinter, rs_dec, derand, depad, outf )
+
+ tb.run()
+
+if __name__ == '__main__':
+ graph (sys.argv[1:])
+
diff --git a/gr-atsc/python/atsc/btl-fsd.py b/gr-atsc/python/atsc/btl-fsd.py
deleted file mode 100755
index 6bcab3dce3..0000000000
--- a/gr-atsc/python/atsc/btl-fsd.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2004,2005,2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-
-from gnuradio import gr
-from gnuradio import atsc
-from gnuradio import blocks
-import os
-
-print os.getpid()
-
-tb = gr.top_block()
-
-btl = atsc.bit_timing_loop()
-fsc = atsc.fs_checker()
-eq = atsc.equalizer()
-fsd = atsc.field_sync_demux()
-
-out_data = blocks.file_sink(atsc.sizeof_atsc_soft_data_segment,"/tmp/atsc_pipe_5")
-
-inp = blocks.file_source(gr.sizeof_float,"/tmp/atsc_pipe_3")
-
-tb.connect(inp,btl)
-tb.connect((btl,0),(fsc,0),(eq,0),(fsd,0))
-tb.connect((btl,1),(fsc,1),(eq,1),(fsd,1))
-tb.connect(fsd,out_data)
-
-tb.run()
-
-
diff --git a/gr-atsc/python/atsc/fpll.py b/gr-atsc/python/atsc/fpll.py
deleted file mode 100755
index dee81da13d..0000000000
--- a/gr-atsc/python/atsc/fpll.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2004,2005 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-
-from gnuradio import gr, atsc
-from gnuradio import blocks
-from gnuradio import filter
-import math, os
-
-def main():
-
- print os.getpid()
-
- tb = gr.top_block()
-
- u = blocks.file_source(gr.sizeof_float,"/tmp/atsc_pipe_2")
-
- input_rate = 19.2e6
- IF_freq = 5.75e6
-
-
- # 1/2 as wide because we're designing lp filter
- symbol_rate = atsc.ATSC_SYMBOL_RATE/2.
- NTAPS = 279
- tt = filter.firdes.root_raised_cosine (1.0, input_rate, symbol_rate, .115, NTAPS)
- # heterodyne the low pass coefficients up to the specified bandpass
- # center frequency. Note that when we do this, the filter bandwidth
- # is effectively twice the low pass (2.69 * 2 = 5.38) and hence
- # matches the diagram in the ATSC spec.
- arg = 2. * math.pi * IF_freq / input_rate
- t=[]
- for i in range(len(tt)):
- t += [tt[i] * 2. * math.cos(arg * i)]
- rrc = filter.fir_filter_fff(1, t)
-
- fpll = atsc.fpll()
-
- pilot_freq = IF_freq - 3e6 + 0.31e6
- lower_edge = 6e6 - 0.31e6
- upper_edge = IF_freq - 3e6 + pilot_freq
- transition_width = upper_edge - lower_edge
- lp_coeffs = filter.firdes.low_pass (1.0,
- input_rate,
- (lower_edge + upper_edge) * 0.5,
- transition_width,
- filter.firdes.WIN_HAMMING);
-
- lp_filter = filter.fir_filter_fff (1,lp_coeffs)
-
- alpha = 1e-5
- iir = filter.single_pole_iir_filter_ff(alpha)
- remove_dc = blocks.sub_ff()
-
- out = blocks.file_sink(gr.sizeof_float,"/tmp/atsc_pipe_3")
- # out = blocks.file_sink(gr.sizeof_float,"/mnt/sata/atsc_data_float")
-
- tb.connect(u, fpll, lp_filter)
- tb.connect(lp_filter, iir)
- tb.connect(lp_filter, (remove_dc,0))
- tb.connect(iir, (remove_dc,1))
- tb.connect(remove_dc, out)
-
- tb.run()
-
-
-if __name__ == '__main__':
- main ()
-
-
-
diff --git a/gr-atsc/python/atsc/interp.py b/gr-atsc/python/atsc/interp.py
deleted file mode 100755
index ee2d234892..0000000000
--- a/gr-atsc/python/atsc/interp.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env /usr/bin/python
-#
-# Copyright 2004,2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-# This module starts the atsc processing chain taking the captured
-# off-air signal created with:
-#
-# uhd_rx_cfile.py --samp-rate=6.4e6
-# -f <center of tv signal channel freq>
-# -g <appropriate gain for best signal / noise>
-#
-# All this module does is multiply the sample rate by 3, from 6.4e6 to
-# 19.2e6 complex samples / sec, then lowpass filter with a cutoff of 3.2MHz
-# and a transition band width of .5MHz. Center of the tv channels is
-# then at 0 with edges at -3.2MHz and 3.2MHz.
-
-from gnuradio import gr
-from gnuradio import blocks
-import sys
-
-def graph(args):
-
- nargs = len(args)
- if nargs == 1:
- infile = args[0]
- else:
- sys.stderr.write('usage: interp.py input_file\n')
- sys.exit(1)
-
- tb = gr.top_block()
-
- src0 = blocks.file_source(gr.sizeof_gr_complex, infile)
-
- lp_coeffs = filter.firdes.low_pass(3, 19.2e6, 3.2e6, .5e6,
- filter.firdes.WIN_HAMMING )
- lp = filter.interp_fir_filter_ccf(1, lp_coeffs)
-
- file = blocks.file_sink(gr.sizeof_gr_complex, "/tmp/atsc_pipe_1")
-
- tb.connect(src0, lp, file)
-
- tb.start()
- raw_input('Head End: Press Enter to stop')
- tb.stop()
-
-if __name__ == '__main__':
- graph(sys.argv[1:])
-
-
diff --git a/gr-atsc/python/atsc/interp_short.py b/gr-atsc/python/atsc/interp_short.py
deleted file mode 100755
index d07b941c12..0000000000
--- a/gr-atsc/python/atsc/interp_short.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env /usr/bin/python
-#
-# Copyright 2004 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-# This module starts the atsc processing chain taking the captured
-# off-air signal created with:
-#
-# uhd_rx_cfile.py --samp-rate=6.4e6
-# -f <center of tv signal channel freq>
-# -g <appropriate gain for best signal / noise>
-# -s output shorts
-#
-# All this module does is multiply the sample rate by 3, from 6.4e6 to
-# 19.2e6 complex samples / sec, then lowpass filter with a cutoff of 3.2MHz
-# and a transition band width of .5MHz. Center of the tv channels is
-# then at 0 with edges at -3.2MHz and 3.2MHz.
-
-from gnuradio import gr
-from gnuradio import blocks
-from gnuradio import filter
-import sys, os
-
-def graph (args):
-
- print os.getpid()
-
- nargs = len (args)
- if nargs == 1:
- infile = args[0]
- else:
- sys.stderr.write('usage: interp.py input_file\n')
- sys.exit (1)
-
- tb = gr.top_block()
-
- srcf = blocks.file_source(gr.sizeof_short,infile)
- s2ss = blocks.stream_to_streams(gr.sizeof_short,2)
- s2f1 = blocks.short_to_float()
- s2f2 = blocks.short_to_float()
- src0 = blocks.float_to_complex()
-
-
- lp_coeffs = filter.firdes.low_pass(3, 19.2e6, 3.2e6, .5e6,
- filter.firdes.WIN_HAMMING)
- lp = filter.interp_fir_filter_ccf(3, lp_coeffs)
-
- file = blocks.file_sink(gr.sizeof_gr_complex,"/tmp/atsc_pipe_1")
-
- tb.connect( srcf, s2ss )
- tb.connect( (s2ss, 0), s2f1, (src0,0) )
- tb.connect( (s2ss, 1), s2f2, (src0,1) )
- tb.connect( src0, lp, file)
-
- tb.start()
- raw_input ('Head End: Press Enter to stop')
- tb.stop()
-
-if __name__ == '__main__':
- graph (sys.argv[1:])
-
-
diff --git a/gr-atsc/python/atsc/viterbi-out.py b/gr-atsc/python/atsc/viterbi-out.py
deleted file mode 100755
index cc60ffda42..0000000000
--- a/gr-atsc/python/atsc/viterbi-out.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2004,2006,2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-
-from gnuradio import gr, atsc
-from gnuradio import blocks
-import sys, os
-
-def main(args):
-
- print os.getpid()
-
- nargs = len (args)
- if nargs == 1:
- outfile = args[0]
- else:
- sys.stderr.write ('usage: viterbi_out.py output_file\n')
- sys.exit (1)
-
- tb = gr.top_block()
-
- src = blocks.file_source(atsc.sizeof_atsc_soft_data_segment, "/tmp/atsc_pipe_5")
- viterbi = atsc.viterbi_decoder()
- deinter = atsc.deinterleaver()
- rs_dec = atsc.rs_decoder()
- derand = atsc.derandomizer()
- depad = atsc.depad()
- dst = blocks.file_sink(gr.sizeof_char,outfile)
- tb.connect(src, viterbi, deinter, rs_dec, derand, depad, dst)
- tb.run ()
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])
-
-
-
-
-
-
diff --git a/gr-atsc/python/atsc/xlate.py b/gr-atsc/python/atsc/xlate.py
deleted file mode 100755
index eb04ecc68a..0000000000
--- a/gr-atsc/python/atsc/xlate.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env /usr/bin/python
-#
-# Copyright 2004,2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-#
-# This module upconverts the 19.2e6 sample rate signal from a center
-# of 0 to 5.75e6 and converts to float, to prepare the signal for
-# the old gnuradio 0.9 block (bit timing loop, field sync checker,
-# equalizer and field sync demux), effectively simulating an
-# mc4020 card, except the sample rate is 19.2e6 instead of 20e6.
-#
-# The signal is then centered on 5.75e6 with edges at 5.75 + 3.2 = 8.95MHz
-# and 5.75 - 3.2 = 2.55Mhz, low pass filtered with cutoff at 9Mhz and a
-# transition band width of 1Mhz.
-#
-# Input complex -3.2 to 3.2Mhz, output float 2.55 to 8.95Mhz.
-
-from gnuradio import gr
-from gnuradio import filter
-from gnuradio import blocks
-import os
-
-def graph ():
- print os.getpid()
- sampling_freq = 19200000
-
- tb = gr.top_block ()
-
- src0 = blocks.file_source(gr.sizeof_gr_complex,"/tmp/atsc_pipe_1")
-
- duc_coeffs = filter.firdes.low_pass( 1, 19.2e6, 9e6, 1e6, filter.firdes.WIN_HAMMING )
- duc = filter.freq_xlating_fir_filter_ccf( 1, duc_coeffs, 5.75e6, 19.2e6 )
-
- c2f = blocks.complex_to_float()
- file = blocks.file_sink(gr.sizeof_float,"/tmp/atsc_pipe_2")
-
- tb.connect( src0, duc, c2f, file )
-
- tb.run()
-
-if __name__ == '__main__':
- graph ()
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml
index 150b3f1c93..c6c797f52a 100644
--- a/gr-blocks/grc/blocks_block_tree.xml
+++ b/gr-blocks/grc/blocks_block_tree.xml
@@ -53,6 +53,7 @@
<name>Control Port</name>
<block>blocks_ctrlport_monitor</block>
<block>blocks_ctrlport_monitor_performance</block>
+ <block>blocks_ctrlport_probe2_x</block>
<block>blocks_ctrlport_probe2_c</block>
<block>blocks_ctrlport_probe_c</block>
</cat>
@@ -62,6 +63,8 @@
<block>blocks_tag_debug</block>
<block>blocks_message_debug</block>
<block>blocks_random_pdu</block>
+ <block>blocks_message_strobe</block>
+ <block>blocks_tags_strobe</block>
</cat>
<cat>
<name>File Operators</name>
diff --git a/gr-blocks/grc/blocks_ctrlport_probe2_c.xml b/gr-blocks/grc/blocks_ctrlport_probe2_c.xml
index 3add69aa7b..b5f0b089a7 100644
--- a/gr-blocks/grc/blocks_ctrlport_probe2_c.xml
+++ b/gr-blocks/grc/blocks_ctrlport_probe2_c.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- Copyright 2012 Free Software Foundation, Inc.
+ Copyright 2012-2013 Free Software Foundation, Inc.
This file is part of GNU Radio
@@ -22,23 +22,23 @@
-->
<block>
- <name>Ctrlport Complex Probe (fixed len)</name>
+ <name>Ctrlport Probe</name>
<key>blocks_ctrlport_probe2_c</key>
<import>from gnuradio import blocks</import>
- <make>blocks.ctrlport_probe2_c($name, $desc, $len)</make>
+ <make>blocks.ctrlport_probe2_c($name, $desc, $len, $disp_mask)</make>
<callback>set_length($len)</callback>
<param>
<name>Name</name>
<key>name</key>
- <value>constellation</value>
+ <value>samples</value>
<type>string</type>
</param>
<param>
<name>Description</name>
<key>desc</key>
- <value>Constellation Points</value>
+ <value>Sample Points</value>
<type>string</type>
</param>
@@ -49,6 +49,32 @@
<type>int</type>
</param>
+ <param>
+ <name>Display Mask</name>
+ <key>disp_mask</key>
+ <value>gr.DISPTIME</value>
+ <type>int</type>
+ <option>
+ <name>Constellation</name>
+ <key>gr.DISPXY | gr.DISPOPTSCATTER</key>
+ </option>
+ <option>
+ <name>Time</name>
+ <key>gr.DISPTIME</key>
+ </option>
+ <option>
+ <name>PSD</name>
+ <key>gr.DISPPSD</key>
+ </option>
+ <option>
+ <name>Spectrogram</name>
+ <key>gr.DISPSPEC</key>
+ </option>
+ <option>
+ <name>Raster</name>
+ <key>gr.DISPRAST</key>
+ </option>
+ </param>
<sink>
<name>in</name>
@@ -56,9 +82,10 @@
</sink>
<doc>
- Place this in a graph to export complex values to a GRCP port probe.
+ Place this in a graph to export vectors of samples to a GRCP port probe.
- * Version 2 allows you to specify a length in samples that you wish to get every probe
+ * Specify the number of samples to transmit at once and the type
+ of default display to use.
</doc>
</block>
diff --git a/gr-blocks/grc/blocks_ctrlport_probe2_x.xml b/gr-blocks/grc/blocks_ctrlport_probe2_x.xml
new file mode 100644
index 0000000000..b9b1660bc9
--- /dev/null
+++ b/gr-blocks/grc/blocks_ctrlport_probe2_x.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2013 Free Software Foundation, Inc.
+
+ This file is part of GNU Radio
+
+ GNU Radio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Radio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Radio; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street,
+ Boston, MA 02110-1301, USA.
+-->
+
+<block>
+ <name>Ctrlport Probe</name>
+ <key>blocks_ctrlport_probe2_x</key>
+ <import>from gnuradio import blocks</import>
+ <make>blocks.ctrlport_probe2_$(type.fcn)($name, $desc, $len, $disp_mask)</make>
+ <callback>set_length($len)</callback>
+
+ <param>
+ <name>Input Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Complex</name>
+ <key>complex</key>
+ <opt>fcn:c</opt>
+ </option>
+ <option>
+ <name>Float</name>
+ <key>float</key>
+ <opt>fcn:f</opt>
+ </option>
+ <option>
+ <name>Int</name>
+ <key>int</key>
+ <opt>fcn:i</opt>
+ </option>
+ <option>
+ <name>Short</name>
+ <key>short</key>
+ <opt>fcn:s</opt>
+ </option>
+ <option>
+ <name>Byte</name>
+ <key>byte</key>
+ <opt>fcn:b</opt>
+ </option>
+ </param>
+
+ <param>
+ <name>Name</name>
+ <key>name</key>
+ <value>samples</value>
+ <type>string</type>
+ </param>
+
+ <param>
+ <name>Description</name>
+ <key>desc</key>
+ <value>Sample Points</value>
+ <type>string</type>
+ </param>
+
+ <param>
+ <name>Length</name>
+ <key>len</key>
+ <value>1024</value>
+ <type>int</type>
+ </param>
+
+ <param>
+ <name>Display Mask</name>
+ <key>disp_mask</key>
+ <value>gr.DISPTIME</value>
+ <type>int</type>
+ <option>
+ <name>Constellation</name>
+ <key>gr.DISPXY | gr.DISPOPTSCATTER</key>
+ </option>
+ <option>
+ <name>Time</name>
+ <key>gr.DISPTIME</key>
+ </option>
+ <option>
+ <name>PSD</name>
+ <key>gr.DISPPSD</key>
+ </option>
+ <option>
+ <name>Spectrogram</name>
+ <key>gr.DISPSPEC</key>
+ </option>
+ <option>
+ <name>Raster</name>
+ <key>gr.DISPRAST</key>
+ </option>
+ </param>
+
+ <sink>
+ <name>in</name>
+ <type>$type</type>
+ </sink>
+
+ <doc>
+ Place this in a graph to export vectors of samples to a GRCP port probe.
+
+ * Specify the number of samples to transmit at once and the type
+ of default display to use.
+ </doc>
+
+</block>
+
diff --git a/gr-blocks/grc/blocks_interleaved_char_to_complex.xml b/gr-blocks/grc/blocks_interleaved_char_to_complex.xml
new file mode 100644
index 0000000000..9c0cdef6f8
--- /dev/null
+++ b/gr-blocks/grc/blocks_interleaved_char_to_complex.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Interleaved Char to Complex:
+###################################################
+ -->
+<block>
+ <name>IChar To Complex</name>
+ <key>blocks_interleaved_char_to_complex</key>
+ <import>from gnuradio import blocks</import>
+ <make>blocks.interleaved_char_to_complex($vector_input)</make>
+ <param>
+ <name>Vector Input</name>
+ <key>vector_input</key>
+ <value>False</value>
+ <type>enum</type>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ <opt>vlen:1</opt>
+ </option>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ <opt>vlen:2</opt>
+ </option>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ <vlen>$vector_input.vlen</vlen>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-blocks/grc/blocks_tag_debug.xml b/gr-blocks/grc/blocks_tag_debug.xml
index 929e53afed..bf2b4a7ec0 100644
--- a/gr-blocks/grc/blocks_tag_debug.xml
+++ b/gr-blocks/grc/blocks_tag_debug.xml
@@ -8,7 +8,7 @@
<name>Tag Debug</name>
<key>blocks_tag_debug</key>
<import>from gnuradio import blocks</import>
- <make>blocks.tag_debug($type.size*$vlen, $name)</make>
+ <make>blocks.tag_debug($type.size*$vlen, $name); self.$(id).set_display($display)</make>
<callback>set_display($display)</callback>
<param>
<name>Input Type</name>
diff --git a/gr-blocks/grc/blocks_tags_strobe.xml b/gr-blocks/grc/blocks_tags_strobe.xml
new file mode 100644
index 0000000000..16109eaad1
--- /dev/null
+++ b/gr-blocks/grc/blocks_tags_strobe.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Tags Strobe
+###################################################
+ -->
+<block>
+ <name>Tags Strobe</name>
+ <key>blocks_tags_strobe</key>
+ <import>from gnuradio import blocks</import>
+ <import>import pmt</import>
+ <make>blocks.tags_strobe($type.size*$vlen, $value, $nsamps)</make>
+ <callback>set_value($value)</callback>
+ <callback>set_nsamps($nsamps)</callback>
+ <param>
+ <name>Output Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Complex</name>
+ <key>complex</key>
+ <opt>size:gr.sizeof_gr_complex</opt>
+ </option>
+ <option>
+ <name>Float</name>
+ <key>float</key>
+ <opt>size:gr.sizeof_float</opt>
+ </option>
+ <option>
+ <name>Int</name>
+ <key>int</key>
+ <opt>size:gr.sizeof_int</opt>
+ </option>
+ <option>
+ <name>Short</name>
+ <key>short</key>
+ <opt>size:gr.sizeof_short</opt>
+ </option>
+ <option>
+ <name>Byte</name>
+ <key>byte</key>
+ <opt>size:gr.sizeof_char</opt>
+ </option>
+ </param>
+ <param>
+ <name>Value (PMT)</name>
+ <key>value</key>
+ <value>pmt.intern("TEST")</value>
+ <type>raw</type>
+ </param>
+ <param>
+ <name>Num. Samples</name>
+ <key>nsamps</key>
+ <value>1000</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Vec Length</name>
+ <key>vlen</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+ <check>$vlen &gt; 0</check>
+ <source>
+ <name>out</name>
+ <type>$type</type>
+ <vlen>$vlen</vlen>
+ </source>
+</block>
diff --git a/gr-blocks/grc/blocks_vco_c.xml b/gr-blocks/grc/blocks_vco_c.xml
new file mode 100644
index 0000000000..f6246441b9
--- /dev/null
+++ b/gr-blocks/grc/blocks_vco_c.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##VCO
+###################################################
+ -->
+<block>
+ <name>VCO (complex)</name>
+ <key>blocks_vco_c</key>
+ <import>from gnuradio import blocks</import>
+ <make>blocks.vco_c($samp_rate, $sensitivity, $amplitude)</make>
+ <param>
+ <name>Sample Rate</name>
+ <key>samp_rate</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Sensitivity</name>
+ <key>sensitivity</key>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Amplitude</name>
+ <key>amplitude</key>
+ <type>real</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>float</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
index 13e1ac71b8..de52e3e3e7 100644
--- a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
+++ b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt
@@ -146,6 +146,7 @@ install(FILES
int_to_float.h
interleave.h
interleaved_short_to_complex.h
+ interleaved_char_to_complex.h
keep_m_in_n.h
keep_one_in_n.h
lfsr_32k_source_s.h
@@ -191,6 +192,7 @@ install(FILES
tagged_file_sink.h
tagged_stream_mux.h
tagged_stream_to_pdu.h
+ tags_strobe.h
threshold_ff.h
throttle.h
transcendental.h
@@ -200,6 +202,7 @@ install(FILES
udp_source.h
unpack_k_bits_bb.h
vco_f.h
+ vco_c.h
vector_map.h
vector_to_stream.h
vector_to_streams.h
@@ -213,6 +216,10 @@ if(ENABLE_GR_CTRLPORT)
install(FILES
ctrlport_probe_c.h
ctrlport_probe2_c.h
+ ctrlport_probe2_f.h
+ ctrlport_probe2_s.h
+ ctrlport_probe2_i.h
+ ctrlport_probe2_b.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/blocks
COMPONENT "blocks_devel"
)
diff --git a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_b.h b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_b.h
new file mode 100644
index 0000000000..5ad31655cf
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_b.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_B_H
+#define INCLUDED_CTRLPORT_PROBE2_B_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief A ControlPort probe to export vectors of signals.
+ * \ingroup measurement_tools_blk
+ * \ingroup controlport_blk
+ *
+ * \details
+ * This block acts as a sink in the flowgraph but also exports
+ * vectors of complex samples over ControlPort. This block holds
+ * the latest \p len number of complex samples so that every query
+ * by a ControlPort client will get the same length vector.
+ */
+ class BLOCKS_API ctrlport_probe2_b : virtual public sync_block
+ {
+ public:
+ // gr::blocks::ctrlport_probe2_b::sptr
+ typedef boost::shared_ptr<ctrlport_probe2_b> sptr;
+
+ /*!
+ * \brief Make a ControlPort probe block.
+ * \param id A string ID to name the probe over ControlPort.
+ * \param desc A string describing the probe.
+ * \param len Number of samples to transmit.
+ * \param disp_mask Mask to set default display params.
+ */
+ static sptr make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+
+ virtual std::vector<signed char> get() = 0;
+
+ virtual void set_length(int len) = 0;
+ virtual int length() const = 0;
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_B_H */
+
diff --git a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_c.h b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_c.h
index 3841c43b74..51d908b47a 100644
--- a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_c.h
+++ b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_c.h
@@ -51,8 +51,10 @@ namespace gr {
* \param id A string ID to name the probe over ControlPort.
* \param desc A string describing the probe.
* \param len Number of samples to transmit.
+ * \param disp_mask Mask to set default display params.
*/
- static sptr make(const std::string &id, const std::string &desc, int len);
+ static sptr make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
virtual std::vector<gr_complex> get() = 0;
diff --git a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_f.h b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_f.h
new file mode 100644
index 0000000000..38d1906ed0
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_f.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_F_H
+#define INCLUDED_CTRLPORT_PROBE2_F_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief A ControlPort probe to export vectors of signals.
+ * \ingroup measurement_tools_blk
+ * \ingroup controlport_blk
+ *
+ * \details
+ * This block acts as a sink in the flowgraph but also exports
+ * vectors of complex samples over ControlPort. This block holds
+ * the latest \p len number of complex samples so that every query
+ * by a ControlPort client will get the same length vector.
+ */
+ class BLOCKS_API ctrlport_probe2_f : virtual public sync_block
+ {
+ public:
+ // gr::blocks::ctrlport_probe2_f::sptr
+ typedef boost::shared_ptr<ctrlport_probe2_f> sptr;
+
+ /*!
+ * \brief Make a ControlPort probe block.
+ * \param id A string ID to name the probe over ControlPort.
+ * \param desc A string describing the probe.
+ * \param len Number of samples to transmit.
+ * \param disp_mask Mask to set default display params.
+ */
+ static sptr make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+
+ virtual std::vector<float> get() = 0;
+
+ virtual void set_length(int len) = 0;
+ virtual int length() const = 0;
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_F_H */
+
diff --git a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_i.h b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_i.h
new file mode 100644
index 0000000000..cdfb1b86a4
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_i.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_I_H
+#define INCLUDED_CTRLPORT_PROBE2_I_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief A ControlPort probe to export vectors of signals.
+ * \ingroup measurement_tools_blk
+ * \ingroup controlport_blk
+ *
+ * \details
+ * This block acts as a sink in the flowgraph but also exports
+ * vectors of complex samples over ControlPort. This block holds
+ * the latest \p len number of complex samples so that every query
+ * by a ControlPort client will get the same length vector.
+ */
+ class BLOCKS_API ctrlport_probe2_i : virtual public sync_block
+ {
+ public:
+ // gr::blocks::ctrlport_probe2_i::sptr
+ typedef boost::shared_ptr<ctrlport_probe2_i> sptr;
+
+ /*!
+ * \brief Make a ControlPort probe block.
+ * \param id A string ID to name the probe over ControlPort.
+ * \param desc A string describing the probe.
+ * \param len Number of samples to transmit.
+ * \param disp_mask Mask to set default display params.
+ */
+ static sptr make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+
+ virtual std::vector<int> get() = 0;
+
+ virtual void set_length(int len) = 0;
+ virtual int length() const = 0;
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_I_H */
+
diff --git a/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_s.h b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_s.h
new file mode 100644
index 0000000000..676a24822a
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/ctrlport_probe2_s.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_S_H
+#define INCLUDED_CTRLPORT_PROBE2_S_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief A ControlPort probe to export vectors of signals.
+ * \ingroup measurement_tools_blk
+ * \ingroup controlport_blk
+ *
+ * \details
+ * This block acts as a sink in the flowgraph but also exports
+ * vectors of complex samples over ControlPort. This block holds
+ * the latest \p len number of complex samples so that every query
+ * by a ControlPort client will get the same length vector.
+ */
+ class BLOCKS_API ctrlport_probe2_s : virtual public sync_block
+ {
+ public:
+ // gr::blocks::ctrlport_probe2_s::sptr
+ typedef boost::shared_ptr<ctrlport_probe2_s> sptr;
+
+ /*!
+ * \brief Make a ControlPort probe block.
+ * \param id A string ID to name the probe over ControlPort.
+ * \param desc A string describing the probe.
+ * \param len Number of samples to transmit.
+ * \param disp_mask Mask to set default display params.
+ */
+ static sptr make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+
+ virtual std::vector<short> get() = 0;
+
+ virtual void set_length(int len) = 0;
+ virtual int length() const = 0;
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_S_H */
+
diff --git a/gr-blocks/include/gnuradio/blocks/interleaved_char_to_complex.h b/gr-blocks/include/gnuradio/blocks/interleaved_char_to_complex.h
new file mode 100644
index 0000000000..53a77e7cd0
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/interleaved_char_to_complex.h
@@ -0,0 +1,51 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_BLOCKS_INTERLEAVED_CHAR_TO_COMPLEX_H
+#define INCLUDED_BLOCKS_INTERLEAVED_CHAR_TO_COMPLEX_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_decimator.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief Convert stream of interleaved chars to a stream of complex
+ * \ingroup type_converters_blk
+ */
+ class BLOCKS_API interleaved_char_to_complex : virtual public sync_decimator
+ {
+ public:
+ // gr::blocks::interleaved_char_to_complex::sptr
+ typedef boost::shared_ptr<interleaved_char_to_complex> sptr;
+
+ /*!
+ * Build an interleaved char to complex block.
+ */
+ static sptr make(bool vector_input=false);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_BLOCKS_INTERLEAVED_CHAR_TO_COMPLEX_H */
diff --git a/gr-blocks/include/gnuradio/blocks/tag_debug.h b/gr-blocks/include/gnuradio/blocks/tag_debug.h
index 8368713175..ab222f02f1 100644
--- a/gr-blocks/include/gnuradio/blocks/tag_debug.h
+++ b/gr-blocks/include/gnuradio/blocks/tag_debug.h
@@ -72,6 +72,11 @@ namespace gr {
virtual std::vector<tag_t> current_tags() = 0;
/*!
+ * \brief Return the total number of tags in the tag queue.
+ */
+ virtual int num_tags() = 0;
+
+ /*!
* \brief Set the display of tags to stdout on/off.
*/
virtual void set_display(bool d) = 0;
diff --git a/gr-blocks/include/gnuradio/blocks/tags_strobe.h b/gr-blocks/include/gnuradio/blocks/tags_strobe.h
new file mode 100644
index 0000000000..3660ca4c1b
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/tags_strobe.h
@@ -0,0 +1,87 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_TAGS_STROBE_H
+#define INCLUDED_GR_TAGS_STROBE_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief Send tags at defined interval
+ * \ingroup debug_blk
+ *
+ * \details
+ * Sends a tag with key 'strobe' and a user-defined value (as a
+ * PMT) every \p nsamps number of samples. Useful for
+ * testing/debugging the tags system.
+ *
+ * Because tags are sent with a data stream, this is a source
+ * block that acts identical to a null_source block.
+ */
+ class BLOCKS_API tags_strobe : virtual public sync_block
+ {
+ public:
+ // gr::blocks::tags_strobe::sptr
+ typedef boost::shared_ptr<tags_strobe> sptr;
+
+ /*!
+ * Make a tags stobe block to send tags with value \p value
+ * every \p nsamps number of samples.
+ *
+ * \param sizeof_stream_item size of the stream items in bytes.
+ * \param value The value of the tags to send, as a PMT.
+ * \param nsamps the number of samples between each tag.
+ */
+ static sptr make(size_t sizeof_stream_item,
+ pmt::pmt_t value, uint64_t nsamps);
+
+ /*!
+ * Reset the value of the tags being sent.
+ * \param value The value of the tags to send as a PMT.
+ */
+ virtual void set_value(pmt::pmt_t value) = 0;
+
+ /*!
+ * Get the value of the tags being sent.
+ */
+ virtual pmt::pmt_t value() const = 0;
+
+ /*!
+ * Reset the sending interval.
+ * \param nsamps the number of samples between each tag
+ */
+ virtual void set_nsamps(uint64_t nsamps) = 0;
+
+ /*!
+ * Get the number of samples between the tag strobe.
+ */
+ virtual uint64_t nsamps() const = 0;
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_TAGS_STROBE_H */
diff --git a/gr-blocks/include/gnuradio/blocks/vco_c.h b/gr-blocks/include/gnuradio/blocks/vco_c.h
new file mode 100644
index 0000000000..ab9723af5b
--- /dev/null
+++ b/gr-blocks/include/gnuradio/blocks/vco_c.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_VCO_C_H
+#define INCLUDED_GR_VCO_C_H
+
+#include <gnuradio/blocks/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace blocks {
+
+ /*!
+ * \brief VCO - Voltage controlled oscillator
+ * \ingroup modulators_blk
+ * \ingroup waveform_generators_blk
+ *
+ * \details
+ * input: float stream of control voltages; output: complex oscillator output
+ */
+ class BLOCKS_API vco_c : virtual public sync_block
+ {
+ public:
+ // gr::blocks::vco_c::sptr
+ typedef boost::shared_ptr<vco_c> sptr;
+
+ /*!
+ * \brief VCO - Voltage controlled oscillator
+ *
+ * \param sampling_rate sampling rate (Hz)
+ * \param sensitivity units are radians/sec/volt
+ * \param amplitude output amplitude
+ */
+ static sptr make(double sampling_rate, double sensitivity, double amplitude);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_VCO_C_H */
diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt
index 529c6de054..1c7bd80ae0 100644
--- a/gr-blocks/lib/CMakeLists.txt
+++ b/gr-blocks/lib/CMakeLists.txt
@@ -186,6 +186,7 @@ list(APPEND gr_blocks_sources
interleave_impl.cc
interleaved_short_array_to_complex.cc
interleaved_short_to_complex_impl.cc
+ interleaved_char_to_complex_impl.cc
keep_m_in_n_impl.cc
keep_one_in_n_impl.cc
lfsr_32k_source_s_impl.cc
@@ -230,6 +231,7 @@ list(APPEND gr_blocks_sources
stretch_ff_impl.cc
tagged_file_sink_impl.cc
tagged_stream_to_pdu_impl.cc
+ tags_strobe_impl.cc
threshold_ff_impl.cc
throttle_impl.cc
transcendental_impl.cc
@@ -242,6 +244,7 @@ list(APPEND gr_blocks_sources
udp_source_impl.cc
unpack_k_bits_bb_impl.cc
vco_f_impl.cc
+ vco_c_impl.cc
vector_map_impl.cc
vector_to_stream_impl.cc
vector_to_streams_impl.cc
@@ -253,6 +256,10 @@ if(ENABLE_GR_CTRLPORT)
list(APPEND gr_blocks_sources
ctrlport_probe_c_impl.cc
ctrlport_probe2_c_impl.cc
+ ctrlport_probe2_f_impl.cc
+ ctrlport_probe2_s_impl.cc
+ ctrlport_probe2_i_impl.cc
+ ctrlport_probe2_b_impl.cc
)
endif(ENABLE_GR_CTRLPORT)
diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.cc b/gr-blocks/lib/ctrlport_probe2_b_impl.cc
new file mode 100644
index 0000000000..74c2980a7a
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_b_impl.cc
@@ -0,0 +1,162 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ctrlport_probe2_b_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+ namespace blocks {
+
+ ctrlport_probe2_b::sptr
+ ctrlport_probe2_b::make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask)
+ {
+ return gnuradio::get_initial_sptr
+ (new ctrlport_probe2_b_impl(id, desc, len, disp_mask));
+ }
+
+ ctrlport_probe2_b_impl::ctrlport_probe2_b_impl(const std::string &id,
+ const std::string &desc,
+ int len, unsigned int disp_mask)
+ : sync_block("probe2_b",
+ io_signature::make(1, 1, sizeof(char)),
+ io_signature::make(0, 0, 0)),
+ d_id(id), d_desc(desc), d_len(len), d_disp_mask(disp_mask)
+ {
+ set_length(len);
+ }
+
+ ctrlport_probe2_b_impl::~ctrlport_probe2_b_impl()
+ {
+ }
+
+ void
+ ctrlport_probe2_b_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ // make sure all inputs have noutput_items available
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = d_len;
+ }
+
+ // boost::shared_mutex mutex_buffer;
+ // mutable boost::mutex mutex_notify;
+ // boost::condition_variable condition_buffer_ready;
+ std::vector<signed char>
+ ctrlport_probe2_b_impl::get()
+ {
+ mutex_buffer.lock();
+ d_buffer.clear();
+ mutex_buffer.unlock();
+
+ // wait for condition
+ boost::mutex::scoped_lock lock(mutex_notify);
+ condition_buffer_ready.wait(lock);
+
+ mutex_buffer.lock();
+ std::vector<signed char> buf_copy = d_buffer;
+ assert(buf_copy.size() == d_len);
+ mutex_buffer.unlock();
+
+ return buf_copy;
+ }
+
+ void
+ ctrlport_probe2_b_impl::set_length(int len)
+ {
+ if(len > 8191) {
+ std::cerr << "probe2_b: length " << len
+ << " exceeds maximum buffer size of 8191" << std::endl;
+ len = 8191;
+ }
+
+ d_len = len;
+ d_buffer.reserve(d_len);
+ }
+
+ int
+ ctrlport_probe2_b_impl::length() const
+ {
+ return (int)d_len;
+ }
+
+ int
+ ctrlport_probe2_b_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const char *in = (const char*)input_items[0];
+
+ // copy samples to get buffer if we need samples
+ mutex_buffer.lock();
+ if(d_buffer.size() < d_len) {
+ // copy smaller of remaining buffer space and num inputs to work()
+ int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+
+ // TODO: convert this to a copy operator for speed...
+ for(int i = 0; i < num_copy; i++) {
+ d_buffer.push_back(in[i]);
+ }
+
+ // notify the waiting get() if we fill up the buffer
+ if(d_buffer.size() == d_len) {
+ condition_buffer_ready.notify_one();
+ }
+ }
+ mutex_buffer.unlock();
+
+ return noutput_items;
+ }
+
+ void
+ ctrlport_probe2_b_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ int len = static_cast<int>(d_len);
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_b, std::vector<signed char> >(
+ alias(), d_id.c_str(), &ctrlport_probe2_b::get,
+ pmt::mp(-128), pmt::mp(127), pmt::mp(0),
+ "volts", d_desc.c_str(), RPC_PRIVLVL_MIN,
+ d_disp_mask)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_b, int>(
+ alias(), "length", &ctrlport_probe2_b::length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "get vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_set<ctrlport_probe2_b, int>(
+ alias(), "length", &ctrlport_probe2_b::set_length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "set vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.h b/gr-blocks/lib/ctrlport_probe2_b_impl.h
new file mode 100644
index 0000000000..155dd4c23c
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_b_impl.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_B_IMPL_H
+#define INCLUDED_CTRLPORT_PROBE2_B_IMPL_H
+
+#include <gnuradio/blocks/ctrlport_probe2_b.h>
+#include <gnuradio/rpcregisterhelpers.h>
+#include <boost/thread/shared_mutex.hpp>
+
+namespace gr {
+ namespace blocks {
+
+ class ctrlport_probe2_b_impl : public ctrlport_probe2_b
+ {
+ private:
+ std::string d_id;
+ std::string d_desc;
+ size_t d_len;
+ unsigned int d_disp_mask;
+ boost::shared_mutex mutex_buffer;
+ mutable boost::mutex mutex_notify;
+ boost::condition_variable condition_buffer_ready;
+
+ std::vector<signed char> d_buffer;
+
+ public:
+ ctrlport_probe2_b_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+ ~ctrlport_probe2_b_impl();
+
+ void setup_rpc();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ std::vector<signed char> get();
+
+ void set_length(int len);
+ int length() const;
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_C_IMPL_H */
+
diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.cc b/gr-blocks/lib/ctrlport_probe2_c_impl.cc
index bc6febdb2d..3e324b0d00 100644
--- a/gr-blocks/lib/ctrlport_probe2_c_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_c_impl.cc
@@ -32,18 +32,20 @@ namespace gr {
ctrlport_probe2_c::sptr
ctrlport_probe2_c::make(const std::string &id,
- const std::string &desc, int len)
+ const std::string &desc,
+ int len, unsigned int disp_mask)
{
return gnuradio::get_initial_sptr
- (new ctrlport_probe2_c_impl(id, desc, len));
+ (new ctrlport_probe2_c_impl(id, desc, len, disp_mask));
}
ctrlport_probe2_c_impl::ctrlport_probe2_c_impl(const std::string &id,
- const std::string &desc, int len)
+ const std::string &desc,
+ int len, unsigned int disp_mask)
: sync_block("probe2_c",
io_signature::make(1, 1, sizeof(gr_complex)),
io_signature::make(0, 0, 0)),
- d_id(id), d_desc(desc), d_len(len)
+ d_id(id), d_desc(desc), d_len(len), d_disp_mask(disp_mask)
{
set_length(len);
}
@@ -139,11 +141,9 @@ namespace gr {
d_rpc_vars.push_back(
rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_c, std::vector<std::complex<float> > >(
alias(), d_id.c_str(), &ctrlport_probe2_c::get,
- pmt::make_c32vector(0,-2),
- pmt::make_c32vector(0,2),
- pmt::make_c32vector(0,0),
+ pmt::mp(-2), pmt::mp(2), pmt::mp(0),
"volts", d_desc.c_str(), RPC_PRIVLVL_MIN,
- DISPXY | DISPOPTSCATTER)));
+ d_disp_mask | DISPOPTCPLX)));
d_rpc_vars.push_back(
rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_c, int>(
diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.h b/gr-blocks/lib/ctrlport_probe2_c_impl.h
index c58d97f078..15ff0f4ea2 100644
--- a/gr-blocks/lib/ctrlport_probe2_c_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_c_impl.h
@@ -36,6 +36,7 @@ namespace gr {
std::string d_id;
std::string d_desc;
size_t d_len;
+ unsigned int d_disp_mask;
boost::shared_mutex mutex_buffer;
mutable boost::mutex mutex_notify;
boost::condition_variable condition_buffer_ready;
@@ -43,7 +44,8 @@ namespace gr {
std::vector<gr_complex> d_buffer;
public:
- ctrlport_probe2_c_impl(const std::string &id, const std::string &desc, int len);
+ ctrlport_probe2_c_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
~ctrlport_probe2_c_impl();
void setup_rpc();
diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.cc b/gr-blocks/lib/ctrlport_probe2_f_impl.cc
new file mode 100644
index 0000000000..3c723f8834
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_f_impl.cc
@@ -0,0 +1,164 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ctrlport_probe2_f_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+ namespace blocks {
+
+ ctrlport_probe2_f::sptr
+ ctrlport_probe2_f::make(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask)
+ {
+ return gnuradio::get_initial_sptr
+ (new ctrlport_probe2_f_impl(id, desc, len, disp_mask));
+ }
+
+ ctrlport_probe2_f_impl::ctrlport_probe2_f_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask)
+ : sync_block("probe2_f",
+ io_signature::make(1, 1, sizeof(float)),
+ io_signature::make(0, 0, 0)),
+ d_id(id), d_desc(desc), d_len(len), d_disp_mask(disp_mask)
+ {
+ set_length(len);
+ }
+
+ ctrlport_probe2_f_impl::~ctrlport_probe2_f_impl()
+ {
+ }
+
+ void
+ ctrlport_probe2_f_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ // make sure all inputs have noutput_items available
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = d_len;
+ }
+
+ // boost::shared_mutex mutex_buffer;
+ // mutable boost::mutex mutex_notify;
+ // boost::condition_variable condition_buffer_ready;
+ std::vector<float>
+ ctrlport_probe2_f_impl::get()
+ {
+ mutex_buffer.lock();
+ d_buffer.clear();
+ mutex_buffer.unlock();
+
+ // wait for condition
+ boost::mutex::scoped_lock lock(mutex_notify);
+ condition_buffer_ready.wait(lock);
+
+ mutex_buffer.lock();
+ std::vector<float> buf_copy = d_buffer;
+ assert(buf_copy.size() == d_len);
+ mutex_buffer.unlock();
+
+ return buf_copy;
+ }
+
+ void
+ ctrlport_probe2_f_impl::set_length(int len)
+ {
+ if(len > 8191) {
+ std::cerr << "probe2_f: length " << len
+ << " exceeds maximum buffer size of 8191" << std::endl;
+ len = 8191;
+ }
+
+ d_len = len;
+ d_buffer.reserve(d_len);
+ }
+
+ int
+ ctrlport_probe2_f_impl::length() const
+ {
+ return (int)d_len;
+ }
+
+ int
+ ctrlport_probe2_f_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const float *in = (const float*)input_items[0];
+
+ // copy samples to get buffer if we need samples
+ mutex_buffer.lock();
+ if(d_buffer.size() < d_len) {
+ // copy smaller of remaining buffer space and num inputs to work()
+ int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+
+ // TODO: convert this to a copy operator for speed...
+ for(int i = 0; i < num_copy; i++) {
+ d_buffer.push_back(in[i]);
+ }
+
+ // notify the waiting get() if we fill up the buffer
+ if(d_buffer.size() == d_len) {
+ condition_buffer_ready.notify_one();
+ }
+ }
+ mutex_buffer.unlock();
+
+ return noutput_items;
+ }
+
+ void
+ ctrlport_probe2_f_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ int len = static_cast<int>(d_len);
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_f, std::vector<float> >(
+ alias(), d_id.c_str(), &ctrlport_probe2_f::get,
+ pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f),
+// pmt::make_f32vector(1,-2),
+// pmt::make_f32vector(1,2),
+// pmt::make_f32vector(1,0),
+ "volts", d_desc.c_str(), RPC_PRIVLVL_MIN,
+ d_disp_mask)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_f, int>(
+ alias(), "length", &ctrlport_probe2_f::length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "get vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_set<ctrlport_probe2_f, int>(
+ alias(), "length", &ctrlport_probe2_f::set_length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "set vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.h b/gr-blocks/lib/ctrlport_probe2_f_impl.h
new file mode 100644
index 0000000000..a4aa099237
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_f_impl.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_F_IMPL_H
+#define INCLUDED_CTRLPORT_PROBE2_F_IMPL_H
+
+#include <gnuradio/blocks/ctrlport_probe2_f.h>
+#include <gnuradio/rpcregisterhelpers.h>
+#include <boost/thread/shared_mutex.hpp>
+
+namespace gr {
+ namespace blocks {
+
+ class ctrlport_probe2_f_impl : public ctrlport_probe2_f
+ {
+ private:
+ std::string d_id;
+ std::string d_desc;
+ size_t d_len;
+ unsigned int d_disp_mask;
+ boost::shared_mutex mutex_buffer;
+ mutable boost::mutex mutex_notify;
+ boost::condition_variable condition_buffer_ready;
+
+ std::vector<float> d_buffer;
+
+ public:
+ ctrlport_probe2_f_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+ ~ctrlport_probe2_f_impl();
+
+ void setup_rpc();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ std::vector<float> get();
+
+ void set_length(int len);
+ int length() const;
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_F_IMPL_H */
+
diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.cc b/gr-blocks/lib/ctrlport_probe2_i_impl.cc
new file mode 100644
index 0000000000..be7ae4d9d3
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_i_impl.cc
@@ -0,0 +1,163 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ctrlport_probe2_i_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+ namespace blocks {
+
+ ctrlport_probe2_i::sptr
+ ctrlport_probe2_i::make(const std::string &id,
+ const std::string &desc,
+ int len, unsigned int disp_mask)
+ {
+ return gnuradio::get_initial_sptr
+ (new ctrlport_probe2_i_impl(id, desc, len, disp_mask));
+ }
+
+ ctrlport_probe2_i_impl::ctrlport_probe2_i_impl(const std::string &id,
+ const std::string &desc,
+ int len, unsigned int disp_mask)
+ : sync_block("probe2_i",
+ io_signature::make(1, 1, sizeof(int)),
+ io_signature::make(0, 0, 0)),
+ d_id(id), d_desc(desc), d_len(len), d_disp_mask(disp_mask)
+ {
+ set_length(len);
+ }
+
+ ctrlport_probe2_i_impl::~ctrlport_probe2_i_impl()
+ {
+ }
+
+ void
+ ctrlport_probe2_i_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ // make sure all inputs have noutput_items available
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = d_len;
+ }
+
+ // boost::shared_mutex mutex_buffer;
+ // mutable boost::mutex mutex_notify;
+ // boost::condition_variable condition_buffer_ready;
+ std::vector<int>
+ ctrlport_probe2_i_impl::get()
+ {
+ mutex_buffer.lock();
+ d_buffer.clear();
+ mutex_buffer.unlock();
+
+ // wait for condition
+ boost::mutex::scoped_lock lock(mutex_notify);
+ condition_buffer_ready.wait(lock);
+
+ mutex_buffer.lock();
+ std::vector<int> buf_copy = d_buffer;
+ assert(buf_copy.size() == d_len);
+ mutex_buffer.unlock();
+
+ return buf_copy;
+ }
+
+ void
+ ctrlport_probe2_i_impl::set_length(int len)
+ {
+ if(len > 8191) {
+ std::cerr << "probe2_i: length " << len
+ << " exceeds maximum buffer size of 8191" << std::endl;
+ len = 8191;
+ }
+
+ d_len = len;
+ d_buffer.reserve(d_len);
+ }
+
+ int
+ ctrlport_probe2_i_impl::length() const
+ {
+ return (int)d_len;
+ }
+
+ int
+ ctrlport_probe2_i_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const int *in = (const int*)input_items[0];
+
+ // copy samples to get buffer if we need samples
+ mutex_buffer.lock();
+ if(d_buffer.size() < d_len) {
+ // copy smaller of remaining buffer space and num inputs to work()
+ int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+
+ // TODO: convert this to a copy operator for speed...
+ for(int i = 0; i < num_copy; i++) {
+ d_buffer.push_back(in[i]);
+ }
+
+ // notify the waiting get() if we fill up the buffer
+ if(d_buffer.size() == d_len) {
+ condition_buffer_ready.notify_one();
+ }
+ }
+ mutex_buffer.unlock();
+
+ return noutput_items;
+ }
+
+ void
+ ctrlport_probe2_i_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ int len = static_cast<int>(d_len);
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_i, std::vector<int> >(
+ alias(), d_id.c_str(), &ctrlport_probe2_i::get,
+ pmt::mp(-32768), pmt::mp(32767), pmt::mp(0),
+ "volts", d_desc.c_str(), RPC_PRIVLVL_MIN,
+ d_disp_mask)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_i, int>(
+ alias(), "length", &ctrlport_probe2_i::length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "get vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_set<ctrlport_probe2_i, int>(
+ alias(), "length", &ctrlport_probe2_i::set_length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "set vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.h b/gr-blocks/lib/ctrlport_probe2_i_impl.h
new file mode 100644
index 0000000000..06493ac23a
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_i_impl.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_I_IMPL_H
+#define INCLUDED_CTRLPORT_PROBE2_I_IMPL_H
+
+#include <gnuradio/blocks/ctrlport_probe2_i.h>
+#include <gnuradio/rpcregisterhelpers.h>
+#include <boost/thread/shared_mutex.hpp>
+
+namespace gr {
+ namespace blocks {
+
+ class ctrlport_probe2_i_impl : public ctrlport_probe2_i
+ {
+ private:
+ std::string d_id;
+ std::string d_desc;
+ size_t d_len;
+ unsigned int d_disp_mask;
+ boost::shared_mutex mutex_buffer;
+ mutable boost::mutex mutex_notify;
+ boost::condition_variable condition_buffer_ready;
+
+ std::vector<int> d_buffer;
+
+ public:
+ ctrlport_probe2_i_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+ ~ctrlport_probe2_i_impl();
+
+ void setup_rpc();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ std::vector<int> get();
+
+ void set_length(int len);
+ int length() const;
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_I_IMPL_H */
+
diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.cc b/gr-blocks/lib/ctrlport_probe2_s_impl.cc
new file mode 100644
index 0000000000..b10c419eb5
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_s_impl.cc
@@ -0,0 +1,163 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ctrlport_probe2_s_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+ namespace blocks {
+
+ ctrlport_probe2_s::sptr
+ ctrlport_probe2_s::make(const std::string &id,
+ const std::string &desc,
+ int len, unsigned disp_mask)
+ {
+ return gnuradio::get_initial_sptr
+ (new ctrlport_probe2_s_impl(id, desc, len, disp_mask));
+ }
+
+ ctrlport_probe2_s_impl::ctrlport_probe2_s_impl(const std::string &id,
+ const std::string &desc,
+ int len, unsigned disp_mask)
+ : sync_block("probe2_s",
+ io_signature::make(1, 1, sizeof(short)),
+ io_signature::make(0, 0, 0)),
+ d_id(id), d_desc(desc), d_len(len), d_disp_mask(disp_mask)
+ {
+ set_length(len);
+ }
+
+ ctrlport_probe2_s_impl::~ctrlport_probe2_s_impl()
+ {
+ }
+
+ void
+ ctrlport_probe2_s_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ // make sure all inputs have noutput_items available
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = d_len;
+ }
+
+ // boost::shared_mutex mutex_buffer;
+ // mutable boost::mutex mutex_notify;
+ // boost::condition_variable condition_buffer_ready;
+ std::vector<short>
+ ctrlport_probe2_s_impl::get()
+ {
+ mutex_buffer.lock();
+ d_buffer.clear();
+ mutex_buffer.unlock();
+
+ // wait for condition
+ boost::mutex::scoped_lock lock(mutex_notify);
+ condition_buffer_ready.wait(lock);
+
+ mutex_buffer.lock();
+ std::vector<short> buf_copy = d_buffer;
+ assert(buf_copy.size() == d_len);
+ mutex_buffer.unlock();
+
+ return buf_copy;
+ }
+
+ void
+ ctrlport_probe2_s_impl::set_length(int len)
+ {
+ if(len > 8191) {
+ std::cerr << "probe2_s: length " << len
+ << " exceeds maximum buffer size of 8191" << std::endl;
+ len = 8191;
+ }
+
+ d_len = len;
+ d_buffer.reserve(d_len);
+ }
+
+ int
+ ctrlport_probe2_s_impl::length() const
+ {
+ return (int)d_len;
+ }
+
+ int
+ ctrlport_probe2_s_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const short *in = (const short*)input_items[0];
+
+ // copy samples to get buffer if we need samples
+ mutex_buffer.lock();
+ if(d_buffer.size() < d_len) {
+ // copy smaller of remaining buffer space and num inputs to work()
+ int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+
+ // TODO: convert this to a copy operator for speed...
+ for(int i = 0; i < num_copy; i++) {
+ d_buffer.push_back(in[i]);
+ }
+
+ // notify the waiting get() if we fill up the buffer
+ if(d_buffer.size() == d_len) {
+ condition_buffer_ready.notify_one();
+ }
+ }
+ mutex_buffer.unlock();
+
+ return noutput_items;
+ }
+
+ void
+ ctrlport_probe2_s_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ int len = static_cast<int>(d_len);
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_s, std::vector<short> >(
+ alias(), d_id.c_str(), &ctrlport_probe2_s::get,
+ pmt::mp(-32768), pmt::mp(32767), pmt::mp(0),
+ "volts", d_desc.c_str(), RPC_PRIVLVL_MIN,
+ d_disp_mask)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe2_s, int>(
+ alias(), "length", &ctrlport_probe2_s::length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "get vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+
+ d_rpc_vars.push_back(
+ rpcbasic_sptr(new rpcbasic_register_set<ctrlport_probe2_s, int>(
+ alias(), "length", &ctrlport_probe2_s::set_length,
+ pmt::mp(1), pmt::mp(10*len), pmt::mp(len),
+ "samples", "set vector length", RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.h b/gr-blocks/lib/ctrlport_probe2_s_impl.h
new file mode 100644
index 0000000000..078dd56b73
--- /dev/null
+++ b/gr-blocks/lib/ctrlport_probe2_s_impl.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CTRLPORT_PROBE2_S_IMPL_H
+#define INCLUDED_CTRLPORT_PROBE2_S_IMPL_H
+
+#include <gnuradio/blocks/ctrlport_probe2_s.h>
+#include <gnuradio/rpcregisterhelpers.h>
+#include <boost/thread/shared_mutex.hpp>
+
+namespace gr {
+ namespace blocks {
+
+ class ctrlport_probe2_s_impl : public ctrlport_probe2_s
+ {
+ private:
+ std::string d_id;
+ std::string d_desc;
+ size_t d_len;
+ unsigned int d_disp_mask;
+ boost::shared_mutex mutex_buffer;
+ mutable boost::mutex mutex_notify;
+ boost::condition_variable condition_buffer_ready;
+
+ std::vector<short> d_buffer;
+
+ public:
+ ctrlport_probe2_s_impl(const std::string &id, const std::string &desc,
+ int len, unsigned int disp_mask);
+ ~ctrlport_probe2_s_impl();
+
+ void setup_rpc();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ std::vector<short> get();
+
+ void set_length(int len);
+ int length() const;
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_CTRLPORT_PROBE2_S_IMPL_H */
+
diff --git a/gr-blocks/lib/interleaved_char_to_complex_impl.cc b/gr-blocks/lib/interleaved_char_to_complex_impl.cc
new file mode 100644
index 0000000000..34114e3651
--- /dev/null
+++ b/gr-blocks/lib/interleaved_char_to_complex_impl.cc
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "interleaved_char_to_complex_impl.h"
+#include <gnuradio/io_signature.h>
+#include <volk/volk.h>
+
+namespace gr {
+ namespace blocks {
+
+ interleaved_char_to_complex::sptr interleaved_char_to_complex::make(bool vector_input)
+ {
+ return gnuradio::get_initial_sptr(new interleaved_char_to_complex_impl(vector_input));
+ }
+
+ interleaved_char_to_complex_impl::interleaved_char_to_complex_impl(bool vector_input)
+ : sync_decimator("interleaved_char_to_complex",
+ gr::io_signature::make (1, 1, (vector_input?2:1)*sizeof(char)),
+ gr::io_signature::make (1, 1, sizeof(gr_complex)),
+ vector_input?1:2),
+ d_vector_input(vector_input)
+ {
+ const int alignment_multiple =
+ volk_get_alignment() / sizeof(gr_complex);
+ set_alignment(std::max(1, alignment_multiple));
+ }
+
+ int
+ interleaved_char_to_complex_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const int8_t *in = (const int8_t *) input_items[0];
+ float *out = (float *) output_items[0];
+
+ volk_8i_s32f_convert_32f_u(out, in, 1.0, 2*noutput_items);
+
+ return noutput_items;
+ }
+
+ } /* namespace blocks */
+}/* namespace gr */
diff --git a/gr-blocks/lib/interleaved_char_to_complex_impl.h b/gr-blocks/lib/interleaved_char_to_complex_impl.h
new file mode 100644
index 0000000000..e815f08a1e
--- /dev/null
+++ b/gr-blocks/lib/interleaved_char_to_complex_impl.h
@@ -0,0 +1,47 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_INTERLEAVED_CHAR_TO_COMPLEX_IMPL_H
+#define INCLUDED_INTERLEAVED_CHAR_TO_COMPLEX_IMPL_H
+
+#include <gnuradio/blocks/interleaved_char_to_complex.h>
+
+namespace gr {
+ namespace blocks {
+
+ class BLOCKS_API interleaved_char_to_complex_impl : public interleaved_char_to_complex
+ {
+ private:
+ bool d_vector_input;
+ public:
+ interleaved_char_to_complex_impl(bool vector_input=false);
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+
+#endif /* INCLUDED_INTERLEAVED_CHAR_TO_COMPLEX_IMPL_H */
diff --git a/gr-blocks/lib/tag_debug_impl.cc b/gr-blocks/lib/tag_debug_impl.cc
index 56f701b9d7..567f83dcb6 100644
--- a/gr-blocks/lib/tag_debug_impl.cc
+++ b/gr-blocks/lib/tag_debug_impl.cc
@@ -60,10 +60,17 @@ namespace gr {
return d_tags;
}
+ int
+ tag_debug_impl::num_tags()
+ {
+ std::vector<tag_t> t;
+ get_tags_in_range(t, 0, 0, nitems_read(0));
+ return static_cast<int>(t.size());
+ }
+
void
tag_debug_impl::set_display(bool d)
{
- gr::thread::scoped_lock l(d_mutex);
d_display = d;
}
@@ -114,5 +121,19 @@ namespace gr {
return noutput_items;
}
+ void
+ tag_debug_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<tag_debug, int>(
+ alias(), "num. tags",
+ &tag_debug::num_tags,
+ pmt::from_long(0), pmt::from_long(10000), pmt::from_long(0),
+ "", "Number of Tags", RPC_PRIVLVL_MIN,
+ DISPTIME | DISPOPTSTRIP)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace blocks */
} /* namespace gr */
diff --git a/gr-blocks/lib/tag_debug_impl.h b/gr-blocks/lib/tag_debug_impl.h
index 80d714edc2..03b1846139 100644
--- a/gr-blocks/lib/tag_debug_impl.h
+++ b/gr-blocks/lib/tag_debug_impl.h
@@ -43,7 +43,10 @@ namespace gr {
tag_debug_impl(size_t sizeof_stream_item, const std::string &name);
~tag_debug_impl();
+ void setup_rpc();
+
std::vector<tag_t> current_tags();
+ int num_tags();
void set_display(bool d);
diff --git a/gr-blocks/lib/tags_strobe_impl.cc b/gr-blocks/lib/tags_strobe_impl.cc
new file mode 100644
index 0000000000..41329d88a3
--- /dev/null
+++ b/gr-blocks/lib/tags_strobe_impl.cc
@@ -0,0 +1,99 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tags_strobe_impl.h"
+#include <gnuradio/io_signature.h>
+#include <cstdio>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdexcept>
+#include <string.h>
+#include <iostream>
+
+namespace gr {
+ namespace blocks {
+
+ tags_strobe::sptr
+ tags_strobe::make(size_t sizeof_stream_item,
+ pmt::pmt_t value, uint64_t nsamps)
+ {
+ return gnuradio::get_initial_sptr
+ (new tags_strobe_impl(sizeof_stream_item, value, nsamps));
+ }
+
+ tags_strobe_impl::tags_strobe_impl(size_t sizeof_stream_item,
+ pmt::pmt_t value, uint64_t nsamps)
+ : sync_block("tags_strobe",
+ io_signature::make(0, 0, 0),
+ io_signature::make(1, 1, sizeof_stream_item)),
+ d_itemsize(sizeof_stream_item)
+ {
+ set_value(value);
+ set_nsamps(nsamps);
+ }
+
+ tags_strobe_impl::~tags_strobe_impl()
+ {
+ }
+
+ void
+ tags_strobe_impl::set_value(pmt::pmt_t value)
+ {
+ d_tag.offset = 0;
+ d_tag.key = pmt::intern("strobe");
+ d_tag.value = value;
+ d_tag.srcid = alias_pmt();
+ }
+
+ void
+ tags_strobe_impl::set_nsamps(uint64_t nsamps)
+ {
+ d_nsamps = nsamps;
+ d_offset = 0;
+ }
+
+ int
+ tags_strobe_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ void *optr = (void*)output_items[0];
+ memset(optr, 0, noutput_items * d_itemsize);
+
+ uint64_t nitems = static_cast<uint64_t>(noutput_items) + nitems_written(0);
+ while((nitems - d_offset) > d_nsamps) {
+ d_offset += d_nsamps;
+ d_tag.offset = d_offset;
+ add_item_tag(0, d_tag);
+ }
+
+ return noutput_items;
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/tags_strobe_impl.h b/gr-blocks/lib/tags_strobe_impl.h
new file mode 100644
index 0000000000..a6d73cfead
--- /dev/null
+++ b/gr-blocks/lib/tags_strobe_impl.h
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_TAGS_STROBE_IMPL_H
+#define INCLUDED_GR_TAGS_STROBE_IMPL_H
+
+#include <gnuradio/blocks/tags_strobe.h>
+
+namespace gr {
+ namespace blocks {
+
+ class BLOCKS_API tags_strobe_impl : public tags_strobe
+ {
+ private:
+ size_t d_itemsize;
+ uint64_t d_nsamps;
+ tag_t d_tag;
+ uint64_t d_offset;
+
+ void run();
+
+ public:
+ tags_strobe_impl(size_t sizeof_stream_item,
+ pmt::pmt_t value, uint64_t nsamps);
+ ~tags_strobe_impl();
+
+ void set_value(pmt::pmt_t value);
+ pmt::pmt_t value() const { return d_tag.value; }
+ void set_nsamps(uint64_t nsamps);
+ uint64_t nsamps() const { return d_nsamps; }
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_TAGS_STROBE_IMPL_H */
diff --git a/gr-blocks/lib/vco_c_impl.cc b/gr-blocks/lib/vco_c_impl.cc
new file mode 100644
index 0000000000..5103ce1851
--- /dev/null
+++ b/gr-blocks/lib/vco_c_impl.cc
@@ -0,0 +1,68 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vco_c_impl.h"
+#include <gnuradio/io_signature.h>
+#include <math.h>
+
+namespace gr {
+ namespace blocks {
+
+ vco_c::sptr
+ vco_c::make(double sampling_rate, double sensitivity, double amplitude)
+ {
+ return gnuradio::get_initial_sptr
+ (new vco_c_impl(sampling_rate, sensitivity, amplitude));
+ }
+
+ vco_c_impl::vco_c_impl(double sampling_rate, double sensitivity, double amplitude)
+ : sync_block("vco_c",
+ io_signature::make(1, 1, sizeof(float)),
+ io_signature::make(1, 1, sizeof(gr_complex))),
+ d_sampling_rate(sampling_rate), d_sensitivity(sensitivity),
+ d_amplitude(amplitude), d_k(d_sensitivity/d_sampling_rate)
+ {
+ }
+
+ vco_c_impl::~vco_c_impl()
+ {
+ }
+
+ int
+ vco_c_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const float *input = (const float*)input_items[0];
+ gr_complex *output = (gr_complex*)output_items[0];
+
+ d_vco.sincos(output, input, noutput_items, d_k, d_amplitude);
+
+ return noutput_items;
+ }
+
+ } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/vco_c_impl.h b/gr-blocks/lib/vco_c_impl.h
new file mode 100644
index 0000000000..53def4f1da
--- /dev/null
+++ b/gr-blocks/lib/vco_c_impl.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_VCO_F_IMPL_H
+#define INCLUDED_GR_VCO_F_IMPL_H
+
+#include <gnuradio/blocks/vco_c.h>
+#include <gnuradio/fxpt_vco.h>
+
+namespace gr {
+ namespace blocks {
+
+ class vco_c_impl : public vco_c
+ {
+ private:
+ double d_sampling_rate;
+ double d_sensitivity;
+ double d_amplitude;
+ double d_k;
+ gr::fxpt_vco d_vco;
+
+ public:
+ vco_c_impl(double sampling_rate, double sensitivity, double amplitude);
+ ~vco_c_impl();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_VCO_C_H */
diff --git a/gr-blocks/python/blocks/CMakeLists.txt b/gr-blocks/python/blocks/CMakeLists.txt
index 01e8d16587..9050eff6c2 100644
--- a/gr-blocks/python/blocks/CMakeLists.txt
+++ b/gr-blocks/python/blocks/CMakeLists.txt
@@ -48,6 +48,7 @@ if(ENABLE_TESTING)
list(REMOVE_ITEM py_qa_test_files
${CMAKE_CURRENT_SOURCE_DIR}/qa_cpp_py_binding.py
${CMAKE_CURRENT_SOURCE_DIR}/qa_cpp_py_binding_set.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/qa_ctrlport_probes.py
)
endif(NOT ENABLE_GR_CTRLPORT)
diff --git a/gr-blocks/python/blocks/qa_ctrlport_probes.py b/gr-blocks/python/blocks/qa_ctrlport_probes.py
new file mode 100644
index 0000000000..b31934f705
--- /dev/null
+++ b/gr-blocks/python/blocks/qa_ctrlport_probes.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import Ice
+import sys, time, random, numpy
+from gnuradio import gr, gr_unittest, blocks
+
+from gnuradio.ctrlport import GNURadio
+from gnuradio import ctrlport
+import os, struct
+
+class test_ctrlport_probes(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+ os.environ['GR_CONF_CONTROLPORT_ON'] = 'True'
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_001(self):
+ data = range(1,9)
+
+ self.src = blocks.vector_source_c(data, True)
+ self.probe = blocks.ctrlport_probe2_c("samples","Complex",
+ len(data), gr.DISPNULL)
+ probe_name = self.probe.alias()
+
+ self.tb.connect(self.src, self.probe)
+ self.tb.start()
+
+ # Probes return complex values as list of floats with re, im
+ # Imaginary parts of this data set are 0.
+ expected_result = [1, 0, 2, 0, 3, 0, 4, 0,
+ 5, 0, 6, 0, 7, 0, 8, 0]
+
+ # Make sure we have time for flowgraph to run
+ time.sleep(0.1)
+
+ # Get available endpoint
+ ep = gr.rpcmanager_get().endpoints()[0]
+
+ # Initialize a simple Ice client from endpoint
+ ic = Ice.initialize(sys.argv)
+ base = ic.stringToProxy(ep)
+ radio = GNURadio.ControlPortPrx.checkedCast(base)
+
+ # Get all exported knobs
+ ret = radio.get([probe_name + "::samples"])
+ for name in ret.keys():
+ # Get data in probe, which might be offset; find the
+ # beginning and unwrap.
+ result = ret[name].value
+ i = result.index(1.0)
+ result = result[i:] + result[0:i]
+ self.assertEqual(expected_result, result)
+
+ self.tb.stop()
+
+
+ def test_002(self):
+ data = range(1,9)
+
+ self.src = blocks.vector_source_f(data, True)
+ self.probe = blocks.ctrlport_probe2_f("samples","Floats",
+ len(data), gr.DISPNULL)
+ probe_name = self.probe.alias()
+
+ self.tb.connect(self.src, self.probe)
+ self.tb.start()
+
+ expected_result = [1, 2, 3, 4, 5, 6, 7, 8,]
+
+ # Make sure we have time for flowgraph to run
+ time.sleep(0.1)
+
+ # Get available endpoint
+ ep = gr.rpcmanager_get().endpoints()[0]
+
+ # Initialize a simple Ice client from endpoint
+ ic = Ice.initialize(sys.argv)
+ base = ic.stringToProxy(ep)
+ radio = GNURadio.ControlPortPrx.checkedCast(base)
+
+ # Get all exported knobs
+ ret = radio.get([probe_name + "::samples"])
+ for name in ret.keys():
+ # Get data in probe, which might be offset; find the
+ # beginning and unwrap.
+ result = ret[name].value
+ i = result.index(1.0)
+ result = result[i:] + result[0:i]
+ self.assertEqual(expected_result, result)
+
+ self.tb.stop()
+
+
+ def test_003(self):
+ data = range(1,9)
+
+ self.src = blocks.vector_source_i(data, True)
+ self.probe = blocks.ctrlport_probe2_i("samples","Integers",
+ len(data), gr.DISPNULL)
+ probe_name = self.probe.alias()
+
+ self.tb.connect(self.src, self.probe)
+ self.tb.start()
+
+ expected_result = [1, 2, 3, 4, 5, 6, 7, 8,]
+
+ # Make sure we have time for flowgraph to run
+ time.sleep(0.1)
+
+ # Get available endpoint
+ ep = gr.rpcmanager_get().endpoints()[0]
+
+ # Initialize a simple Ice client from endpoint
+ ic = Ice.initialize(sys.argv)
+ base = ic.stringToProxy(ep)
+ radio = GNURadio.ControlPortPrx.checkedCast(base)
+
+ # Get all exported knobs
+ ret = radio.get([probe_name + "::samples"])
+ for name in ret.keys():
+ # Get data in probe, which might be offset; find the
+ # beginning and unwrap.
+ result = ret[name].value
+ i = result.index(1.0)
+ result = result[i:] + result[0:i]
+ self.assertEqual(expected_result, result)
+
+ self.tb.stop()
+
+
+ def test_004(self):
+ data = range(1,9)
+
+ self.src = blocks.vector_source_s(data, True)
+ self.probe = blocks.ctrlport_probe2_s("samples","Shorts",
+ len(data), gr.DISPNULL)
+ probe_name = self.probe.alias()
+
+ self.tb.connect(self.src, self.probe)
+ self.tb.start()
+
+ expected_result = [1, 2, 3, 4, 5, 6, 7, 8,]
+
+ # Make sure we have time for flowgraph to run
+ time.sleep(0.1)
+
+ # Get available endpoint
+ ep = gr.rpcmanager_get().endpoints()[0]
+
+ # Initialize a simple Ice client from endpoint
+ ic = Ice.initialize(sys.argv)
+ base = ic.stringToProxy(ep)
+ radio = GNURadio.ControlPortPrx.checkedCast(base)
+
+ # Get all exported knobs
+ ret = radio.get([probe_name + "::samples"])
+ for name in ret.keys():
+ # Get data in probe, which might be offset; find the
+ # beginning and unwrap.
+ result = ret[name].value
+ i = result.index(1.0)
+ result = result[i:] + result[0:i]
+ self.assertEqual(expected_result, result)
+
+ self.tb.stop()
+
+ def test_005(self):
+ data = range(1,9)
+
+ self.src = blocks.vector_source_b(data, True)
+ self.probe = blocks.ctrlport_probe2_b("samples","Bytes",
+ len(data), gr.DISPNULL)
+ probe_name = self.probe.alias()
+
+ self.tb.connect(self.src, self.probe)
+ self.tb.start()
+
+ expected_result = [1, 2, 3, 4, 5, 6, 7, 8,]
+
+ # Make sure we have time for flowgraph to run
+ time.sleep(0.1)
+
+ # Get available endpoint
+ ep = gr.rpcmanager_get().endpoints()[0]
+
+ # Initialize a simple Ice client from endpoint
+ ic = Ice.initialize(sys.argv)
+ base = ic.stringToProxy(ep)
+ radio = GNURadio.ControlPortPrx.checkedCast(base)
+
+ # Get all exported knobs
+ ret = radio.get([probe_name + "::samples"])
+ for name in ret.keys():
+ # Get data in probe, which might be offset; find the
+ # beginning and unwrap.
+ result = ret[name].value
+ result = list(struct.unpack(len(result)*'b', result))
+ i = result.index(1)
+ result = result[i:] + result[0:i]
+ self.assertEqual(expected_result, result)
+
+ self.tb.stop()
+
+if __name__ == '__main__':
+ gr_unittest.run(test_ctrlport_probes, "test_ctrlport_probes.xml")
+
diff --git a/gr-blocks/python/blocks/qa_hier_block2.py b/gr-blocks/python/blocks/qa_hier_block2.py
index 51f420e8eb..5a351f2b37 100755
--- a/gr-blocks/python/blocks/qa_hier_block2.py
+++ b/gr-blocks/python/blocks/qa_hier_block2.py
@@ -393,5 +393,38 @@ class test_hier_block2(gr_unittest.TestCase):
self.assertEquals(dst.data(), (3.0,))
+ def test_033a_set_affinity(self):
+ expected = (1.0, 2.0, 3.0, 4.0)
+ hblock = gr.top_block("test_block")
+ src = blocks.vector_source_f(expected, False)
+ snk = blocks.vector_sink_f()
+ hblock.connect(src, snk)
+ hblock.set_processor_affinity([0,])
+ hblock.run()
+ actual = snk.data()
+ self.assertEquals(expected, actual)
+
+ def test_033b_unset_affinity(self):
+ expected = (1.0, 2.0, 3.0, 4.0)
+ hblock = gr.top_block("test_block")
+ src = blocks.vector_source_f(expected, False)
+ snk = blocks.vector_sink_f()
+ hblock.connect(src, snk)
+ hblock.set_processor_affinity([0,])
+ hblock.unset_processor_affinity()
+ hblock.run()
+ actual = snk.data()
+ self.assertEquals(expected, actual)
+
+ def test_033c_get_affinity(self):
+ expected = (1.0, 2.0, 3.0, 4.0)
+ hblock = gr.top_block("test_block")
+ src = blocks.vector_source_f(expected, False)
+ snk = blocks.vector_sink_f()
+ hblock.connect(src, snk)
+ hblock.set_processor_affinity([0,])
+ procs = hblock.processor_affinity()
+ self.assertEquals((0,), procs)
+
if __name__ == "__main__":
gr_unittest.run(test_hier_block2, "test_hier_block2.xml")
diff --git a/gr-blocks/python/blocks/qa_tags_strobe.py b/gr-blocks/python/blocks/qa_tags_strobe.py
new file mode 100644
index 0000000000..51b1c63bad
--- /dev/null
+++ b/gr-blocks/python/blocks/qa_tags_strobe.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest, blocks
+import pmt
+import math
+
+class test_tags_strobe(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_001(self):
+ N = 10000
+ nsamps = 1000
+ ntags = N / nsamps - 1
+
+ src = blocks.tags_strobe(gr.sizeof_float,
+ pmt.intern("TEST"), nsamps)
+ hed = blocks.head(gr.sizeof_float, N)
+ dst = blocks.vector_sink_f()
+
+ self.tb.connect(src, hed, dst)
+ self.tb.run()
+
+ self.assertEqual(ntags, len(dst.tags()))
+
+ n_expected = nsamps
+ for tag in dst.tags():
+ self.assertEqual(tag.offset, n_expected)
+ n_expected += nsamps
+
+ def test_002(self):
+ N = 10000
+ nsamps = 123
+ ntags = N / nsamps
+
+ src = blocks.tags_strobe(gr.sizeof_float,
+ pmt.intern("TEST"), nsamps)
+ hed = blocks.head(gr.sizeof_float, N)
+ dst = blocks.vector_sink_f()
+
+ self.tb.connect(src, hed, dst)
+ self.tb.run()
+
+ self.assertEqual(ntags, len(dst.tags()))
+
+ n_expected = nsamps
+ for tag in dst.tags():
+ self.assertEqual(tag.offset, n_expected)
+ n_expected += nsamps
+
+ def test_003(self):
+ N = 100000
+ nsamps = 10000
+ ntags = N / nsamps - 1
+
+ src = blocks.tags_strobe(gr.sizeof_float,
+ pmt.intern("TEST"), nsamps)
+ hed = blocks.head(gr.sizeof_float, N)
+ dst = blocks.vector_sink_f()
+
+ self.tb.connect(src, hed, dst)
+ self.tb.run()
+
+ self.assertEqual(ntags, len(dst.tags()))
+
+ n_expected = nsamps
+ for tag in dst.tags():
+ self.assertEqual(tag.offset, n_expected)
+ n_expected += nsamps
+
+if __name__ == '__main__':
+ gr_unittest.run(test_tags_strobe, "test_tags_strobe.xml")
diff --git a/gr-blocks/python/blocks/qa_vco.py b/gr-blocks/python/blocks/qa_vco.py
index 4ed2a71c04..fdd1eb1001 100644
--- a/gr-blocks/python/blocks/qa_vco.py
+++ b/gr-blocks/python/blocks/qa_vco.py
@@ -28,6 +28,12 @@ def sig_source_f(samp_rate, freq, amp, N):
y = map(lambda x: amp*math.cos(2.*math.pi*freq*x), t)
return y
+def sig_source_c(samp_rate, freq, amp, N):
+ t = map(lambda x: float(x)/samp_rate, xrange(N))
+ y = map(lambda x: math.cos(2.*math.pi*freq*x) + \
+ 1j*math.sin(2.*math.pi*freq*x), t)
+ return y
+
class test_vco(gr_unittest.TestCase):
def setUp (self):
@@ -53,6 +59,23 @@ class test_vco(gr_unittest.TestCase):
self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5)
+ def test_002(self):
+ src_data = 200*[0,] + 200*[0.5,] + 200*[1,]
+ expected_result = 200*[1,] + \
+ sig_source_c(1, 0.125, 1, 200) + \
+ sig_source_c(1, 0.25, 1, 200)
+
+ src = blocks.vector_source_f(src_data)
+ op = blocks.vco_c(1, math.pi/2.0, 1)
+ dst = blocks.vector_sink_c()
+
+ self.tb.connect(src, op, dst)
+ self.tb.run()
+
+ result_data = dst.data()
+ self.assertComplexTuplesAlmostEqual(expected_result, result_data, 5)
+
+
if __name__ == '__main__':
gr_unittest.run(test_vco, "test_vco.xml")
diff --git a/gr-blocks/swig/blocks_swig0.i b/gr-blocks/swig/blocks_swig0.i
index ec5b75b0d1..28e14fea35 100644
--- a/gr-blocks/swig/blocks_swig0.i
+++ b/gr-blocks/swig/blocks_swig0.i
@@ -103,12 +103,24 @@ GR_SWIG_BLOCK_MAGIC2(blocks, null_source);
%{
#include "gnuradio/blocks/ctrlport_probe_c.h"
#include "gnuradio/blocks/ctrlport_probe2_c.h"
+#include "gnuradio/blocks/ctrlport_probe2_f.h"
+#include "gnuradio/blocks/ctrlport_probe2_s.h"
+#include "gnuradio/blocks/ctrlport_probe2_i.h"
+#include "gnuradio/blocks/ctrlport_probe2_b.h"
%}
%include "gnuradio/blocks/ctrlport_probe_c.h"
%include "gnuradio/blocks/ctrlport_probe2_c.h"
+%include "gnuradio/blocks/ctrlport_probe2_f.h"
+%include "gnuradio/blocks/ctrlport_probe2_s.h"
+%include "gnuradio/blocks/ctrlport_probe2_i.h"
+%include "gnuradio/blocks/ctrlport_probe2_b.h"
GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe_c);
GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe2_c);
+GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe2_f);
+GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe2_s);
+GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe2_i);
+GR_SWIG_BLOCK_MAGIC2(blocks, ctrlport_probe2_b);
#endif /* GR_CTRLPORT */
diff --git a/gr-blocks/swig/blocks_swig3.i b/gr-blocks/swig/blocks_swig3.i
index 7e7e8bf365..ab921a559a 100644
--- a/gr-blocks/swig/blocks_swig3.i
+++ b/gr-blocks/swig/blocks_swig3.i
@@ -40,6 +40,7 @@
#include "gnuradio/blocks/integrate_cc.h"
#include "gnuradio/blocks/interleave.h"
#include "gnuradio/blocks/interleaved_short_to_complex.h"
+#include "gnuradio/blocks/interleaved_char_to_complex.h"
#include "gnuradio/blocks/keep_m_in_n.h"
#include "gnuradio/blocks/keep_one_in_n.h"
#include "gnuradio/blocks/lfsr_32k_source_s.h"
@@ -81,6 +82,7 @@
%include "gnuradio/blocks/integrate_cc.h"
%include "gnuradio/blocks/interleave.h"
%include "gnuradio/blocks/interleaved_short_to_complex.h"
+%include "gnuradio/blocks/interleaved_char_to_complex.h"
%include "gnuradio/blocks/keep_m_in_n.h"
%include "gnuradio/blocks/keep_one_in_n.h"
%include "gnuradio/blocks/lfsr_32k_source_s.h"
@@ -121,6 +123,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, integrate_ff);
GR_SWIG_BLOCK_MAGIC2(blocks, integrate_cc);
GR_SWIG_BLOCK_MAGIC2(blocks, interleave);
GR_SWIG_BLOCK_MAGIC2(blocks, interleaved_short_to_complex);
+GR_SWIG_BLOCK_MAGIC2(blocks, interleaved_char_to_complex);
GR_SWIG_BLOCK_MAGIC2(blocks, keep_m_in_n);
GR_SWIG_BLOCK_MAGIC2(blocks, keep_one_in_n);
GR_SWIG_BLOCK_MAGIC2(blocks, lfsr_32k_source_s);
diff --git a/gr-blocks/swig/blocks_swig5.i b/gr-blocks/swig/blocks_swig5.i
index 1b99720be8..09679531d9 100644
--- a/gr-blocks/swig/blocks_swig5.i
+++ b/gr-blocks/swig/blocks_swig5.i
@@ -52,6 +52,7 @@
#include "gnuradio/blocks/tag_gate.h"
#include "gnuradio/blocks/tagged_stream_mux.h"
#include "gnuradio/blocks/tagged_stream_to_pdu.h"
+#include "gnuradio/blocks/tags_strobe.h"
#include "gnuradio/blocks/threshold_ff.h"
#include "gnuradio/blocks/transcendental.h"
#include "gnuradio/blocks/tuntap_pdu.h"
@@ -63,6 +64,7 @@
#include "gnuradio/blocks/unpacked_to_packed_ss.h"
#include "gnuradio/blocks/unpacked_to_packed_ii.h"
#include "gnuradio/blocks/vco_f.h"
+#include "gnuradio/blocks/vco_c.h"
#include "gnuradio/blocks/xor_bb.h"
#include "gnuradio/blocks/xor_ss.h"
#include "gnuradio/blocks/xor_ii.h"
@@ -89,6 +91,7 @@
%include "gnuradio/blocks/tag_gate.h"
%include "gnuradio/blocks/tagged_stream_mux.h"
%include "gnuradio/blocks/tagged_stream_to_pdu.h"
+%include "gnuradio/blocks/tags_strobe.h"
%include "gnuradio/blocks/threshold_ff.h"
%include "gnuradio/blocks/transcendental.h"
%include "gnuradio/blocks/tuntap_pdu.h"
@@ -100,6 +103,7 @@
%include "gnuradio/blocks/unpacked_to_packed_ss.h"
%include "gnuradio/blocks/unpacked_to_packed_ii.h"
%include "gnuradio/blocks/vco_f.h"
+%include "gnuradio/blocks/vco_c.h"
%include "gnuradio/blocks/xor_bb.h"
%include "gnuradio/blocks/xor_ss.h"
%include "gnuradio/blocks/xor_ii.h"
@@ -125,6 +129,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, sub_cc);
GR_SWIG_BLOCK_MAGIC2(blocks, tag_gate);
GR_SWIG_BLOCK_MAGIC2(blocks, tagged_stream_mux);
GR_SWIG_BLOCK_MAGIC2(blocks, tagged_stream_to_pdu);
+GR_SWIG_BLOCK_MAGIC2(blocks, tags_strobe);
GR_SWIG_BLOCK_MAGIC2(blocks, threshold_ff);
GR_SWIG_BLOCK_MAGIC2(blocks, transcendental);
GR_SWIG_BLOCK_MAGIC2(blocks, tuntap_pdu);
@@ -136,6 +141,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_bb);
GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ss);
GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ii);
GR_SWIG_BLOCK_MAGIC2(blocks, vco_f);
+GR_SWIG_BLOCK_MAGIC2(blocks, vco_c);
GR_SWIG_BLOCK_MAGIC2(blocks, xor_bb);
GR_SWIG_BLOCK_MAGIC2(blocks, xor_ss);
GR_SWIG_BLOCK_MAGIC2(blocks, xor_ii);
diff --git a/gr-channels/CMakeLists.txt b/gr-channels/CMakeLists.txt
index f8e46fd207..2b5b4cd7d5 100644
--- a/gr-channels/CMakeLists.txt
+++ b/gr-channels/CMakeLists.txt
@@ -42,6 +42,8 @@ GR_SET_GLOBAL(GR_CHANNELS_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
)
+SET(GR_PKG_CHANNELS_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/channels)
+
########################################################################
# Begin conditional configuration
########################################################################
@@ -90,8 +92,8 @@ if(ENABLE_PYTHON)
add_subdirectory(swig)
add_subdirectory(python/channels)
add_subdirectory(grc)
+ add_subdirectory(examples)
endif(ENABLE_PYTHON)
-#add_subdirectory(examples)
add_subdirectory(doc)
########################################################################
diff --git a/gr-channels/doc/channels.dox b/gr-channels/doc/channels.dox
index c4440b45b0..05d51b9ba2 100644
--- a/gr-channels/doc/channels.dox
+++ b/gr-channels/doc/channels.dox
@@ -20,4 +20,114 @@ after importing by using:
help(channels)
\endcode
+
+\section channels_types Available Channel Models
+
+\subsection channels_awgn AWGN Channel
+
+The basic gr::channels::channel_model block is essentially an
+additive white Gaussian noise (AWGN) channel with a few extra
+additions. This channel model simulates AWGN as well as frequency and
+timing offsets between the transmit and receiver and a simple static
+multipath environment.
+
+The parameters include:
+
+\li noise_voltage: The AWGN noise level as a voltage (to be calculated
+ externally to meet, say, a desired SNR).
+\li frequency_offset The normalized frequency offset. 0 is no offset;
+ 0.25 would be, for a digital modem, one quarter of the symbol
+ rate.
+\li epsilon The sample timing offset to emulate the different rates
+ between the sample clocks of the transmitter and receiver. 1.0 is
+ no difference.
+\li taps Taps of a FIR filter to emulate a multipath delay profile.
+\li noise_seed A random number generator seed for the noise source.
+
+
+\subsection channels_fading Fading Channel Model
+
+The gr::channels::fading_model builds a basic fading simulation. This
+model approximates a fading channel using the sum of sinusoids method
+for the number of expected multipath components. This block also takes
+in the Doppler frequency shift as a normalized value, a line-of-sight
+(LOS) parameter that is either true or false, the Rician K factor, and
+a random seed to the noise generators. These parameters are provided
+in the documentation as:
+
+\li N The number of sinusiods to use in simulating the channel 8 is a good value
+\li fDTs normalized maximum Doppler frequency, fD * Ts
+\li LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
+\li K Rician factor (ratio of the specular power to the scattered power)
+\li seed a random number to seed the noise generators
+
+
+\subsection channels_selective_fading Frequency-Selective Fading Model
+
+Extending the fading model, the gr::channels::selective_fading_model
+channel model allows us to specify frequency selective parameters for
+the model. Starting with the same inputs as the
+gr::channels::fading_model, this block also takes in power delay
+profile (PDP). The PDP is given as a vector of the times of the delays
+and another vector of the corresponding magnitudes of the PDP. We also
+specify the number of taps in the filter to simulate this. These
+parameters are provided in the documentation as:
+
+\li N The number of sinusiods to use in simulating the channel 8 is a good value
+\li fDTs normalized maximum Doppler frequency, fD * Ts
+\li LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
+\li K Rician factor (ratio of the specular power to the scattered power)
+\li seed a random number to seed the noise generators
+\li delays A vector of values the specify the time delay of each impulse
+\li mags A vector of values that specifies the magnitude of each impulse
+\li ntaps The number of filter taps.
+
+
+\subsection channels_hw_impairments Hardware Impairments Model
+
+GNU Radio also provides a model for incorporating parameters of a
+radio transmitter and receiver to better simulate signals as they
+would be transmitted and received through real hardware. This
+simulation tool can be used to see how a waveform would behave over a
+known radio, or if designing radio hardware, this block could help
+understand the requirements and tolerances for the new system.
+
+The hardware impairments model is a Python-only hierarchical block,
+which is declared as digital.impairments(...). The block is also
+represented in GRC under the "Impairment Models" category.
+
+The impairments model is actually made up of a handful of other
+hierarchical blocks, each of which perform one aspect of the
+impairments model. Each subsection is usable on its own, and each one
+can be used in GRC. These subsystems are:
+
+\li digital.phase_noise_gen ("Phase Noise Generator")
+\li digital.iqbal_gen ("IQ Imbalance Generator")
+\li digital.distortion_3_gen ("Third Order Distortion")
+\li digital.distortion_2_gen ("Second Order Distortion")
+
+There are also a few other blocks that were built to develop and
+simulate different hardware behaviors
+
+\li digital.quantizer ("Quantizer"): quantizes to b number of bits.
+\li digital.amp_bal ("Amplitude Balance"): corrects IQ amplitude imbalance.
+\li digital.phase_bal ("Phase Balance"): corrects IQ phase imbalance.
+
+The digital.impairments model combines the phase noise, IQ imbalance,
+and second and third order distortion generators. It also performs I
+and Q offset imbalance and internal frequency shifting problems.
+
+The parameters for using the hardware impairments model are:
+
+\li phase_noise_mag: the level of the phase noise (in dB).
+\li magbal: The level of the magnitude imbalance between I and Q.
+\li phasebal: The level of the phase imbalance (as an angle).
+\li q_ofs: Offset value of the quadrature arm (as a magnitude).
+\li i_ofs: Offset value of the in-phase arm (as a magnitude).
+\li freq_offset: normalized frequency offset.
+\li gamma: Level of the 2nd order distortion.
+\li beta: level of the 3rd order distortion.
+
+
+
*/
diff --git a/gr-channels/examples/CMakeLists.txt b/gr-channels/examples/CMakeLists.txt
new file mode 100644
index 0000000000..af33a8f66f
--- /dev/null
+++ b/gr-channels/examples/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+include(GrPython)
+
+install(
+ FILES
+ channel_tone_response.grc
+ demo_quantization.grc
+ demo_two_tone.grc
+ demo_spec_an.grc
+ demo_gmsk.grc
+ demo_qam.grc
+ demo_ofdm.grc
+ DESTINATION ${GR_PKG_CHANNELS_EXAMPLES_DIR}
+ COMPONENT "channels_python"
+)
diff --git a/gr-channels/examples/demo_gmsk.grc b/gr-channels/examples/demo_gmsk.grc
new file mode 100644
index 0000000000..a5531fb46b
--- /dev/null
+++ b/gr-channels/examples/demo_gmsk.grc
@@ -0,0 +1,894 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Thu Aug 1 13:51:27 2013</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_gmsk</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>const_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(9, 89)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>32000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(98, 90)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 152)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>256</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>100000</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(13, 203)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>digital_gmsk_mod</key>
+ <param>
+ <key>id</key>
+ <value>digital_gmsk_mod_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>samples_per_symbol</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>bt</key>
+ <value>0.3</value>
+ </param>
+ <param>
+ <key>verbose</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>log</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(214, 219)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_impairments</key>
+ <param>
+ <key>id</key>
+ <value>channels_impairments_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>phase_noise_mag</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>magbal</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>phasebal</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>q_ofs</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>i_ofs</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>freq_offset</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>gamma</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>beta</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(451, 195)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,1,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(916, 235)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_quadrature_demod_cf</key>
+ <param>
+ <key>id</key>
+ <value>analog_quadrature_demod_cf_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>gain</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(708, 251)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_const_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_const_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>xmin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>xmax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,0,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(706, 176)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(227, 310)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Q offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(933, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>I offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(826, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Phase Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>45</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(672, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Magnitude Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(494, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Frequency Offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-0.5</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0.5</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(354, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Phase Noise Mag (dB)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0, 0, 1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(191, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>k3 (IP3)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1041, 12)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>analog_random_source_x_0</source_block_id>
+ <sink_block_id>digital_gmsk_mod_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>channels_impairments_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>digital_gmsk_mod_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_quadrature_demod_cf_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>analog_quadrature_demod_cf_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/examples/demo_ofdm.grc b/gr-channels/examples/demo_ofdm.grc
new file mode 100644
index 0000000000..f3c3a80e0e
--- /dev/null
+++ b/gr-channels/examples/demo_ofdm.grc
@@ -0,0 +1,1410 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Thu Aug 1 15:11:44 2013</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_ofdm</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>const_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>64</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 89)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(99, 89)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>32000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 151)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>k</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>math.log(const_size)/math.log(2)</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(100, 151)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(168, 153)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Q offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(936, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>I offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(829, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Phase Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>45</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(675, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Magnitude Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(497, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Frequency Offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-0.5</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0.5</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(357, 8)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Phase Noise Mag (dB)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0, 0, 1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(194, 7)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,1,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1102, 249)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>k3 (IP3)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-10</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.01</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1042, 8)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_complex</key>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_complex_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(237, 424)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>fft_vxx</key>
+ <param>
+ <key>id</key>
+ <value>fft_fft_vxx_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>forward</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>window</key>
+ <value>fft_size*[1.0/math.sqrt(fft_size)]</value>
+ </param>
+ <param>
+ <key>shift</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>nthreads</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(689, 150)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>fft_vxx</key>
+ <param>
+ <key>id</key>
+ <value>fft_fft_vxx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>forward</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>window</key>
+ <value>fft_size*[1.0/math.sqrt(fft_size)]</value>
+ </param>
+ <param>
+ <key>shift</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>nthreads</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(565, 485)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>1.0/fft_size</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(854, 571)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_to_stream</key>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_to_stream_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_items</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(833, 468)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_impairments</key>
+ <param>
+ <key>id</key>
+ <value>channels_impairments_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>phase_noise_mag</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>magbal</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>phasebal</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>q_ofs</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>i_ofs</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>freq_offset</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>gamma</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>beta</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1074, 460)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_stream_to_vector</key>
+ <param>
+ <key>id</key>
+ <value>blocks_stream_to_vector_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_items</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(889, 400)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>180</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_vector_to_stream</key>
+ <param>
+ <key>id</key>
+ <value>blocks_vector_to_stream_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_items</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(806, 315)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_stream_to_vector</key>
+ <param>
+ <key>id</key>
+ <value>blocks_stream_to_vector_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_items</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(449, 343)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>180</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_const_vxx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_add_const_vxx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>(-1-1j)/2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(337, 175)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(438, 243)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>180</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_const_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_const_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>xmin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>xmax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,0,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1102, 175)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_int_to_float</key>
+ <param>
+ <key>id</key>
+ <value>blocks_int_to_float_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>k-1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(63, 412)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_int_to_float</key>
+ <param>
+ <key>id</key>
+ <value>blocks_int_to_float_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>k-1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(63, 462)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>int(k)</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>10000</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(22, 271)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>int(k)</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>10000</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(36, 543)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>blocks_stream_to_vector_0_0</source_block_id>
+ <sink_block_id>fft_fft_vxx_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>blocks_stream_to_vector_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>blocks_stream_to_vector_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_fft_vxx_0_0</source_block_id>
+ <sink_block_id>blocks_vector_to_stream_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_const_vxx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_complex_0</source_block_id>
+ <sink_block_id>blocks_add_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_random_source_x_0</source_block_id>
+ <sink_block_id>blocks_int_to_float_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_int_to_float_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_int_to_float_0_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_random_source_x_0_0</source_block_id>
+ <sink_block_id>blocks_int_to_float_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_to_stream_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_to_stream_0</source_block_id>
+ <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_fft_vxx_0</source_block_id>
+ <sink_block_id>blocks_vector_to_stream_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_vector_to_stream_0_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
+ <sink_block_id>channels_impairments_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_stream_to_vector_0</source_block_id>
+ <sink_block_id>fft_fft_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/examples/demo_qam.grc b/gr-channels/examples/demo_qam.grc
new file mode 100644
index 0000000000..d4c56d7d1a
--- /dev/null
+++ b/gr-channels/examples/demo_qam.grc
@@ -0,0 +1,1048 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Thu Aug 1 15:09:47 2013</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_qam</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>32000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(97, 91)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>const_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>16</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(9, 90)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>k</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>math.log(const_size)/math.log(2)</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(101, 153)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Q offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(943, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>I offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(836, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Magnitude Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(504, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Phase Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>45</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(682, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Frequency Offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-0.5</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0.5</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(364, 18)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Phase Noise Mag (dB)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0, 0, 1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(201, 17)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 154)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,1,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1038, 334)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_impairments</key>
+ <param>
+ <key>id</key>
+ <value>channels_impairments_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>phase_noise_mag</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>magbal</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>phasebal</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>q_ofs</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>i_ofs</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>freq_offset</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>gamma</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>beta</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(776, 251)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_float_to_complex</key>
+ <param>
+ <key>id</key>
+ <value>blocks_float_to_complex_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(374, 294)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(593, 307)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_const_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_const_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>xmin</key>
+ <value>-2</value>
+ </param>
+ <param>
+ <key>xmax</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,0,1,1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1038, 261)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>k3 (IP3)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1051, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>int(k)</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>10000</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(13, 239)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_random_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_random_source_x_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>int(k)</value>
+ </param>
+ <param>
+ <key>num_samps</key>
+ <value>10000</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(13, 332)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_int_to_float</key>
+ <param>
+ <key>id</key>
+ <value>blocks_int_to_float_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>k-1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(190, 263)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_int_to_float</key>
+ <param>
+ <key>id</key>
+ <value>blocks_int_to_float_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>k-1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(191, 356)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_const_vxx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_add_const_vxx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>(-1-1j)/2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(402, 396)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>qtgui_const_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>channels_impairments_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_random_source_x_0_0</source_block_id>
+ <sink_block_id>blocks_int_to_float_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_int_to_float_0_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_int_to_float_0</source_block_id>
+ <sink_block_id>blocks_float_to_complex_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_const_vxx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_float_to_complex_0</source_block_id>
+ <sink_block_id>blocks_add_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_random_source_x_0</source_block_id>
+ <sink_block_id>blocks_int_to_float_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/examples/demo_quantization.grc b/gr-channels/examples/demo_quantization.grc
new file mode 100644
index 0000000000..134e224e7f
--- /dev/null
+++ b/gr-channels/examples/demo_quantization.grc
@@ -0,0 +1,958 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Fri Aug 2 16:57:39 2013</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_quantization</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>100000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 134)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 88)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>bw</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>BW</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>samp_rate/100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,2,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(873, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>center</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Center Freq.</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>samp_rate/11.0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(724, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_chooser</key>
+ <param>
+ <key>id</key>
+ <value>bits</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Bits</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int</value>
+ </param>
+ <param>
+ <key>num_opts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>16</value>
+ </param>
+ <param>
+ <key>options</key>
+ <value>[0, 1, 2, 4, 6, 8, 10, 12, 14, 16]</value>
+ </param>
+ <param>
+ <key>labels</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>option0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>label0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>option1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>option2</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>option3</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>option4</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>combo_box</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.QVBoxLayout</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,2,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(570, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>sigfreq</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Signal Freq</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>samp_rate*1.0247385/11.0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(427, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>signal_amp</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Signal Power</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-150</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-150</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,2,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(301, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>noise_amp</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Noise Power</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-150</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-150</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(173, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_add_xx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(489, 297)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_quantizer</key>
+ <param>
+ <key>id</key>
+ <value>channels_quantizer_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>bits</key>
+ <value>bits</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(827, 203)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_multiply_const_vxx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_multiply_const_vxx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>const</key>
+ <value>pow(2,bits-1)</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(800, 287)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_freq_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_freq_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>fftsize</key>
+ <value>2048</value>
+ </param>
+ <param>
+ <key>wintype</key>
+ <value>firdes.WIN_BLACKMAN_hARRIS</value>
+ </param>
+ <param>
+ <key>fc</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>bw</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-140</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,1,1,2</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(998, 170)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_COS_WAVE</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>sigfreq</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>pow(10.0,signal_amp/20.0)</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(7, 295)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>band_pass_filter</key>
+ <param>
+ <key>id</key>
+ <value>band_pass_filter_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fir_filter_fff</value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>interp</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>gain</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>low_cutoff_freq</key>
+ <value>max(bw/15.0,center-bw/2.0)</value>
+ </param>
+ <param>
+ <key>high_cutoff_freq</key>
+ <value>min(samp_rate/2.0-bw/15.0,center+bw/2.0)</value>
+ </param>
+ <param>
+ <key>width</key>
+ <value>bw/5.0</value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>firdes.WIN_HANN</value>
+ </param>
+ <param>
+ <key>beta</key>
+ <value>6.76</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(212, 173)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_noise_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_noise_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>noise_type</key>
+ <value>analog.GR_GAUSSIAN</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>pow(10.0,noise_amp/20.0)</value>
+ </param>
+ <param>
+ <key>seed</key>
+ <value>42</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(9, 213)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(634, 203)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_histogram_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_histogram_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>10240</value>
+ </param>
+ <param>
+ <key>bins</key>
+ <value>1000</value>
+ </param>
+ <param>
+ <key>xmin</key>
+ <value>-10000</value>
+ </param>
+ <param>
+ <key>xmax</key>
+ <value>10000</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(998, 271)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>channels_quantizer_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_quantizer_0</source_block_id>
+ <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>band_pass_filter_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_xx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_quantizer_0</source_block_id>
+ <sink_block_id>blocks_multiply_const_vxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_multiply_const_vxx_0</source_block_id>
+ <sink_block_id>qtgui_histogram_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_noise_source_x_0</source_block_id>
+ <sink_block_id>band_pass_filter_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/examples/demo_spec_an.grc b/gr-channels/examples/demo_spec_an.grc
new file mode 100644
index 0000000000..572ded6e67
--- /dev/null
+++ b/gr-channels/examples/demo_spec_an.grc
@@ -0,0 +1,1087 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Thu Aug 1 13:13:07 2013</timestamp>
+ <block>
+ <key>blocks_add_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_add_xx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(251, 344)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>fft_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(17, 84)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>100000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 170)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>imp0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(238, 60)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_noise_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_noise_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>noise_type</key>
+ <value>analog.GR_GAUSSIAN</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>math.pow(10.0,snr/20.0)/math.sqrt(2.0)</value>
+ </param>
+ <param>
+ <key>seed</key>
+ <value>42</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(16, 295)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_slider</key>
+ <param>
+ <key>id</key>
+ <value>freq_offset</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Freq_offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>-5*samp_rate/fft_size</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>5*samp_rate/fft_size</value>
+ </param>
+ <param>
+ <key>num_steps</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.SL_HORIZONTAL</value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>float_converter</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(314, 514)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_COS_WAVE</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>float(samp_rate)/float(fft_size)*26+freq_offset</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(16, 386)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(370, 357)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_slider</key>
+ <param>
+ <key>id</key>
+ <value>snr</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>"Noise Level"</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>num_steps</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.SL_HORIZONTAL</value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>float_converter</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(167, 510)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_rms_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_rms_xx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>alpha</key>
+ <value>.0001</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(491, 138)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_rms_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_rms_xx_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>alpha</key>
+ <value>.0001</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(465, 458)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_divide_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_divide_xx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(680, 630)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_nlog10_ff</key>
+ <param>
+ <key>id</key>
+ <value>blocks_nlog10_ff_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>n</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>k</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(813, 640)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_numbersink2</key>
+ <param>
+ <key>id</key>
+ <value>snr_disp</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>SNR</value>
+ </param>
+ <param>
+ <key>units</key>
+ <value>dB</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>min_value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>max_value</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>factor</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>decimal_places</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>number_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>show_gauge</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(907, 654)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_numbersink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_numbersink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Noise Amplitude</value>
+ </param>
+ <param>
+ <key>units</key>
+ <value></value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>min_value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>max_value</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>factor</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>decimal_places</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>number_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>show_gauge</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(774, 46)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_numbersink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_numbersink2_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Signal Amplitude</value>
+ </param>
+ <param>
+ <key>units</key>
+ <value></value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>min_value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>max_value</key>
+ <value>100</value>
+ </param>
+ <param>
+ <key>factor</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>decimal_places</key>
+ <value>5</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>number_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>show_gauge</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(774, 452)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_scopesink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_scopesink2_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>Scope Plot</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>v_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>v_offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>t_scale</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ac_couple</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>xy_mode</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>trig_mode</key>
+ <value>wxgui.TRIG_MODE_AUTO</value>
+ </param>
+ <param>
+ <key>y_axis_label</key>
+ <value>Counts</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(696, 244)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_fftsink2</key>
+ <param>
+ <key>id</key>
+ <value>wxgui_fftsink2_0</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>0</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>fft_size</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>20</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>window.flattop</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(894, 271)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_spec_an</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>wx_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_noise_source_x_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_xx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>wxgui_fftsink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_noise_source_x_0</source_block_id>
+ <sink_block_id>blocks_rms_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_rms_xx_0</source_block_id>
+ <sink_block_id>wxgui_numbersink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>blocks_rms_xx_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_rms_xx_0_0</source_block_id>
+ <sink_block_id>wxgui_numbersink2_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_nlog10_ff_0</source_block_id>
+ <sink_block_id>snr_disp</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_divide_xx_0</source_block_id>
+ <sink_block_id>blocks_nlog10_ff_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_rms_xx_0</source_block_id>
+ <sink_block_id>blocks_divide_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_rms_xx_0_0</source_block_id>
+ <sink_block_id>blocks_divide_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>wxgui_scopesink2_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/examples/demo_two_tone.grc b/gr-channels/examples/demo_two_tone.grc
new file mode 100644
index 0000000000..df544d8e85
--- /dev/null
+++ b/gr-channels/examples/demo_two_tone.grc
@@ -0,0 +1,1190 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+ <timestamp>Thu Aug 1 13:37:58 2013</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>demo_two_tone</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value>mettus</value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <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>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>32000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(11, 93)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>const_size</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>4</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(102, 93)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_throttle</key>
+ <param>
+ <key>id</key>
+ <value>blocks_throttle_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(397, 368)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_impairments</key>
+ <param>
+ <key>id</key>
+ <value>channels_impairments_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>phase_noise_mag</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>magbal</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>phasebal</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>q_ofs</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>i_ofs</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>freq_offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>gamma</key>
+ <value>gamma</value>
+ </param>
+ <param>
+ <key>beta</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(578, 312)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_add_xx</key>
+ <param>
+ <key>id</key>
+ <value>blocks_add_xx_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>num_inputs</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(287, 338)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_COS_WAVE</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>f2</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>pow(10,sig_amp/20.0)*twotones</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(24, 336)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_COS_WAVE</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>f1</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>pow(10,sig_amp/20.0)</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(25, 225)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_noise_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_noise_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>noise_type</key>
+ <value>analog.GR_GAUSSIAN</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>.00001</value>
+ </param>
+ <param>
+ <key>seed</key>
+ <value>42</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(24, 446)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>import</key>
+ <param>
+ <key>id</key>
+ <value>import_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>import</key>
+ <value>import math</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 160)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_phase_bal</key>
+ <param>
+ <key>id</key>
+ <value>channels_phase_bal_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>alpha</key>
+ <value>0.00001</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(822, 329)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>channels_amp_bal</key>
+ <param>
+ <key>id</key>
+ <value>channels_amp_bal_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alpha</key>
+ <value>0.0001</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(822, 392)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>sig_amp</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Singal Power (dB)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(214, 8)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phase_noise_mag</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Phase Noise Mag (dB)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-100</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>1,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(357, 8)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>f1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>f1</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>samp_rate/7.0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-samp_rate/2</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(522, 8)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>f2</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>f2</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>samp_rate/9.0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-samp_rate/2</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>samp_rate/2</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>2,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(670, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>magbal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Magnitude Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(814, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>phasebal</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>IQ Phase Imbalance</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>45</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(990, 9)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>gamma</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>k2 (IP2)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(322, 138)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>beta</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>k3 (IP3)</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-.1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>4,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(215, 137)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_check_box</key>
+ <param>
+ <key>id</key>
+ <value>twotones</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Two Tones?</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>bool</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>true</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>false</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(650, 143)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>q_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>Q offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>5,1,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(538, 139)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>i_ofs</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>I offset</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>5,0,1,1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(430, 138)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_freq_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_freq_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ </param>
+ <param>
+ <key>fftsize</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>wintype</key>
+ <value>firdes.WIN_BLACKMAN_hARRIS</value>
+ </param>
+ <param>
+ <key>fc</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>bw</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-140</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>6,0,1,2</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1059, 323)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>channels_phase_bal_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_impairments_0</source_block_id>
+ <sink_block_id>channels_amp_bal_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>channels_impairments_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_noise_source_x_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_1</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>blocks_add_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_add_xx_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_phase_bal_0</source_block_id>
+ <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>channels_amp_bal_0</source_block_id>
+ <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-channels/grc/CMakeLists.txt b/gr-channels/grc/CMakeLists.txt
index 3bda29f01d..75e2bc0ddd 100644
--- a/gr-channels/grc/CMakeLists.txt
+++ b/gr-channels/grc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2012 Free Software Foundation, Inc.
+# Copyright 2012-2013 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -17,11 +17,7 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
-install(FILES
- channels_block_tree.xml
- channels_channel_model.xml
- channels_fading_model.xml
- channels_selective_fading_model.xml
- DESTINATION ${GRC_BLOCKS_DIR}
- COMPONENT "channels_python"
+file(GLOB xml_files "*.xml")
+install(FILES ${xml_files}
+ DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "channels_python"
)
diff --git a/gr-channels/grc/channels_amp_bal.xml b/gr-channels/grc/channels_amp_bal.xml
new file mode 100644
index 0000000000..7e0738ec98
--- /dev/null
+++ b/gr-channels/grc/channels_amp_bal.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Amplitude balance
+###################################################
+ -->
+<block>
+ <name>Amplitude Balance</name>
+ <key>channels_amp_bal</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.amp_bal($alpha)</make>
+ <callback>set_alpha($alpha)</callback>
+ <param>
+ <name>Alpha</name>
+ <key>alpha</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_block_tree.xml b/gr-channels/grc/channels_block_tree.xml
index efa808fd53..154e9204d1 100644
--- a/gr-channels/grc/channels_block_tree.xml
+++ b/gr-channels/grc/channels_block_tree.xml
@@ -33,4 +33,15 @@
<block>channels_channel_model</block>
<block>channels_fading_model</block>
</cat>
+ <cat>
+ <name>Impairment Models</name>
+ <block>channels_impairments</block>
+ <block>channels_quantizer</block>
+ <block>channels_phase_noise_gen</block>
+ <block>channels_iqbal_gen</block>
+ <block>channels_distortion_2_gen</block>
+ <block>channels_distortion_3_gen</block>
+ <block>channels_amp_bal</block>
+ <block>channels_phase_bal</block>
+ </cat>
</cat>
diff --git a/gr-channels/grc/channels_channel_model2.xml b/gr-channels/grc/channels_channel_model2.xml
new file mode 100644
index 0000000000..e8162f53d4
--- /dev/null
+++ b/gr-channels/grc/channels_channel_model2.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Channel Model
+###################################################
+ -->
+<block>
+ <name>Channel Model 2</name>
+ <key>channels_channel_model2</key>
+ <import>from gnuradio import channels</import>
+ <import>from gnuradio.filter import firdes</import>
+ <make>channels.channel_model2(
+ noise_voltage=$noise_voltage,
+ epsilon=$epsilon,
+ taps=$taps,
+ noise_seed=$seed,
+)</make>
+ <callback>set_noise_voltage($noise_voltage)</callback>
+ <callback>set_taps($taps)</callback>
+ <callback>set_timing_offset($epsilon)</callback>
+ <param>
+ <name>Noise Voltage</name>
+ <key>noise_voltage</key>
+ <value>0.0</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Time Offset</name>
+ <key>epsilon</key>
+ <value>1.0</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Taps</name>
+ <key>taps</key>
+ <value>1.0 + 1.0j</value>
+ <type>complex_vector</type>
+ </param>
+ <param>
+ <name>Seed</name>
+ <key>seed</key>
+ <value>0</value>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <sink>
+ <name>freq</name>
+ <type>float</type>
+ </sink>
+ <sink>
+ <name>time</name>
+ <type>float</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_conj_fs_iqcorr.xml b/gr-channels/grc/channels_conj_fs_iqcorr.xml
new file mode 100644
index 0000000000..354f1a2030
--- /dev/null
+++ b/gr-channels/grc/channels_conj_fs_iqcorr.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Freq. Selective IQ Correction
+###################################################
+ -->
+<block>
+ <name>Freq. Selective IQ Correction</name>
+ <key>channels_conj_fs_iqcorr</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.conj_fs_iqcorr($delay, $taps)</make>
+ <callback>set_delay($delay)</callback>
+ <callback>set_taps($taps)</callback>
+ <param>
+ <name>Delay</name>
+ <key>delay</key>
+ <value>0</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Taps</name>
+ <key>taps</key>
+ <value>0</value>
+ <type>complex_vector</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_distortion_2_gen.xml b/gr-channels/grc/channels_distortion_2_gen.xml
new file mode 100644
index 0000000000..5b117a9d00
--- /dev/null
+++ b/gr-channels/grc/channels_distortion_2_gen.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Second Order Distortion Generator
+###################################################
+ -->
+<block>
+ <name>Second Order Distortion</name>
+ <key>channels_distortion_2_gen</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.distortion_2_gen($beta)</make>
+ <callback>set_beta($beta)</callback>
+ <param>
+ <name>Distortion</name>
+ <key>beta</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_distortion_3_gen.xml b/gr-channels/grc/channels_distortion_3_gen.xml
new file mode 100644
index 0000000000..7bf145c27e
--- /dev/null
+++ b/gr-channels/grc/channels_distortion_3_gen.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Third Order Distortion Generator
+###################################################
+ -->
+<block>
+ <name>Third Order Distortion</name>
+ <key>channels_distortion_3_gen</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.distortion_3_gen($beta)</make>
+ <callback>set_beta($beta)</callback>
+ <param>
+ <name>Distortion</name>
+ <key>beta</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_impairments.xml b/gr-channels/grc/channels_impairments.xml
new file mode 100644
index 0000000000..12ee65c740
--- /dev/null
+++ b/gr-channels/grc/channels_impairments.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Impairments Model
+###################################################
+ -->
+<block>
+ <name>HW Impairments</name>
+ <key>channels_impairments</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.impairments($phase_noise_mag, $magbal, $phasebal, $q_ofs, $i_ofs, $freq_offset, $gamma, $beta)</make>
+ <callback>set_phase_noise_mag($phase_noise_mag)</callback>
+ <callback>set_magbal($magbal)</callback>
+ <callback>set_phasebal($phasebal)</callback>
+ <callback>set_q_ofs($q_ofs)</callback>
+ <callback>set_i_ofs($i_ofs)</callback>
+ <callback>set_freq_offset($freq_offset)</callback>
+ <callback>set_gamma($gamma)</callback>
+ <callback>set_beta($beta)</callback>
+ <param>
+ <name>Phase Noise Mag.</name>
+ <key>phase_noise_mag</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>IQ Mag. Imbalance</name>
+ <key>magbal</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>IQ Phase. Imbalance</name>
+ <key>phasebal</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Quadrature Offset</name>
+ <key>q_ofs</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Inphase Offset</name>
+ <key>i_ofs</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Frequency Offset</name>
+ <key>freq_offset</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Second Order Distortion</name>
+ <key>gamma</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Third Order Distortion</name>
+ <key>beta</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_iqbal_gen.xml b/gr-channels/grc/channels_iqbal_gen.xml
new file mode 100644
index 0000000000..9cb267adec
--- /dev/null
+++ b/gr-channels/grc/channels_iqbal_gen.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##IQ Imbalance Generator
+###################################################
+ -->
+<block>
+ <name>IQ Imbalance Generator</name>
+ <key>channels_iqbal_gen</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.iqbal_gen($mag, $phase)</make>
+ <callback>set_magnitude($mag)</callback>
+ <callback>set_phase($phase)</callback>
+ <param>
+ <name>Magnitude</name>
+ <key>mag</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Phase</name>
+ <key>phase</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_phase_bal.xml b/gr-channels/grc/channels_phase_bal.xml
new file mode 100644
index 0000000000..ce17ab79ab
--- /dev/null
+++ b/gr-channels/grc/channels_phase_bal.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Phase balance
+###################################################
+ -->
+<block>
+ <name>Phase Balance</name>
+ <key>channels_phase_bal</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.phase_bal($alpha)</make>
+ <callback>set_alpha($alpha)</callback>
+ <param>
+ <name>Alpha</name>
+ <key>alpha</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_phase_noise_gen.xml b/gr-channels/grc/channels_phase_noise_gen.xml
new file mode 100644
index 0000000000..852b4c9966
--- /dev/null
+++ b/gr-channels/grc/channels_phase_noise_gen.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Phase Noise Generator
+###################################################
+ -->
+<block>
+ <name>Phase Noise Generator</name>
+ <key>channels_phase_noise_gen</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.phase_noise_gen($noise_mag, $alpha)</make>
+ <callback>set_noise_mag($noise_mag)</callback>
+ <callback>set_alpha($alpha)</callback>
+ <param>
+ <name>Noise Magnitude</name>
+ <key>noise_mag</key>
+ <value>0</value>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Alpha</name>
+ <key>alpha</key>
+ <value>0.1</value>
+ <type>float</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-channels/grc/channels_quantizer.xml b/gr-channels/grc/channels_quantizer.xml
new file mode 100644
index 0000000000..57bed74ee7
--- /dev/null
+++ b/gr-channels/grc/channels_quantizer.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Quantization
+###################################################
+ -->
+<block>
+ <name>Quantizer</name>
+ <key>channels_quantizer</key>
+ <import>from gnuradio import channels</import>
+ <make>channels.quantizer($bits)</make>
+ <callback>set_bits($bits)</callback>
+ <param>
+ <name>Bits</name>
+ <key>bits</key>
+ <value>16</value>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>float</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>float</type>
+ </source>
+</block>
diff --git a/gr-channels/include/gnuradio/channels/CMakeLists.txt b/gr-channels/include/gnuradio/channels/CMakeLists.txt
index f9a535b9c0..cb618a7e8d 100644
--- a/gr-channels/include/gnuradio/channels/CMakeLists.txt
+++ b/gr-channels/include/gnuradio/channels/CMakeLists.txt
@@ -23,6 +23,7 @@
install(FILES
api.h
channel_model.h
+ channel_model2.h
fading_model.h
selective_fading_model.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/channels
diff --git a/gr-channels/include/gnuradio/channels/channel_model2.h b/gr-channels/include/gnuradio/channels/channel_model2.h
new file mode 100644
index 0000000000..05084931ee
--- /dev/null
+++ b/gr-channels/include/gnuradio/channels/channel_model2.h
@@ -0,0 +1,102 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,2012,2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CHANNELS_CHANNEL_MODEL2_H
+#define INCLUDED_CHANNELS_CHANNEL_MODEL2_H
+
+#include <gnuradio/channels/api.h>
+#include <gnuradio/hier_block2.h>
+#include <gnuradio/types.h>
+
+namespace gr {
+ namespace channels {
+
+ /*!
+ * \brief channel model2
+ * \ingroup channel_models_blk
+ *
+ * \details
+ * This block implements a basic channel model simulator that can
+ * be used to help evaluate, design, and test various signals,
+ * waveforms, and algorithms.
+ *
+ * This model allows the user to set the voltage of an AWGN noise
+ * source, an initial timing offset, and a noise seed to randomize
+ * the AWGN noise source.
+ *
+ * Multipath can be approximated in this model by using a FIR
+ * filter representation of a multipath delay profile.
+ *
+ * Unlike gr::channels::channel_model, this block is designed to
+ * enable time-varying frequency and timing offsets.
+ * * Port 0: input signal to be run through the channel.
+ * * Port 1: frequency function. A constant value between -0.5 and
+ * 0.5 here will turn into a constant frequency offset
+ * from -fs/2 to fs/2 (where fs is the sample rate).
+ * * Port 2: timing offset function. Sets the resampling rate of
+ * the channel model. A constant value here produces
+ * that value as the timing offset, so a constant 1.0
+ * input stream is the same as not having a timing
+ * offset.
+ *
+ * Since the models for frequency and timing offset may vary and
+ * what we are trying to model may be different for different
+ * simulations, we provide the time-varying nature as an input
+ * function that is user-defined. If only constant frequency and
+ * timing offsets are required, it is easier and less expensive to
+ * use gr::channels::channel_model.
+ */
+ class CHANNELS_API channel_model2 : virtual public hier_block2
+ {
+ public:
+ // gr::channels::channel_model2::sptr
+ typedef boost::shared_ptr<channel_model2> sptr;
+
+ /*! \brief Build the channel simulator.
+ *
+ * \param noise_voltage The AWGN noise level as a voltage (to be
+ * calculated externally to meet, say, a
+ * desired SNR).
+ * \param epsilon The initial sample timing offset to emulate the
+ * different rates between the sample clocks of
+ * the transmitter and receiver. 1.0 is no difference.
+ * \param taps Taps of a FIR filter to emulate a multipath delay profile.
+ * \param noise_seed A random number generator seed for the noise source.
+ */
+ static sptr make(double noise_voltage=0.0,
+ double epsilon=1.0,
+ const std::vector<gr_complex> &taps=std::vector<gr_complex>(1,1),
+ double noise_seed=0);
+
+ virtual void set_noise_voltage(double noise_voltage) = 0;
+ virtual void set_taps(const std::vector<gr_complex> &taps) = 0;
+ virtual void set_timing_offset(double epsilon) = 0;
+
+ virtual double noise_voltage() const = 0;
+ virtual std::vector<gr_complex> taps() const = 0;
+ virtual double timing_offset() const = 0;
+ };
+
+ } /* namespace channels */
+} /* namespace gr */
+
+#endif /* INCLUDED_CHANNELS_CHANNEL_MODEL2_H */
diff --git a/gr-channels/include/gnuradio/channels/fading_model.h b/gr-channels/include/gnuradio/channels/fading_model.h
index c5946d3598..fe8bb33615 100644
--- a/gr-channels/include/gnuradio/channels/fading_model.h
+++ b/gr-channels/include/gnuradio/channels/fading_model.h
@@ -47,11 +47,11 @@ namespace gr {
/*! \brief Build the channel simulator.
*
- * \param N The number of sinusiods to use in simulating the channel 8 is a good value
- * \param fDTs normalized maximum doppler frequency, fD * Ts
- * \param LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
- * \param K Rician factor (ratio of the specular power to the scattered power)
- * \param seed a random number to seed the noise generators
+ * \param N The number of sinusiods to use in simulating the channel; 8 is a good value
+ * \param fDTs normalized maximum Doppler frequency, fD * Ts
+ * \param LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
+ * \param K Rician factor (ratio of the specular power to the scattered power)
+ * \param seed a random number to seed the noise generators
*/
static sptr make(unsigned int N,
float fDTs=0.01,
diff --git a/gr-channels/include/gnuradio/channels/selective_fading_model.h b/gr-channels/include/gnuradio/channels/selective_fading_model.h
index 3135f5caae..914388c5fe 100644
--- a/gr-channels/include/gnuradio/channels/selective_fading_model.h
+++ b/gr-channels/include/gnuradio/channels/selective_fading_model.h
@@ -50,14 +50,14 @@ namespace gr {
/*! \brief Build the channel simulator.
*
- * \param N The number of sinusiods to use in simulating the channel 8 is a good value
- * \param fDTs normalized maximum doppler frequency, fD * Ts
- * \param LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
- * \param K Rician factor (ratio of the specular power to the scattered power)
- * \param seed a random number to seed the noise generators
- * \param delays A vector of values the specify the time delay of each impulse
- * \param mags A vector of values that specifies the magnitude of each inpulse
- * \param ntaps The number of filter taps.
+ * \param N The number of sinusiods to use in simulating the channel; 8 is a good value
+ * \param fDTs normalized maximum Doppler frequency, fD * Ts
+ * \param LOS include Line-of-Site path? selects between Rayleigh (NLOS) and Rician (LOS) models
+ * \param K Rician factor (ratio of the specular power to the scattered power)
+ * \param seed a random number to seed the noise generators
+ * \param delays A vector of values the specify the time delay of each impulse
+ * \param mags A vector of values that specifies the magnitude of each impulse
+ * \param ntaps The number of filter taps.
*/
static sptr make(unsigned int N,
float fDTs,
diff --git a/gr-channels/lib/CMakeLists.txt b/gr-channels/lib/CMakeLists.txt
index 46c90671c2..f429fae0fc 100644
--- a/gr-channels/lib/CMakeLists.txt
+++ b/gr-channels/lib/CMakeLists.txt
@@ -43,6 +43,7 @@ endif(ENABLE_GR_CTRLPORT)
########################################################################
list(APPEND channels_sources
channel_model_impl.cc
+ channel_model2_impl.cc
fading_model_impl.cc
selective_fading_model_impl.cc
flat_fader_impl.cc
diff --git a/gr-channels/lib/channel_model2_impl.cc b/gr-channels/lib/channel_model2_impl.cc
new file mode 100644
index 0000000000..13eb033def
--- /dev/null
+++ b/gr-channels/lib/channel_model2_impl.cc
@@ -0,0 +1,176 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,2012,2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+ #define _USE_MATH_DEFINES
+
+#include "channel_model2_impl.h"
+#include <gnuradio/io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace channels {
+
+ channel_model2::sptr
+ channel_model2::make(double noise_voltage,
+ double epsilon,
+ const std::vector<gr_complex> &taps,
+ double noise_seed)
+ {
+ return gnuradio::get_initial_sptr
+ (new channel_model2_impl(noise_voltage,
+ epsilon,
+ taps,
+ noise_seed));
+ }
+
+ // Hierarchical block constructor
+ channel_model2_impl::channel_model2_impl(double noise_voltage,
+ double epsilon,
+ const std::vector<gr_complex> &taps,
+ double noise_seed)
+ : hier_block2("channel_model2",
+ io_signature::make2(3, 3, sizeof(gr_complex), sizeof(float)),
+ io_signature::make(1, 1, sizeof(gr_complex)))
+ {
+ d_taps = taps;
+ while(d_taps.size() < 2) {
+ d_taps.push_back(0);
+ }
+
+ d_timing_offset = filter::fractional_resampler_cc::make(0, epsilon);
+
+ d_multipath = filter::fir_filter_ccc::make(1, d_taps);
+
+ d_noise_adder = blocks::add_cc::make();
+ d_noise = analog::fastnoise_source_c::make(analog::GR_GAUSSIAN,
+ noise_voltage, noise_seed);
+ d_freq_gen = blocks::vco_c::make(1.0, 2*M_PI, 1.0);
+
+ d_mixer_offset = blocks::multiply_cc::make();
+
+ connect(self(), 0, d_timing_offset, 0);
+ connect(self(), 2, d_timing_offset, 1);
+ connect(d_timing_offset, 0, d_multipath, 0);
+ connect(d_multipath, 0, d_mixer_offset, 0);
+
+ connect(self(), 1, d_freq_gen, 0);
+ connect(d_freq_gen, 0, d_mixer_offset, 1);
+
+ connect(d_mixer_offset, 0, d_noise_adder, 1);
+ connect(d_noise, 0, d_noise_adder, 0);
+ connect(d_noise_adder, 0, self(), 0);
+ }
+
+ channel_model2_impl::~channel_model2_impl()
+ {
+ }
+
+ void
+ channel_model2_impl::set_noise_voltage(double noise_voltage)
+ {
+ d_noise->set_amplitude(noise_voltage);
+ }
+
+ void
+ channel_model2_impl::set_taps(const std::vector<gr_complex> &taps)
+ {
+ d_taps = taps;
+ while(d_taps.size() < 2) {
+ d_taps.push_back(0);
+ }
+ d_multipath->set_taps(d_taps);
+ }
+
+ void
+ channel_model2_impl::set_timing_offset(double epsilon)
+ {
+ d_timing_offset->set_resamp_ratio(epsilon);
+ }
+
+ double
+ channel_model2_impl::noise_voltage() const
+ {
+ return d_noise->amplitude();
+ }
+
+ std::vector<gr_complex>
+ channel_model2_impl::taps() const
+ {
+ return d_multipath->taps();
+ }
+
+ double
+ channel_model2_impl::timing_offset() const
+ {
+ return d_timing_offset->resamp_ratio();
+ }
+
+ void
+ channel_model2_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<channel_model2, double>(
+ alias(), "noise",
+ &channel_model2::noise_voltage,
+ pmt::mp(-10.0f), pmt::mp(10.0f), pmt::mp(0.0f),
+ "", "Noise Voltage", RPC_PRIVLVL_MIN,
+ DISPTIME | DISPOPTSTRIP)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<channel_model2, double>(
+ alias(), "timing",
+ &channel_model2::timing_offset,
+ pmt::mp(0.0), pmt::mp(2.0), pmt::mp(0.0),
+ "", "Timing Offset", RPC_PRIVLVL_MIN,
+ DISPTIME | DISPOPTSTRIP)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<channel_model2, std::vector<gr_complex> >(
+ alias(), "taps",
+ &channel_model2::taps,
+ pmt::make_c32vector(0,-10),
+ pmt::make_c32vector(0,10),
+ pmt::make_c32vector(0,0),
+ "", "Multipath taps", RPC_PRIVLVL_MIN,
+ DISPTIME | DISPOPTCPLX | DISPOPTSTRIP)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_set<channel_model2, double>(
+ alias(), "noise",
+ &channel_model2::set_noise_voltage,
+ pmt::mp(-10.0), pmt::mp(10.0), pmt::mp(0.0),
+ "V", "Noise Voltage",
+ RPC_PRIVLVL_MIN, DISPNULL)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_set<channel_model2, double>(
+ alias(), "timing",
+ &channel_model2::set_timing_offset,
+ pmt::mp(0.0f), pmt::mp(2.0f), pmt::mp(0.0f),
+ "", "Timing Offset",
+ RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+ }
+
+ } /* namespace channels */
+} /* namespace gr */
diff --git a/gr-channels/lib/channel_model2_impl.h b/gr-channels/lib/channel_model2_impl.h
new file mode 100644
index 0000000000..db2a667f9c
--- /dev/null
+++ b/gr-channels/lib/channel_model2_impl.h
@@ -0,0 +1,76 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,2012,2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H
+#define INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H
+
+#include <gnuradio/channels/channel_model2.h>
+#include <gnuradio/top_block.h>
+#include <gnuradio/blocks/add_cc.h>
+#include <gnuradio/blocks/multiply_cc.h>
+#include <gnuradio/analog/sig_source_c.h>
+#include <gnuradio/analog/fastnoise_source_c.h>
+#include <gnuradio/filter/fractional_resampler_cc.h>
+#include <gnuradio/filter/fir_filter_ccc.h>
+#include <gnuradio/blocks/vco_c.h>
+
+namespace gr {
+ namespace channels {
+
+ class CHANNELS_API channel_model2_impl : public channel_model2
+ {
+ private:
+ blocks::add_cc::sptr d_noise_adder;
+ blocks::multiply_cc::sptr d_mixer_offset;
+
+ blocks::vco_c::sptr d_freq_gen;
+
+ analog::fastnoise_source_c::sptr d_noise;
+
+ filter::fractional_resampler_cc::sptr d_timing_offset;
+ filter::fir_filter_ccc::sptr d_multipath;
+
+ std::vector<gr_complex> d_taps;
+
+ public:
+ channel_model2_impl(double noise_voltage,
+ double epsilon,
+ const std::vector<gr_complex> &taps,
+ double noise_seed);
+
+ ~channel_model2_impl();
+
+ void setup_rpc();
+
+ void set_noise_voltage(double noise_voltage);
+ void set_taps(const std::vector<gr_complex> &taps);
+ void set_timing_offset(double epsilon);
+
+ double noise_voltage() const;
+ std::vector<gr_complex> taps() const;
+ double timing_offset() const;
+ };
+
+ } /* namespace channels */
+} /* namespace gr */
+
+#endif /* INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H */
diff --git a/gr-channels/python/channels/CMakeLists.txt b/gr-channels/python/channels/CMakeLists.txt
index 4ebf029b75..1f6f08bb69 100644
--- a/gr-channels/python/channels/CMakeLists.txt
+++ b/gr-channels/python/channels/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2012 Free Software Foundation, Inc.
+# Copyright 2012-2013 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -23,6 +23,15 @@ include(GrPython)
GR_PYTHON_INSTALL(
FILES
__init__.py
+ amp_bal.py
+ conj_fs_iqcorr.py
+ distortion_2_gen.py
+ distortion_3_gen.py
+ impairments.py
+ iqbal_gen.py
+ phase_bal.py
+ phase_noise_gen.py
+ quantizer.py
DESTINATION ${GR_PYTHON_DIR}/gnuradio/channels
COMPONENT "channels_python"
)
diff --git a/gr-channels/python/channels/__init__.py b/gr-channels/python/channels/__init__.py
index c4d3271f28..ae4c4ab715 100644
--- a/gr-channels/python/channels/__init__.py
+++ b/gr-channels/python/channels/__init__.py
@@ -1,5 +1,5 @@
#
-# Copyright 2012 Free Software Foundation, Inc.
+# Copyright 2012-2013 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -31,3 +31,14 @@ except ImportError:
dirname, filename = os.path.split(os.path.abspath(__file__))
__path__.append(os.path.join(dirname, "..", "..", "swig"))
from channels_swig import *
+
+# Blocks for Hardware Impairments
+from amp_bal import *
+from conj_fs_iqcorr import *
+from distortion_2_gen import *
+from distortion_3_gen import *
+from iqbal_gen import *
+from impairments import *
+from phase_bal import *
+from phase_noise_gen import *
+from quantizer import *
diff --git a/gr-channels/python/channels/amp_bal.py b/gr-channels/python/channels/amp_bal.py
new file mode 100644
index 0000000000..30e0f0d8e2
--- /dev/null
+++ b/gr-channels/python/channels/amp_bal.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Amplitude Balance
+# Author: mettus
+# Description: Restores IQ amplitude balance
+# Generated: Thu Aug 1 11:47:46 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+
+class amp_bal(gr.hier_block2):
+
+ def __init__(self, alpha=0):
+ gr.hier_block2.__init__(
+ self, "Amplitude Balance",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.alpha = alpha
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.blocks_rms_xx0 = blocks.rms_ff(alpha)
+ self.blocks_rms_xx = blocks.rms_ff(alpha)
+ self.blocks_multiply_vxx1 = blocks.multiply_vff(1)
+ self.blocks_float_to_complex = blocks.float_to_complex(1)
+ self.blocks_divide_xx = blocks.divide_ff(1)
+ self.blocks_complex_to_float = blocks.complex_to_float(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_float_to_complex, 0), (self, 0))
+ self.connect((self, 0), (self.blocks_complex_to_float, 0))
+ self.connect((self.blocks_complex_to_float, 0), (self.blocks_rms_xx, 0))
+ self.connect((self.blocks_complex_to_float, 1), (self.blocks_rms_xx0, 0))
+ self.connect((self.blocks_rms_xx, 0), (self.blocks_divide_xx, 0))
+ self.connect((self.blocks_rms_xx0, 0), (self.blocks_divide_xx, 1))
+ self.connect((self.blocks_complex_to_float, 0), (self.blocks_float_to_complex, 0))
+ self.connect((self.blocks_complex_to_float, 1), (self.blocks_multiply_vxx1, 1))
+ self.connect((self.blocks_divide_xx, 0), (self.blocks_multiply_vxx1, 0))
+ self.connect((self.blocks_multiply_vxx1, 0), (self.blocks_float_to_complex, 1))
+
+
+# QT sink close method reimplementation
+
+ def get_alpha(self):
+ return self.alpha
+
+ def set_alpha(self, alpha):
+ self.alpha = alpha
+ self.blocks_rms_xx.set_alpha(self.alpha)
+ self.blocks_rms_xx0.set_alpha(self.alpha)
+
+
diff --git a/gr-channels/python/channels/conj_fs_iqcorr.py b/gr-channels/python/channels/conj_fs_iqcorr.py
new file mode 100644
index 0000000000..700eb645c2
--- /dev/null
+++ b/gr-channels/python/channels/conj_fs_iqcorr.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Conj FS IQBal
+# Author: matt@ettus.com
+# Description: Frequency Selective Conjugate Method IQ Balance Corrector
+# Generated: Thu Aug 1 13:00:27 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.filter import firdes
+
+class conj_fs_iqcorr(gr.hier_block2):
+
+ def __init__(self, delay=0, taps=[]):
+ gr.hier_block2.__init__(
+ self, "Conj FS IQBal",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.delay = delay
+ self.taps = taps
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.filter_fir_filter_xxx_0 = filter.fir_filter_ccc(1, (taps))
+ self.delay_0 = blocks.delay(gr.sizeof_gr_complex*1, delay)
+ self.blocks_conjugate_cc_0 = blocks.conjugate_cc()
+ self.blocks_add_xx_0 = blocks.add_vcc(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_add_xx_0, 0), (self, 0))
+ self.connect((self, 0), (self.blocks_conjugate_cc_0, 0))
+ self.connect((self.filter_fir_filter_xxx_0, 0), (self.blocks_add_xx_0, 1))
+ self.connect((self.blocks_conjugate_cc_0, 0), (self.filter_fir_filter_xxx_0, 0))
+ self.connect((self, 0), (self.delay_0, 0))
+ self.connect((self.delay_0, 0), (self.blocks_add_xx_0, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_delay(self):
+ return self.delay
+
+ def set_delay(self, delay):
+ self.delay = delay
+ self.delay_0.set_dly(self.delay)
+
+ def get_taps(self):
+ return self.taps
+
+ def set_taps(self, taps):
+ self.taps = taps
+ self.filter_fir_filter_xxx_0.set_taps((self.taps))
+
+
diff --git a/gr-channels/python/channels/distortion_2_gen.py b/gr-channels/python/channels/distortion_2_gen.py
new file mode 100644
index 0000000000..f8933cf7aa
--- /dev/null
+++ b/gr-channels/python/channels/distortion_2_gen.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Second Order Distortion
+# Author: mettus
+# Generated: Thu Aug 1 12:30:23 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+import math
+
+class distortion_2_gen(gr.hier_block2):
+
+ def __init__(self, beta=0):
+ gr.hier_block2.__init__(
+ self, "Second Order Distortion",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.beta = beta
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1)
+ self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc((beta, ))
+ self.blocks_conjugate_cc_0 = blocks.conjugate_cc()
+ self.blocks_add_xx_0_0 = blocks.add_vcc(1)
+ self.blocks_add_xx_0 = blocks.add_vcc(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_add_xx_0, 1))
+ self.connect((self, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self, 0), (self.blocks_add_xx_0, 0))
+ self.connect((self.blocks_add_xx_0, 0), (self, 0))
+ self.connect((self, 0), (self.blocks_conjugate_cc_0, 0))
+ self.connect((self.blocks_conjugate_cc_0, 0), (self.blocks_multiply_xx_0_0, 1))
+ self.connect((self, 0), (self.blocks_multiply_xx_0, 1))
+ self.connect((self, 0), (self.blocks_multiply_xx_0_0, 0))
+ self.connect((self.blocks_multiply_xx_0_0, 0), (self.blocks_add_xx_0_0, 1))
+ self.connect((self.blocks_multiply_xx_0, 0), (self.blocks_add_xx_0_0, 0))
+ self.connect((self.blocks_add_xx_0_0, 0), (self.blocks_multiply_const_vxx_0, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_beta(self):
+ return self.beta
+
+ def set_beta(self, beta):
+ self.beta = beta
+ self.blocks_multiply_const_vxx_0.set_k((self.beta, ))
+
+
diff --git a/gr-channels/python/channels/distortion_3_gen.py b/gr-channels/python/channels/distortion_3_gen.py
new file mode 100644
index 0000000000..1607e01bf2
--- /dev/null
+++ b/gr-channels/python/channels/distortion_3_gen.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Third Order Distortion
+# Author: mettus
+# Generated: Thu Aug 1 12:37:59 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+import math
+
+class distortion_3_gen(gr.hier_block2):
+
+ def __init__(self, beta=0):
+ gr.hier_block2.__init__(
+ self, "Third Order Distortion",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.beta = beta
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.blocks_null_source_0 = blocks.null_source(gr.sizeof_float*1)
+ self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc((beta, ))
+ self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
+ self.blocks_complex_to_mag_squared_0 = blocks.complex_to_mag_squared(1)
+ self.blocks_add_xx_0 = blocks.add_vcc(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_float_to_complex_0, 0), (self.blocks_multiply_xx_0, 1))
+ self.connect((self.blocks_null_source_0, 0), (self.blocks_float_to_complex_0, 1))
+ self.connect((self.blocks_complex_to_mag_squared_0, 0), (self.blocks_float_to_complex_0, 0))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_add_xx_0, 1))
+ self.connect((self.blocks_multiply_xx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
+ self.connect((self, 0), (self.blocks_complex_to_mag_squared_0, 0))
+ self.connect((self, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self, 0), (self.blocks_add_xx_0, 0))
+ self.connect((self.blocks_add_xx_0, 0), (self, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_beta(self):
+ return self.beta
+
+ def set_beta(self, beta):
+ self.beta = beta
+ self.blocks_multiply_const_vxx_0.set_k((self.beta, ))
+
+
diff --git a/gr-channels/python/channels/impairments.py b/gr-channels/python/channels/impairments.py
new file mode 100644
index 0000000000..3da838a902
--- /dev/null
+++ b/gr-channels/python/channels/impairments.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Radio Impairments Model
+# Author: mettus
+# Generated: Thu Aug 1 12:46:10 2013
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+import math
+
+#Import locally
+from phase_noise_gen import *
+from iqbal_gen import *
+from distortion_2_gen import *
+from distortion_3_gen import *
+
+class impairments(gr.hier_block2):
+
+ def __init__(self, phase_noise_mag=0, magbal=0, phasebal=0, q_ofs=0, i_ofs=0, freq_offset=0, gamma=0, beta=0):
+ gr.hier_block2.__init__(
+ self, "Radio Impairments Model",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.phase_noise_mag = phase_noise_mag
+ self.magbal = magbal
+ self.phasebal = phasebal
+ self.q_ofs = q_ofs
+ self.i_ofs = i_ofs
+ self.freq_offset = freq_offset
+ self.gamma = gamma
+ self.beta = beta
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.channels_phase_noise_gen_0_0 = phase_noise_gen(math.pow(10.0,phase_noise_mag/20.0), .01)
+ self.channels_iqbal_gen_0 = iqbal_gen(magbal, phasebal)
+ self.channels_distortion_3_gen_0 = distortion_3_gen(beta)
+ self.channels_distortion_2_gen_0 = distortion_2_gen(gamma)
+ self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1)
+ self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
+ self.blocks_conjugate_cc_0 = blocks.conjugate_cc()
+ self.blocks_add_const_vxx_0 = blocks.add_const_vcc((i_ofs + q_ofs* 1j, ))
+ self.analog_sig_source_x_0 = analog.sig_source_c(1.0, analog.GR_COS_WAVE, freq_offset, 1, 0)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.channels_phase_noise_gen_0_0, 0), (self.channels_distortion_3_gen_0, 0))
+ self.connect((self.blocks_multiply_xx_0, 0), (self, 0))
+ self.connect((self.blocks_add_const_vxx_0, 0), (self.blocks_multiply_xx_0, 1))
+ self.connect((self.analog_sig_source_x_0, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self.blocks_multiply_xx_0_0, 0), (self.channels_phase_noise_gen_0_0, 0))
+ self.connect((self.analog_sig_source_x_0, 0), (self.blocks_conjugate_cc_0, 0))
+ self.connect((self, 0), (self.blocks_multiply_xx_0_0, 1))
+ self.connect((self.blocks_conjugate_cc_0, 0), (self.blocks_multiply_xx_0_0, 0))
+ self.connect((self.channels_iqbal_gen_0, 0), (self.blocks_add_const_vxx_0, 0))
+ self.connect((self.channels_distortion_3_gen_0, 0), (self.channels_distortion_2_gen_0, 0))
+ self.connect((self.channels_distortion_2_gen_0, 0), (self.channels_iqbal_gen_0, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_phase_noise_mag(self):
+ return self.phase_noise_mag
+
+ def set_phase_noise_mag(self, phase_noise_mag):
+ self.phase_noise_mag = phase_noise_mag
+ self.channels_phase_noise_gen_0_0.set_noise_mag(math.pow(10.0,self.phase_noise_mag/20.0))
+
+ def get_magbal(self):
+ return self.magbal
+
+ def set_magbal(self, magbal):
+ self.magbal = magbal
+ self.channels_iqbal_gen_0.set_magnitude(self.magbal)
+
+ def get_phasebal(self):
+ return self.phasebal
+
+ def set_phasebal(self, phasebal):
+ self.phasebal = phasebal
+ self.channels_iqbal_gen_0.set_phase(self.phasebal)
+
+ def get_q_ofs(self):
+ return self.q_ofs
+
+ def set_q_ofs(self, q_ofs):
+ self.q_ofs = q_ofs
+ self.blocks_add_const_vxx_0.set_k((self.i_ofs + self.q_ofs* 1j, ))
+
+ def get_i_ofs(self):
+ return self.i_ofs
+
+ def set_i_ofs(self, i_ofs):
+ self.i_ofs = i_ofs
+ self.blocks_add_const_vxx_0.set_k((self.i_ofs + self.q_ofs* 1j, ))
+
+ def get_freq_offset(self):
+ return self.freq_offset
+
+ def set_freq_offset(self, freq_offset):
+ self.freq_offset = freq_offset
+ self.analog_sig_source_x_0.set_frequency(self.freq_offset)
+
+ def get_gamma(self):
+ return self.gamma
+
+ def set_gamma(self, gamma):
+ self.gamma = gamma
+ self.channels_distortion_2_gen_0.set_beta(self.gamma)
+
+ def get_beta(self):
+ return self.beta
+
+ def set_beta(self, beta):
+ self.beta = beta
+ self.channels_distortion_3_gen_0.set_beta(self.beta)
+
+
diff --git a/gr-channels/python/channels/iqbal_gen.py b/gr-channels/python/channels/iqbal_gen.py
new file mode 100644
index 0000000000..d42ca22778
--- /dev/null
+++ b/gr-channels/python/channels/iqbal_gen.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: IQ Imbalance Generator
+# Author: mettus
+# Generated: Thu Aug 1 12:08:07 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+import math
+
+class iqbal_gen(gr.hier_block2):
+
+ def __init__(self, magnitude=0, phase=0):
+ gr.hier_block2.__init__(
+ self, "IQ Imbalance Generator",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.magnitude = magnitude
+ self.phase = phase
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.mag = blocks.multiply_const_vff((math.pow(10,magnitude/20.0), ))
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vff((math.sin(phase*math.pi/180.0), ))
+ self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
+ self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
+ self.blocks_add_xx_0 = blocks.add_vff(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_float_to_complex_0, 0), (self, 0))
+ self.connect((self, 0), (self.blocks_complex_to_float_0, 0))
+ self.connect((self.blocks_complex_to_float_0, 0), (self.mag, 0))
+ self.connect((self.mag, 0), (self.blocks_float_to_complex_0, 0))
+ self.connect((self.blocks_add_xx_0, 0), (self.blocks_float_to_complex_0, 1))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_add_xx_0, 0))
+ self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_add_xx_0, 1))
+ self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_multiply_const_vxx_0, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_magnitude(self):
+ return self.magnitude
+
+ def set_magnitude(self, magnitude):
+ self.magnitude = magnitude
+ self.mag.set_k((math.pow(10,self.magnitude/20.0), ))
+
+ def get_phase(self):
+ return self.phase
+
+ def set_phase(self, phase):
+ self.phase = phase
+ self.blocks_multiply_const_vxx_0.set_k((math.sin(self.phase*math.pi/180.0), ))
+
+
diff --git a/gr-channels/python/channels/phase_bal.py b/gr-channels/python/channels/phase_bal.py
new file mode 100644
index 0000000000..b760e6f439
--- /dev/null
+++ b/gr-channels/python/channels/phase_bal.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: IQ Phase Balancer
+# Author: matt@ettus.com
+# Generated: Thu Aug 1 11:49:41 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.filter import firdes
+
+class phase_bal(gr.hier_block2):
+
+ def __init__(self, alpha=0):
+ gr.hier_block2.__init__(
+ self, "IQ Phase Balancer",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.alpha = alpha
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.filter_single_pole_iir_filter_xx_0 = filter.single_pole_iir_filter_ff(alpha, 1)
+ self.blocks_sub_xx_1 = blocks.sub_ff(1)
+ self.blocks_sub_xx_0 = blocks.sub_ff(1)
+ self.blocks_multiply_xx_2 = blocks.multiply_vff(1)
+ self.blocks_multiply_xx_1 = blocks.multiply_vff(1)
+ self.blocks_multiply_xx_0 = blocks.multiply_vff(1)
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vff((2, ))
+ self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
+ self.blocks_divide_xx_0 = blocks.divide_ff(1)
+ self.blocks_complex_to_mag_squared_0 = blocks.complex_to_mag_squared(1)
+ self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_multiply_xx_0, 1))
+ self.connect((self.blocks_multiply_xx_0, 0), (self.blocks_divide_xx_0, 0))
+ self.connect((self.blocks_sub_xx_0, 0), (self.blocks_float_to_complex_0, 1))
+ self.connect((self.blocks_multiply_xx_1, 0), (self.blocks_sub_xx_0, 1))
+ self.connect((self.filter_single_pole_iir_filter_xx_0, 0), (self.blocks_multiply_xx_1, 1))
+ self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_multiply_xx_1, 0))
+ self.connect((self.blocks_multiply_xx_2, 0), (self.blocks_sub_xx_1, 1))
+ self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_sub_xx_0, 0))
+ self.connect((self.blocks_sub_xx_1, 0), (self.blocks_float_to_complex_0, 0))
+ self.connect((self.blocks_complex_to_mag_squared_0, 0), (self.blocks_divide_xx_0, 1))
+ self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_sub_xx_1, 0))
+ self.connect((self.blocks_divide_xx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.filter_single_pole_iir_filter_xx_0, 0))
+ self.connect((self, 0), (self.blocks_complex_to_float_0, 0))
+ self.connect((self, 0), (self.blocks_complex_to_mag_squared_0, 0))
+ self.connect((self.blocks_float_to_complex_0, 0), (self, 0))
+ self.connect((self.filter_single_pole_iir_filter_xx_0, 0), (self.blocks_multiply_xx_2, 0))
+ self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_multiply_xx_2, 1))
+
+
+# QT sink close method reimplementation
+
+ def get_alpha(self):
+ return self.alpha
+
+ def set_alpha(self, alpha):
+ self.alpha = alpha
+ self.filter_single_pole_iir_filter_xx_0.set_taps(self.alpha)
+
+
diff --git a/gr-channels/python/channels/phase_noise_gen.py b/gr-channels/python/channels/phase_noise_gen.py
new file mode 100644
index 0000000000..95c5676e40
--- /dev/null
+++ b/gr-channels/python/channels/phase_noise_gen.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Phase Noise Generator
+# Author: mettus
+# Generated: Thu Aug 1 11:59:39 2013
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.filter import firdes
+
+class phase_noise_gen(gr.hier_block2):
+
+ def __init__(self, noise_mag=0, alpha=0.1):
+ gr.hier_block2.__init__(
+ self, "Phase Noise Generator",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.noise_mag = noise_mag
+ self.alpha = alpha
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.filter_single_pole_iir_filter_xx_0 = filter.single_pole_iir_filter_ff(alpha, 1)
+ self.blocks_transcendental_0_0 = blocks.transcendental("sin", "float")
+ self.blocks_transcendental_0 = blocks.transcendental("cos", "float")
+ self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
+ self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
+ self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, noise_mag, 42)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_float_to_complex_0, 0), (self.blocks_multiply_xx_0, 1))
+ self.connect((self.analog_noise_source_x_0, 0), (self.filter_single_pole_iir_filter_xx_0, 0))
+ self.connect((self.blocks_multiply_xx_0, 0), (self, 0))
+ self.connect((self, 0), (self.blocks_multiply_xx_0, 0))
+ self.connect((self.filter_single_pole_iir_filter_xx_0, 0), (self.blocks_transcendental_0, 0))
+ self.connect((self.filter_single_pole_iir_filter_xx_0, 0), (self.blocks_transcendental_0_0, 0))
+ self.connect((self.blocks_transcendental_0, 0), (self.blocks_float_to_complex_0, 0))
+ self.connect((self.blocks_transcendental_0_0, 0), (self.blocks_float_to_complex_0, 1))
+
+
+# QT sink close method reimplementation
+
+ def get_noise_mag(self):
+ return self.noise_mag
+
+ def set_noise_mag(self, noise_mag):
+ self.noise_mag = noise_mag
+ self.analog_noise_source_x_0.set_amplitude(self.noise_mag)
+
+ def get_alpha(self):
+ return self.alpha
+
+ def set_alpha(self, alpha):
+ self.alpha = alpha
+ self.filter_single_pole_iir_filter_xx_0.set_taps(self.alpha)
+
+
diff --git a/gr-channels/python/channels/quantizer.py b/gr-channels/python/channels/quantizer.py
new file mode 100644
index 0000000000..a3d918c7c2
--- /dev/null
+++ b/gr-channels/python/channels/quantizer.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Quantizer
+# Generated: Thu Aug 1 11:09:51 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio.filter import firdes
+
+class quantizer(gr.hier_block2):
+
+ def __init__(self, bits=16):
+ gr.hier_block2.__init__(
+ self, "Quantizer",
+ gr.io_signature(1, 1, gr.sizeof_float*1),
+ gr.io_signature(1, 1, gr.sizeof_float*1),
+ )
+
+ ##################################################
+ # Parameters
+ ##################################################
+ self.bits = bits
+
+ ##################################################
+ # Blocks
+ ##################################################
+ self.blocks_short_to_float_0 = blocks.short_to_float(1, 1)
+ self.blocks_multiply_const_vxx_0_0 = blocks.multiply_const_vff((1.0/pow(2.0,bits-1.0), ))
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vff((pow(2,bits-1.0), ))
+ self.blocks_float_to_short_0 = blocks.float_to_short(1, 1)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.blocks_multiply_const_vxx_0_0, 0), (self, 0))
+ self.connect((self.blocks_short_to_float_0, 0), (self.blocks_multiply_const_vxx_0_0, 0))
+ self.connect((self.blocks_float_to_short_0, 0), (self.blocks_short_to_float_0, 0))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_float_to_short_0, 0))
+ self.connect((self, 0), (self.blocks_multiply_const_vxx_0, 0))
+
+
+# QT sink close method reimplementation
+
+ def get_bits(self):
+ return self.bits
+
+ def set_bits(self, bits):
+ self.bits = bits
+ self.blocks_multiply_const_vxx_0_0.set_k((1.0/pow(2.0,self.bits-1.0), ))
+ self.blocks_multiply_const_vxx_0.set_k((pow(2,self.bits-1.0), ))
+
+
diff --git a/gr-channels/swig/channels_swig.i b/gr-channels/swig/channels_swig.i
index fb7ada7dae..784a10a085 100644
--- a/gr-channels/swig/channels_swig.i
+++ b/gr-channels/swig/channels_swig.i
@@ -29,14 +29,17 @@
%{
#include "gnuradio/channels/channel_model.h"
+#include "gnuradio/channels/channel_model2.h"
#include "gnuradio/channels/fading_model.h"
#include "gnuradio/channels/selective_fading_model.h"
%}
%include "gnuradio/channels/channel_model.h"
+%include "gnuradio/channels/channel_model2.h"
%include "gnuradio/channels/fading_model.h"
%include "gnuradio/channels/selective_fading_model.h"
GR_SWIG_BLOCK_MAGIC2(channels, channel_model);
+GR_SWIG_BLOCK_MAGIC2(channels, channel_model2);
GR_SWIG_BLOCK_MAGIC2(channels, fading_model);
GR_SWIG_BLOCK_MAGIC2(channels, selective_fading_model);
diff --git a/gr-digital/examples/narrowband/benchmark_rx.py b/gr-digital/examples/narrowband/benchmark_rx.py
index 622773aac5..09d923fc6b 100755
--- a/gr-digital/examples/narrowband/benchmark_rx.py
+++ b/gr-digital/examples/narrowband/benchmark_rx.py
@@ -50,10 +50,10 @@ class my_top_block(gr.top_block):
symbol_rate = options.bitrate / demodulator(**args).bits_per_symbol()
self.source = uhd_receiver(options.args, symbol_rate,
- options.samples_per_symbol,
- options.rx_freq, options.rx_gain,
+ options.samples_per_symbol, options.rx_freq,
+ options.lo_offset, options.rx_gain,
options.spec, options.antenna,
- options.verbose)
+ options.clock_source, options.verbose)
options.samples_per_symbol = self.source._sps
elif(options.from_file is not None):
diff --git a/gr-digital/examples/narrowband/benchmark_tx.py b/gr-digital/examples/narrowband/benchmark_tx.py
index 11ad7ea26e..2cb74d5a77 100755
--- a/gr-digital/examples/narrowband/benchmark_tx.py
+++ b/gr-digital/examples/narrowband/benchmark_tx.py
@@ -49,10 +49,10 @@ class my_top_block(gr.top_block):
symbol_rate = options.bitrate / modulator(**args).bits_per_symbol()
self.sink = uhd_transmitter(options.args, symbol_rate,
- options.samples_per_symbol,
- options.tx_freq, options.tx_gain,
+ options.samples_per_symbol, options.tx_freq,
+ options.lo_offset, options.tx_gain,
options.spec, options.antenna,
- options.verbose)
+ options.clock_source, options.verbose)
options.samples_per_symbol = self.sink._sps
elif(options.to_file is not None):
diff --git a/gr-digital/examples/narrowband/uhd_interface.py b/gr-digital/examples/narrowband/uhd_interface.py
index fe022c731c..474e96f486 100644
--- a/gr-digital/examples/narrowband/uhd_interface.py
+++ b/gr-digital/examples/narrowband/uhd_interface.py
@@ -42,14 +42,18 @@ def add_freq_option(parser):
metavar="FREQ")
class uhd_interface:
- def __init__(self, istx, args, sym_rate, sps, freq=None,
- gain=None, spec=None, antenna=None):
+ def __init__(self, istx, args, sym_rate, sps, freq=None, lo_offset=None,
+ gain=None, spec=None, antenna=None, clock_source=None):
if(istx):
self.u = uhd.usrp_sink(device_addr=args, stream_args=uhd.stream_args('fc32'))
else:
self.u = uhd.usrp_source(device_addr=args, stream_args=uhd.stream_args('fc32'))
+ # Set clock source
+ if(clock_source):
+ self.u.set_clock_source(clock_source, 0)
+
# Set the subdevice spec
if(spec):
self.u.set_subdev_spec(spec, 0)
@@ -62,9 +66,10 @@ class uhd_interface:
self._ant = antenna
self._spec = spec
self._gain = self.set_gain(gain)
- self._freq = self.set_freq(freq)
-
+ self._lo_offset = lo_offset
+ self._freq = self.set_freq(freq, lo_offset)
self._rate, self._sps = self.set_sample_rate(sym_rate, sps)
+ self._clock_source = clock_source
def set_sample_rate(self, sym_rate, req_sps):
start_sps = req_sps
@@ -107,12 +112,12 @@ class uhd_interface:
self.u.set_gain(gain, 0)
return gain
- def set_freq(self, freq=None):
+ def set_freq(self, freq=None, lo_offset=None):
if(freq is None):
sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
sys.exit(1)
- r = self.u.set_center_freq(freq, 0)
+ r = self.u.set_center_freq(uhd.tune_request(freq, lo_offset))
if r:
return freq
else:
@@ -126,15 +131,15 @@ class uhd_interface:
#-------------------------------------------------------------------#
class uhd_transmitter(uhd_interface, gr.hier_block2):
- def __init__(self, args, sym_rate, sps, freq=None, gain=None,
- spec=None, antenna=None, verbose=False):
+ def __init__(self, args, sym_rate, sps, freq=None, lo_offset=None, gain=None,
+ spec=None, antenna=None, clock_source=None, verbose=False):
gr.hier_block2.__init__(self, "uhd_transmitter",
gr.io_signature(1,1,gr.sizeof_gr_complex),
gr.io_signature(0,0,0))
# Set up the UHD interface as a transmitter
uhd_interface.__init__(self, True, args, sym_rate, sps,
- freq, gain, spec, antenna)
+ freq, lo_offset, gain, spec, antenna, clock_source)
self.connect(self, self.u)
@@ -152,8 +157,12 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
parser.add_option("", "--tx-freq", type="eng_float", default=None,
help="set transmit frequency to FREQ [default=%default]",
metavar="FREQ")
+ parser.add_option("", "--lo-offset", type="eng_float", default=0,
+ help="set local oscillator offset in Hz (default is 0)")
parser.add_option("", "--tx-gain", type="eng_float", default=None,
help="set transmit gain in dB (default is midpoint)")
+ parser.add_option("-C", "--clock-source", type="string", default=None,
+ help="select clock source (e.g. 'external') [default=%default]")
parser.add_option("-v", "--verbose", action="store_true", default=False)
# Make a static method to call before instantiation
@@ -166,11 +175,12 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
print "\nUHD Transmitter:"
print "Args: %s" % (self._args)
print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
+ print "LO Offset: %sHz" % (eng_notation.num_to_str(self._lo_offset))
print "Gain: %f dB" % (self._gain)
print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
print "Antenna: %s" % (self._ant)
- print "Subdev Sec: %s" % (self._spec)
-
+ print "Subdev Spec: %s" % (self._spec)
+ print "Clock Source: %s" % (self._clock_source)
#-------------------------------------------------------------------#
# RECEIVER
@@ -178,15 +188,15 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
class uhd_receiver(uhd_interface, gr.hier_block2):
- def __init__(self, args, sym_rate, sps, freq=None, gain=None,
- spec=None, antenna=None, verbose=False):
+ def __init__(self, args, sym_rate, sps, freq=None, lo_offset=None, gain=None,
+ spec=None, antenna=None, clock_source=None, verbose=False):
gr.hier_block2.__init__(self, "uhd_receiver",
gr.io_signature(0,0,0),
gr.io_signature(1,1,gr.sizeof_gr_complex))
# Set up the UHD interface as a receiver
uhd_interface.__init__(self, False, args, sym_rate, sps,
- freq, gain, spec, antenna)
+ freq, lo_offset, gain, spec, antenna, clock_source)
self.connect(self.u, self)
@@ -204,8 +214,12 @@ class uhd_receiver(uhd_interface, gr.hier_block2):
parser.add_option("", "--rx-freq", type="eng_float", default=None,
help="set receive frequency to FREQ [default=%default]",
metavar="FREQ")
+ parser.add_option("", "--lo-offset", type="eng_float", default=0,
+ help="set local oscillator offset in Hz (default is 0)")
parser.add_option("", "--rx-gain", type="eng_float", default=None,
help="set receive gain in dB (default is midpoint)")
+ parser.add_option("-C", "--clock-source", type="string", default=None,
+ help="select clock source (e.g. 'external') [default=%default]")
if not parser.has_option("--verbose"):
parser.add_option("-v", "--verbose", action="store_true", default=False)
@@ -217,9 +231,12 @@ class uhd_receiver(uhd_interface, gr.hier_block2):
Prints information about the UHD transmitter
"""
print "\nUHD Receiver:"
- print "UHD Args: %s" % (self._args)
- print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
- print "Gain: %f dB" % (self._gain)
- print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
- print "Antenna: %s" % (self._ant)
- print "Spec: %s" % (self._spec)
+ print "UHD Args: %s" % (self._args)
+ print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
+ print "LO Offset: %sHz" % (eng_notation.num_to_str(self._lo_offset))
+ print "Gain: %f dB" % (self._gain)
+ print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
+ print "Antenna: %s" % (self._ant)
+ print "Spec: %s" % (self._spec)
+ print "Clock Source: %s" % (self._clock_source)
+
diff --git a/gr-digital/examples/ofdm/benchmark_rx.py b/gr-digital/examples/ofdm/benchmark_rx.py
index dbcd866ad2..fdf81176ac 100755
--- a/gr-digital/examples/ofdm/benchmark_rx.py
+++ b/gr-digital/examples/ofdm/benchmark_rx.py
@@ -40,10 +40,10 @@ class my_top_block(gr.top_block):
if(options.rx_freq is not None):
self.source = uhd_receiver(options.args,
- options.bandwidth,
- options.rx_freq, options.rx_gain,
+ options.bandwidth, options.rx_freq,
+ options.lo_offset, options.rx_gain,
options.spec, options.antenna,
- options.verbose)
+ options.clock_source, options.verbose)
elif(options.from_file is not None):
self.source = blocks.file_source(gr.sizeof_gr_complex, options.from_file)
else:
diff --git a/gr-digital/examples/ofdm/benchmark_tx.py b/gr-digital/examples/ofdm/benchmark_tx.py
index 2942178ccf..47dc80964a 100755
--- a/gr-digital/examples/ofdm/benchmark_tx.py
+++ b/gr-digital/examples/ofdm/benchmark_tx.py
@@ -39,10 +39,10 @@ class my_top_block(gr.top_block):
if(options.tx_freq is not None):
self.sink = uhd_transmitter(options.args,
- options.bandwidth,
- options.tx_freq, options.tx_gain,
+ options.bandwidth, options.tx_freq,
+ options.lo_offset, options.tx_gain,
options.spec, options.antenna,
- options.verbose)
+ options.clock_source, options.verbose)
elif(options.to_file is not None):
self.sink = blocks.file_sink(gr.sizeof_gr_complex, options.to_file)
else:
@@ -114,7 +114,8 @@ def main():
pktno += 1
send_pkt(eof=True)
- tb.wait() # wait for it to finish
+ time.sleep(2) # allow time for queued packets to be sent
+ tb.wait() # wait for it to finish
if __name__ == '__main__':
try:
diff --git a/gr-digital/examples/ofdm/uhd_interface.py b/gr-digital/examples/ofdm/uhd_interface.py
index e4b13955dc..5b4d707b07 100644
--- a/gr-digital/examples/ofdm/uhd_interface.py
+++ b/gr-digital/examples/ofdm/uhd_interface.py
@@ -42,14 +42,18 @@ def add_freq_option(parser):
metavar="FREQ")
class uhd_interface:
- def __init__(self, istx, args, bandwidth, freq=None,
- gain=None, spec=None, antenna=None):
+ def __init__(self, istx, args, bandwidth, freq=None, lo_offset=None,
+ gain=None, spec=None, antenna=None, clock_source=None):
if(istx):
self.u = uhd.usrp_sink(device_addr=args, stream_args=uhd.stream_args('fc32'))
else:
self.u = uhd.usrp_source(device_addr=args, stream_args=uhd.stream_args('fc32'))
+ # Set clock source to external.
+ if(clock_source):
+ self.u.set_clock_source(clock_source, 0)
+
# Set the subdevice spec
if(spec):
self.u.set_subdev_spec(spec, 0)
@@ -62,9 +66,10 @@ class uhd_interface:
self._ant = antenna
self._spec = spec
self._gain = self.set_gain(gain)
- self._freq = self.set_freq(freq)
-
+ self._lo_offset = lo_offset
+ self._freq = self.set_freq(freq, lo_offset)
self._rate = self.set_sample_rate(bandwidth)
+ self._clock_source = clock_source
def set_sample_rate(self, bandwidth):
self.u.set_samp_rate(bandwidth)
@@ -87,12 +92,13 @@ class uhd_interface:
self.u.set_gain(gain, 0)
return gain
- def set_freq(self, freq=None):
+ def set_freq(self, freq=None, lo_offset=None):
if(freq is None):
sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
sys.exit(1)
- r = self.u.set_center_freq(freq, 0)
+ r = self.u.set_center_freq(uhd.tune_request(freq, lo_offset))
+
if r:
return freq
else:
@@ -106,15 +112,15 @@ class uhd_interface:
#-------------------------------------------------------------------#
class uhd_transmitter(uhd_interface, gr.hier_block2):
- def __init__(self, args, bandwidth, freq=None, gain=None,
- spec=None, antenna=None, verbose=False):
+ def __init__(self, args, bandwidth, freq=None, lo_offset=None, gain=None,
+ spec=None, antenna=None, clock_source=None, verbose=False):
gr.hier_block2.__init__(self, "uhd_transmitter",
gr.io_signature(1,1,gr.sizeof_gr_complex),
gr.io_signature(0,0,0))
# Set up the UHD interface as a transmitter
uhd_interface.__init__(self, True, args, bandwidth,
- freq, gain, spec, antenna)
+ freq, lo_offset, gain, spec, antenna, clock_source)
self.connect(self, self.u)
@@ -132,8 +138,12 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
parser.add_option("", "--tx-freq", type="eng_float", default=None,
help="set transmit frequency to FREQ [default=%default]",
metavar="FREQ")
+ parser.add_option("", "--lo-offset", type="eng_float", default=0,
+ help="set local oscillator offset in Hz (default is 0)")
parser.add_option("", "--tx-gain", type="eng_float", default=None,
help="set transmit gain in dB (default is midpoint)")
+ parser.add_option("-C", "--clock-source", type="string", default=None,
+ help="select clock source (e.g. 'external') [default=%default]")
parser.add_option("-v", "--verbose", action="store_true", default=False)
# Make a static method to call before instantiation
@@ -144,12 +154,14 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
Prints information about the UHD transmitter
"""
print "\nUHD Transmitter:"
- print "UHD Args: %s" % (self._args)
- print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
- print "Gain: %f dB" % (self._gain)
- print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
- print "Antenna: %s" % (self._ant)
- print "Subdev Sec: %s" % (self._spec)
+ print "UHD Args: %s" % (self._args)
+ print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
+ print "LO Offset: %sHz" % (eng_notation.num_to_str(self._lo_offset))
+ print "Gain: %f dB" % (self._gain)
+ print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
+ print "Antenna: %s" % (self._ant)
+ print "Subdev Sec: %s" % (self._spec)
+ print "Clock Source: %s" % (self._clock_source)
@@ -159,15 +171,15 @@ class uhd_transmitter(uhd_interface, gr.hier_block2):
class uhd_receiver(uhd_interface, gr.hier_block2):
- def __init__(self, args, bandwidth, freq=None, gain=None,
- spec=None, antenna=None, verbose=False):
+ def __init__(self, args, bandwidth, freq=None, lo_offset=None, gain=None,
+ spec=None, antenna=None, clock_source=None, verbose=False):
gr.hier_block2.__init__(self, "uhd_receiver",
gr.io_signature(0,0,0),
gr.io_signature(1,1,gr.sizeof_gr_complex))
# Set up the UHD interface as a receiver
uhd_interface.__init__(self, False, args, bandwidth,
- freq, gain, spec, antenna)
+ freq, lo_offset, gain, spec, antenna, clock_source)
self.connect(self.u, self)
@@ -185,8 +197,12 @@ class uhd_receiver(uhd_interface, gr.hier_block2):
parser.add_option("", "--rx-freq", type="eng_float", default=None,
help="set receive frequency to FREQ [default=%default]",
metavar="FREQ")
+ parser.add_option("", "--lo-offset", type="eng_float", default=0,
+ help="set local oscillator offset in Hz (default is 0)")
parser.add_option("", "--rx-gain", type="eng_float", default=None,
help="set receive gain in dB (default is midpoint)")
+ parser.add_option("-C", "--clock-source", type="string", default=None,
+ help="select clock source (e.g. 'external') [default=%default]")
if not parser.has_option("--verbose"):
parser.add_option("-v", "--verbose", action="store_true", default=False)
@@ -198,10 +214,12 @@ class uhd_receiver(uhd_interface, gr.hier_block2):
Prints information about the UHD transmitter
"""
print "\nUHD Receiver:"
- print "UHD Args: %s" % (self._args)
- print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
- print "Gain: %f dB" % (self._gain)
- print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
- print "Antenna: %s" % (self._ant)
- print "Subdev Sec: %s" % (self._spec)
+ print "UHD Args: %s" % (self._args)
+ print "Freq: %sHz" % (eng_notation.num_to_str(self._freq))
+ print "LO Offset: %sHz" % (eng_notation.num_to_str(self._lo_offset))
+ print "Gain: %f dB" % (self._gain)
+ print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
+ print "Antenna: %s" % (self._ant)
+ print "Subdev Sec: %s" % (self._spec)
+ print "Clock Source: %s" % (self._clock_source)
diff --git a/gr-digital/include/gnuradio/digital/constellation.h b/gr-digital/include/gnuradio/digital/constellation.h
index f8b99bb9c5..6ee274dd04 100644
--- a/gr-digital/include/gnuradio/digital/constellation.h
+++ b/gr-digital/include/gnuradio/digital/constellation.h
@@ -154,7 +154,15 @@ namespace gr {
public:
typedef boost::shared_ptr<constellation_calcdist> sptr;
- // public constructor
+ /*!
+ * Make a general constellation object that calculates the Euclidean distance for hard decisions.
+ *
+ * \param constell List of constellation points (order of list matches pre_diff_code)
+ * \param pre_diff_code List of alphabet symbols (before applying any differential
+ * coding) (order of list matches constell)
+ * \param rotational_symmetry Number of rotations around unit circle that have the same representation.
+ * \param dimensionality Number of dimensions to the constellation.
+ */
static sptr make(std::vector<gr_complex> constell,
std::vector<int> pre_diff_code,
unsigned int rotational_symmetry,
@@ -236,7 +244,18 @@ namespace gr {
public:
typedef boost::shared_ptr<constellation_rect> sptr;
- // public constructor
+ /*!
+ * Make a rectangular constellation object.
+ *
+ * \param constell List of constellation points (order of list matches pre_diff_code)
+ * \param pre_diff_code List of alphabet symbols (before applying any differential
+ * coding) (order of list matches constell)
+ * \param rotational_symmetry Number of rotations around unit circle that have the same representation.
+ * \param real_sectors Number of sectors the real axis is split in to.
+ * \param imag_sectors Number of sectors the imag axis is split in to.
+ * \param width_real_sectors width of each real sector to calculate decision boundaries.
+ * \param width_imag_sectors width of each imag sector to calculate decision boundaries.
+ */
static constellation_rect::sptr make(std::vector<gr_complex> constell,
std::vector<int> pre_diff_code,
unsigned int rotational_symmetry,
diff --git a/gr-filter/grc/filter_fractional_resampler_xx.xml b/gr-filter/grc/filter_fractional_resampler_xx.xml
index 48d624d432..40957b889d 100644
--- a/gr-filter/grc/filter_fractional_resampler_xx.xml
+++ b/gr-filter/grc/filter_fractional_resampler_xx.xml
@@ -39,6 +39,11 @@
<name>in</name>
<type>$type</type>
</sink>
+ <sink>
+ <name>rate</name>
+ <type>float</type>
+ <optional>1</optional>
+ </sink>
<source>
<name>out</name>
<type>$type</type>
diff --git a/gr-filter/lib/fractional_resampler_cc_impl.cc b/gr-filter/lib/fractional_resampler_cc_impl.cc
index 27f139d813..b17e13638b 100644
--- a/gr-filter/lib/fractional_resampler_cc_impl.cc
+++ b/gr-filter/lib/fractional_resampler_cc_impl.cc
@@ -41,8 +41,8 @@ namespace gr {
fractional_resampler_cc_impl::fractional_resampler_cc_impl
(float phase_shift, float resamp_ratio)
: block("fractional_resampler_cc",
- io_signature::make(1, 1, sizeof(gr_complex)),
- io_signature::make(1, 1, sizeof(gr_complex))),
+ io_signature::make2(1, 2, sizeof(gr_complex), sizeof(float)),
+ io_signature::make(1, 1, sizeof(gr_complex))),
d_mu(phase_shift), d_mu_inc(resamp_ratio),
d_resamp(new mmse_fir_interpolator_cc())
{
@@ -82,19 +82,38 @@ namespace gr {
int ii = 0; // input index
int oo = 0; // output index
- while(oo < noutput_items) {
- out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
+ if(ninput_items.size() == 1) {
+ while(oo < noutput_items) {
+ out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
- double s = d_mu + d_mu_inc;
- double f = floor(s);
- int incr = (int)f;
- d_mu = s - f;
- ii += incr;
- }
+ double s = d_mu + d_mu_inc;
+ double f = floor(s);
+ int incr = (int)f;
+ d_mu = s - f;
+ ii += incr;
+ }
- consume_each(ii);
+ consume_each(ii);
+ return noutput_items;
+ }
- return noutput_items;
+ else {
+ const float *rr = (const float*)input_items[1];
+ while(oo < noutput_items) {
+ out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
+ d_mu_inc = rr[ii];
+
+ double s = d_mu + d_mu_inc;
+ double f = floor(s);
+ int incr = (int)f;
+ d_mu = s - f;
+ ii += incr;
+ }
+
+ set_relative_rate(1.0 / d_mu_inc);
+ consume_each(ii);
+ return noutput_items;
+ }
}
float
diff --git a/gr-filter/lib/fractional_resampler_ff_impl.cc b/gr-filter/lib/fractional_resampler_ff_impl.cc
index 61950d92c0..131ccaae4e 100644
--- a/gr-filter/lib/fractional_resampler_ff_impl.cc
+++ b/gr-filter/lib/fractional_resampler_ff_impl.cc
@@ -41,8 +41,8 @@ namespace gr {
fractional_resampler_ff_impl::fractional_resampler_ff_impl
(float phase_shift, float resamp_ratio)
: block("fractional_resampler_ff",
- io_signature::make(1, 1, sizeof(float)),
- io_signature::make(1, 1, sizeof(float))),
+ io_signature::make(1, 2, sizeof(float)),
+ io_signature::make(1, 1, sizeof(float))),
d_mu (phase_shift), d_mu_inc (resamp_ratio),
d_resamp(new mmse_fir_interpolator_ff())
{
@@ -82,19 +82,37 @@ namespace gr {
int ii = 0; // input index
int oo = 0; // output index
- while(oo < noutput_items) {
- out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
+ if(ninput_items.size() == 1) {
+ while(oo < noutput_items) {
+ out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
- double s = d_mu + d_mu_inc;
- double f = floor(s);
- int incr = (int)f;
- d_mu = s - f;
- ii += incr;
- }
-
- consume_each(ii);
+ double s = d_mu + d_mu_inc;
+ double f = floor(s);
+ int incr = (int)f;
+ d_mu = s - f;
+ ii += incr;
+ }
- return noutput_items;
+ consume_each(ii);
+ return noutput_items;
+ }
+ else {
+ const float *rr = (const float*)input_items[1];
+ while(oo < noutput_items) {
+ out[oo++] = d_resamp->interpolate(&in[ii], d_mu);
+ d_mu_inc = rr[ii];
+
+ double s = d_mu + d_mu_inc;
+ double f = floor(s);
+ int incr = (int)f;
+ d_mu = s - f;
+ ii += incr;
+ }
+
+ set_relative_rate(1.0 / d_mu_inc);
+ consume_each(ii);
+ return noutput_items;
+ }
}
float
diff --git a/gr-filter/python/filter/qa_fractional_resampler.py b/gr-filter/python/filter/qa_fractional_resampler.py
index 220ebd9e30..ea01cf7eef 100644
--- a/gr-filter/python/filter/qa_fractional_resampler.py
+++ b/gr-filter/python/filter/qa_fractional_resampler.py
@@ -35,6 +35,10 @@ def sig_source_c(samp_rate, freq, amp, N):
1j*math.sin(2.*math.pi*freq*x), t)
return y
+def const_source_f(amp, N):
+ y = N*[amp,]
+ return y
+
class test_fractional_resampler(gr_unittest.TestCase):
def setUp(self):
@@ -68,7 +72,6 @@ class test_fractional_resampler(gr_unittest.TestCase):
self.assertFloatTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
-
def test_002_cc(self):
N = 10000 # number of samples to use
fs = 1000 # baseband sampling rate
@@ -95,6 +98,62 @@ class test_fractional_resampler(gr_unittest.TestCase):
self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
+ def test_003_ff(self):
+ N = 10000 # number of samples to use
+ fs = 1000 # baseband sampling rate
+ rrate = 1.123 # resampling rate
+
+ freq = 10
+ data = sig_source_f(fs, freq, 1, N)
+ ctrl = const_source_f(rrate, N)
+ signal = blocks.vector_source_f(data)
+ control = blocks.vector_source_f(ctrl)
+ op = filter.fractional_resampler_ff(0, 1)
+ snk = blocks.vector_sink_f()
+
+ self.tb.connect(signal, op, snk)
+ self.tb.connect(control, (op,1))
+ self.tb.run()
+
+ Ntest = 5000
+ L = len(snk.data())
+ t = map(lambda x: float(x)/(fs/rrate), xrange(L))
+
+ phase = 0.1884
+ expected_data = map(lambda x: math.sin(2.*math.pi*freq*x+phase), t)
+
+ dst_data = snk.data()
+
+ self.assertFloatTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
+
+ def test_004_cc(self):
+ N = 10000 # number of samples to use
+ fs = 1000 # baseband sampling rate
+ rrate = 1.123 # resampling rate
+
+ freq = 10
+ data = sig_source_c(fs, freq, 1, N)
+ ctrl = const_source_f(rrate, N)
+ signal = blocks.vector_source_c(data)
+ control = blocks.vector_source_f(ctrl)
+ op = filter.fractional_resampler_cc(0.0, 1)
+ snk = blocks.vector_sink_c()
+
+ self.tb.connect(signal, op, snk)
+ self.tb.connect(control, (op,1))
+ self.tb.run()
+
+ Ntest = 5000
+ L = len(snk.data())
+ t = map(lambda x: float(x)/(fs/rrate), xrange(L))
+
+ phase = 0.1884
+ expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \
+ 1j*math.sin(2.*math.pi*freq*x+phase), t)
+
+ dst_data = snk.data()
+
+ self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
if __name__ == '__main__':
gr_unittest.run(test_fractional_resampler, "test_fractional_resampler.xml")
diff --git a/gr-qtgui/grc/qtgui_block_tree.xml b/gr-qtgui/grc/qtgui_block_tree.xml
index e9d57a664c..14516df71e 100644
--- a/gr-qtgui/grc/qtgui_block_tree.xml
+++ b/gr-qtgui/grc/qtgui_block_tree.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- Copyright 2012 Free Software Foundation, Inc.
+ Copyright 2012-2013 Free Software Foundation, Inc.
This file is part of GNU Radio
@@ -37,6 +37,7 @@
<block>qtgui_const_sink_x</block>
<block>qtgui_waterfall_sink_x</block>
<block>qtgui_time_raster_sink_x</block>
+ <block>qtgui_histogram_sink_x</block>
<block>qtgui_sink_x</block>
</cat>
</cat>
diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml
new file mode 100644
index 0000000000..8a810abab7
--- /dev/null
+++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##QT GUI Histogram Sink
+###################################################
+ -->
+<block>
+ <name>QT GUI Histogram Sink</name>
+ <key>qtgui_histogram_sink_x</key>
+ <import>from PyQt4 import Qt</import>
+ <import>from gnuradio import qtgui</import>
+ <import>import sip</import>
+ <make>#set $win = 'self._%s_win'%$id
+qtgui.histogram_sink_f(
+ $size,
+ $bins,
+ $xmin,
+ $xmax,
+ $name,
+ $nconnections
+)
+self.$(id).set_update_time($update_time)
+self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget)
+$(gui_hint()($win))</make>
+ <callback>set_update_time($update_time)</callback>
+ <callback>set_title($which, $title)</callback>
+ <callback>set_color($which, $color)</callback>
+ <callback>set_bins($bins)</callback>
+ <callback>set_x_axis($bins)</callback>
+ <param>
+ <name>Name</name>
+ <key>name</key>
+ <value>QT GUI Plot</value>
+ <type>string</type>
+ </param>
+ <param>
+ <name>Number of Points</name>
+ <key>size</key>
+ <value>1024</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Number of Bins</name>
+ <key>bins</key>
+ <value>100</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Min x-axis</name>
+ <key>xmin</key>
+ <value>-1</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Max x-axis</name>
+ <key>xmax</key>
+ <value>1</value>
+ <type>real</type>
+ </param>
+ <param>
+ <name>Number of Inputs</name>
+ <key>nconnections</key>
+ <value>1</value>
+ <type>int</type>
+ <hide>part</hide>
+ </param>
+ <param>
+ <name>Update Period</name>
+ <key>update_time</key>
+ <value>0.10</value>
+ <type>float</type>
+ <hide>part</hide>
+ </param>
+ <param>
+ <name>GUI Hint</name>
+ <key>gui_hint</key>
+ <value></value>
+ <type>gui_hint</type>
+ <hide>part</hide>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>float</type>
+ <nports>$nconnections</nports>
+ </sink>
+ <doc>
+The GUI hint can be used to position the widget within the application. \
+The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \
+Both the tab specification and the grid position are optional.
+ </doc>
+</block>
diff --git a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
index 8f95837fec..0d5cb58f5d 100644
--- a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
+++ b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
@@ -33,6 +33,9 @@ install(FILES
freq_sink_c.h
freq_sink_f.h
FrequencyDisplayPlot.h
+ histogram_sink_f.h
+ histogramdisplayform.h
+ HistogramDisplayPlot.h
plot_raster.h
plot_waterfall.h
qtgui_types.h
diff --git a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
index bafc712aac..895328ad6e 100644
--- a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
+++ b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
@@ -180,20 +180,21 @@ public:
// void PlotNewData(...);
public slots:
- void setYaxis(double min, double max);
- void setXaxis(double min, double max);
- void setLineLabel(int which, QString label);
- QString getLineLabel(int which);
- void setLineColor(int which, QColor color);
- QColor getLineColor(int which) const;
- void setLineWidth(int which, int width);
- int getLineWidth(int which) const;
- void setLineStyle(int which, Qt::PenStyle style);
- const Qt::PenStyle getLineStyle(int which) const;
- void setLineMarker(int which, QwtSymbol::Style marker);
- const QwtSymbol::Style getLineMarker(int which) const;
- void setMarkerAlpha(int which, int alpha);
- int getMarkerAlpha(int which) const;
+ virtual void setYaxis(double min, double max);
+ virtual void setXaxis(double min, double max);
+ virtual void setLineLabel(int which, QString label);
+ virtual QString getLineLabel(int which);
+ virtual void setLineColor(int which, QColor color);
+ virtual QColor getLineColor(int which) const;
+ virtual void setLineWidth(int which, int width);
+ virtual int getLineWidth(int which) const;
+ virtual void setLineStyle(int which, Qt::PenStyle style);
+ virtual const Qt::PenStyle getLineStyle(int which) const;
+ virtual void setLineMarker(int which, QwtSymbol::Style marker);
+ virtual const QwtSymbol::Style getLineMarker(int which) const;
+ virtual void setMarkerAlpha(int which, int alpha);
+ virtual int getMarkerAlpha(int which) const;
+
// Need a function for each curve for setting via stylesheet.
// Can't use preprocessor directives because we're inside a Q_OBJECT.
void setLineColor1 (QColor);
diff --git a/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h
new file mode 100644
index 0000000000..bcf7272691
--- /dev/null
+++ b/gr-qtgui/include/gnuradio/qtgui/HistogramDisplayPlot.h
@@ -0,0 +1,74 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef HISTOGRAM_DISPLAY_PLOT_H
+#define HISTOGRAM_DISPLAY_PLOT_H
+
+#include <stdint.h>
+#include <cstdio>
+#include <vector>
+#include <gnuradio/qtgui/DisplayPlot.h>
+
+/*!
+ * \brief QWidget for displaying time domain plots.
+ * \ingroup qtgui_blk
+ */
+class HistogramDisplayPlot: public DisplayPlot
+{
+ Q_OBJECT
+
+public:
+ HistogramDisplayPlot(int nplots, QWidget*);
+ virtual ~HistogramDisplayPlot();
+
+ void plotNewData(const std::vector<double*> dataPoints,
+ const int64_t numDataPoints, const double timeInterval);
+
+ void replot();
+
+public slots:
+ void setAutoScale(bool state);
+ void setSemilogx(bool en);
+ void setSemilogy(bool en);
+ void setAccumulate(bool en);
+
+ void setMarkerAlpha(int which, int alpha);
+ int getMarkerAlpha(int which) const;
+ void setLineColor(int which, QColor color);
+
+ void setNumBins(int bins);
+
+private:
+ void _resetXAxisPoints(double bottom, double top);
+ void _autoScale(double bottom, double top);
+
+ double* _xAxisPoints;
+ std::vector<double*> _yDataPoints;
+
+ int _bins;
+ bool _accum;
+
+ bool d_semilogx;
+ bool d_semilogy;
+};
+
+#endif /* HISTOGRAM_DISPLAY_PLOT_H */
diff --git a/gr-qtgui/include/gnuradio/qtgui/displayform.h b/gr-qtgui/include/gnuradio/qtgui/displayform.h
index f94bb7fd04..54f878dc47 100644
--- a/gr-qtgui/include/gnuradio/qtgui/displayform.h
+++ b/gr-qtgui/include/gnuradio/qtgui/displayform.h
@@ -77,7 +77,7 @@ public slots:
QwtSymbol::Style lineMarker(int which);
int markerAlpha(int which);
- virtual void setSampleRate(const QString &rate) = 0;
+ virtual void setSampleRate(const QString &rate);
void setStop(bool on);
void setStop();
diff --git a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
new file mode 100644
index 0000000000..82fbca64f5
--- /dev/null
+++ b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
@@ -0,0 +1,108 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_QTGUI_HISTOGRAM_SINK_F_H
+#define INCLUDED_QTGUI_HISTOGRAM_SINK_F_H
+
+#include <Python.h>
+#include <gnuradio/qtgui/api.h>
+#include <gnuradio/sync_block.h>
+#include <qapplication.h>
+
+namespace gr {
+ namespace qtgui {
+
+ /*!
+ * \brief A graphical sink to display a histogram.
+ * \ingroup instrumentation_blk
+ * \ingroup qtgui_blk
+ *
+ * \details
+ * This is a QT-based graphical sink the displays a histogram of
+ * the data.
+ */
+ class QTGUI_API histogram_sink_f : virtual public sync_block
+ {
+ public:
+ // gr::qtgui::histogram_sink_f::sptr
+ typedef boost::shared_ptr<histogram_sink_f> sptr;
+
+ /*!
+ * \brief Build floating point histogram sink
+ *
+ * \param size number of points to plot at once
+ * \param bins number of bins to sort the data into
+ * \param xmin minimum x-axis value
+ * \param xmax maximum x-axis value
+ * \param name title for the plot
+ * \param nconnections number of signals connected to sink
+ * \param parent a QWidget parent object, if any
+ */
+ static sptr make(int size, int bins,
+ double xmin, double xmax,
+ const std::string &name,
+ int nconnections=1,
+ QWidget *parent=NULL);
+
+ virtual void exec_() = 0;
+ virtual PyObject* pyqwidget() = 0;
+
+ virtual void set_y_axis(double min, double max) = 0;
+ virtual void set_x_axis(double min, double max) = 0;
+ virtual void set_update_time(double t) = 0;
+ virtual void set_title(const std::string &title) = 0;
+ virtual void set_line_label(int which, const std::string &line) = 0;
+ virtual void set_line_color(int which, const std::string &color) = 0;
+ virtual void set_line_width(int which, int width) = 0;
+ virtual void set_line_style(int which, int style) = 0;
+ virtual void set_line_marker(int which, int marker) = 0;
+ virtual void set_line_alpha(int which, double alpha) = 0;
+ virtual void set_nsamps(const int newsize) = 0;
+ virtual void set_bins(const int bins) = 0;
+
+ virtual std::string title() = 0;
+ virtual std::string line_label(int which) = 0;
+ virtual std::string line_color(int which) = 0;
+ virtual int line_width(int which) = 0;
+ virtual int line_style(int which) = 0;
+ virtual int line_marker(int which) = 0;
+ virtual double line_alpha(int which) = 0;
+
+ virtual void set_size(int width, int height) = 0;
+
+ virtual void enable_menu(bool en=true) = 0;
+ virtual void enable_grid(bool en=true) = 0;
+ virtual void enable_autoscale(bool en=true) = 0;
+ virtual void enable_semilogx(bool en=true) = 0;
+ virtual void enable_semilogy(bool en=true) = 0;
+ virtual void enable_accumulate(bool en=true) = 0;
+ virtual int nsamps() const = 0;
+ virtual int bins() const = 0;
+ virtual void reset() = 0;
+
+ QApplication *d_qApplication;
+ };
+
+ } /* namespace qtgui */
+} /* namespace gr */
+
+#endif /* INCLUDED_QTGUI_HISTOGRAM_SINK_F_H */
diff --git a/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h
new file mode 100644
index 0000000000..b1a242ed99
--- /dev/null
+++ b/gr-qtgui/include/gnuradio/qtgui/histogramdisplayform.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef HISTOGRAM_DISPLAY_FORM_H
+#define HISTOGRAM_DISPLAY_FORM_H
+
+#include <gnuradio/qtgui/spectrumUpdateEvents.h>
+#include <gnuradio/qtgui/HistogramDisplayPlot.h>
+#include <QtGui/QtGui>
+#include <vector>
+
+#include <gnuradio/qtgui/displayform.h>
+
+/*!
+ * \brief DisplayForm child for managing histogram domain plots.
+ * \ingroup qtgui_blk
+ */
+class HistogramDisplayForm : public DisplayForm
+{
+ Q_OBJECT
+
+ public:
+ HistogramDisplayForm(int nplots=1, QWidget* parent = 0);
+ ~HistogramDisplayForm();
+
+ HistogramDisplayPlot* getPlot();
+
+ int getNPoints() const;
+
+public slots:
+ void customEvent(QEvent * e);
+
+ void setYaxis(double min, double max);
+ void setXaxis(double min, double max);
+ void setNPoints(const int);
+ void autoScale(bool en);
+ void setSemilogx(bool en);
+ void setSemilogy(bool en);
+
+ void setNumBins(const int);
+ void setAccumulate(bool en);
+
+private slots:
+ void newData(const QEvent*);
+
+private:
+ QIntValidator* _intValidator;
+
+ double _startFrequency;
+ double _stopFrequency;
+
+ int d_npoints;
+
+ bool d_semilogx;
+ bool d_semilogy;
+
+ QAction *d_semilogxmenu;
+ QAction *d_semilogymenu;
+};
+
+#endif /* HISTOGRAM_DISPLAY_FORM_H */
diff --git a/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h b/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h
index f3bb486d82..c1dbdafc26 100644
--- a/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h
+++ b/gr-qtgui/include/gnuradio/qtgui/spectrumUpdateEvents.h
@@ -262,4 +262,32 @@ private:
};
+/********************************************************************/
+
+
+class HistogramUpdateEvent: public QEvent
+{
+public:
+ HistogramUpdateEvent(const std::vector<double*> points,
+ const uint64_t npoints);
+
+ ~HistogramUpdateEvent();
+
+ int which() const;
+ const std::vector<double*> getDataPoints() const;
+ uint64_t getNumDataPoints() const;
+ bool getRepeatDataFlag() const;
+
+ static QEvent::Type Type()
+ { return QEvent::Type(SpectrumUpdateEventType); }
+
+protected:
+
+private:
+ size_t _nplots;
+ std::vector<double*> _points;
+ uint64_t _npoints;
+};
+
+
#endif /* SPECTRUM_UPDATE_EVENTS_H */
diff --git a/gr-qtgui/lib/CMakeLists.txt b/gr-qtgui/lib/CMakeLists.txt
index 2df8b31555..257f03a2a2 100644
--- a/gr-qtgui/lib/CMakeLists.txt
+++ b/gr-qtgui/lib/CMakeLists.txt
@@ -29,6 +29,7 @@ set(qtgui_moc_hdrs
${qtgui_mod_includedir}/freqdisplayform.h
${qtgui_mod_includedir}/constellationdisplayform.h
${qtgui_mod_includedir}/waterfalldisplayform.h
+ ${qtgui_mod_includedir}/histogramdisplayform.h
${qtgui_mod_includedir}/form_menus.h
${qtgui_mod_includedir}/DisplayPlot.h
${qtgui_mod_includedir}/FrequencyDisplayPlot.h
@@ -36,6 +37,7 @@ set(qtgui_moc_hdrs
${qtgui_mod_includedir}/TimeRasterDisplayPlot.h
${qtgui_mod_includedir}/WaterfallDisplayPlot.h
${qtgui_mod_includedir}/ConstellationDisplayPlot.h
+ ${qtgui_mod_includedir}/HistogramDisplayPlot.h
)
QT4_WRAP_CPP(qtgui_moc_srcs ${qtgui_moc_hdrs})
QT4_WRAP_UI(qtgui_ui_hdrs spectrumdisplayform.ui)
@@ -58,12 +60,14 @@ set(qtgui_srcs
WaterfallDisplayPlot.cc
waterfallGlobalData.cc
ConstellationDisplayPlot.cc
+ HistogramDisplayPlot.cc
spectrumdisplayform.cc
displayform.cc
timedisplayform.cc
timerasterdisplayform.cc
freqdisplayform.cc
constellationdisplayform.cc
+ histogramdisplayform.cc
waterfalldisplayform.cc
SpectrumGUIClass.cc
spectrumUpdateEvents.cc
@@ -80,6 +84,7 @@ set(qtgui_srcs
const_sink_c_impl.cc
waterfall_sink_c_impl.cc
waterfall_sink_f_impl.cc
+ histogram_sink_f_impl.cc
qtgui_util.cc
)
diff --git a/gr-qtgui/lib/ConstellationDisplayPlot.cc b/gr-qtgui/lib/ConstellationDisplayPlot.cc
index f483867776..f14016743f 100644
--- a/gr-qtgui/lib/ConstellationDisplayPlot.cc
+++ b/gr-qtgui/lib/ConstellationDisplayPlot.cc
@@ -80,6 +80,9 @@ ConstellationDisplayPlot::ConstellationDisplayPlot(int nplots, QWidget* parent)
_zoomer->setRubberBandPen(c);
_zoomer->setTrackerPen(c);
+ _magnifier->setAxisEnabled(QwtPlot::xBottom, true);
+ _magnifier->setAxisEnabled(QwtPlot::yLeft, true);
+
setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
set_xaxis(-2.0, 2.0);
setAxisTitle(QwtPlot::xBottom, "In-phase");
diff --git a/gr-qtgui/lib/HistogramDisplayPlot.cc b/gr-qtgui/lib/HistogramDisplayPlot.cc
new file mode 100644
index 0000000000..bcdab6b3f4
--- /dev/null
+++ b/gr-qtgui/lib/HistogramDisplayPlot.cc
@@ -0,0 +1,440 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef HISTOGRAM_DISPLAY_PLOT_C
+#define HISTOGRAM_DISPLAY_PLOT_C
+
+#include <gnuradio/qtgui/HistogramDisplayPlot.h>
+
+#include <qwt_scale_draw.h>
+#include <qwt_legend.h>
+#include <QColor>
+#include <cmath>
+#include <iostream>
+#include <volk/volk.h>
+#include <gnuradio/math.h>
+#include <boost/math/special_functions/round.hpp>
+
+class TimePrecisionClass
+{
+public:
+ TimePrecisionClass(const int timePrecision)
+ {
+ _timePrecision = timePrecision;
+ }
+
+ virtual ~TimePrecisionClass()
+ {
+ }
+
+ virtual unsigned int getTimePrecision() const
+ {
+ return _timePrecision;
+ }
+
+ virtual void setTimePrecision(const unsigned int newPrecision)
+ {
+ _timePrecision = newPrecision;
+ }
+protected:
+ unsigned int _timePrecision;
+};
+
+
+class HistogramDisplayZoomer: public QwtPlotZoomer, public TimePrecisionClass
+{
+public:
+ HistogramDisplayZoomer(QwtPlotCanvas* canvas, const unsigned int timePrecision)
+ : QwtPlotZoomer(canvas),TimePrecisionClass(timePrecision)
+ {
+ setTrackerMode(QwtPicker::AlwaysOn);
+ }
+
+ virtual ~HistogramDisplayZoomer()
+ {
+ }
+
+ virtual void updateTrackerText()
+ {
+ updateDisplay();
+ }
+
+ void setUnitType(const std::string &type)
+ {
+ _unitType = type;
+ }
+
+protected:
+ using QwtPlotZoomer::trackerText;
+ virtual QwtText trackerText(const QPoint& p) const
+ {
+ QwtText t;
+ QwtDoublePoint dp = QwtPlotZoomer::invTransform(p);
+ if((dp.y() > 0.0001) && (dp.y() < 10000)) {
+ t.setText(QString("%1, %2").
+ arg(dp.x(), 0, 'f', 4).
+ arg(dp.y(), 0, 'f', 0));
+ }
+ else {
+ t.setText(QString("%1, %2").
+ arg(dp.x(), 0, 'f', 4).
+ arg(dp.y(), 0, 'e', 0));
+ }
+
+ return t;
+ }
+
+private:
+ std::string _unitType;
+};
+
+
+/***********************************************************************
+ * Main Time domain plotter widget
+ **********************************************************************/
+HistogramDisplayPlot::HistogramDisplayPlot(int nplots, QWidget* parent)
+ : DisplayPlot(nplots, parent)
+{
+ _bins = 100;
+ _accum = false;
+
+ // Initialize x-axis data array
+ _xAxisPoints = new double[_bins];
+ memset(_xAxisPoints, 0x0, _bins*sizeof(double));
+
+ _zoomer = new HistogramDisplayZoomer(canvas(), 0);
+
+#if QWT_VERSION < 0x060000
+ _zoomer->setSelectionFlags(QwtPicker::RectSelection | QwtPicker::DragSelection);
+#endif
+
+ _zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
+ Qt::RightButton, Qt::ControlModifier);
+ _zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
+ Qt::RightButton);
+
+ const QColor c(Qt::darkRed);
+ _zoomer->setRubberBandPen(c);
+ _zoomer->setTrackerPen(c);
+
+ _magnifier->setAxisEnabled(QwtPlot::xBottom, true);
+ _magnifier->setAxisEnabled(QwtPlot::yLeft, false);
+
+ d_semilogx = false;
+ d_semilogy = false;
+
+ setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
+ setXaxis(-1, 1);
+ setAxisTitle(QwtPlot::xBottom, "Value");
+
+ setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
+ setYaxis(-2.0, _bins);
+ setAxisTitle(QwtPlot::yLeft, "Count");
+
+ QList<QColor> colors;
+ colors << QColor(Qt::blue) << QColor(Qt::red) << QColor(Qt::green)
+ << QColor(Qt::black) << QColor(Qt::cyan) << QColor(Qt::magenta)
+ << QColor(Qt::yellow) << QColor(Qt::gray) << QColor(Qt::darkRed)
+ << QColor(Qt::darkGreen) << QColor(Qt::darkBlue) << QColor(Qt::darkGray);
+
+ // Setup dataPoints and plot vectors
+ // Automatically deleted when parent is deleted
+ for(int i = 0; i < _nplots; i++) {
+ _yDataPoints.push_back(new double[_bins]);
+ memset(_yDataPoints[i], 0, _bins*sizeof(double));
+
+ _plot_curve.push_back(new QwtPlotCurve(QString("Data %1").arg(i)));
+ _plot_curve[i]->attach(this);
+ _plot_curve[i]->setPen(QPen(colors[i]));
+ _plot_curve[i]->setRenderHint(QwtPlotItem::RenderAntialiased);
+
+ // Adjust color's transparency for the brush
+ colors[i].setAlpha(127 / _nplots);
+ _plot_curve[i]->setBrush(QBrush(colors[i]));
+
+ colors[i].setAlpha(255 / _nplots);
+ QwtSymbol *symbol = new QwtSymbol(QwtSymbol::NoSymbol, QBrush(colors[i]),
+ QPen(colors[i]), QSize(7,7));
+
+#if QWT_VERSION < 0x060000
+ _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setSymbol(*symbol);
+#else
+ _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins);
+ _plot_curve[i]->setSymbol(symbol);
+#endif
+ }
+
+ _resetXAxisPoints(-1, 1);
+}
+
+HistogramDisplayPlot::~HistogramDisplayPlot()
+{
+ for(int i = 0; i < _nplots; i++)
+ delete[] _yDataPoints[i];
+ delete[] _xAxisPoints;
+
+ // _zoomer and _panner deleted when parent deleted
+}
+
+void
+HistogramDisplayPlot::replot()
+{
+ QwtPlot::replot();
+}
+
+void
+HistogramDisplayPlot::plotNewData(const std::vector<double*> dataPoints,
+ const int64_t numDataPoints,
+ const double timeInterval)
+{
+ if(!_stop) {
+ if((numDataPoints > 0)) {
+
+ double bottom = *std::min_element(dataPoints[0], dataPoints[0]+numDataPoints);
+ double top = *std::max_element(dataPoints[0], dataPoints[0]+numDataPoints);
+ for(int n = 1; n < _nplots; n++) {
+ bottom = std::min(bottom, *std::min_element(dataPoints[n], dataPoints[n]+numDataPoints));
+ top = std::max(top, *std::max_element(dataPoints[n], dataPoints[n]+numDataPoints));
+ }
+
+ _resetXAxisPoints(bottom, top);
+
+ int index;
+ double width = (top - bottom)/(_bins-1);
+
+ // Something's wrong with the data (NaN, Inf, or something else)
+ if((bottom == top) || (bottom > top))
+ return;
+
+ for(int n = 0; n < _nplots; n++) {
+ if(!_accum)
+ memset(_yDataPoints[n], 0, _bins*sizeof(double));
+ for(int64_t point = 0; point < numDataPoints; point++) {
+ index = boost::math::iround(1e-20 + (dataPoints[n][point] - bottom)/width);
+ index = std::max(std::min(index, _bins), 0);
+ _yDataPoints[n][static_cast<int>(index)] += 1;
+ }
+ }
+
+ double height = *std::max_element(_yDataPoints[0], _yDataPoints[0]+_bins);
+ for(int n = 1; n < _nplots; n++) {
+ height = std::max(height, *std::max_element(_yDataPoints[n], _yDataPoints[n]+_bins));
+ }
+ _autoScale(0, height);
+
+ replot();
+ }
+ }
+}
+
+void
+HistogramDisplayPlot::_resetXAxisPoints(double bottom, double top)
+{
+ double width = (top - bottom)/(_bins-1);
+ for(long loc = 0; loc < _bins; loc++){
+ _xAxisPoints[loc] = bottom + loc*width;
+ }
+
+ if(!_autoscale_state) {
+ bottom = axisScaleDiv(QwtPlot::xBottom)->lowerBound();
+ top = axisScaleDiv(QwtPlot::xBottom)->upperBound();
+ }
+
+ // Set up zoomer base for maximum unzoom x-axis
+ // and reset to maximum unzoom level
+ QwtDoubleRect zbase = _zoomer->zoomBase();
+
+ if(d_semilogx) {
+ setAxisScale(QwtPlot::xBottom, 1e-1, top);
+ zbase.setLeft(1e-1);
+ }
+ else {
+ setAxisScale(QwtPlot::xBottom, bottom, top);
+ zbase.setLeft(bottom);
+ }
+
+ zbase.setRight(top);
+ _zoomer->zoom(zbase);
+ _zoomer->setZoomBase(zbase);
+ _zoomer->zoom(0);
+}
+
+void
+HistogramDisplayPlot::_autoScale(double bottom, double top)
+{
+ // Auto scale the y-axis with a margin of 20% (10 dB for log scale)
+ double _bot = bottom - fabs(bottom)*0.20;
+ double _top = top + fabs(top)*0.20;
+ if(d_semilogy) {
+ if(bottom > 0) {
+ setYaxis(_bot-10, _top+10);
+ }
+ else {
+ setYaxis(1e-3, _top+10);
+ }
+ }
+ else {
+ setYaxis(_bot, _top);
+ }
+}
+
+void
+HistogramDisplayPlot::setAutoScale(bool state)
+{
+ _autoscale_state = state;
+}
+
+void
+HistogramDisplayPlot::setSemilogx(bool en)
+{
+ d_semilogx = en;
+ if(!d_semilogx) {
+ setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
+ }
+ else {
+ setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine);
+ }
+}
+
+void
+HistogramDisplayPlot::setSemilogy(bool en)
+{
+ if(d_semilogy != en) {
+ d_semilogy = en;
+ double max = axisScaleDiv(QwtPlot::yLeft)->upperBound();
+ if(!d_semilogy) {
+ setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
+ setYaxis(-pow(10.0, max/10.0), pow(10.0, max/10.0));
+ }
+ else {
+ setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
+ setYaxis(1e-10, 10.0*log10(100*max));
+ }
+ }
+}
+
+void
+HistogramDisplayPlot::setAccumulate(bool state)
+{
+ _accum = state;
+}
+
+void
+HistogramDisplayPlot::setMarkerAlpha(int which, int alpha)
+{
+ if(which < _nplots) {
+ // Get the pen color
+ QPen pen(_plot_curve[which]->pen());
+ QBrush brush(_plot_curve[which]->brush());
+ QColor color = brush.color();
+
+ // Set new alpha and update pen
+ color.setAlpha(alpha);
+ brush.setColor(color);
+ color.setAlpha(std::min(255, static_cast<int>(alpha*1.5)));
+ pen.setColor(color);
+ _plot_curve[which]->setBrush(brush);
+ _plot_curve[which]->setPen(pen);
+
+ // And set the new color for the markers
+#if QWT_VERSION < 0x060000
+ QwtSymbol sym = (QwtSymbol)_plot_curve[which]->symbol();
+ setLineMarker(which, sym.style());
+#else
+ QwtSymbol *sym = (QwtSymbol*)_plot_curve[which]->symbol();
+ if(sym) {
+ sym->setColor(color);
+ sym->setPen(pen);
+ _plot_curve[which]->setSymbol(sym);
+ }
+#endif
+ }
+}
+
+int
+HistogramDisplayPlot::getMarkerAlpha(int which) const
+{
+ if(which < _nplots) {
+ return _plot_curve[which]->brush().color().alpha();
+ }
+ else {
+ return 0;
+ }
+}
+
+void
+HistogramDisplayPlot::setLineColor(int which, QColor color)
+{
+ if(which < _nplots) {
+ // Adjust color's transparency for the brush
+ color.setAlpha(127 / _nplots);
+
+ QBrush brush(_plot_curve[which]->brush());
+ brush.setColor(color);
+ _plot_curve[which]->setBrush(brush);
+
+ // Adjust color's transparency darker for the pen and markers
+ color.setAlpha(255 / _nplots);
+
+ QPen pen(_plot_curve[which]->pen());
+ pen.setColor(color);
+ _plot_curve[which]->setPen(pen);
+
+#if QWT_VERSION < 0x060000
+ _plot_curve[which]->setPen(pen);
+ QwtSymbol sym = (QwtSymbol)_plot_curve[which]->symbol();
+ setLineMarker(which, sym.style());
+#else
+ QwtSymbol *sym = (QwtSymbol*)_plot_curve[which]->symbol();
+ if(sym) {
+ sym->setColor(color);
+ sym->setPen(pen);
+ _plot_curve[which]->setSymbol(sym);
+ }
+#endif
+ }
+}
+
+void
+HistogramDisplayPlot::setNumBins(int bins)
+{
+ _bins = bins;
+
+ delete [] _xAxisPoints;
+ _xAxisPoints = new double[_bins];
+ memset(_xAxisPoints, 0x0, _bins*sizeof(double));
+
+ for(int i = 0; i < _nplots; i++) {
+ delete [] _yDataPoints[i];
+ _yDataPoints[i] = new double[_bins];
+ memset(_yDataPoints[i], 0, _bins*sizeof(double));
+
+#if QWT_VERSION < 0x060000
+ _plot_curve[i]->setRawData(_xAxisPoints, _yDataPoints[i], _bins);
+#else
+ _plot_curve[i]->setRawSamples(_xAxisPoints, _yDataPoints[i], _bins);
+#endif
+ }
+}
+
+#endif /* HISTOGRAM_DISPLAY_PLOT_C */
diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc
index ecc878b0a8..ce83c96389 100644
--- a/gr-qtgui/lib/displayform.cc
+++ b/gr-qtgui/lib/displayform.cc
@@ -300,6 +300,11 @@ DisplayForm::markerAlpha(int which)
}
void
+DisplayForm::setSampleRate(const QString &rate)
+{
+}
+
+void
DisplayForm::setStop(bool on)
{
if(!on) {
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.cc b/gr-qtgui/lib/histogram_sink_f_impl.cc
new file mode 100644
index 0000000000..cd4012f4f5
--- /dev/null
+++ b/gr-qtgui/lib/histogram_sink_f_impl.cc
@@ -0,0 +1,391 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "histogram_sink_f_impl.h"
+#include <gnuradio/io_signature.h>
+#include <string.h>
+#include <volk/volk.h>
+#include <gnuradio/fft/fft.h>
+#include <qwt_symbol.h>
+
+namespace gr {
+ namespace qtgui {
+
+ histogram_sink_f::sptr
+ histogram_sink_f::make(int size, int bins,
+ double xmin, double xmax,
+ const std::string &name,
+ int nconnections,
+ QWidget *parent)
+ {
+ return gnuradio::get_initial_sptr
+ (new histogram_sink_f_impl(size, bins, xmin, xmax, name,
+ nconnections, parent));
+ }
+
+ histogram_sink_f_impl::histogram_sink_f_impl(int size, int bins,
+ double xmin, double xmax,
+ const std::string &name,
+ int nconnections,
+ QWidget *parent)
+ : sync_block("histogram_sink_f",
+ io_signature::make(nconnections, nconnections, sizeof(float)),
+ io_signature::make(0, 0, 0)),
+ d_size(size), d_bins(bins), d_xmin(xmin), d_xmax(xmax), d_name(name),
+ d_nconnections(nconnections), d_parent(parent)
+ {
+ d_main_gui = NULL;
+
+ d_index = 0;
+
+ for(int i = 0; i < d_nconnections; i++) {
+ d_residbufs.push_back(fft::malloc_double(d_size));
+ memset(d_residbufs[i], 0, d_size*sizeof(double));
+ }
+
+ // Set alignment properties for VOLK
+ const int alignment_multiple =
+ volk_get_alignment() / sizeof(gr_complex);
+ set_alignment(std::max(1,alignment_multiple));
+
+ initialize();
+ }
+
+ histogram_sink_f_impl::~histogram_sink_f_impl()
+ {
+ if(!d_main_gui->isClosed())
+ d_main_gui->close();
+
+ // d_main_gui is a qwidget destroyed with its parent
+ for(int i = 0; i < d_nconnections; i++) {
+ fft::free(d_residbufs[i]);
+ }
+ }
+
+ bool
+ histogram_sink_f_impl::check_topology(int ninputs, int noutputs)
+ {
+ return ninputs == d_nconnections;
+ }
+
+ void
+ histogram_sink_f_impl::initialize()
+ {
+ if(qApp != NULL) {
+ d_qApplication = qApp;
+ }
+ else {
+ int argc=0;
+ char **argv = NULL;
+ d_qApplication = new QApplication(argc, argv);
+ }
+
+ d_main_gui = new HistogramDisplayForm(d_nconnections, d_parent);
+ d_main_gui->setNumBins(d_bins);
+ d_main_gui->setNPoints(d_size);
+ d_main_gui->setXaxis(d_xmin, d_xmax);
+
+ // initialize update time to 10 times a second
+ set_update_time(0.1);
+ }
+
+ void
+ histogram_sink_f_impl::exec_()
+ {
+ d_qApplication->exec();
+ }
+
+ QWidget*
+ histogram_sink_f_impl::qwidget()
+ {
+ return d_main_gui;
+ }
+
+ PyObject*
+ histogram_sink_f_impl::pyqwidget()
+ {
+ PyObject *w = PyLong_FromVoidPtr((void*)d_main_gui);
+ PyObject *retarg = Py_BuildValue("N", w);
+ return retarg;
+ }
+
+ void
+ histogram_sink_f_impl::set_y_axis(double min, double max)
+ {
+ d_main_gui->setYaxis(min, max);
+ }
+
+ void
+ histogram_sink_f_impl::set_x_axis(double min, double max)
+ {
+ d_main_gui->setXaxis(min, max);
+ }
+
+ void
+ histogram_sink_f_impl::set_update_time(double t)
+ {
+ //convert update time to ticks
+ gr::high_res_timer_type tps = gr::high_res_timer_tps();
+ d_update_time = t * tps;
+ d_main_gui->setUpdateTime(t);
+ d_last_time = 0;
+ }
+
+ void
+ histogram_sink_f_impl::set_title(const std::string &title)
+ {
+ d_main_gui->setTitle(title.c_str());
+ }
+
+ void
+ histogram_sink_f_impl::set_line_label(int which, const std::string &label)
+ {
+ d_main_gui->setLineLabel(which, label.c_str());
+ }
+
+ void
+ histogram_sink_f_impl::set_line_color(int which, const std::string &color)
+ {
+ d_main_gui->setLineColor(which, color.c_str());
+ }
+
+ void
+ histogram_sink_f_impl::set_line_width(int which, int width)
+ {
+ d_main_gui->setLineWidth(which, width);
+ }
+
+ void
+ histogram_sink_f_impl::set_line_style(int which, int style)
+ {
+ d_main_gui->setLineStyle(which, (Qt::PenStyle)style);
+ }
+
+ void
+ histogram_sink_f_impl::set_line_marker(int which, int marker)
+ {
+ d_main_gui->setLineMarker(which, (QwtSymbol::Style)marker);
+ }
+
+ void
+ histogram_sink_f_impl::set_line_alpha(int which, double alpha)
+ {
+ d_main_gui->setMarkerAlpha(which, (int)(255.0*alpha));
+ }
+
+ void
+ histogram_sink_f_impl::set_size(int width, int height)
+ {
+ d_main_gui->resize(QSize(width, height));
+ }
+
+ std::string
+ histogram_sink_f_impl::title()
+ {
+ return d_main_gui->title().toStdString();
+ }
+
+ std::string
+ histogram_sink_f_impl::line_label(int which)
+ {
+ return d_main_gui->lineLabel(which).toStdString();
+ }
+
+ std::string
+ histogram_sink_f_impl::line_color(int which)
+ {
+ return d_main_gui->lineColor(which).toStdString();
+ }
+
+ int
+ histogram_sink_f_impl::line_width(int which)
+ {
+ return d_main_gui->lineWidth(which);
+ }
+
+ int
+ histogram_sink_f_impl::line_style(int which)
+ {
+ return d_main_gui->lineStyle(which);
+ }
+
+ int
+ histogram_sink_f_impl::line_marker(int which)
+ {
+ return d_main_gui->lineMarker(which);
+ }
+
+ double
+ histogram_sink_f_impl::line_alpha(int which)
+ {
+ return (double)(d_main_gui->markerAlpha(which))/255.0;
+ }
+
+ void
+ histogram_sink_f_impl::set_nsamps(const int newsize)
+ {
+ gr::thread::scoped_lock lock(d_mutex);
+
+ if(newsize != d_size) {
+ // Resize residbuf and replace data
+ for(int i = 0; i < d_nconnections; i++) {
+ fft::free(d_residbufs[i]);
+ d_residbufs[i] = fft::malloc_double(newsize);
+
+ memset(d_residbufs[i], 0, newsize*sizeof(double));
+ }
+
+ // Set new size and reset buffer index
+ // (throws away any currently held data, but who cares?)
+ d_size = newsize;
+ d_index = 0;
+
+ d_main_gui->setNPoints(d_size);
+ }
+ }
+
+ void
+ histogram_sink_f_impl::set_bins(const int bins)
+ {
+ gr::thread::scoped_lock lock(d_mutex);
+ d_bins = bins;
+ d_main_gui->setNumBins(d_bins);
+ }
+
+ int
+ histogram_sink_f_impl::nsamps() const
+ {
+ return d_size;
+ }
+
+ int
+ histogram_sink_f_impl::bins() const
+ {
+ return d_bins;
+ }
+
+ void
+ histogram_sink_f_impl::npoints_resize()
+ {
+ int newsize = d_main_gui->getNPoints();
+ set_nsamps(newsize);
+ }
+
+ void
+ histogram_sink_f_impl::enable_menu(bool en)
+ {
+ d_main_gui->enableMenu(en);
+ }
+
+ void
+ histogram_sink_f_impl::enable_grid(bool en)
+ {
+ d_main_gui->setGrid(en);
+ }
+
+ void
+ histogram_sink_f_impl::enable_autoscale(bool en)
+ {
+ d_main_gui->autoScale(en);
+ }
+
+ void
+ histogram_sink_f_impl::enable_semilogx(bool en)
+ {
+ d_main_gui->setSemilogx(en);
+ }
+
+ void
+ histogram_sink_f_impl::enable_semilogy(bool en)
+ {
+ d_main_gui->setSemilogy(en);
+ }
+
+ void
+ histogram_sink_f_impl::enable_accumulate(bool en)
+ {
+ d_main_gui->setAccumulate(en);
+ }
+
+ void
+ histogram_sink_f_impl::reset()
+ {
+ d_index = 0;
+ }
+
+ int
+ histogram_sink_f_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int n=0, j=0, idx=0;
+ const float *in = (const float*)input_items[idx];
+
+ npoints_resize();
+
+ for(int i=0; i < noutput_items; i+=d_size) {
+ unsigned int datasize = noutput_items - i;
+ unsigned int resid = d_size-d_index;
+ idx = 0;
+
+ // If we have enough input for one full plot, do it
+ if(datasize >= resid) {
+
+ // Fill up residbufs with d_size number of items
+ for(n = 0; n < d_nconnections; n++) {
+ in = (const float*)input_items[idx++];
+ volk_32f_convert_64f_u(&d_residbufs[n][d_index],
+ &in[j], resid);
+ }
+
+ // Update the plot if its time
+ if(gr::high_res_timer_now() - d_last_time > d_update_time) {
+ d_last_time = gr::high_res_timer_now();
+ d_qApplication->postEvent(d_main_gui,
+ new HistogramUpdateEvent(d_residbufs, d_size));
+ }
+
+ d_index = 0;
+ j += resid;
+ }
+ // Otherwise, copy what we received into the residbufs for next time
+ // because we set the output_multiple, this should never need to be called
+ else {
+ for(n = 0; n < d_nconnections; n++) {
+ in = (const float*)input_items[idx++];
+ volk_32f_convert_64f_u(&d_residbufs[n][d_index],
+ &in[j], datasize);
+ }
+ d_index += datasize;
+ j += datasize;
+ }
+ }
+
+ return j;
+ }
+
+ } /* namespace qtgui */
+} /* namespace gr */
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.h b/gr-qtgui/lib/histogram_sink_f_impl.h
new file mode 100644
index 0000000000..83c8558c1b
--- /dev/null
+++ b/gr-qtgui/lib/histogram_sink_f_impl.h
@@ -0,0 +1,113 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H
+#define INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H
+
+#include <gnuradio/qtgui/histogram_sink_f.h>
+#include <gnuradio/qtgui/histogramdisplayform.h>
+#include <gnuradio/thread/thread.h>
+#include <gnuradio/high_res_timer.h>
+
+namespace gr {
+ namespace qtgui {
+
+ class QTGUI_API histogram_sink_f_impl : public histogram_sink_f
+ {
+ private:
+ void initialize();
+
+ gr::thread::mutex d_mutex;
+
+ int d_size;
+ int d_bins;
+ double d_xmin, d_xmax;
+ std::string d_name;
+ int d_nconnections;
+
+ int d_index;
+ std::vector<double*> d_residbufs;
+
+ QWidget *d_parent;
+ HistogramDisplayForm *d_main_gui;
+
+ gr::high_res_timer_type d_update_time;
+ gr::high_res_timer_type d_last_time;
+
+ void npoints_resize();
+
+ public:
+ histogram_sink_f_impl(int size, int bins,
+ double xmin, double xmax,
+ const std::string &name,
+ int nconnections,
+ QWidget *parent=NULL);
+ ~histogram_sink_f_impl();
+
+ bool check_topology(int ninputs, int noutputs);
+
+ void exec_();
+ QWidget* qwidget();
+ PyObject* pyqwidget();
+
+ void set_y_axis(double min, double max);
+ void set_x_axis(double min, double max);
+ void set_update_time(double t);
+ void set_title(const std::string &title);
+ void set_line_label(int which, const std::string &label);
+ void set_line_color(int which, const std::string &color);
+ void set_line_width(int which, int width);
+ void set_line_style(int which, int style);
+ void set_line_marker(int which, int marker);
+ void set_line_alpha(int which, double alpha);
+ void set_nsamps(const int newsize);
+ void set_bins(const int bins);
+
+ std::string title();
+ std::string line_label(int which);
+ std::string line_color(int which);
+ int line_width(int which);
+ int line_style(int which);
+ int line_marker(int which);
+ double line_alpha(int which);
+
+ void set_size(int width, int height);
+
+ void enable_menu(bool en);
+ void enable_grid(bool en);
+ void enable_autoscale(bool en);
+ void enable_semilogx(bool en);
+ void enable_semilogy(bool en);
+ void enable_accumulate(bool en);
+ int nsamps() const;
+ int bins() const;
+ void reset();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace qtgui */
+} /* namespace gr */
+
+#endif /* INCLUDED_QTGUI_HISTOGRAM_SINK_F_IMPL_H */
diff --git a/gr-qtgui/lib/histogramdisplayform.cc b/gr-qtgui/lib/histogramdisplayform.cc
new file mode 100644
index 0000000000..a56ad86d3a
--- /dev/null
+++ b/gr-qtgui/lib/histogramdisplayform.cc
@@ -0,0 +1,174 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <cmath>
+#include <QMessageBox>
+#include <gnuradio/qtgui/histogramdisplayform.h>
+#include <iostream>
+
+HistogramDisplayForm::HistogramDisplayForm(int nplots, QWidget* parent)
+ : DisplayForm(nplots, parent)
+{
+ d_semilogx = false;
+ d_semilogy = false;
+
+ _intValidator = new QIntValidator(this);
+ _intValidator->setBottom(0);
+
+ _layout = new QGridLayout(this);
+ _displayPlot = new HistogramDisplayPlot(nplots, this);
+ _layout->addWidget(_displayPlot, 0, 0);
+ setLayout(_layout);
+
+ NPointsMenu *nptsmenu = new NPointsMenu(this);
+ _menu->addAction(nptsmenu);
+ connect(nptsmenu, SIGNAL(whichTrigger(int)),
+ this, SLOT(setNPoints(const int)));
+
+ NPointsMenu *nbinsmenu = new NPointsMenu(this);
+ nbinsmenu->setText("Number of Bins");
+ _menu->addAction(nbinsmenu);
+ connect(nbinsmenu, SIGNAL(whichTrigger(int)),
+ this, SLOT(setNumBins(const int)));
+
+ QAction *accummenu = new QAction("Accumulate", this);
+ accummenu->setCheckable(true);
+ _menu->addAction(accummenu);
+ connect(accummenu, SIGNAL(triggered(bool)),
+ this, SLOT(setAccumulate(bool)));
+
+// d_semilogxmenu = new QAction("Semilog X", this);
+// d_semilogxmenu->setCheckable(true);
+// _menu->addAction(d_semilogxmenu);
+// connect(d_semilogxmenu, SIGNAL(triggered(bool)),
+// this, SLOT(setSemilogx(bool)));
+//
+// d_semilogymenu = new QAction("Semilog Y", this);
+// d_semilogymenu->setCheckable(true);
+// _menu->addAction(d_semilogymenu);
+// connect(d_semilogymenu, SIGNAL(triggered(bool)),
+// this, SLOT(setSemilogy(bool)));
+
+ Reset();
+
+ connect(_displayPlot, SIGNAL(plotPointSelected(const QPointF)),
+ this, SLOT(onPlotPointSelected(const QPointF)));
+}
+
+HistogramDisplayForm::~HistogramDisplayForm()
+{
+ // Qt deletes children when parent is deleted
+
+ // Don't worry about deleting Display Plots - they are deleted when parents are deleted
+ delete _intValidator;
+}
+
+HistogramDisplayPlot*
+HistogramDisplayForm::getPlot()
+{
+ return ((HistogramDisplayPlot*)_displayPlot);
+}
+
+void
+HistogramDisplayForm::newData(const QEvent* updateEvent)
+{
+ HistogramUpdateEvent *hevent = (HistogramUpdateEvent*)updateEvent;
+ const std::vector<double*> dataPoints = hevent->getDataPoints();
+ const uint64_t numDataPoints = hevent->getNumDataPoints();
+
+ getPlot()->plotNewData(dataPoints,
+ numDataPoints,
+ d_update_time);
+}
+
+void
+HistogramDisplayForm::customEvent(QEvent * e)
+{
+ if(e->type() == HistogramUpdateEvent::Type()) {
+ newData(e);
+ }
+}
+
+void
+HistogramDisplayForm::setYaxis(double min, double max)
+{
+ getPlot()->setYaxis(min, max);
+}
+
+void
+HistogramDisplayForm::setXaxis(double min, double max)
+{
+ getPlot()->setXaxis(min, max);
+}
+
+int
+HistogramDisplayForm::getNPoints() const
+{
+ return d_npoints;
+}
+
+void
+HistogramDisplayForm::setNPoints(const int npoints)
+{
+ d_npoints = npoints;
+}
+
+void
+HistogramDisplayForm::autoScale(bool en)
+{
+ _autoscale_state = en;
+ _autoscale_act->setChecked(en);
+ getPlot()->setAutoScale(_autoscale_state);
+ getPlot()->replot();
+}
+
+void
+HistogramDisplayForm::setSemilogx(bool en)
+{
+ d_semilogx = en;
+ d_semilogxmenu->setChecked(en);
+ getPlot()->setSemilogx(d_semilogx);
+ getPlot()->replot();
+}
+
+void
+HistogramDisplayForm::setSemilogy(bool en)
+{
+ d_semilogy = en;
+ d_semilogymenu->setChecked(en);
+ getPlot()->setSemilogy(d_semilogy);
+ getPlot()->replot();
+}
+
+void
+HistogramDisplayForm::setNumBins(const int bins)
+{
+ getPlot()->setNumBins(bins);
+ getPlot()->replot();
+}
+
+void
+HistogramDisplayForm::setAccumulate(bool en)
+{
+ getPlot()->setAccumulate(en);
+ getPlot()->replot();
+}
diff --git a/gr-qtgui/lib/spectrumUpdateEvents.cc b/gr-qtgui/lib/spectrumUpdateEvents.cc
index 7d7f689f25..393cd3edec 100644
--- a/gr-qtgui/lib/spectrumUpdateEvents.cc
+++ b/gr-qtgui/lib/spectrumUpdateEvents.cc
@@ -439,4 +439,47 @@ TimeRasterUpdateEvent::getNumDataPoints() const
return _numDataPoints;
}
+/***************************************************************************/
+
+
+HistogramUpdateEvent::HistogramUpdateEvent(const std::vector<double*> points,
+ const uint64_t npoints)
+ : QEvent(QEvent::Type(SpectrumUpdateEventType))
+{
+ if(npoints < 1) {
+ _npoints = 1;
+ }
+ else {
+ _npoints = npoints;
+ }
+
+ _nplots = points.size();
+ for(size_t i = 0; i < _nplots; i++) {
+ _points.push_back(new double[_npoints]);
+ if(npoints > 0) {
+ memcpy(_points[i], points[i], _npoints*sizeof(double));
+ }
+ }
+}
+
+HistogramUpdateEvent::~HistogramUpdateEvent()
+{
+ for(size_t i = 0; i < _nplots; i++) {
+ delete[] _points[i];
+ }
+}
+
+const std::vector<double*>
+HistogramUpdateEvent::getDataPoints() const
+{
+ return _points;
+}
+
+uint64_t
+HistogramUpdateEvent::getNumDataPoints() const
+{
+ return _npoints;
+}
+
+
#endif /* SPECTRUM_UPDATE_EVENTS_C */
diff --git a/gr-qtgui/python/qtgui/qa_qtgui.py b/gr-qtgui/python/qtgui/qa_qtgui.py
index 51c0727de4..d98cf1fc28 100755
--- a/gr-qtgui/python/qtgui/qa_qtgui.py
+++ b/gr-qtgui/python/qtgui/qa_qtgui.py
@@ -77,5 +77,8 @@ class test_qtgui(gr_unittest.TestCase):
self.qtsnk = qtgui.time_raster_sink_f(1024, 100, 100.5,
[], [], "Test", 1)
+ def test12(self):
+ self.qtsnk = qtgui.histogram_sink_f(1024, 100, -1, 1, "Test", 1)
+
if __name__ == '__main__':
gr_unittest.run(test_qtgui, "test_qtgui.xml")
diff --git a/gr-qtgui/swig/qtgui_swig.i b/gr-qtgui/swig/qtgui_swig.i
index f974fa2e86..124c5ee7fc 100644
--- a/gr-qtgui/swig/qtgui_swig.i
+++ b/gr-qtgui/swig/qtgui_swig.i
@@ -46,6 +46,7 @@
#include "gnuradio/qtgui/const_sink_c.h"
#include "gnuradio/qtgui/waterfall_sink_c.h"
#include "gnuradio/qtgui/waterfall_sink_f.h"
+#include "gnuradio/qtgui/histogram_sink_f.h"
%}
%include "gnuradio/qtgui/sink_c.h"
@@ -59,6 +60,7 @@
%include "gnuradio/qtgui/const_sink_c.h"
%include "gnuradio/qtgui/waterfall_sink_c.h"
%include "gnuradio/qtgui/waterfall_sink_f.h"
+%include "gnuradio/qtgui/histogram_sink_f.h"
GR_SWIG_BLOCK_MAGIC2(qtgui, sink_c);
GR_SWIG_BLOCK_MAGIC2(qtgui, sink_f);
@@ -71,3 +73,4 @@ GR_SWIG_BLOCK_MAGIC2(qtgui, freq_sink_f);
GR_SWIG_BLOCK_MAGIC2(qtgui, const_sink_c);
GR_SWIG_BLOCK_MAGIC2(qtgui, waterfall_sink_c);
GR_SWIG_BLOCK_MAGIC2(qtgui, waterfall_sink_f);
+GR_SWIG_BLOCK_MAGIC2(qtgui, histogram_sink_f);
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index b7efa07623..02a89afc56 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -36,7 +36,11 @@ MAIN_TMPL = """\
\#if \$stream_args()
args=\$stream_args,
\#end if
+ \#if \$stream_chans()
+ channels=\$stream_chans,
+ \#else
channels=range(\$nchan),
+ \#end if
),
)
\#if \$clock_rate()
@@ -146,6 +150,19 @@ self.\$(id).set_bandwidth(\$bw$(n), $n)
</option>
</param>
<param>
+ <name>Stream channels</name>
+ <key>stream_chans</key>
+ <value>[]</value>
+ <type>int_vector</type>
+ <hide>
+ \#if \$stream_chans()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
<name>Device Addr</name>
<key>dev_addr</key>
<value></value>
diff --git a/gr-uhd/lib/gr_uhd_common.h b/gr-uhd/lib/gr_uhd_common.h
index 0c18fa4634..f6a0f91cad 100644
--- a/gr-uhd/lib/gr_uhd_common.h
+++ b/gr-uhd/lib/gr_uhd_common.h
@@ -49,4 +49,19 @@ namespace gr {
} /* namespace uhd */
} /* namespace gr */
+/*!
+ * The stream args ensure function sanitizes random user input.
+ * We may extend this to handle more things in the future,
+ * but ATM it ensures that the channels are initialized.
+ */
+static inline uhd::stream_args_t stream_args_ensure(const uhd::stream_args_t &args)
+{
+ uhd::stream_args_t sanitized = args;
+ if (sanitized.channels.empty())
+ {
+ sanitized.channels.push_back(0);
+ }
+ return sanitized;
+}
+
#endif /* INCLUDED_GR_UHD_COMMON_H */
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index d38ffc344d..828537fab3 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -55,7 +55,7 @@ namespace gr {
{
check_abi();
return usrp_sink::sptr
- (new usrp_sink_impl(device_addr, stream_args));
+ (new usrp_sink_impl(device_addr, stream_args_ensure(stream_args)));
}
usrp_sink_impl::usrp_sink_impl(const ::uhd::device_addr_t &device_addr,
@@ -64,7 +64,7 @@ namespace gr {
args_to_io_sig(stream_args),
io_signature::make(0, 0, 0)),
_stream_args(stream_args),
- _nchan(std::max<size_t>(1, stream_args.channels.size())),
+ _nchan(stream_args.channels.size()),
_stream_now(_nchan == 1),
_start_time_set(false)
{
@@ -82,6 +82,7 @@ namespace gr {
::uhd::dict<std::string, std::string>
usrp_sink_impl::get_usrp_info(size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_GET_USRP_INFO_API
return _dev->get_usrp_tx_info(chan);
#else
@@ -105,21 +106,24 @@ namespace gr {
void
usrp_sink_impl::set_samp_rate(double rate)
{
- _dev->set_tx_rate(rate);
+ BOOST_FOREACH(const size_t chan, _stream_args.channels)
+ {
+ _dev->set_tx_rate(rate, chan);
+ }
_sample_rate = this->get_samp_rate();
}
double
usrp_sink_impl::get_samp_rate(void)
{
- return _dev->get_tx_rate();
+ return _dev->get_tx_rate(_stream_args.channels[0]);
}
::uhd::meta_range_t
usrp_sink_impl::get_samp_rates(void)
{
#ifdef UHD_USRP_MULTI_USRP_GET_RATES_API
- return _dev->get_tx_rates();
+ return _dev->get_tx_rates(_stream_args.channels[0]);
#else
throw std::runtime_error("not implemented in this version");
#endif
@@ -129,24 +133,28 @@ namespace gr {
usrp_sink_impl::set_center_freq(const ::uhd::tune_request_t tune_request,
size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_tx_freq(tune_request, chan);
}
double
usrp_sink_impl::get_center_freq(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_freq(chan);
}
::uhd::freq_range_t
usrp_sink_impl::get_freq_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_freq_range(chan);
}
void
usrp_sink_impl::set_gain(double gain, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_tx_gain(gain, chan);
}
@@ -155,30 +163,35 @@ namespace gr {
const std::string &name,
size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_tx_gain(gain, name, chan);
}
double
usrp_sink_impl::get_gain(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_gain(chan);
}
double
usrp_sink_impl::get_gain(const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_gain(name, chan);
}
std::vector<std::string>
usrp_sink_impl::get_gain_names(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_gain_names(chan);
}
::uhd::gain_range_t
usrp_sink_impl::get_gain_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_gain_range(chan);
}
@@ -186,6 +199,7 @@ namespace gr {
usrp_sink_impl::get_gain_range(const std::string &name,
size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_gain_range(name, chan);
}
@@ -193,36 +207,42 @@ namespace gr {
usrp_sink_impl::set_antenna(const std::string &ant,
size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_tx_antenna(ant, chan);
}
std::string
usrp_sink_impl::get_antenna(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_antenna(chan);
}
std::vector<std::string>
usrp_sink_impl::get_antennas(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_antennas(chan);
}
void
usrp_sink_impl::set_bandwidth(double bandwidth, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_tx_bandwidth(bandwidth, chan);
}
double
usrp_sink_impl::get_bandwidth(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_bandwidth(chan);
}
::uhd::freq_range_t
usrp_sink_impl::get_bandwidth_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_bandwidth_range(chan);
}
@@ -230,6 +250,7 @@ namespace gr {
usrp_sink_impl::set_dc_offset(const std::complex<double> &offset,
size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
return _dev->set_tx_dc_offset(offset, chan);
#else
@@ -241,6 +262,7 @@ namespace gr {
usrp_sink_impl::set_iq_balance(const std::complex<double> &correction,
size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
return _dev->set_tx_iq_balance(correction, chan);
#else
@@ -251,12 +273,14 @@ namespace gr {
::uhd::sensor_value_t
usrp_sink_impl::get_sensor(const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_sensor(name, chan);
}
std::vector<std::string>
usrp_sink_impl::get_sensor_names(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_sensor_names(chan);
}
@@ -409,6 +433,7 @@ namespace gr {
::uhd::usrp::dboard_iface::sptr
usrp_sink_impl::get_dboard_iface(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_tx_dboard_iface(chan);
}
diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc
index c5df60222a..318bdb627d 100644
--- a/gr-uhd/lib/usrp_source_impl.cc
+++ b/gr-uhd/lib/usrp_source_impl.cc
@@ -58,7 +58,7 @@ namespace gr {
{
check_abi();
return usrp_source::sptr
- (new usrp_source_impl(device_addr, stream_args));
+ (new usrp_source_impl(device_addr, stream_args_ensure(stream_args)));
}
usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr,
@@ -67,7 +67,7 @@ namespace gr {
io_signature::make(0, 0, 0),
args_to_io_sig(stream_args)),
_stream_args(stream_args),
- _nchan(std::max<size_t>(1, stream_args.channels.size())),
+ _nchan(stream_args.channels.size()),
_stream_now(_nchan == 1),
_tag_now(false),
_start_time_set(false)
@@ -89,6 +89,7 @@ namespace gr {
::uhd::dict<std::string, std::string>
usrp_source_impl::get_usrp_info(size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_GET_USRP_INFO_API
return _dev->get_usrp_rx_info(chan);
#else
@@ -111,22 +112,25 @@ namespace gr {
void
usrp_source_impl::set_samp_rate(double rate)
{
- _dev->set_rx_rate(rate);
+ BOOST_FOREACH(const size_t chan, _stream_args.channels)
+ {
+ _dev->set_rx_rate(rate, chan);
+ }
_samp_rate = this->get_samp_rate();
_tag_now = true;
}
- double
+ double
usrp_source_impl::get_samp_rate(void)
{
- return _dev->get_rx_rate();
+ return _dev->get_rx_rate(_stream_args.channels[0]);
}
::uhd::meta_range_t
usrp_source_impl::get_samp_rates(void)
{
#ifdef UHD_USRP_MULTI_USRP_GET_RATES_API
- return _dev->get_rx_rates();
+ return _dev->get_rx_rates(_stream_args.channels[0]);
#else
throw std::runtime_error("not implemented in this version");
#endif
@@ -136,8 +140,10 @@ namespace gr {
usrp_source_impl::set_center_freq(const ::uhd::tune_request_t tune_request,
size_t chan)
{
+ const size_t user_chan = chan;
+ chan = _stream_args.channels[chan];
const ::uhd::tune_result_t res = _dev->set_rx_freq(tune_request, chan);
- _center_freq = this->get_center_freq(chan);
+ _center_freq = this->get_center_freq(user_chan);
_tag_now = true;
return res;
}
@@ -145,96 +151,112 @@ namespace gr {
double
usrp_source_impl::get_center_freq(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_freq(chan);
}
::uhd::freq_range_t
usrp_source_impl::get_freq_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_freq_range(chan);
}
void
usrp_source_impl::set_gain(double gain, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_rx_gain(gain, chan);
}
void
usrp_source_impl::set_gain(double gain, const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_rx_gain(gain, name, chan);
}
double
usrp_source_impl::get_gain(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_gain(chan);
}
double
usrp_source_impl::get_gain(const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_gain(name, chan);
}
std::vector<std::string>
usrp_source_impl::get_gain_names(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_gain_names(chan);
}
::uhd::gain_range_t
usrp_source_impl::get_gain_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_gain_range(chan);
}
::uhd::gain_range_t
usrp_source_impl::get_gain_range(const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_gain_range(name, chan);
}
void
usrp_source_impl::set_antenna(const std::string &ant, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_rx_antenna(ant, chan);
}
std::string
usrp_source_impl::get_antenna(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_antenna(chan);
}
std::vector<std::string>
usrp_source_impl::get_antennas(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_antennas(chan);
}
void
usrp_source_impl::set_bandwidth(double bandwidth, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->set_rx_bandwidth(bandwidth, chan);
}
double
usrp_source_impl::get_bandwidth(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_bandwidth(chan);
}
::uhd::freq_range_t
usrp_source_impl::get_bandwidth_range(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_bandwidth_range(chan);
}
void
usrp_source_impl::set_auto_dc_offset(const bool enable, size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
return _dev->set_rx_dc_offset(enable, chan);
#else
@@ -246,6 +268,7 @@ namespace gr {
usrp_source_impl::set_dc_offset(const std::complex<double> &offset,
size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
return _dev->set_rx_dc_offset(offset, chan);
#else
@@ -257,6 +280,7 @@ namespace gr {
usrp_source_impl::set_iq_balance(const std::complex<double> &correction,
size_t chan)
{
+ chan = _stream_args.channels[chan];
#ifdef UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
return _dev->set_rx_iq_balance(correction, chan);
#else
@@ -267,12 +291,14 @@ namespace gr {
::uhd::sensor_value_t
usrp_source_impl::get_sensor(const std::string &name, size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_sensor(name, chan);
}
std::vector<std::string>
usrp_source_impl::get_sensor_names(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_sensor_names(chan);
}
@@ -423,6 +449,7 @@ namespace gr {
::uhd::usrp::dboard_iface::sptr
usrp_source_impl::get_dboard_iface(size_t chan)
{
+ chan = _stream_args.channels[chan];
return _dev->get_rx_dboard_iface(chan);
}
@@ -455,7 +482,10 @@ namespace gr {
void
usrp_source_impl::issue_stream_cmd(const ::uhd::stream_cmd_t &cmd)
{
- _dev->issue_stream_cmd(cmd);
+ for (size_t i = 0; i < _stream_args.channels.size(); i++)
+ {
+ _dev->issue_stream_cmd(cmd, _stream_args.channels[i]);
+ }
}
bool
@@ -476,7 +506,7 @@ namespace gr {
else {
stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
}
- _dev->issue_stream_cmd(stream_cmd);
+ this->issue_stream_cmd(stream_cmd);
_tag_now = true;
return true;
}
@@ -507,7 +537,7 @@ namespace gr {
bool
usrp_source_impl::stop(void)
{
- _dev->issue_stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ this->issue_stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
this->flush();
@@ -551,7 +581,7 @@ namespace gr {
cmd.stream_now = _stream_now;
static const double reasonable_delay = 0.1; //order of magnitude over RTT
cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
- _dev->issue_stream_cmd(cmd);
+ this->issue_stream_cmd(cmd);
//receive samples until timeout
const size_t actual_num_samps = _rx_stream->recv
diff --git a/gr-utils/python/modtool/gr-newmod/cmake/Modules/FindGnuradioRuntime.cmake b/gr-utils/python/modtool/gr-newmod/cmake/Modules/FindGnuradioRuntime.cmake
index 2833fb1781..afed684a5e 100644
--- a/gr-utils/python/modtool/gr-newmod/cmake/Modules/FindGnuradioRuntime.cmake
+++ b/gr-utils/python/modtool/gr-newmod/cmake/Modules/FindGnuradioRuntime.cmake
@@ -31,5 +31,6 @@ if(PC_GNURADIO_RUNTIME_FOUND)
endif(PC_GNURADIO_RUNTIME_FOUND)
INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
+# do not check GNURADIO_RUNTIME_INCLUDE_DIRS, is not set when default include path us used.
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_RUNTIME DEFAULT_MSG GNURADIO_RUNTIME_LIBRARIES)
MARK_AS_ADVANCED(GNURADIO_RUNTIME_LIBRARIES GNURADIO_RUNTIME_INCLUDE_DIRS)
diff --git a/gr-utils/python/modtool/modtool_base.py b/gr-utils/python/modtool/modtool_base.py
index a03334bedc..081c10aaf9 100644
--- a/gr-utils/python/modtool/modtool_base.py
+++ b/gr-utils/python/modtool/modtool_base.py
@@ -131,7 +131,8 @@ class ModTool(object):
return False
for f in files:
if os.path.isfile(f) and f == 'CMakeLists.txt':
- if re.search('find_package\(GnuradioRuntime\)', open(f).read()) is not None:
+ if re.search('find_package\(GnuradioRuntime\)', open(f).read()) is not None or \
+ re.search('find_package\(Gnuradio(\s+[0-9".]+)?\)', open(f).read()) is not None:
self._info['version'] = '36' # Might be 37, check that later
has_makefile = True
elif re.search('GR_REGISTER_COMPONENT', open(f).read()) is not None:
diff --git a/gr-utils/python/modtool/templates.py b/gr-utils/python/modtool/templates.py
index 227a8d3971..47314891c0 100644
--- a/gr-utils/python/modtool/templates.py
+++ b/gr-utils/python/modtool/templates.py
@@ -228,8 +228,16 @@ namespace gr {
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
+#if $blocktype == 'source'
+#silent pass
+#else
const <+ITYPE+> *in = (const <+ITYPE+> *) input_items[0];
+#end if
+#if $blocktype == 'sink'
+#silent pass
+#else
<+OTYPE+> *out = (<+OTYPE+> *) output_items[0];
+#end if
// Do <+signal processing+>
diff --git a/grc/base/Block.py b/grc/base/Block.py
index 223f3183b7..9736c0ac44 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -22,256 +22,397 @@ from Element import Element
from Cheetah.Template import Template
from UserDict import UserDict
+from .. gui import Actions
class TemplateArg(UserDict):
- """
- A cheetah template argument created from a param.
- The str of this class evaluates to the param's to code method.
- The use of this class as a dictionary (enum only) will reveal the enum opts.
- The __call__ or () method can return the param evaluated to a raw python data type.
- """
-
- def __init__(self, param):
- UserDict.__init__(self)
- self._param = param
- if param.is_enum():
- for key in param.get_opt_keys():
- self[key] = str(param.get_opt(key))
-
- def __str__(self):
- return str(self._param.to_code())
-
- def __call__(self):
- return self._param.get_evaluated()
+ """
+ A cheetah template argument created from a param.
+ The str of this class evaluates to the param's to code method.
+ The use of this class as a dictionary (enum only) will reveal the enum opts.
+ The __call__ or () method can return the param evaluated to a raw python data type.
+ """
+
+ def __init__(self, param):
+ UserDict.__init__(self)
+ self._param = param
+ if param.is_enum():
+ for key in param.get_opt_keys():
+ self[key] = str(param.get_opt(key))
+
+ def __str__(self):
+ return str(self._param.to_code())
+
+ def __call__(self):
+ return self._param.get_evaluated()
def _get_keys(lst): return [elem.get_key() for elem in lst]
def _get_elem(lst, key):
- try: return lst[_get_keys(lst).index(key)]
- except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Block(Element):
- def __init__(self, flow_graph, n):
- """
- Make a new block from nested data.
-
- Args:
- flow: graph the parent element
- n: the nested odict
-
- Returns:
- block a new block
- """
- #build the block
- Element.__init__(self, flow_graph)
- #grab the data
- params = n.findall('param')
- sources = n.findall('source')
- sinks = n.findall('sink')
- self._name = n.find('name')
- self._key = n.find('key')
- self._category = n.find('category') or ''
- self._grc_source = n.find('grc_source') or ''
- self._block_wrapper_path = n.find('block_wrapper_path')
- #create the param objects
- self._params = list()
- #add the id param
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({
- 'name': 'ID',
- 'key': 'id',
- 'type': 'id',
- })
- ))
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({
- 'name': 'Enabled',
- 'key': '_enabled',
- 'type': 'raw',
- 'value': 'True',
- 'hide': 'all',
- })
- ))
- for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
- key = param.get_key()
- #test against repeated keys
- if key in self.get_param_keys():
- raise Exception, 'Key "%s" already exists in params'%key
- #store the param
- self.get_params().append(param)
- #create the source objects
- self._sources = list()
- for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
- key = source.get_key()
- #test against repeated keys
- if key in self.get_source_keys():
- raise Exception, 'Key "%s" already exists in sources'%key
- #store the port
- self.get_sources().append(source)
- #create the sink objects
- self._sinks = list()
- for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
- key = sink.get_key()
- #test against repeated keys
- if key in self.get_sink_keys():
- raise Exception, 'Key "%s" already exists in sinks'%key
- #store the port
- self.get_sinks().append(sink)
-
- def get_enabled(self):
- """
- Get the enabled state of the block.
-
- Returns:
- true for enabled
- """
- try: return eval(self.get_param('_enabled').get_value())
- except: return True
-
- def set_enabled(self, enabled):
- """
- Set the enabled state of the block.
-
- Args:
- enabled: true for enabled
- """
- self.get_param('_enabled').set_value(str(enabled))
-
- def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
-
- def get_id(self): return self.get_param('id').get_value()
- def is_block(self): return True
- def get_name(self): return self._name
- def get_key(self): return self._key
- def get_category(self): return self._category
- def get_doc(self): return ''
- def get_ports(self): return self.get_sources() + self.get_sinks()
- def get_children(self): return self.get_ports() + self.get_params()
- def get_block_wrapper_path(self): return self._block_wrapper_path
-
- ##############################################
- # Access Params
- ##############################################
- def get_param_keys(self): return _get_keys(self._params)
- def get_param(self, key): return _get_elem(self._params, key)
- def get_params(self): return self._params
-
- ##############################################
- # Access Sinks
- ##############################################
- def get_sink_keys(self): return _get_keys(self._sinks)
- def get_sink(self, key): return _get_elem(self._sinks, key)
- def get_sinks(self): return self._sinks
-
- ##############################################
- # Access Sources
- ##############################################
- def get_source_keys(self): return _get_keys(self._sources)
- def get_source(self, key): return _get_elem(self._sources, key)
- def get_sources(self): return self._sources
-
- def get_connections(self):
- return sum([port.get_connections() for port in self.get_ports()], [])
-
- def resolve_dependencies(self, tmpl):
- """
- Resolve a paramater dependency with cheetah templates.
-
- Args:
- tmpl: the string with dependencies
-
- Returns:
- the resolved value
- """
- tmpl = str(tmpl)
- if '$' not in tmpl: return tmpl
- n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
- try: return str(Template(tmpl, n))
- except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
-
- ##############################################
- # Controller Modify
- ##############################################
- def type_controller_modify(self, direction):
- """
- Change the type controller.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for change
- """
- changed = False
- type_param = None
- for param in filter(lambda p: p.is_enum(), self.get_params()):
- children = self.get_ports() + self.get_params()
- #priority to the type controller
- if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param
- #use param if type param is unset
- if not type_param: type_param = param
- if type_param:
- #try to increment the enum by direction
- try:
- keys = type_param.get_option_keys()
- old_index = keys.index(type_param.get_value())
- new_index = (old_index + direction + len(keys))%len(keys)
- type_param.set_value(keys[new_index])
- changed = True
- except: pass
- return changed
-
- def port_controller_modify(self, direction):
- """
- Change the port controller.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for change
- """
- return False
-
- ##############################################
- ## Import/Export Methods
- ##############################################
- def export_data(self):
- """
- Export this block's params to nested data.
-
- Returns:
- a nested data odict
- """
- n = odict()
- n['key'] = self.get_key()
- n['param'] = map(lambda p: p.export_data(), self.get_params())
- return n
-
- def import_data(self, n):
- """
- Import this block's params from nested data.
- Any param keys that do not exist will be ignored.
- Since params can be dynamically created based another param,
- call rewrite, and repeat the load until the params stick.
- This call to rewrite will also create any dynamic ports
- that are needed for the connections creation phase.
-
- Args:
- n: the nested data odict
- """
- get_hash = lambda: hash(tuple(map(hash, self.get_params())))
- my_hash = 0
- while get_hash() != my_hash:
- params_n = n.findall('param')
- for param_n in params_n:
- key = param_n.find('key')
- value = param_n.find('value')
- #the key must exist in this block's params
- if key in self.get_param_keys():
- self.get_param(key).set_value(value)
- #store hash and call rewrite
- my_hash = get_hash()
- self.rewrite()
+ def __init__(self, flow_graph, n):
+ """
+ Make a new block from nested data.
+
+ Args:
+ flow: graph the parent element
+ n: the nested odict
+
+ Returns:
+ block a new block
+ """
+ #build the block
+ Element.__init__(self, flow_graph)
+ #grab the data
+ params = n.findall('param')
+ sources = n.findall('source')
+ sinks = n.findall('sink')
+ self._name = n.find('name')
+ self._key = n.find('key')
+ self._category = n.find('category') or ''
+ self._grc_source = n.find('grc_source') or ''
+ self._block_wrapper_path = n.find('block_wrapper_path')
+ self._bussify_sink = n.find('bus_sink')
+ self._bussify_source = n.find('bus_source')
+ #create the param objects
+ self._params = list()
+ #add the id param
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({
+ 'name': 'ID',
+ 'key': 'id',
+ 'type': 'id',
+ })
+ ))
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({
+ 'name': 'Enabled',
+ 'key': '_enabled',
+ 'type': 'raw',
+ 'value': 'True',
+ 'hide': 'all',
+ })
+ ))
+ for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
+ key = param.get_key()
+ #test against repeated keys
+ if key in self.get_param_keys():
+ raise Exception, 'Key "%s" already exists in params'%key
+ #store the param
+ self.get_params().append(param)
+ #create the source objects
+ self._sources = list()
+ for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
+ key = source.get_key()
+ #test against repeated keys
+ if key in self.get_source_keys():
+ raise Exception, 'Key "%s" already exists in sources'%key
+ #store the port
+ self.get_sources().append(source)
+ self.back_ofthe_bus(self.get_sources())
+ #create the sink objects
+ self._sinks = list()
+ for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
+ key = sink.get_key()
+ #test against repeated keys
+ if key in self.get_sink_keys():
+ raise Exception, 'Key "%s" already exists in sinks'%key
+ #store the port
+ self.get_sinks().append(sink)
+ self.back_ofthe_bus(self.get_sinks())
+ self.current_bus_structure = {'source':'','sink':''};
+
+ # Virtual source/sink and pad source/sink blocks are
+ # indistinguishable from normal GR blocks. Make explicit
+ # checks for them here since they have no work function or
+ # buffers to manage.
+ is_not_virtual_or_pad = ((self._key != "virtual_source") \
+ and (self._key != "virtual_sink") \
+ and (self._key != "pad_source") \
+ and (self._key != "pad_sink"))
+
+ if (len(sources) or len(sinks)) and is_not_virtual_or_pad:
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({'name': 'Core Affinity',
+ 'key': 'affinity',
+ 'type': 'int_vector',
+ 'hide': 'part',
+ })
+ ))
+ if len(sources) and is_not_virtual_or_pad:
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({'name': 'Min Output Buffer',
+ 'key': 'minoutbuf',
+ 'type': 'int',
+ 'hide': 'part',
+ 'value': '0'
+ })
+ ))
+
+ def back_ofthe_bus(self, portlist):
+ portlist.sort(key=lambda a: a.get_type() == 'bus');
+
+
+ def filter_bus_port(self, ports):
+ buslist = [i for i in ports if i.get_type() == 'bus'];
+ if len(buslist) == 0:
+ return ports;
+ else:
+ return buslist;
+
+ def get_enabled(self):
+ """
+ Get the enabled state of the block.
+
+ Returns:
+ true for enabled
+ """
+ try: return eval(self.get_param('_enabled').get_value())
+ except: return True
+
+ def set_enabled(self, enabled):
+ """
+ Set the enabled state of the block.
+
+ Args:
+ enabled: true for enabled
+ """
+ self.get_param('_enabled').set_value(str(enabled))
+
+ def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
+
+ def get_id(self): return self.get_param('id').get_value()
+ def is_block(self): return True
+ def get_name(self): return self._name
+ def get_key(self): return self._key
+ def get_category(self): return self._category
+ def get_doc(self): return ''
+ def get_ports(self): return self.get_sources() + self.get_sinks()
+ def get_ports_gui(self): return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks());
+ def get_children(self): return self.get_ports() + self.get_params()
+ def get_children_gui(self): return self.get_ports_gui() + self.get_params()
+ def get_block_wrapper_path(self): return self._block_wrapper_path
+
+ ##############################################
+ # Access Params
+ ##############################################
+ def get_param_keys(self): return _get_keys(self._params)
+ def get_param(self, key): return _get_elem(self._params, key)
+ def get_params(self): return self._params
+ def has_param(self, key):
+ try:
+ _get_elem(self._params, key);
+ return True;
+ except:
+ return False;
+
+ ##############################################
+ # Access Sinks
+ ##############################################
+ def get_sink_keys(self): return _get_keys(self._sinks)
+ def get_sink(self, key): return _get_elem(self._sinks, key)
+ def get_sinks(self): return self._sinks
+ def get_sinks_gui(self): return self.filter_bus_port(self.get_sinks())
+
+ ##############################################
+ # Access Sources
+ ##############################################
+ def get_source_keys(self): return _get_keys(self._sources)
+ def get_source(self, key): return _get_elem(self._sources, key)
+ def get_sources(self): return self._sources
+ def get_sources_gui(self): return self.filter_bus_port(self.get_sources());
+
+ def get_connections(self):
+ return sum([port.get_connections() for port in self.get_ports()], [])
+
+ def resolve_dependencies(self, tmpl):
+ """
+ Resolve a paramater dependency with cheetah templates.
+
+ Args:
+ tmpl: the string with dependencies
+
+ Returns:
+ the resolved value
+ """
+ tmpl = str(tmpl)
+ if '$' not in tmpl: return tmpl
+ n = dict((p.get_key(), TemplateArg(p)) for p in self.get_params())
+ try: return str(Template(tmpl, n))
+ except Exception, e: return "-------->\n%s: %s\n<--------"%(e, tmpl)
+
+ ##############################################
+ # Controller Modify
+ ##############################################
+ def type_controller_modify(self, direction):
+ """
+ Change the type controller.
+
+ Args:
+ direction: +1 or -1
+
+ Returns:
+ true for change
+ """
+ changed = False
+ type_param = None
+ for param in filter(lambda p: p.is_enum(), self.get_params()):
+ children = self.get_ports() + self.get_params()
+ #priority to the type controller
+ if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param
+ #use param if type param is unset
+ if not type_param: type_param = param
+ if type_param:
+ #try to increment the enum by direction
+ try:
+ keys = type_param.get_option_keys()
+ old_index = keys.index(type_param.get_value())
+ new_index = (old_index + direction + len(keys))%len(keys)
+ type_param.set_value(keys[new_index])
+ changed = True
+ except: pass
+ return changed
+
+ def port_controller_modify(self, direction):
+ """
+ Change the port controller.
+
+ Args:
+ direction: +1 or -1
+
+ Returns:
+ true for change
+ """
+ return False
+
+ def form_bus_structure(self, direc):
+ if direc == 'source':
+ get_p = self.get_sources;
+ get_p_gui = self.get_sources_gui;
+ bus_structure = self.get_bus_structure('source');
+ else:
+ get_p = self.get_sinks;
+ get_p_gui = self.get_sinks_gui
+ bus_structure = self.get_bus_structure('sink');
+
+ struct = [range(len(get_p()))];
+ if True in map(lambda a: isinstance(a.get_nports(), int), get_p()):
+
+
+ structlet = [];
+ last = 0;
+ for j in [i.get_nports() for i in get_p() if isinstance(i.get_nports(), int)]:
+ structlet.extend(map(lambda a: a+last, range(j)));
+ last = structlet[-1] + 1;
+ struct = [structlet];
+ if bus_structure:
+
+ struct = bus_structure
+
+ self.current_bus_structure[direc] = struct;
+ return struct
+
+ def bussify(self, n, direc):
+ if direc == 'source':
+ get_p = self.get_sources;
+ get_p_gui = self.get_sources_gui;
+ bus_structure = self.get_bus_structure('source');
+ else:
+ get_p = self.get_sinks;
+ get_p_gui = self.get_sinks_gui
+ bus_structure = self.get_bus_structure('sink');
+
+
+ for elt in get_p():
+ for connect in elt.get_connections():
+ self.get_parent().remove_element(connect);
+
+
+
+
+
+
+ if (not 'bus' in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0:
+
+ struct = self.form_bus_structure(direc);
+ self.current_bus_structure[direc] = struct;
+ if get_p()[0].get_nports():
+ n['nports'] = str(1);
+
+ for i in range(len(struct)):
+ n['key'] = str(len(get_p()));
+ n = odict(n);
+ port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc);
+ get_p().append(port);
+
+
+
+
+ elif 'bus' in map(lambda a: a.get_type(), get_p()):
+ for elt in get_p_gui():
+ get_p().remove(elt);
+ self.current_bus_structure[direc] = ''
+ ##############################################
+ ## Import/Export Methods
+ ##############################################
+ def export_data(self):
+ """
+ Export this block's params to nested data.
+
+ Returns:
+ a nested data odict
+ """
+ n = odict()
+ n['key'] = self.get_key()
+ n['param'] = map(lambda p: p.export_data(), self.get_params())
+ if 'bus' in map(lambda a: a.get_type(), self.get_sinks()):
+ n['bus_sink'] = str(1);
+ if 'bus' in map(lambda a: a.get_type(), self.get_sources()):
+ n['bus_source'] = str(1);
+ return n
+
+ def import_data(self, n):
+ """
+ Import this block's params from nested data.
+ Any param keys that do not exist will be ignored.
+ Since params can be dynamically created based another param,
+ call rewrite, and repeat the load until the params stick.
+ This call to rewrite will also create any dynamic ports
+ that are needed for the connections creation phase.
+
+ Args:
+ n: the nested data odict
+ """
+ get_hash = lambda: hash(tuple(map(hash, self.get_params())))
+ my_hash = 0
+ while get_hash() != my_hash:
+ params_n = n.findall('param')
+ for param_n in params_n:
+ key = param_n.find('key')
+ value = param_n.find('value')
+ #the key must exist in this block's params
+ if key in self.get_param_keys():
+ self.get_param(key).set_value(value)
+ #store hash and call rewrite
+ my_hash = get_hash()
+ self.rewrite()
+ bussinks = n.findall('bus_sink');
+ if len(bussinks) > 0 and not self._bussify_sink:
+ self.bussify({'name':'bus','type':'bus'}, 'sink')
+ elif len(bussinks) > 0:
+ self.bussify({'name':'bus','type':'bus'}, 'sink')
+ self.bussify({'name':'bus','type':'bus'}, 'sink')
+ bussrcs = n.findall('bus_source');
+ if len(bussrcs) > 0 and not self._bussify_source:
+ self.bussify({'name':'bus','type':'bus'}, 'source')
+ elif len(bussrcs) > 0:
+ self.bussify({'name':'bus','type':'bus'}, 'source')
+ self.bussify({'name':'bus','type':'bus'}, 'source')
+
+
diff --git a/grc/base/Connection.py b/grc/base/Connection.py
index b9afe1434d..252b7deac1 100644
--- a/grc/base/Connection.py
+++ b/grc/base/Connection.py
@@ -22,84 +22,99 @@ from . import odict
class Connection(Element):
- def __init__(self, flow_graph, porta, portb):
- """
- Make a new connection given the parent and 2 ports.
-
- Args:
- flow_graph: the parent of this element
- porta: a port (any direction)
- portb: a port (any direction)
- @throws Error cannot make connection
-
- Returns:
- a new connection
- """
- Element.__init__(self, flow_graph)
- source = sink = None
- #separate the source and sink
- for port in (porta, portb):
- if port.is_source(): source = port
- if port.is_sink(): sink = port
- if not source: raise ValueError('Connection could not isolate source')
- if not sink: raise ValueError('Connection could not isolate sink')
- #ensure that this connection (source -> sink) is unique
- for connection in self.get_parent().get_connections():
- if connection.get_source() is source and connection.get_sink() is sink:
- raise Exception('This connection between source and sink is not unique.')
- self._source = source
- self._sink = sink
+ def __init__(self, flow_graph, porta, portb):
+ """
+ Make a new connection given the parent and 2 ports.
+
+ Args:
+ flow_graph: the parent of this element
+ porta: a port (any direction)
+ portb: a port (any direction)
+ @throws Error cannot make connection
+
+ Returns:
+ a new connection
+ """
+ Element.__init__(self, flow_graph)
+ source = sink = None
+ #separate the source and sink
+ for port in (porta, portb):
+ if port.is_source(): source = port
+ if port.is_sink(): sink = port
+ if not source: raise ValueError('Connection could not isolate source')
+ if not sink: raise ValueError('Connection could not isolate sink')
+ busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink]))%2
+ if not busses == 0: raise ValueError('busses must get with busses')
- def __str__(self):
- return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%(
- self.get_source().get_parent(),
- self.get_source(),
- self.get_sink().get_parent(),
- self.get_sink(),
- )
+ if not len(source.get_associated_ports()) == len(sink.get_associated_ports()):
+ raise ValueError('port connections must have same cardinality');
+ #ensure that this connection (source -> sink) is unique
+ for connection in self.get_parent().get_connections():
+ if connection.get_source() is source and connection.get_sink() is sink:
+ raise Exception('This connection between source and sink is not unique.')
+ self._source = source
+ self._sink = sink
+ if source.get_type() == 'bus':
+
+ sources = source.get_associated_ports();
+ sinks = sink.get_associated_ports();
+
+ for i in range(len(sources)):
+ try:
+ flow_graph.connect(sources[i], sinks[i]);
+ except:
+ pass
- def is_connection(self): return True
+ def __str__(self):
+ return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%(
+ self.get_source().get_parent(),
+ self.get_source(),
+ self.get_sink().get_parent(),
+ self.get_sink(),
+ )
- def validate(self):
- """
- Validate the connections.
- The ports must match in type.
- """
- Element.validate(self)
- source_type = self.get_source().get_type()
- sink_type = self.get_sink().get_type()
- if source_type != sink_type:
- self.add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type))
+ def is_connection(self): return True
- def get_enabled(self):
- """
- Get the enabled state of this connection.
-
- Returns:
- true if source and sink blocks are enabled
- """
- return self.get_source().get_parent().get_enabled() and \
- self.get_sink().get_parent().get_enabled()
+ def validate(self):
+ """
+ Validate the connections.
+ The ports must match in type.
+ """
+ Element.validate(self)
+ source_type = self.get_source().get_type()
+ sink_type = self.get_sink().get_type()
+ if source_type != sink_type:
+ self.add_error_message('Source type "%s" does not match sink type "%s".'%(source_type, sink_type))
- #############################
- # Access Ports
- #############################
- def get_sink(self): return self._sink
- def get_source(self): return self._source
+ def get_enabled(self):
+ """
+ Get the enabled state of this connection.
+
+ Returns:
+ true if source and sink blocks are enabled
+ """
+ return self.get_source().get_parent().get_enabled() and \
+ self.get_sink().get_parent().get_enabled()
- ##############################################
- ## Import/Export Methods
- ##############################################
- def export_data(self):
- """
- Export this connection's info.
-
- Returns:
- a nested data odict
- """
- n = odict()
- n['source_block_id'] = self.get_source().get_parent().get_id()
- n['sink_block_id'] = self.get_sink().get_parent().get_id()
- n['source_key'] = self.get_source().get_key()
- n['sink_key'] = self.get_sink().get_key()
- return n
+ #############################
+ # Access Ports
+ #############################
+ def get_sink(self): return self._sink
+ def get_source(self): return self._source
+
+ ##############################################
+ ## Import/Export Methods
+ ##############################################
+ def export_data(self):
+ """
+ Export this connection's info.
+
+ Returns:
+ a nested data odict
+ """
+ n = odict()
+ n['source_block_id'] = self.get_source().get_parent().get_id()
+ n['sink_block_id'] = self.get_sink().get_parent().get_id()
+ n['source_key'] = self.get_source().get_key()
+ n['sink_key'] = self.get_sink().get_key()
+ return n
diff --git a/grc/base/Element.py b/grc/base/Element.py
index 74097eea9a..17b2234a8c 100644
--- a/grc/base/Element.py
+++ b/grc/base/Element.py
@@ -19,77 +19,77 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
class Element(object):
- def __init__(self, parent=None):
- self._parent = parent
+ def __init__(self, parent=None):
+ self._parent = parent
- ##################################################
- # Element Validation API
- ##################################################
- def validate(self):
- """
- Validate this element and call validate on all children.
- Call this base method before adding error messages in the subclass.
- """
- self._error_messages = list()
- for child in self.get_children(): child.validate()
+ ##################################################
+ # Element Validation API
+ ##################################################
+ def validate(self):
+ """
+ Validate this element and call validate on all children.
+ Call this base method before adding error messages in the subclass.
+ """
+ self._error_messages = list()
+ for child in self.get_children(): child.validate()
- def is_valid(self):
- """
- Is this element valid?
-
- Returns:
- true when the element is enabled and has no error messages
- """
- return not self.get_error_messages() or not self.get_enabled()
+ def is_valid(self):
+ """
+ Is this element valid?
+
+ Returns:
+ true when the element is enabled and has no error messages
+ """
+ return not self.get_error_messages() or not self.get_enabled()
- def add_error_message(self, msg):
- """
- Add an error message to the list of errors.
-
- Args:
- msg: the error message string
- """
- self._error_messages.append(msg)
+ def add_error_message(self, msg):
+ """
+ Add an error message to the list of errors.
+
+ Args:
+ msg: the error message string
+ """
+ self._error_messages.append(msg)
- def get_error_messages(self):
- """
- Get the list of error messages from this element and all of its children.
- Do not include the error messages from disabled children.
- Cleverly indent the children error messages for printing purposes.
-
- Returns:
- a list of error message strings
- """
- error_messages = list(self._error_messages) #make a copy
- for child in filter(lambda c: c.get_enabled(), self.get_children()):
- for msg in child.get_error_messages():
- error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
- return error_messages
+ def get_error_messages(self):
+ """
+ Get the list of error messages from this element and all of its children.
+ Do not include the error messages from disabled children.
+ Cleverly indent the children error messages for printing purposes.
+
+ Returns:
+ a list of error message strings
+ """
+ error_messages = list(self._error_messages) #make a copy
+ for child in filter(lambda c: c.get_enabled(), self.get_children()):
+ for msg in child.get_error_messages():
+ error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
+ return error_messages
- def rewrite(self):
- """
- Rewrite this element and call rewrite on all children.
- Call this base method before rewriting the element.
- """
- for child in self.get_children(): child.rewrite()
+ def rewrite(self):
+ """
+ Rewrite this element and call rewrite on all children.
+ Call this base method before rewriting the element.
+ """
+ for child in self.get_children(): child.rewrite()
- def get_enabled(self): return True
+ def get_enabled(self): return True
- ##############################################
- ## Tree-like API
- ##############################################
- def get_parent(self): return self._parent
- def get_children(self): return list()
+ ##############################################
+ ## Tree-like API
+ ##############################################
+ def get_parent(self): return self._parent
+ def get_children(self): return list()
- ##############################################
- ## Type testing methods
- ##############################################
- def is_element(self): return True
- def is_platform(self): return False
- def is_flow_graph(self): return False
- def is_connection(self): return False
- def is_block(self): return False
- def is_source(self): return False
- def is_sink(self): return False
- def is_port(self): return False
- def is_param(self): return False
+ ##############################################
+ ## Type testing methods
+ ##############################################
+ def is_element(self): return True
+ def is_platform(self): return False
+ def is_flow_graph(self): return False
+ def is_connection(self): return False
+ def is_block(self): return False
+ def is_source(self): return False
+ def is_sink(self): return False
+ def is_port(self): return False
+ def is_param(self): return False
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
index e8c49466d0..2f2d8c65e1 100644
--- a/grc/base/FlowGraph.py
+++ b/grc/base/FlowGraph.py
@@ -23,229 +23,288 @@ from .. gui import Messages
class FlowGraph(Element):
- def __init__(self, platform):
- """
- Make a flow graph from the arguments.
-
- Args:
- platform: a platforms with blocks and contrcutors
-
- Returns:
- the flow graph object
- """
- #initialize
- Element.__init__(self, platform)
- #inital blank import
- self.import_data()
-
- def _get_unique_id(self, base_id=''):
- """
- Get a unique id starting with the base id.
-
- Args:
- base_id: the id starts with this and appends a count
-
- Returns:
- a unique id
- """
- index = 0
- while True:
- id = '%s_%d'%(base_id, index)
- index = index + 1
- #make sure that the id is not used by another block
- if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
-
- def __str__(self): return 'FlowGraph - %s(%s)'%(self.get_option('title'), self.get_option('id'))
-
- def get_option(self, key):
- """
- Get the option for a given key.
- The option comes from the special options block.
-
- Args:
- key: the param key for the options block
-
- Returns:
- the value held by that param
- """
- return self._options_block.get_param(key).get_evaluated()
-
- def is_flow_graph(self): return True
-
- ##############################################
- ## Access Elements
- ##############################################
- def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
- def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements())
- def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
- def get_children(self): return self.get_elements()
- def get_elements(self):
- """
- Get a list of all the elements.
- Always ensure that the options block is in the list (only once).
-
- Returns:
- the element list
- """
- options_block_count = self._elements.count(self._options_block)
- if not options_block_count:
- self._elements.append(self._options_block)
- for i in range(options_block_count-1):
- self._elements.remove(self._options_block)
- return self._elements
-
- def get_enabled_blocks(self):
- """
- Get a list of all blocks that are enabled.
-
- Returns:
- a list of blocks
- """
- return filter(lambda b: b.get_enabled(), self.get_blocks())
-
- def get_enabled_connections(self):
- """
- Get a list of all connections that are enabled.
-
- Returns:
- a list of connections
- """
- return filter(lambda c: c.get_enabled(), self.get_connections())
-
- def get_new_block(self, key):
- """
- Get a new block of the specified key.
- Add the block to the list of elements.
-
- Args:
- key: the block key
-
- Returns:
- the new block or None if not found
- """
- if key not in self.get_parent().get_block_keys(): return None
- block = self.get_parent().get_new_block(self, key)
- self.get_elements().append(block)
- return block
-
- def connect(self, porta, portb):
- """
- Create a connection between porta and portb.
-
- Args:
- porta: a port
- portb: another port
- @throw Exception bad connection
-
- Returns:
- the new connection
- """
- connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
- self.get_elements().append(connection)
- return connection
-
- def remove_element(self, element):
- """
- Remove the element from the list of elements.
- If the element is a port, remove the whole block.
- If the element is a block, remove its connections.
- If the element is a connection, just remove the connection.
- """
- if element not in self.get_elements(): return
- #found a port, set to parent signal block
- if element.is_port():
- element = element.get_parent()
- #remove block, remove all involved connections
- if element.is_block():
- for port in element.get_ports():
- map(self.remove_element, port.get_connections())
- self.get_elements().remove(element)
-
- def evaluate(self, expr):
- """
- Evaluate the expression.
-
- Args:
- expr: the string expression
- @throw NotImplementedError
- """
- raise NotImplementedError
-
- ##############################################
- ## Import/Export Methods
- ##############################################
- def export_data(self):
- """
- Export this flow graph to nested data.
- Export all block and connection data.
-
- Returns:
- a nested data odict
- """
- import time
- n = odict()
- n['timestamp'] = time.ctime()
- n['block'] = [block.export_data() for block in self.get_blocks()]
- n['connection'] = [connection.export_data() for connection in self.get_connections()]
- return odict({'flow_graph': n})
-
- def import_data(self, n=None):
- """
- Import blocks and connections into this flow graph.
- Clear this flowgraph of all previous blocks and connections.
- Any blocks or connections in error will be ignored.
-
- Args:
- n: the nested data odict
- """
- #remove previous elements
- self._elements = list()
- #use blank data if none provided
- fg_n = n and n.find('flow_graph') or odict()
- blocks_n = fg_n.findall('block')
- connections_n = fg_n.findall('connection')
- #create option block
- self._options_block = self.get_parent().get_new_block(self, 'options')
- #build the blocks
- for block_n in blocks_n:
- key = block_n.find('key')
- if key == 'options': block = self._options_block
- else: block = self.get_new_block(key)
- #only load the block when the block key was valid
- if block: block.import_data(block_n)
- else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
- #build the connections
- for connection_n in connections_n:
- #try to make the connection
- try:
- #get the block ids
- source_block_id = connection_n.find('source_block_id')
- sink_block_id = connection_n.find('sink_block_id')
- #get the port keys
- source_key = connection_n.find('source_key')
- sink_key = connection_n.find('sink_key')
- #verify the blocks
- block_ids = map(lambda b: b.get_id(), self.get_blocks())
- if source_block_id not in block_ids:
- raise LookupError('source block id "%s" not in block ids'%source_block_id)
- if sink_block_id not in block_ids:
- raise LookupError('sink block id "%s" not in block ids'%sink_block_id)
- #get the blocks
- source_block = self.get_block(source_block_id)
- sink_block = self.get_block(sink_block_id)
- #verify the ports
- if source_key not in source_block.get_source_keys():
- raise LookupError('source key "%s" not in source block keys'%source_key)
- if sink_key not in sink_block.get_sink_keys():
- raise LookupError('sink key "%s" not in sink block keys'%sink_key)
- #get the ports
- source = source_block.get_source(source_key)
- sink = sink_block.get_sink(sink_key)
- #build the connection
- self.connect(source, sink)
- except LookupError, e: Messages.send_error_load(
- 'Connection between %s(%s) and %s(%s) could not be made.\n\t%s'%(
- source_block_id, source_key, sink_block_id, sink_key, e
- )
- )
- self.rewrite() #global rewrite
+ def __init__(self, platform):
+ """
+ Make a flow graph from the arguments.
+
+ Args:
+ platform: a platforms with blocks and contrcutors
+
+ Returns:
+ the flow graph object
+ """
+ #initialize
+ Element.__init__(self, platform)
+ #inital blank import
+ self.import_data()
+
+ def _get_unique_id(self, base_id=''):
+ """
+ Get a unique id starting with the base id.
+
+ Args:
+ base_id: the id starts with this and appends a count
+
+ Returns:
+ a unique id
+ """
+ index = 0
+ while True:
+ id = '%s_%d'%(base_id, index)
+ index = index + 1
+ #make sure that the id is not used by another block
+ if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
+
+ def __str__(self): return 'FlowGraph - %s(%s)'%(self.get_option('title'), self.get_option('id'))
+ def rewrite(self):
+ def refactor_bus_structure():
+
+ for block in self.get_blocks():
+ for direc in ['source', 'sink']:
+ if direc == 'source':
+ get_p = block.get_sources;
+ get_p_gui = block.get_sources_gui;
+ bus_structure = block.form_bus_structure('source');
+ else:
+ get_p = block.get_sinks;
+ get_p_gui = block.get_sinks_gui
+ bus_structure = block.form_bus_structure('sink');
+
+ if 'bus' in map(lambda a: a.get_type(), get_p_gui()):
+
+
+
+ if len(get_p_gui()) > len(bus_structure):
+ times = range(len(bus_structure), len(get_p_gui()));
+ for i in times:
+ for connect in get_p_gui()[-1].get_connections():
+ block.get_parent().remove_element(connect);
+ get_p().remove(get_p_gui()[-1]);
+ elif len(get_p_gui()) < len(bus_structure):
+ n = {'name':'bus','type':'bus'};
+ if True in map(lambda a: isinstance(a.get_nports(), int), get_p()):
+ n['nports'] = str(1);
+
+ times = range(len(get_p_gui()), len(bus_structure));
+
+ for i in times:
+ n['key'] = str(len(get_p()));
+ n = odict(n);
+ port = block.get_parent().get_parent().Port(block=block, n=n, dir=direc);
+ get_p().append(port);
+
+
+
+ for child in self.get_children(): child.rewrite()
+ refactor_bus_structure();
+
+ def get_option(self, key):
+ """
+ Get the option for a given key.
+ The option comes from the special options block.
+
+ Args:
+ key: the param key for the options block
+
+ Returns:
+ the value held by that param
+ """
+ return self._options_block.get_param(key).get_evaluated()
+
+ def is_flow_graph(self): return True
+
+ ##############################################
+ ## Access Elements
+ ##############################################
+ def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
+ def get_blocks_unordered(self): return filter(lambda e: e.is_block(), self.get_elements())
+ def get_blocks(self):
+ blocks = self.get_blocks_unordered();
+ for i in range(len(blocks)):
+ if blocks[i].get_key() == 'variable':
+ blk = blocks[i];
+ blocks.remove(blk);
+ blocks.insert(1, blk);
+ return blocks;
+ def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
+ def get_children(self): return self.get_elements()
+ def get_elements(self):
+ """
+ Get a list of all the elements.
+ Always ensure that the options block is in the list (only once).
+
+ Returns:
+ the element list
+ """
+ options_block_count = self._elements.count(self._options_block)
+ if not options_block_count:
+ self._elements.append(self._options_block)
+ for i in range(options_block_count-1):
+ self._elements.remove(self._options_block)
+ return self._elements
+
+ def get_enabled_blocks(self):
+ """
+ Get a list of all blocks that are enabled.
+
+ Returns:
+ a list of blocks
+ """
+ return filter(lambda b: b.get_enabled(), self.get_blocks())
+
+ def get_enabled_connections(self):
+ """
+ Get a list of all connections that are enabled.
+
+ Returns:
+ a list of connections
+ """
+ return filter(lambda c: c.get_enabled(), self.get_connections())
+
+ def get_new_block(self, key):
+ """
+ Get a new block of the specified key.
+ Add the block to the list of elements.
+
+ Args:
+ key: the block key
+
+ Returns:
+ the new block or None if not found
+ """
+ if key not in self.get_parent().get_block_keys(): return None
+ block = self.get_parent().get_new_block(self, key)
+ self.get_elements().append(block);
+ if block._bussify_sink:
+ block.bussify({'name':'bus','type':'bus'}, 'sink')
+ if block._bussify_source:
+ block.bussify({'name':'bus','type':'bus'}, 'source')
+ return block;
+
+ def connect(self, porta, portb):
+ """
+ Create a connection between porta and portb.
+
+ Args:
+ porta: a port
+ portb: another port
+ @throw Exception bad connection
+
+ Returns:
+ the new connection
+ """
+ connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
+ self.get_elements().append(connection)
+ return connection
+
+ def remove_element(self, element):
+ """
+ Remove the element from the list of elements.
+ If the element is a port, remove the whole block.
+ If the element is a block, remove its connections.
+ If the element is a connection, just remove the connection.
+ """
+ if element not in self.get_elements(): return
+ #found a port, set to parent signal block
+ if element.is_port():
+ element = element.get_parent()
+ #remove block, remove all involved connections
+ if element.is_block():
+ for port in element.get_ports():
+ map(self.remove_element, port.get_connections())
+ if element.is_connection():
+ if element.is_bus():
+ cons_list = []
+ for i in map(lambda a: a.get_connections(), element.get_source().get_associated_ports()):
+ cons_list.extend(i);
+ map(self.remove_element, cons_list);
+ self.get_elements().remove(element)
+
+ def evaluate(self, expr):
+ """
+ Evaluate the expression.
+
+ Args:
+ expr: the string expression
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
+ ##############################################
+ ## Import/Export Methods
+ ##############################################
+ def export_data(self):
+ """
+ Export this flow graph to nested data.
+ Export all block and connection data.
+
+ Returns:
+ a nested data odict
+ """
+ import time
+ n = odict()
+ n['timestamp'] = time.ctime()
+ n['block'] = [block.export_data() for block in self.get_blocks()]
+ n['connection'] = [connection.export_data() for connection in self.get_connections()]
+ return odict({'flow_graph': n})
+
+ def import_data(self, n=None):
+ """
+ Import blocks and connections into this flow graph.
+ Clear this flowgraph of all previous blocks and connections.
+ Any blocks or connections in error will be ignored.
+
+ Args:
+ n: the nested data odict
+ """
+ #remove previous elements
+ self._elements = list()
+ #use blank data if none provided
+ fg_n = n and n.find('flow_graph') or odict()
+ blocks_n = fg_n.findall('block')
+ connections_n = fg_n.findall('connection')
+ #create option block
+ self._options_block = self.get_parent().get_new_block(self, 'options')
+ #build the blocks
+ for block_n in blocks_n:
+ key = block_n.find('key')
+ if key == 'options': block = self._options_block
+ else: block = self.get_new_block(key)
+ #only load the block when the block key was valid
+ if block: block.import_data(block_n)
+ else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
+ #build the connections
+ for connection_n in connections_n:
+ #try to make the connection
+ try:
+ #get the block ids
+ source_block_id = connection_n.find('source_block_id')
+ sink_block_id = connection_n.find('sink_block_id')
+ #get the port keys
+ source_key = connection_n.find('source_key')
+ sink_key = connection_n.find('sink_key')
+ #verify the blocks
+ block_ids = map(lambda b: b.get_id(), self.get_blocks())
+ if source_block_id not in block_ids:
+ raise LookupError('source block id "%s" not in block ids'%source_block_id)
+ if sink_block_id not in block_ids:
+ raise LookupError('sink block id "%s" not in block ids'%sink_block_id)
+ #get the blocks
+ source_block = self.get_block(source_block_id)
+ sink_block = self.get_block(sink_block_id)
+ #verify the ports
+ if source_key not in source_block.get_source_keys():
+ raise LookupError('source key "%s" not in source block keys'%source_key)
+ if sink_key not in sink_block.get_sink_keys():
+ raise LookupError('sink key "%s" not in sink block keys'%sink_key)
+ #get the ports
+ source = source_block.get_source(source_key)
+ sink = sink_block.get_sink(sink_key)
+ #build the connection
+ self.connect(source, sink)
+ except LookupError, e: Messages.send_error_load(
+ 'Connection between %s(%s) and %s(%s) could not be made.\n\t%s'%(
+ source_block_id, source_key, sink_block_id, sink_key, e
+ )
+ )
+ self.rewrite() #global rewrite
diff --git a/grc/base/Param.py b/grc/base/Param.py
index 76a74d3ed7..8b8362ac1a 100644
--- a/grc/base/Param.py
+++ b/grc/base/Param.py
@@ -22,166 +22,166 @@ from Element import Element
def _get_keys(lst): return [elem.get_key() for elem in lst]
def _get_elem(lst, key):
- try: return lst[_get_keys(lst).index(key)]
- except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Option(Element):
- def __init__(self, param, n):
- Element.__init__(self, param)
- self._name = n.find('name')
- self._key = n.find('key')
- self._opts = dict()
- opts = n.findall('opt')
- #test against opts when non enum
- if not self.get_parent().is_enum() and opts:
- raise Exception, 'Options for non-enum types cannot have sub-options'
- #extract opts
- for opt in opts:
- #separate the key:value
- try: key, value = opt.split(':')
- except: raise Exception, 'Error separating "%s" into key:value'%opt
- #test against repeated keys
- if self._opts.has_key(key):
- raise Exception, 'Key "%s" already exists in option'%key
- #store the option
- self._opts[key] = value
-
- def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
- def get_name(self): return self._name
- def get_key(self): return self._key
-
- ##############################################
- # Access Opts
- ##############################################
- def get_opt_keys(self): return self._opts.keys()
- def get_opt(self, key): return self._opts[key]
- def get_opts(self): return self._opts.values()
+ def __init__(self, param, n):
+ Element.__init__(self, param)
+ self._name = n.find('name')
+ self._key = n.find('key')
+ self._opts = dict()
+ opts = n.findall('opt')
+ #test against opts when non enum
+ if not self.get_parent().is_enum() and opts:
+ raise Exception, 'Options for non-enum types cannot have sub-options'
+ #extract opts
+ for opt in opts:
+ #separate the key:value
+ try: key, value = opt.split(':')
+ except: raise Exception, 'Error separating "%s" into key:value'%opt
+ #test against repeated keys
+ if self._opts.has_key(key):
+ raise Exception, 'Key "%s" already exists in option'%key
+ #store the option
+ self._opts[key] = value
+
+ def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
+ def get_name(self): return self._name
+ def get_key(self): return self._key
+
+ ##############################################
+ # Access Opts
+ ##############################################
+ def get_opt_keys(self): return self._opts.keys()
+ def get_opt(self, key): return self._opts[key]
+ def get_opts(self): return self._opts.values()
class Param(Element):
- def __init__(self, block, n):
- """
- Make a new param from nested data.
-
- Args:
- block: the parent element
- n: the nested odict
- """
- #grab the data
- self._name = n.find('name')
- self._key = n.find('key')
- value = n.find('value') or ''
- self._type = n.find('type')
- self._hide = n.find('hide') or ''
- #build the param
- Element.__init__(self, block)
- #create the Option objects from the n data
- self._options = list()
- for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
- key = option.get_key()
- #test against repeated keys
- if key in self.get_option_keys():
- raise Exception, 'Key "%s" already exists in options'%key
- #store the option
- self.get_options().append(option)
- #test the enum options
- if self.is_enum():
- #test against options with identical keys
- if len(set(self.get_option_keys())) != len(self.get_options()):
- raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
- #test against inconsistent keys in options
- opt_keys = self.get_options()[0].get_opt_keys()
- for option in self.get_options():
- if set(opt_keys) != set(option.get_opt_keys()):
- raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
- #if a value is specified, it must be in the options keys
- self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0]
- if self.get_value() not in self.get_option_keys():
- raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
- else: self._value = value or ''
-
- def validate(self):
- """
- Validate the param.
- The value must be evaluated and type must a possible type.
- """
- Element.validate(self)
- if self.get_type() not in self.get_types():
- self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
-
- def get_evaluated(self): raise NotImplementedError
-
- def to_code(self):
- """
- Convert the value to code.
- @throw NotImplementedError
- """
- raise NotImplementedError
-
- def get_types(self):
- """
- Get a list of all possible param types.
- @throw NotImplementedError
- """
- raise NotImplementedError
-
- def get_color(self): return '#FFFFFF'
- def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
- def is_param(self): return True
- def get_name(self): return self._name
- def get_key(self): return self._key
- def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
-
- def get_value(self):
- value = self._value
- if self.is_enum() and value not in self.get_option_keys():
- value = self.get_option_keys()[0]
- self.set_value(value)
- return value
-
- def set_value(self, value): self._value = str(value) #must be a string
-
- def get_type(self): return self.get_parent().resolve_dependencies(self._type)
- def is_enum(self): return self._type == 'enum'
-
- def __repr__(self):
- """
- Get the repr (nice string format) for this param.
- Just return the value (special case enum).
- Derived classes can handle complex formatting.
-
- Returns:
- the string representation
- """
- if self.is_enum(): return self.get_option(self.get_value()).get_name()
- return self.get_value()
-
- ##############################################
- # Access Options
- ##############################################
- def get_option_keys(self): return _get_keys(self.get_options())
- def get_option(self, key): return _get_elem(self.get_options(), key)
- def get_options(self): return self._options
-
- ##############################################
- # Access Opts
- ##############################################
- def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
- def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
- def get_opts(self): return self.get_option(self.get_value()).get_opts()
-
- ##############################################
- ## Import/Export Methods
- ##############################################
- def export_data(self):
- """
- Export this param's key/value.
-
- Returns:
- a nested data odict
- """
- n = odict()
- n['key'] = self.get_key()
- n['value'] = self.get_value()
- return n
+ def __init__(self, block, n):
+ """
+ Make a new param from nested data.
+
+ Args:
+ block: the parent element
+ n: the nested odict
+ """
+ #grab the data
+ self._name = n.find('name')
+ self._key = n.find('key')
+ value = n.find('value') or ''
+ self._type = n.find('type')
+ self._hide = n.find('hide') or ''
+ #build the param
+ Element.__init__(self, block)
+ #create the Option objects from the n data
+ self._options = list()
+ for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
+ key = option.get_key()
+ #test against repeated keys
+ if key in self.get_option_keys():
+ raise Exception, 'Key "%s" already exists in options'%key
+ #store the option
+ self.get_options().append(option)
+ #test the enum options
+ if self.is_enum():
+ #test against options with identical keys
+ if len(set(self.get_option_keys())) != len(self.get_options()):
+ raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
+ #test against inconsistent keys in options
+ opt_keys = self.get_options()[0].get_opt_keys()
+ for option in self.get_options():
+ if set(opt_keys) != set(option.get_opt_keys()):
+ raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
+ #if a value is specified, it must be in the options keys
+ self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0]
+ if self.get_value() not in self.get_option_keys():
+ raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
+ else: self._value = value or ''
+
+ def validate(self):
+ """
+ Validate the param.
+ The value must be evaluated and type must a possible type.
+ """
+ Element.validate(self)
+ if self.get_type() not in self.get_types():
+ self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
+
+ def get_evaluated(self): raise NotImplementedError
+
+ def to_code(self):
+ """
+ Convert the value to code.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
+ def get_types(self):
+ """
+ Get a list of all possible param types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
+ def get_color(self): return '#FFFFFF'
+ def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
+ def is_param(self): return True
+ def get_name(self): return self._name
+ def get_key(self): return self._key
+ def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
+
+ def get_value(self):
+ value = self._value
+ if self.is_enum() and value not in self.get_option_keys():
+ value = self.get_option_keys()[0]
+ self.set_value(value)
+ return value
+
+ def set_value(self, value): self._value = str(value) #must be a string
+
+ def get_type(self): return self.get_parent().resolve_dependencies(self._type)
+ def is_enum(self): return self._type == 'enum'
+
+ def __repr__(self):
+ """
+ Get the repr (nice string format) for this param.
+ Just return the value (special case enum).
+ Derived classes can handle complex formatting.
+
+ Returns:
+ the string representation
+ """
+ if self.is_enum(): return self.get_option(self.get_value()).get_name()
+ return self.get_value()
+
+ ##############################################
+ # Access Options
+ ##############################################
+ def get_option_keys(self): return _get_keys(self.get_options())
+ def get_option(self, key): return _get_elem(self.get_options(), key)
+ def get_options(self): return self._options
+
+ ##############################################
+ # Access Opts
+ ##############################################
+ def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
+ def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
+ def get_opts(self): return self.get_option(self.get_value()).get_opts()
+
+ ##############################################
+ ## Import/Export Methods
+ ##############################################
+ def export_data(self):
+ """
+ Export this param's key/value.
+
+ Returns:
+ a nested data odict
+ """
+ n = odict()
+ n['key'] = self.get_key()
+ n['value'] = self.get_value()
+ return n
diff --git a/grc/base/ParseXML.py b/grc/base/ParseXML.py
index 0d19f6b212..56097395dd 100644
--- a/grc/base/ParseXML.py
+++ b/grc/base/ParseXML.py
@@ -21,98 +21,99 @@ from lxml import etree
from . import odict
class XMLSyntaxError(Exception):
- def __init__(self, error_log):
- self._error_log = error_log
- def __str__(self):
- return '\n'.join(map(str, self._error_log.filter_from_errors()))
+ def __init__(self, error_log):
+ self._error_log = error_log
+ def __str__(self):
+ return '\n'.join(map(str, self._error_log.filter_from_errors()))
def validate_dtd(xml_file, dtd_file=None):
- """
- Validate an xml file against its dtd.
-
- Args:
- xml_file: the xml file
- dtd_file: the optional dtd file
- @throws Exception validation fails
- """
- #perform parsing, use dtd validation if dtd file is not specified
- parser = etree.XMLParser(dtd_validation=not dtd_file)
- xml = etree.parse(xml_file, parser=parser)
- if parser.error_log: raise XMLSyntaxError(parser.error_log)
- #perform dtd validation if the dtd file is specified
- if not dtd_file: return
- dtd = etree.DTD(dtd_file)
- if not dtd.validate(xml.getroot()): raise XMLSyntaxError(dtd.error_log)
+ """
+ Validate an xml file against its dtd.
+
+ Args:
+ xml_file: the xml file
+ dtd_file: the optional dtd file
+ @throws Exception validation fails
+ """
+ #perform parsing, use dtd validation if dtd file is not specified
+ parser = etree.XMLParser(dtd_validation=not dtd_file)
+ xml = etree.parse(xml_file, parser=parser)
+ if parser.error_log: raise XMLSyntaxError(parser.error_log)
+ #perform dtd validation if the dtd file is specified
+ if not dtd_file: return
+ dtd = etree.DTD(dtd_file)
+ if not dtd.validate(xml.getroot()): raise XMLSyntaxError(dtd.error_log)
def from_file(xml_file):
- """
- Create nested data from an xml file using the from xml helper.
-
- Args:
- xml_file: the xml file path
-
- Returns:
- the nested data
- """
- xml = etree.parse(xml_file).getroot()
- return _from_file(xml)
+ """
+ Create nested data from an xml file using the from xml helper.
+
+ Args:
+ xml_file: the xml file path
+
+ Returns:
+ the nested data
+ """
+ xml = etree.parse(xml_file).getroot()
+ return _from_file(xml)
def _from_file(xml):
- """
- Recursivly parse the xml tree into nested data format.
-
- Args:
- xml: the xml tree
-
- Returns:
- the nested data
- """
- tag = xml.tag
- if not len(xml):
- return odict({tag: xml.text or ''}) #store empty tags (text is None) as empty string
- nested_data = odict()
- for elem in xml:
- key, value = _from_file(elem).items()[0]
- if nested_data.has_key(key): nested_data[key].append(value)
- else: nested_data[key] = [value]
- #delistify if the length of values is 1
- for key, values in nested_data.iteritems():
- if len(values) == 1: nested_data[key] = values[0]
- return odict({tag: nested_data})
+ """
+ Recursivly parse the xml tree into nested data format.
+
+ Args:
+ xml: the xml tree
+
+ Returns:
+ the nested data
+ """
+ tag = xml.tag
+ if not len(xml):
+ return odict({tag: xml.text or ''}) #store empty tags (text is None) as empty string
+ nested_data = odict()
+ for elem in xml:
+ key, value = _from_file(elem).items()[0]
+ if nested_data.has_key(key): nested_data[key].append(value)
+ else: nested_data[key] = [value]
+ #delistify if the length of values is 1
+ for key, values in nested_data.iteritems():
+ if len(values) == 1: nested_data[key] = values[0]
+
+ return odict({tag: nested_data})
def to_file(nested_data, xml_file):
- """
- Write an xml file and use the to xml helper method to load it.
-
- Args:
- nested_data: the nested data
- xml_file: the xml file path
- """
- xml = _to_file(nested_data)[0]
- open(xml_file, 'w').write(etree.tostring(xml, xml_declaration=True, pretty_print=True))
+ """
+ Write an xml file and use the to xml helper method to load it.
+
+ Args:
+ nested_data: the nested data
+ xml_file: the xml file path
+ """
+ xml = _to_file(nested_data)[0]
+ open(xml_file, 'w').write(etree.tostring(xml, xml_declaration=True, pretty_print=True))
def _to_file(nested_data):
- """
- Recursivly parse the nested data into xml tree format.
-
- Args:
- nested_data: the nested data
-
- Returns:
- the xml tree filled with child nodes
- """
- nodes = list()
- for key, values in nested_data.iteritems():
- #listify the values if not a list
- if not isinstance(values, (list, set, tuple)):
- values = [values]
- for value in values:
- node = etree.Element(key)
- if isinstance(value, (str, unicode)): node.text = value
- else: node.extend(_to_file(value))
- nodes.append(node)
- return nodes
+ """
+ Recursivly parse the nested data into xml tree format.
+
+ Args:
+ nested_data: the nested data
+
+ Returns:
+ the xml tree filled with child nodes
+ """
+ nodes = list()
+ for key, values in nested_data.iteritems():
+ #listify the values if not a list
+ if not isinstance(values, (list, set, tuple)):
+ values = [values]
+ for value in values:
+ node = etree.Element(key)
+ if isinstance(value, (str, unicode)): node.text = value
+ else: node.extend(_to_file(value))
+ nodes.append(node)
+ return nodes
if __name__ == '__main__':
- """Use the main method to test parse xml's functions."""
- pass
+ """Use the main method to test parse xml's functions."""
+ pass
diff --git a/grc/base/Platform.py b/grc/base/Platform.py
index f0f24a48a7..bb80e29552 100644
--- a/grc/base/Platform.py
+++ b/grc/base/Platform.py
@@ -30,159 +30,159 @@ from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD
class Platform(_Element):
- def __init__(self, name, version, key,
- block_paths, block_dtd, default_flow_graph, generator,
- license='', website=None, colors=[]):
- """
- Make a platform from the arguments.
-
- Args:
- name: the platform name
- version: the version string
- key: the unique platform key
- block_paths: the file paths to blocks in this platform
- block_dtd: the dtd validator for xml block wrappers
- default_flow_graph: the default flow graph file path
- generator: the generator class for this platform
- colors: a list of title, color_spec tuples
- license: a multi-line license (first line is copyright)
- website: the website url for this platform
-
- Returns:
- a platform object
- """
- _Element.__init__(self)
- self._name = name
- self._version = version
- self._key = key
- self._license = license
- self._website = website
- self._block_paths = block_paths
- self._block_dtd = block_dtd
- self._default_flow_graph = default_flow_graph
- self._generator = generator
- self._colors = colors
- #create a dummy flow graph for the blocks
- self._flow_graph = _Element(self)
- #search for *.xml files in the given search path
-
- self.loadblocks();
+ def __init__(self, name, version, key,
+ block_paths, block_dtd, default_flow_graph, generator,
+ license='', website=None, colors=[]):
+ """
+ Make a platform from the arguments.
+
+ Args:
+ name: the platform name
+ version: the version string
+ key: the unique platform key
+ block_paths: the file paths to blocks in this platform
+ block_dtd: the dtd validator for xml block wrappers
+ default_flow_graph: the default flow graph file path
+ generator: the generator class for this platform
+ colors: a list of title, color_spec tuples
+ license: a multi-line license (first line is copyright)
+ website: the website url for this platform
+
+ Returns:
+ a platform object
+ """
+ _Element.__init__(self)
+ self._name = name
+ self._version = version
+ self._key = key
+ self._license = license
+ self._website = website
+ self._block_paths = block_paths
+ self._block_dtd = block_dtd
+ self._default_flow_graph = default_flow_graph
+ self._generator = generator
+ self._colors = colors
+ #create a dummy flow graph for the blocks
+ self._flow_graph = _Element(self)
+ #search for *.xml files in the given search path
+
+ self.loadblocks();
- def loadblocks(self):
- xml_files = list()
- for block_path in self._block_paths:
- if os.path.isfile(block_path): xml_files.append(block_path)
- elif os.path.isdir(block_path):
- for dirpath, dirnames, filenames in os.walk(block_path):
- for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
- xml_files.append(os.path.join(dirpath, filename))
- #load the blocks
- self._blocks = odict()
- self._blocks_n = odict()
- self._block_tree_files = list()
- for xml_file in xml_files:
- try: #try to add the xml file as a block wrapper
- ParseXML.validate_dtd(xml_file, self._block_dtd)
- n = ParseXML.from_file(xml_file).find('block')
- #inject block wrapper path
- n['block_wrapper_path'] = xml_file
- block = self.Block(self._flow_graph, n)
- key = block.get_key()
- #test against repeated keys
- if key in self.get_block_keys():
- print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file)
- #store the block
- else:
- self._blocks[key] = block
- self._blocks_n[key] = n
- except ParseXML.XMLSyntaxError, e:
- try: #try to add the xml file as a block tree
- ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
- self._block_tree_files.append(xml_file)
- except ParseXML.XMLSyntaxError, e:
- print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
- except Exception, e:
- print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
-
- def parse_flow_graph(self, flow_graph_file):
- """
- Parse a saved flow graph file.
- Ensure that the file exists, and passes the dtd check.
-
- Args:
- flow_graph_file: the flow graph file
-
- Returns:
- nested data
- @throws exception if the validation fails
- """
- flow_graph_file = flow_graph_file or self._default_flow_graph
- open(flow_graph_file, 'r') #test open
- ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
- return ParseXML.from_file(flow_graph_file)
-
- def load_block_tree(self, block_tree):
- """
- Load a block tree with categories and blocks.
- Step 1: Load all blocks from the xml specification.
- Step 2: Load blocks with builtin category specifications.
-
- Args:
- block_tree: the block tree object
- """
- #recursive function to load categories and blocks
- def load_category(cat_n, parent=[]):
- #add this category
- parent = parent + [cat_n.find('name')]
- block_tree.add_block(parent)
- #recursive call to load sub categories
- map(lambda c: load_category(c, parent), cat_n.findall('cat'))
- #add blocks in this category
- for block_key in cat_n.findall('block'):
- if block_key not in self.get_block_keys():
- print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.'%(block_key)
- continue
- block = self.get_block(block_key)
- #if it exists, the block's category overrides the block tree
- if not block.get_category(): block_tree.add_block(parent, block)
- #load the block tree
- for block_tree_file in self._block_tree_files:
- #recursivly add all blocks in the tree
- load_category(ParseXML.from_file(block_tree_file).find('cat'))
- #add all other blocks, use the catgory tag
- for block in self.get_blocks():
- #blocks with empty categories are in the xml block tree or hidden
- if not block.get_category(): continue
- block_tree.add_block(block.get_category(), block)
-
- def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
-
- def is_platform(self): return True
-
- def get_new_flow_graph(self): return self.FlowGraph(platform=self)
-
- def get_generator(self): return self._generator
-
- ##############################################
- # Access Blocks
- ##############################################
- def get_block_keys(self): return self._blocks.keys()
- def get_block(self, key): return self._blocks[key]
- def get_blocks(self): return self._blocks.values()
- def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
-
- def get_name(self): return self._name
- def get_version(self): return self._version
- def get_key(self): return self._key
- def get_license(self): return self._license
- def get_website(self): return self._website
- def get_colors(self): return self._colors
-
- ##############################################
- # Constructors
- ##############################################
- FlowGraph = _FlowGraph
- Connection = _Connection
- Block = _Block
- Port = _Port
- Param = _Param
+ def loadblocks(self):
+ xml_files = list()
+ for block_path in self._block_paths:
+ if os.path.isfile(block_path): xml_files.append(block_path)
+ elif os.path.isdir(block_path):
+ for dirpath, dirnames, filenames in os.walk(block_path):
+ for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
+ xml_files.append(os.path.join(dirpath, filename))
+ #load the blocks
+ self._blocks = odict()
+ self._blocks_n = odict()
+ self._block_tree_files = list()
+ for xml_file in xml_files:
+ try: #try to add the xml file as a block wrapper
+ ParseXML.validate_dtd(xml_file, self._block_dtd)
+ n = ParseXML.from_file(xml_file).find('block')
+ #inject block wrapper path
+ n['block_wrapper_path'] = xml_file
+ block = self.Block(self._flow_graph, n)
+ key = block.get_key()
+ #test against repeated keys
+ if key in self.get_block_keys():
+ print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file)
+ #store the block
+ else:
+ self._blocks[key] = block
+ self._blocks_n[key] = n
+ except ParseXML.XMLSyntaxError, e:
+ try: #try to add the xml file as a block tree
+ ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
+ self._block_tree_files.append(xml_file)
+ except ParseXML.XMLSyntaxError, e:
+ print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
+ except Exception, e:
+ print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
+
+ def parse_flow_graph(self, flow_graph_file):
+ """
+ Parse a saved flow graph file.
+ Ensure that the file exists, and passes the dtd check.
+
+ Args:
+ flow_graph_file: the flow graph file
+
+ Returns:
+ nested data
+ @throws exception if the validation fails
+ """
+ flow_graph_file = flow_graph_file or self._default_flow_graph
+ open(flow_graph_file, 'r') #test open
+ ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
+ return ParseXML.from_file(flow_graph_file)
+
+ def load_block_tree(self, block_tree):
+ """
+ Load a block tree with categories and blocks.
+ Step 1: Load all blocks from the xml specification.
+ Step 2: Load blocks with builtin category specifications.
+
+ Args:
+ block_tree: the block tree object
+ """
+ #recursive function to load categories and blocks
+ def load_category(cat_n, parent=[]):
+ #add this category
+ parent = parent + [cat_n.find('name')]
+ block_tree.add_block(parent)
+ #recursive call to load sub categories
+ map(lambda c: load_category(c, parent), cat_n.findall('cat'))
+ #add blocks in this category
+ for block_key in cat_n.findall('block'):
+ if block_key not in self.get_block_keys():
+ print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.'%(block_key)
+ continue
+ block = self.get_block(block_key)
+ #if it exists, the block's category overrides the block tree
+ if not block.get_category(): block_tree.add_block(parent, block)
+ #load the block tree
+ for block_tree_file in self._block_tree_files:
+ #recursivly add all blocks in the tree
+ load_category(ParseXML.from_file(block_tree_file).find('cat'))
+ #add all other blocks, use the catgory tag
+ for block in self.get_blocks():
+ #blocks with empty categories are in the xml block tree or hidden
+ if not block.get_category(): continue
+ block_tree.add_block(block.get_category(), block)
+
+ def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
+
+ def is_platform(self): return True
+
+ def get_new_flow_graph(self): return self.FlowGraph(platform=self)
+
+ def get_generator(self): return self._generator
+
+ ##############################################
+ # Access Blocks
+ ##############################################
+ def get_block_keys(self): return self._blocks.keys()
+ def get_block(self, key): return self._blocks[key]
+ def get_blocks(self): return self._blocks.values()
+ def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
+
+ def get_name(self): return self._name
+ def get_version(self): return self._version
+ def get_key(self): return self._key
+ def get_license(self): return self._license
+ def get_website(self): return self._website
+ def get_colors(self): return self._colors
+
+ ##############################################
+ # Constructors
+ ##############################################
+ FlowGraph = _FlowGraph
+ Connection = _Connection
+ Block = _Block
+ Port = _Port
+ Param = _Param
diff --git a/grc/base/Port.py b/grc/base/Port.py
index 0e58f583c3..b7de5301f1 100644
--- a/grc/base/Port.py
+++ b/grc/base/Port.py
@@ -21,69 +21,96 @@ from Element import Element
class Port(Element):
- def __init__(self, block, n, dir):
- """
- Make a new port from nested data.
-
- Args:
- block: the parent element
- n: the nested odict
- dir: the direction source or sink
- """
- #build the port
- Element.__init__(self, block)
- #grab the data
- self._name = n['name']
- self._key = n['key']
- self._type = n['type']
- self._dir = dir
+ def __init__(self, block, n, dir):
+ """
+ Make a new port from nested data.
+
+ Args:
+ block: the parent element
+ n: the nested odict
+ dir: the direction source or sink
+ """
+ #build the port
+ Element.__init__(self, block)
+ #grab the data
+ self._name = n['name']
+ self._key = n['key']
+ self._type = n['type']
+ self._dir = dir
- def validate(self):
- """
- Validate the port.
- The port must be non-empty and type must a possible type.
- """
- Element.validate(self)
- if self.get_type() not in self.get_types():
- self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
+ def validate(self):
+ """
+ Validate the port.
+ The port must be non-empty and type must a possible type.
+ """
+ Element.validate(self)
+ if self.get_type() not in self.get_types():
+ self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
- def __str__(self):
- if self.is_source():
- return 'Source - %s(%s)'%(self.get_name(), self.get_key())
- if self.is_sink():
- return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
+ def __str__(self):
+ if self.is_source():
+ return 'Source - %s(%s)'%(self.get_name(), self.get_key())
+ if self.is_sink():
+ return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
- def get_types(self):
- """
- Get a list of all possible port types.
- @throw NotImplementedError
- """
- raise NotImplementedError
+ def get_types(self):
+ """
+ Get a list of all possible port types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
- def is_port(self): return True
- def get_color(self): return '#FFFFFF'
- def get_name(self): return self._name
- def get_key(self): return self._key
- def is_sink(self): return self._dir == 'sink'
- def is_source(self): return self._dir == 'source'
- def get_type(self): return self.get_parent().resolve_dependencies(self._type)
+ def is_port(self): return True
+ def get_color(self): return '#FFFFFF'
+ def get_name(self):
+ number = ''
+ if self.get_type() == 'bus':
+ busses = filter(lambda a: a._dir == self._dir, self.get_parent().get_ports_gui());
+
+ number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports()));
+ return self._name + number
- def get_connections(self):
- """
- Get all connections that use this port.
-
- Returns:
- a list of connection objects
- """
- connections = self.get_parent().get_parent().get_connections()
- connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections)
- return connections
+ def get_key(self): return self._key
+ def is_sink(self): return self._dir == 'sink'
+ def is_source(self): return self._dir == 'source'
+ def get_type(self): return self.get_parent().resolve_dependencies(self._type)
- def get_enabled_connections(self):
- """
- Get all enabled connections that use this port.
-
- Returns:
- a list of connection objects
- """
- return filter(lambda c: c.get_enabled(), self.get_connections())
+ def get_connections(self):
+ """
+ Get all connections that use this port.
+
+ Returns:
+ a list of connection objects
+ """
+ connections = self.get_parent().get_parent().get_connections()
+ connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections)
+ return connections
+
+ def get_enabled_connections(self):
+ """
+ Get all enabled connections that use this port.
+
+ Returns:
+ a list of connection objects
+ """
+ return filter(lambda c: c.get_enabled(), self.get_connections())
+
+ def get_associated_ports(self):
+ if not self.get_type() == 'bus':
+ return [self];
+ else:
+ if self.is_source():
+ get_p = self.get_parent().get_sources;
+ bus_structure = self.get_parent().current_bus_structure['source'];
+ direc = 'source'
+ else:
+ get_p = self.get_parent().get_sinks;
+ bus_structure = self.get_parent().current_bus_structure['sink'];
+ direc = 'sink'
+
+ ports = [i for i in get_p() if not i.get_type() == 'bus'];
+ if bus_structure:
+ busses = [i for i in get_p() if i.get_type() == 'bus'];
+ bus_index = busses.index(self);
+ ports = filter(lambda a: ports.index(a) in bus_structure[bus_index], ports);
+ return ports;
diff --git a/grc/base/block_tree.dtd b/grc/base/block_tree.dtd
index 7d4a13ccc3..9e23576477 100644
--- a/grc/base/block_tree.dtd
+++ b/grc/base/block_tree.dtd
@@ -17,9 +17,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-->
<!--
- block_tree.dtd
- Josh Blum
- The document type definition for a block tree category listing.
+ block_tree.dtd
+ Josh Blum
+ The document type definition for a block tree category listing.
-->
<!ELEMENT cat (name, cat*, block*)>
<!ELEMENT name (#PCDATA)>
diff --git a/grc/base/flow_graph.dtd b/grc/base/flow_graph.dtd
index 74f48f10ab..bdfe1dc059 100644
--- a/grc/base/flow_graph.dtd
+++ b/grc/base/flow_graph.dtd
@@ -17,17 +17,19 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-->
<!--
- flow_graph.dtd
- Josh Blum
- The document type definition for flow graph xml files.
+ flow_graph.dtd
+ Josh Blum
+ The document type definition for flow graph xml files.
-->
<!ELEMENT flow_graph (timestamp?, block*, connection*)> <!-- optional timestamp -->
<!ELEMENT timestamp (#PCDATA)>
<!-- Block -->
-<!ELEMENT block (key, param*)>
+<!ELEMENT block (key, param*, bus_sink?, bus_source?)>
<!ELEMENT param (key, value)>
<!ELEMENT key (#PCDATA)>
<!ELEMENT value (#PCDATA)>
+<!ELEMENT bus_sink (#PCDATA)>
+<!ELEMENT bus_source (#PCDATA)>
<!-- Connection -->
<!ELEMENT connection (source_block_id, sink_block_id, source_key, sink_key)>
<!ELEMENT source_block_id (#PCDATA)>
diff --git a/grc/base/odict.py b/grc/base/odict.py
index 302583163b..0c03d753f6 100644
--- a/grc/base/odict.py
+++ b/grc/base/odict.py
@@ -21,85 +21,85 @@ from UserDict import DictMixin
class odict(DictMixin):
- def __init__(self, d={}):
- self._keys = list(d.keys())
- self._data = dict(d.copy())
+ def __init__(self, d={}):
+ self._keys = list(d.keys())
+ self._data = dict(d.copy())
- def __setitem__(self, key, value):
- if key not in self._data:
- self._keys.append(key)
- self._data[key] = value
+ def __setitem__(self, key, value):
+ if key not in self._data:
+ self._keys.append(key)
+ self._data[key] = value
- def __getitem__(self, key):
- return self._data[key]
+ def __getitem__(self, key):
+ return self._data[key]
- def __delitem__(self, key):
- del self._data[key]
- self._keys.remove(key)
+ def __delitem__(self, key):
+ del self._data[key]
+ self._keys.remove(key)
- def keys(self):
- return list(self._keys)
+ def keys(self):
+ return list(self._keys)
- def copy(self):
- copy_dict = odict()
- copy_dict._data = self._data.copy()
- copy_dict._keys = list(self._keys)
- return copy_dict
+ def copy(self):
+ copy_dict = odict()
+ copy_dict._data = self._data.copy()
+ copy_dict._keys = list(self._keys)
+ return copy_dict
- def insert_after(self, pos_key, key, val):
- """
- Insert the new key, value entry after the entry given by the position key.
- If the positional key is None, insert at the end.
-
- Args:
- pos_key: the positional key
- key: the key for the new entry
- val: the value for the new entry
- """
- index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key)
- if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
- self._keys.insert(index+1, key)
- self._data[key] = val
+ def insert_after(self, pos_key, key, val):
+ """
+ Insert the new key, value entry after the entry given by the position key.
+ If the positional key is None, insert at the end.
+
+ Args:
+ pos_key: the positional key
+ key: the key for the new entry
+ val: the value for the new entry
+ """
+ index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key)
+ if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
+ self._keys.insert(index+1, key)
+ self._data[key] = val
- def insert_before(self, pos_key, key, val):
- """
- Insert the new key, value entry before the entry given by the position key.
- If the positional key is None, insert at the begining.
-
- Args:
- pos_key: the positional key
- key: the key for the new entry
- val: the value for the new entry
- """
- index = (pos_key is not None) and self._keys.index(pos_key) or 0
- if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
- self._keys.insert(index, key)
- self._data[key] = val
+ def insert_before(self, pos_key, key, val):
+ """
+ Insert the new key, value entry before the entry given by the position key.
+ If the positional key is None, insert at the begining.
+
+ Args:
+ pos_key: the positional key
+ key: the key for the new entry
+ val: the value for the new entry
+ """
+ index = (pos_key is not None) and self._keys.index(pos_key) or 0
+ if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
+ self._keys.insert(index, key)
+ self._data[key] = val
- def find(self, key):
- """
- Get the value for this key if exists.
-
- Args:
- key: the key to search for
-
- Returns:
- the value or None
- """
- if self.has_key(key): return self[key]
- return None
+ def find(self, key):
+ """
+ Get the value for this key if exists.
+
+ Args:
+ key: the key to search for
+
+ Returns:
+ the value or None
+ """
+ if self.has_key(key): return self[key]
+ return None
- def findall(self, key):
- """
- Get a list of values for this key.
-
- Args:
- key: the key to search for
-
- Returns:
- a list of values or empty list
- """
- obj = self.find(key)
- if obj is None: obj = list()
- if isinstance(obj, list): return obj
- return [obj]
+ def findall(self, key):
+ """
+ Get a list of values for this key.
+
+ Args:
+ key: the key to search for
+
+ Returns:
+ a list of values or empty list
+ """
+ obj = self.find(key)
+ if obj is None: obj = list()
+ if isinstance(obj, list): return obj
+ return [obj]
diff --git a/grc/blocks/bus_sink.xml b/grc/blocks/bus_sink.xml
new file mode 100644
index 0000000000..273b4c517a
--- /dev/null
+++ b/grc/blocks/bus_sink.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Bus Sink
+###################################################
+ -->
+<block>
+ <name>Bus Sink</name>
+ <key>bus_sink</key>
+ <make>$yesno.yesno</make>
+
+ <param>
+ <name>On/Off</name>
+ <key>yesno</key>
+ <type>enum</type>
+ <option>
+ <name>On</name>
+ <key>on</key>
+ <opt>yesno:True</opt>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>off</key>
+ <opt>yesno:False</opt>
+ </option>
+ </param>
+</block>
diff --git a/grc/blocks/bus_source.xml b/grc/blocks/bus_source.xml
new file mode 100644
index 0000000000..15e4a9f31b
--- /dev/null
+++ b/grc/blocks/bus_source.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Bus Sink
+###################################################
+ -->
+<block>
+ <name>Bus Source</name>
+ <key>bus_source</key>
+ <make>$yesno.yesno</make>
+
+ <param>
+ <name>On/Off</name>
+ <key>yesno</key>
+ <type>enum</type>
+ <option>
+ <name>On</name>
+ <key>on</key>
+ <opt>yesno:True</opt>
+ </option>
+ <option>
+ <name>Off</name>
+ <key>off</key>
+ <opt>yesno:False</opt>
+ </option>
+ </param>
+</block>
diff --git a/grc/blocks/bus_structure_sink.xml b/grc/blocks/bus_structure_sink.xml
new file mode 100644
index 0000000000..df16657282
--- /dev/null
+++ b/grc/blocks/bus_structure_sink.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Bus Sink
+###################################################
+ -->
+<block>
+ <name>Bus Sink Structure</name>
+ <key>bus_structure_sink</key>
+ <make>None</make>
+
+ <param>
+ <name>Structure</name>
+ <key>struct</key>
+ <value></value>
+ <type>raw</type>
+ </param>
+</block>
diff --git a/grc/blocks/bus_structure_source.xml b/grc/blocks/bus_structure_source.xml
new file mode 100644
index 0000000000..27652ca3b3
--- /dev/null
+++ b/grc/blocks/bus_structure_source.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Bus Sink
+###################################################
+ -->
+<block>
+ <name>Bus Source Structure</name>
+ <key>bus_structure_source</key>
+ <make>None</make>
+
+ <param>
+ <name>Structure</name>
+ <key>struct</key>
+ <value></value>
+ <type>raw</type>
+ </param>
+</block>
diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml
index f0e10a3391..37e132c34c 100644
--- a/grc/blocks/pad_sink.xml
+++ b/grc/blocks/pad_sink.xml
@@ -62,6 +62,13 @@ None;self.message_port_register_hier_in($label)
<value>1</value>
<type>int</type>
</param>
+
+ <param>
+ <name>Num Streams</name>
+ <key>num_streams</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
<param>
<name>Optional</name>
<key>optional</key>
@@ -78,10 +85,12 @@ None;self.message_port_register_hier_in($label)
</option>
</param>
<check>$vlen &gt; 0</check>
+ <check>$num_streams &gt; 0</check>
<sink>
<name>in</name>
<type>$type</type>
<vlen>$vlen</vlen>
+ <nports>$num_streams</nports>
</sink>
<doc>
The inputs of this block will become the outputs to this flow graph when it is instantiated as a hierarchical block.
diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml
index a56a65dcc3..b6faebfc68 100644
--- a/grc/blocks/pad_source.xml
+++ b/grc/blocks/pad_source.xml
@@ -62,6 +62,14 @@ None;self.message_port_register_hier_out($label)
<value>1</value>
<type>int</type>
</param>
+
+ <param>
+ <name>Num Streams</name>
+ <key>num_streams</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+
<param>
<name>Optional</name>
<key>optional</key>
@@ -78,10 +86,12 @@ None;self.message_port_register_hier_out($label)
</option>
</param>
<check>$vlen &gt; 0</check>
+ <check>$num_streams &gt; 0</check>
<source>
<name>out</name>
<type>$type</type>
<vlen>$vlen</vlen>
+ <nports>$num_streams</nports>
</source>
<doc>
The outputs of this block will become the inputs to this flow graph when it is instantiated as a hierarchical block.
diff --git a/grc/blocks/variable_constellation.xml b/grc/blocks/variable_constellation.xml
new file mode 100644
index 0000000000..7d23ede9be
--- /dev/null
+++ b/grc/blocks/variable_constellation.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Options Block:
+## options for window size,
+## and flow graph building.
+###################################################
+ -->
+<block>
+ <name>Constellation Object</name>
+ <key>variable_constellation</key>
+ <category>Modulators</category>
+ <import>from gnuradio import digital</import>
+ <var_make>self.$(id) = $(id) = digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims).base()</var_make>
+ <make></make>
+ <!--<callback></callback>-->
+
+ <!-- Required to 'trick' GRC into using this as a proper variable-->
+ <param>
+ <name>Ignore Me</name>
+ <key>value</key>
+ <value>"ok"</value>
+ <type>raw</type>
+ <hide>all</hide>
+ </param>
+
+ <param>
+ <name>Symbol Map</name>
+ <key>sym_map</key>
+ <value>[0, 1, 3, 2]</value>
+ <type>int_vector</type>
+ </param>
+ <param>
+ <name>Constellation Points</name>
+ <key>const_points</key>
+ <value>[-1-1j, -1+1j, 1+1j, 1-1j]</value>
+ <type>complex_vector</type>
+ </param>
+ <param>
+ <name>Rotational Symmetry</name>
+ <key>rot_sym</key>
+ <value>4</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Dimensionality</name>
+ <key>dims</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+</block>
diff --git a/grc/blocks/variable_constellation_rect.xml b/grc/blocks/variable_constellation_rect.xml
new file mode 100644
index 0000000000..5c136ee324
--- /dev/null
+++ b/grc/blocks/variable_constellation_rect.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Options Block:
+## options for window size,
+## and flow graph building.
+###################################################
+ -->
+<block>
+ <name>Constellation Rect. Object</name>
+ <key>variable_constellation_rect</key>
+ <category>Modulators</category>
+ <import>from gnuradio import digital</import>
+ <var_make>self.$(id) = $(id) = digital.constellation_rect($const_points, $sym_map, $rot_sym, $real_sect, $imag_sect, $w_real_sect, $w_imag_sect).base()</var_make>
+ <make></make>
+ <!--<callback></callback>-->
+
+ <!-- Required to 'trick' GRC into using this as a proper variable-->
+ <param>
+ <name>Ignore Me</name>
+ <key>value</key>
+ <value>"ok"</value>
+ <type>raw</type>
+ <hide>all</hide>
+ </param>
+
+ <param>
+ <name>Symbol Map</name>
+ <key>sym_map</key>
+ <value>[0, 1, 3, 2]</value>
+ <type>int_vector</type>
+ </param>
+ <param>
+ <name>Constellation Points</name>
+ <key>const_points</key>
+ <value>[-1-1j, -1+1j, 1+1j, 1-1j]</value>
+ <type>complex_vector</type>
+ </param>
+ <param>
+ <name>Rotational Symmetry</name>
+ <key>rot_sym</key>
+ <value>4</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Real Sectors</name>
+ <key>real_sect</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Imaginary Sectors</name>
+ <key>imag_sect</key>
+ <value>2</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Width Real Sectors</name>
+ <key>w_real_sect</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Width Imaginary Sectors</name>
+ <key>w_imag_sect</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+</block>
diff --git a/grc/examples/xmlrpc/xmlrpc_client_script.py b/grc/examples/xmlrpc/xmlrpc_client_script.py
index 8f00fa55d8..e96c4cbf83 100644
--- a/grc/examples/xmlrpc/xmlrpc_client_script.py
+++ b/grc/examples/xmlrpc/xmlrpc_client_script.py
@@ -9,15 +9,15 @@ s = xmlrpclib.Server("http://localhost:1234")
#randomly change parameters of the sinusoid
for i in range(10):
- #generate random values
- new_freq = random.uniform(0, 5000)
- new_ampl = random.uniform(0, 2)
- new_offset = random.uniform(-1, 1)
- #set new values
- time.sleep(1)
- s.set_freq(new_freq)
- time.sleep(1)
- s.set_ampl(new_ampl)
- time.sleep(1)
- s.set_offset(new_offset)
+ #generate random values
+ new_freq = random.uniform(0, 5000)
+ new_ampl = random.uniform(0, 2)
+ new_offset = random.uniform(-1, 1)
+ #set new values
+ time.sleep(1)
+ s.set_freq(new_freq)
+ time.sleep(1)
+ s.set_ampl(new_ampl)
+ time.sleep(1)
+ s.set_offset(new_offset)
diff --git a/grc/grc_gnuradio/blks2/__init__.py b/grc/grc_gnuradio/blks2/__init__.py
index fde76f2563..e6941ab91b 100644
--- a/grc/grc_gnuradio/blks2/__init__.py
+++ b/grc/grc_gnuradio/blks2/__init__.py
@@ -20,7 +20,7 @@
from selector import selector, valve
from packet import options, packet_encoder, packet_decoder, \
- packet_mod_b, packet_mod_s, packet_mod_i, packet_mod_f, packet_mod_c, \
- packet_demod_b, packet_demod_s, packet_demod_i, packet_demod_f, packet_demod_c
+ packet_mod_b, packet_mod_s, packet_mod_i, packet_mod_f, packet_mod_c, \
+ packet_demod_b, packet_demod_s, packet_demod_i, packet_demod_f, packet_demod_c
from error_rate import error_rate
from tcp import tcp_source, tcp_sink
diff --git a/grc/grc_gnuradio/blks2/error_rate.py b/grc/grc_gnuradio/blks2/error_rate.py
index 7970f29bae..95ded7dadc 100644
--- a/grc/grc_gnuradio/blks2/error_rate.py
+++ b/grc/grc_gnuradio/blks2/error_rate.py
@@ -29,112 +29,112 @@ import numpy
_1s_counts = [sum([1&(i>>j) for j in range(8)]) for i in range(2**8)]
class input_watcher(_threading.Thread):
- """
- Read samples from the message queue and hand them to the callback.
- """
+ """
+ Read samples from the message queue and hand them to the callback.
+ """
- def __init__(self, msgq, callback):
- self._msgq = msgq
- self._callback = callback
- _threading.Thread.__init__(self)
- self.setDaemon(1)
- self.keep_running = True
- self.start()
+ def __init__(self, msgq, callback):
+ self._msgq = msgq
+ self._callback = callback
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.keep_running = True
+ self.start()
- def run(self):
- r = ''
- while True:
- msg = self._msgq.delete_head()
- itemsize = int(msg.arg1())
- nitems = int(msg.arg2())
- s = r + msg.to_string()
- i = (nitems-nitems%2)*itemsize
- r = s[i:]
- s = s[:i]
- samples = numpy.fromstring(s, numpy.int8)
- self._callback(samples)
+ def run(self):
+ r = ''
+ while True:
+ msg = self._msgq.delete_head()
+ itemsize = int(msg.arg1())
+ nitems = int(msg.arg2())
+ s = r + msg.to_string()
+ i = (nitems-nitems%2)*itemsize
+ r = s[i:]
+ s = s[:i]
+ samples = numpy.fromstring(s, numpy.int8)
+ self._callback(samples)
class error_rate(gr.hier_block2):
- """
- Sample the incoming data streams (byte) and calculate the bit or symbol error rate.
- Write the running rate to the output data stream (float).
- """
+ """
+ Sample the incoming data streams (byte) and calculate the bit or symbol error rate.
+ Write the running rate to the output data stream (float).
+ """
- def __init__(self, type='BER', win_size=default_win_size, bits_per_symbol=2):
- """
- Error rate constructor.
-
- Args:
- type: a string 'BER' or 'SER'
- win_size: the number of samples to calculate over
- bits_per_symbol: the number of information bits per symbol (BER only)
- """
- #init
- gr.hier_block2.__init__(
- self, 'error_rate',
- gr.io_signature(2, 2, gr.sizeof_char),
- gr.io_signature(1, 1, gr.sizeof_float),
- )
- assert type in ('BER', 'SER')
- self._max_samples = win_size
- self._bits_per_symbol = bits_per_symbol
- #setup message queue
- msg_source = blocks.message_source(gr.sizeof_float, 1)
- self._msgq_source = msg_source.msgq()
- msgq_sink = gr.msg_queue(2)
- msg_sink = blocks.message_sink(gr.sizeof_char, msgq_sink, False) #False -> blocking
- inter = blocks.interleave(gr.sizeof_char)
- #start thread
- self._num_errs = 0
- self._err_index = 0
- self._num_samps = 0
- self._err_array = numpy.zeros(self._max_samples, numpy.int8)
- if type == 'BER':
- input_watcher(msgq_sink, self._handler_ber)
- elif type == 'SER':
- input_watcher(msgq_sink, self._handler_ser)
- #connect
- self.connect(msg_source, self)
- self.connect((self, 0), (inter, 0))
- self.connect((self, 1), (inter, 1))
- self.connect(inter, msg_sink)
+ def __init__(self, type='BER', win_size=default_win_size, bits_per_symbol=2):
+ """
+ Error rate constructor.
+
+ Args:
+ type: a string 'BER' or 'SER'
+ win_size: the number of samples to calculate over
+ bits_per_symbol: the number of information bits per symbol (BER only)
+ """
+ #init
+ gr.hier_block2.__init__(
+ self, 'error_rate',
+ gr.io_signature(2, 2, gr.sizeof_char),
+ gr.io_signature(1, 1, gr.sizeof_float),
+ )
+ assert type in ('BER', 'SER')
+ self._max_samples = win_size
+ self._bits_per_symbol = bits_per_symbol
+ #setup message queue
+ msg_source = blocks.message_source(gr.sizeof_float, 1)
+ self._msgq_source = msg_source.msgq()
+ msgq_sink = gr.msg_queue(2)
+ msg_sink = blocks.message_sink(gr.sizeof_char, msgq_sink, False) #False -> blocking
+ inter = blocks.interleave(gr.sizeof_char)
+ #start thread
+ self._num_errs = 0
+ self._err_index = 0
+ self._num_samps = 0
+ self._err_array = numpy.zeros(self._max_samples, numpy.int8)
+ if type == 'BER':
+ input_watcher(msgq_sink, self._handler_ber)
+ elif type == 'SER':
+ input_watcher(msgq_sink, self._handler_ser)
+ #connect
+ self.connect(msg_source, self)
+ self.connect((self, 0), (inter, 0))
+ self.connect((self, 1), (inter, 1))
+ self.connect(inter, msg_sink)
- def _handler_ber(self, samples):
- num = len(samples)/2
- arr = numpy.zeros(num, numpy.float32)
- for i in range(num):
- old_err = self._err_array[self._err_index]
- #record error
- self._err_array[self._err_index] = _1s_counts[samples[i*2] ^ samples[i*2 + 1]]
- self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err
- #increment index
- self._err_index = (self._err_index + 1)%self._max_samples
- self._num_samps = min(self._num_samps + 1, self._max_samples)
- #write sample
- arr[i] = float(self._num_errs)/float(self._num_samps*self._bits_per_symbol)
- #write message
- msg = blocks.message_from_string(arr.tostring(), 0, gr.sizeof_float, num)
- self._msgq_source.insert_tail(msg)
+ def _handler_ber(self, samples):
+ num = len(samples)/2
+ arr = numpy.zeros(num, numpy.float32)
+ for i in range(num):
+ old_err = self._err_array[self._err_index]
+ #record error
+ self._err_array[self._err_index] = _1s_counts[samples[i*2] ^ samples[i*2 + 1]]
+ self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err
+ #increment index
+ self._err_index = (self._err_index + 1)%self._max_samples
+ self._num_samps = min(self._num_samps + 1, self._max_samples)
+ #write sample
+ arr[i] = float(self._num_errs)/float(self._num_samps*self._bits_per_symbol)
+ #write message
+ msg = blocks.message_from_string(arr.tostring(), 0, gr.sizeof_float, num)
+ self._msgq_source.insert_tail(msg)
- def _handler_ser(self, samples):
- num = len(samples)/2
- arr = numpy.zeros(num, numpy.float32)
- for i in range(num):
- old_err = self._err_array[self._err_index]
- #record error
- ref = samples[i*2]
- res = samples[i*2 + 1]
- if ref == res:
- self._err_array[self._err_index] = 0
- else:
- self._err_array[self._err_index] = 1
- #update number of errors
- self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err
- #increment index
- self._err_index = (self._err_index + 1)%self._max_samples
- self._num_samps = min(self._num_samps + 1, self._max_samples)
- #write sample
- arr[i] = float(self._num_errs)/float(self._num_samps)
- #write message
- msg = blocks.message_from_string(arr.tostring(), 0, gr.sizeof_float, num)
- self._msgq_source.insert_tail(msg)
+ def _handler_ser(self, samples):
+ num = len(samples)/2
+ arr = numpy.zeros(num, numpy.float32)
+ for i in range(num):
+ old_err = self._err_array[self._err_index]
+ #record error
+ ref = samples[i*2]
+ res = samples[i*2 + 1]
+ if ref == res:
+ self._err_array[self._err_index] = 0
+ else:
+ self._err_array[self._err_index] = 1
+ #update number of errors
+ self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err
+ #increment index
+ self._err_index = (self._err_index + 1)%self._max_samples
+ self._num_samps = min(self._num_samps + 1, self._max_samples)
+ #write sample
+ arr[i] = float(self._num_errs)/float(self._num_samps)
+ #write message
+ msg = blocks.message_from_string(arr.tostring(), 0, gr.sizeof_float, num)
+ self._msgq_source.insert_tail(msg)
diff --git a/grc/grc_gnuradio/blks2/packet.py b/grc/grc_gnuradio/blks2/packet.py
index 4c7bd235dd..10dd002471 100644
--- a/grc/grc_gnuradio/blks2/packet.py
+++ b/grc/grc_gnuradio/blks2/packet.py
@@ -36,176 +36,176 @@ DEFAULT_THRESHOLD = 12
## Options Class for OFDM
##################################################
class options(object):
- def __init__(self, **kwargs):
- for key, value in kwargs.iteritems(): setattr(self, key, value)
+ def __init__(self, **kwargs):
+ for key, value in kwargs.iteritems(): setattr(self, key, value)
##################################################
## Packet Encoder
##################################################
class _packet_encoder_thread(_threading.Thread):
- def __init__(self, msgq, payload_length, send):
- self._msgq = msgq
- self._payload_length = payload_length
- self._send = send
- _threading.Thread.__init__(self)
- self.setDaemon(1)
- self.keep_running = True
- self.start()
-
- def run(self):
- sample = '' #residual sample
- while self.keep_running:
- msg = self._msgq.delete_head() #blocking read of message queue
- sample = sample + msg.to_string() #get the body of the msg as a string
- while len(sample) >= self._payload_length:
- payload = sample[:self._payload_length]
- sample = sample[self._payload_length:]
- self._send(payload)
+ def __init__(self, msgq, payload_length, send):
+ self._msgq = msgq
+ self._payload_length = payload_length
+ self._send = send
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.keep_running = True
+ self.start()
+
+ def run(self):
+ sample = '' #residual sample
+ while self.keep_running:
+ msg = self._msgq.delete_head() #blocking read of message queue
+ sample = sample + msg.to_string() #get the body of the msg as a string
+ while len(sample) >= self._payload_length:
+ payload = sample[:self._payload_length]
+ sample = sample[self._payload_length:]
+ self._send(payload)
class packet_encoder(gr.hier_block2):
- """
- Hierarchical block for wrapping packet-based modulators.
- """
-
- def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True):
- """
- packet_mod constructor.
-
- Args:
- samples_per_symbol: number of samples per symbol
- bits_per_symbol: number of bits per symbol
- access_code: AKA sync vector
- pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
- payload_length: number of bytes in a data-stream slice
- """
- #setup parameters
- self._samples_per_symbol = samples_per_symbol
- self._bits_per_symbol = bits_per_symbol
- self._pad_for_usrp = pad_for_usrp
- if not access_code: #get access code
- access_code = packet_utils.default_access_code
- if not packet_utils.is_1_0_string(access_code):
- raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
- self._access_code = access_code
- self._pad_for_usrp = pad_for_usrp
- #create blocks
- msg_source = blocks.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT)
- self._msgq_out = msg_source.msgq()
- #initialize hier2
- gr.hier_block2.__init__(
- self,
- "packet_encoder",
- gr.io_signature(0, 0, 0), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char) # Output signature
- )
- #connect
- self.connect(msg_source, self)
-
- def send_pkt(self, payload):
- """
- Wrap the payload in a packet and push onto the message queue.
-
- Args:
- payload: string, data to send
- """
- packet = packet_utils.make_packet(
- payload,
- self._samples_per_symbol,
- self._bits_per_symbol,
- self._access_code,
- self._pad_for_usrp
- )
- msg = gr.message_from_string(packet)
- self._msgq_out.insert_tail(msg)
+ """
+ Hierarchical block for wrapping packet-based modulators.
+ """
+
+ def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True):
+ """
+ packet_mod constructor.
+
+ Args:
+ samples_per_symbol: number of samples per symbol
+ bits_per_symbol: number of bits per symbol
+ access_code: AKA sync vector
+ pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
+ payload_length: number of bytes in a data-stream slice
+ """
+ #setup parameters
+ self._samples_per_symbol = samples_per_symbol
+ self._bits_per_symbol = bits_per_symbol
+ self._pad_for_usrp = pad_for_usrp
+ if not access_code: #get access code
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+ self._pad_for_usrp = pad_for_usrp
+ #create blocks
+ msg_source = blocks.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT)
+ self._msgq_out = msg_source.msgq()
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "packet_encoder",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char) # Output signature
+ )
+ #connect
+ self.connect(msg_source, self)
+
+ def send_pkt(self, payload):
+ """
+ Wrap the payload in a packet and push onto the message queue.
+
+ Args:
+ payload: string, data to send
+ """
+ packet = packet_utils.make_packet(
+ payload,
+ self._samples_per_symbol,
+ self._bits_per_symbol,
+ self._access_code,
+ self._pad_for_usrp
+ )
+ msg = gr.message_from_string(packet)
+ self._msgq_out.insert_tail(msg)
##################################################
## Packet Decoder
##################################################
class _packet_decoder_thread(_threading.Thread):
- def __init__(self, msgq, callback):
- _threading.Thread.__init__(self)
- self.setDaemon(1)
- self._msgq = msgq
- self.callback = callback
- self.keep_running = True
- self.start()
-
- def run(self):
- while self.keep_running:
- msg = self._msgq.delete_head()
- ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
- if self.callback:
- self.callback(ok, payload)
+ def __init__(self, msgq, callback):
+ _threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self._msgq = msgq
+ self.callback = callback
+ self.keep_running = True
+ self.start()
+
+ def run(self):
+ while self.keep_running:
+ msg = self._msgq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
+ if self.callback:
+ self.callback(ok, payload)
class packet_decoder(gr.hier_block2):
- """
- Hierarchical block for wrapping packet-based demodulators.
- """
-
- def __init__(self, access_code='', threshold=-1, callback=None):
- """
- packet_demod constructor.
-
- Args:
- access_code: AKA sync vector
- threshold: detect access_code with up to threshold bits wrong (0 -> use default)
- callback: a function of args: ok, payload
- """
- #access code
- if not access_code: #get access code
- access_code = packet_utils.default_access_code
- if not packet_utils.is_1_0_string(access_code):
- raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
- self._access_code = access_code
- #threshold
- if threshold < 0: threshold = DEFAULT_THRESHOLD
- self._threshold = threshold
- #blocks
- msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY
- correlator = digital.correlate_access_code_bb(self._access_code, self._threshold)
- framer_sink = digital.framer_sink_1(msgq)
- #initialize hier2
- gr.hier_block2.__init__(
- self,
- "packet_decoder",
- gr.io_signature(1, 1, gr.sizeof_char), # Input signature
- gr.io_signature(0, 0, 0) # Output signature
- )
- #connect
- self.connect(self, correlator, framer_sink)
- #start thread
- _packet_decoder_thread(msgq, callback)
+ """
+ Hierarchical block for wrapping packet-based demodulators.
+ """
+
+ def __init__(self, access_code='', threshold=-1, callback=None):
+ """
+ packet_demod constructor.
+
+ Args:
+ access_code: AKA sync vector
+ threshold: detect access_code with up to threshold bits wrong (0 -> use default)
+ callback: a function of args: ok, payload
+ """
+ #access code
+ if not access_code: #get access code
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+ #threshold
+ if threshold < 0: threshold = DEFAULT_THRESHOLD
+ self._threshold = threshold
+ #blocks
+ msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY
+ correlator = digital.correlate_access_code_bb(self._access_code, self._threshold)
+ framer_sink = digital.framer_sink_1(msgq)
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "packet_decoder",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(0, 0, 0) # Output signature
+ )
+ #connect
+ self.connect(self, correlator, framer_sink)
+ #start thread
+ _packet_decoder_thread(msgq, callback)
##################################################
## Packet Mod for OFDM Mod and Packet Encoder
##################################################
class packet_mod_base(gr.hier_block2):
- """
- Hierarchical block for wrapping packet source block.
- """
-
- def __init__(self, packet_source=None, payload_length=0):
- if not payload_length: #get payload length
- payload_length = DEFAULT_PAYLOAD_LEN
- if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size
- raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in)
- #initialize hier2
- gr.hier_block2.__init__(
- self,
- "ofdm_mod",
- gr.io_signature(1, 1, self._item_size_in), # Input signature
- gr.io_signature(1, 1, packet_source._hb.output_signature().sizeof_stream_item(0)) # Output signature
- )
- #create blocks
- msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT)
- msg_sink = blocks.message_sink(self._item_size_in, msgq, False) #False -> blocking
- #connect
- self.connect(self, msg_sink)
- self.connect(packet_source, self)
- #start thread
- _packet_encoder_thread(msgq, payload_length, packet_source.send_pkt)
+ """
+ Hierarchical block for wrapping packet source block.
+ """
+
+ def __init__(self, packet_source=None, payload_length=0):
+ if not payload_length: #get payload length
+ payload_length = DEFAULT_PAYLOAD_LEN
+ if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size
+ raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in)
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "ofdm_mod",
+ gr.io_signature(1, 1, self._item_size_in), # Input signature
+ gr.io_signature(1, 1, packet_source._hb.output_signature().sizeof_stream_item(0)) # Output signature
+ )
+ #create blocks
+ msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT)
+ msg_sink = blocks.message_sink(self._item_size_in, msgq, False) #False -> blocking
+ #connect
+ self.connect(self, msg_sink)
+ self.connect(packet_source, self)
+ #start thread
+ _packet_encoder_thread(msgq, payload_length, packet_source.send_pkt)
class packet_mod_b(packet_mod_base): _item_size_in = gr.sizeof_char
class packet_mod_s(packet_mod_base): _item_size_in = gr.sizeof_short
@@ -217,32 +217,32 @@ class packet_mod_c(packet_mod_base): _item_size_in = gr.sizeof_gr_complex
## Packet Demod for OFDM Demod and Packet Decoder
##################################################
class packet_demod_base(gr.hier_block2):
- """
- Hierarchical block for wrapping packet sink block.
- """
-
- def __init__(self, packet_sink=None):
- #initialize hier2
- gr.hier_block2.__init__(
- self,
- "ofdm_mod",
- gr.io_signature(1, 1, packet_sink._hb.input_signature().sizeof_stream_item(0)), # Input signature
- gr.io_signature(1, 1, self._item_size_out) # Output signature
- )
- #create blocks
- msg_source = blocks.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT)
- self._msgq_out = msg_source.msgq()
- #connect
- self.connect(self, packet_sink)
- self.connect(msg_source, self)
- if packet_sink._hb.output_signature().sizeof_stream_item(0):
- self.connect(packet_sink,
- blocks.null_sink(packet_sink._hb.output_signature().sizeof_stream_item(0)))
-
- def recv_pkt(self, ok, payload):
- msg = blocks.message_from_string(payload, 0, self._item_size_out,
- len(payload)/self._item_size_out)
- if ok: self._msgq_out.insert_tail(msg)
+ """
+ Hierarchical block for wrapping packet sink block.
+ """
+
+ def __init__(self, packet_sink=None):
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "ofdm_mod",
+ gr.io_signature(1, 1, packet_sink._hb.input_signature().sizeof_stream_item(0)), # Input signature
+ gr.io_signature(1, 1, self._item_size_out) # Output signature
+ )
+ #create blocks
+ msg_source = blocks.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT)
+ self._msgq_out = msg_source.msgq()
+ #connect
+ self.connect(self, packet_sink)
+ self.connect(msg_source, self)
+ if packet_sink._hb.output_signature().sizeof_stream_item(0):
+ self.connect(packet_sink,
+ blocks.null_sink(packet_sink._hb.output_signature().sizeof_stream_item(0)))
+
+ def recv_pkt(self, ok, payload):
+ msg = gr.message_from_string(payload, 0, self._item_size_out,
+ len(payload)/self._item_size_out)
+ if ok: self._msgq_out.insert_tail(msg)
class packet_demod_b(packet_demod_base): _item_size_out = gr.sizeof_char
class packet_demod_s(packet_demod_base): _item_size_out = gr.sizeof_short
diff --git a/grc/grc_gnuradio/blks2/selector.py b/grc/grc_gnuradio/blks2/selector.py
index bc393f84b6..7ae664823b 100644
--- a/grc/grc_gnuradio/blks2/selector.py
+++ b/grc/grc_gnuradio/blks2/selector.py
@@ -23,120 +23,120 @@ from gnuradio import gr
from gnuradio import blocks
class selector(gr.hier_block2):
- """A hier2 block with N inputs and M outputs, where data is only forwarded through input n to output m."""
- def __init__(self, item_size, num_inputs, num_outputs, input_index, output_index):
- """
- Selector constructor.
-
- Args:
- item_size: the size of the gr data stream in bytes
- num_inputs: the number of inputs (integer)
- num_outputs: the number of outputs (integer)
- input_index: the index for the source data
- output_index: the index for the destination data
- """
- gr.hier_block2.__init__(
- self, 'selector',
- gr.io_signature(num_inputs, num_inputs, item_size),
- gr.io_signature(num_outputs, num_outputs, item_size),
- )
- #terminator blocks for unused inputs and outputs
- self.input_terminators = [blocks.null_sink(item_size) for i in range(num_inputs)]
- self.output_terminators = [blocks.head(item_size, 0) for i in range(num_outputs)]
- self.copy = blocks.copy(item_size)
- #connections
- for i in range(num_inputs): self.connect((self, i), self.input_terminators[i])
- for i in range(num_outputs): self.connect(blocks.null_source(item_size),
+ """A hier2 block with N inputs and M outputs, where data is only forwarded through input n to output m."""
+ def __init__(self, item_size, num_inputs, num_outputs, input_index, output_index):
+ """
+ Selector constructor.
+
+ Args:
+ item_size: the size of the gr data stream in bytes
+ num_inputs: the number of inputs (integer)
+ num_outputs: the number of outputs (integer)
+ input_index: the index for the source data
+ output_index: the index for the destination data
+ """
+ gr.hier_block2.__init__(
+ self, 'selector',
+ gr.io_signature(num_inputs, num_inputs, item_size),
+ gr.io_signature(num_outputs, num_outputs, item_size),
+ )
+ #terminator blocks for unused inputs and outputs
+ self.input_terminators = [blocks.null_sink(item_size) for i in range(num_inputs)]
+ self.output_terminators = [blocks.head(item_size, 0) for i in range(num_outputs)]
+ self.copy = blocks.copy(item_size)
+ #connections
+ for i in range(num_inputs): self.connect((self, i), self.input_terminators[i])
+ for i in range(num_outputs): self.connect(blocks.null_source(item_size),
self.output_terminators[i], (self, i))
- self.item_size = item_size
- self.input_index = input_index
- self.output_index = output_index
- self.num_inputs = num_inputs
- self.num_outputs = num_outputs
- self._connect_current()
+ self.item_size = item_size
+ self.input_index = input_index
+ self.output_index = output_index
+ self.num_inputs = num_inputs
+ self.num_outputs = num_outputs
+ self._connect_current()
- def _indexes_valid(self):
- """
- Are the input and output indexes within range of the number of inputs and outputs?
-
- Returns:
- true if input index and output index are in range
- """
- return self.input_index in range(self.num_inputs) and self.output_index in range(self.num_outputs)
+ def _indexes_valid(self):
+ """
+ Are the input and output indexes within range of the number of inputs and outputs?
+
+ Returns:
+ true if input index and output index are in range
+ """
+ return self.input_index in range(self.num_inputs) and self.output_index in range(self.num_outputs)
- def _connect_current(self):
- """If the input and output indexes are valid:
- disconnect the blocks at the input and output index from their terminators,
- and connect them to one another. Then connect the terminators to one another."""
- if self._indexes_valid():
- self.disconnect((self, self.input_index), self.input_terminators[self.input_index])
- self.disconnect(self.output_terminators[self.output_index], (self, self.output_index))
- self.connect((self, self.input_index), self.copy)
- self.connect(self.copy, (self, self.output_index))
- self.connect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
+ def _connect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from their terminators,
+ and connect them to one another. Then connect the terminators to one another."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index), self.input_terminators[self.input_index])
+ self.disconnect(self.output_terminators[self.output_index], (self, self.output_index))
+ self.connect((self, self.input_index), self.copy)
+ self.connect(self.copy, (self, self.output_index))
+ self.connect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
- def _disconnect_current(self):
- """If the input and output indexes are valid:
- disconnect the blocks at the input and output index from one another,
- and the terminators at the input and output index from one another.
- Reconnect the blocks to the terminators."""
- if self._indexes_valid():
- self.disconnect((self, self.input_index), self.copy)
- self.disconnect(self.copy, (self, self.output_index))
- self.disconnect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
- self.connect((self, self.input_index), self.input_terminators[self.input_index])
- self.connect(self.output_terminators[self.output_index], (self, self.output_index))
+ def _disconnect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from one another,
+ and the terminators at the input and output index from one another.
+ Reconnect the blocks to the terminators."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index), self.copy)
+ self.disconnect(self.copy, (self, self.output_index))
+ self.disconnect(self.output_terminators[self.output_index], self.input_terminators[self.input_index])
+ self.connect((self, self.input_index), self.input_terminators[self.input_index])
+ self.connect(self.output_terminators[self.output_index], (self, self.output_index))
- def set_input_index(self, input_index):
- """
- Change the block to the new input index if the index changed.
-
- Args:
- input_index: the new input index
- """
- if self.input_index != input_index:
- self.lock()
- self._disconnect_current()
- self.input_index = input_index
- self._connect_current()
- self.unlock()
+ def set_input_index(self, input_index):
+ """
+ Change the block to the new input index if the index changed.
+
+ Args:
+ input_index: the new input index
+ """
+ if self.input_index != input_index:
+ self.lock()
+ self._disconnect_current()
+ self.input_index = input_index
+ self._connect_current()
+ self.unlock()
- def set_output_index(self, output_index):
- """
- Change the block to the new output index if the index changed.
-
- Args:
- output_index: the new output index
- """
- if self.output_index != output_index:
- self.lock()
- self._disconnect_current()
- self.output_index = output_index
- self._connect_current()
- self.unlock()
+ def set_output_index(self, output_index):
+ """
+ Change the block to the new output index if the index changed.
+
+ Args:
+ output_index: the new output index
+ """
+ if self.output_index != output_index:
+ self.lock()
+ self._disconnect_current()
+ self.output_index = output_index
+ self._connect_current()
+ self.unlock()
class valve(selector):
- """Wrapper for selector with 1 input and 1 output."""
+ """Wrapper for selector with 1 input and 1 output."""
- def __init__(self, item_size, open):
- """
- Constructor for valve.
-
- Args:
- item_size: the size of the gr data stream in bytes
- open: true if initial valve state is open
- """
- if open: output_index = -1
- else: output_index = 0
- selector.__init__(self, item_size, 1, 1, 0, output_index)
+ def __init__(self, item_size, open):
+ """
+ Constructor for valve.
+
+ Args:
+ item_size: the size of the gr data stream in bytes
+ open: true if initial valve state is open
+ """
+ if open: output_index = -1
+ else: output_index = 0
+ selector.__init__(self, item_size, 1, 1, 0, output_index)
- def set_open(self, open):
- """
- Callback to set open state.
-
- Args:
- open: true to set valve state to open
- """
- if open: output_index = -1
- else: output_index = 0
- self.set_output_index(output_index)
+ def set_open(self, open):
+ """
+ Callback to set open state.
+
+ Args:
+ open: true to set valve state to open
+ """
+ if open: output_index = -1
+ else: output_index = 0
+ self.set_output_index(output_index)
diff --git a/grc/grc_gnuradio/blks2/tcp.py b/grc/grc_gnuradio/blks2/tcp.py
index 33160020cb..8613c02a17 100644
--- a/grc/grc_gnuradio/blks2/tcp.py
+++ b/grc/grc_gnuradio/blks2/tcp.py
@@ -24,47 +24,47 @@ import socket
import os
def _get_sock_fd(addr, port, server):
- """
- Get the file descriptor for the socket.
- As a client, block on connect, dup the socket descriptor.
- As a server, block on accept, dup the client descriptor.
-
- Args:
- addr: the ip address string
- port: the tcp port number
- server: true for server mode, false for client mode
-
- Returns:
- the file descriptor number
- """
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- if server:
- sock.bind((addr, port))
- sock.listen(1)
- clientsock, address = sock.accept()
- return os.dup(clientsock.fileno())
- else:
- sock.connect((addr, port))
- return os.dup(sock.fileno())
+ """
+ Get the file descriptor for the socket.
+ As a client, block on connect, dup the socket descriptor.
+ As a server, block on accept, dup the client descriptor.
+
+ Args:
+ addr: the ip address string
+ port: the tcp port number
+ server: true for server mode, false for client mode
+
+ Returns:
+ the file descriptor number
+ """
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if server:
+ sock.bind((addr, port))
+ sock.listen(1)
+ clientsock, address = sock.accept()
+ return os.dup(clientsock.fileno())
+ else:
+ sock.connect((addr, port))
+ return os.dup(sock.fileno())
class tcp_source(gr.hier_block2):
- def __init__(self, itemsize, addr, port, server=True):
- #init hier block
- gr.hier_block2.__init__(
- self, 'tcp_source',
- gr.io_signature(0, 0, 0),
- gr.io_signature(1, 1, itemsize),
- )
- fd = _get_sock_fd(addr, port, server)
- self.connect(blocks.file_descriptor_source(itemsize, fd), self)
+ def __init__(self, itemsize, addr, port, server=True):
+ #init hier block
+ gr.hier_block2.__init__(
+ self, 'tcp_source',
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(1, 1, itemsize),
+ )
+ fd = _get_sock_fd(addr, port, server)
+ self.connect(blocks.file_descriptor_source(itemsize, fd), self)
class tcp_sink(gr.hier_block2):
- def __init__(self, itemsize, addr, port, server=False):
- #init hier block
- gr.hier_block2.__init__(
- self, 'tcp_sink',
- gr.io_signature(1, 1, itemsize),
- gr.io_signature(0, 0, 0),
- )
- fd = _get_sock_fd(addr, port, server)
- self.connect(self, blocks.file_descriptor_sink(itemsize, fd))
+ def __init__(self, itemsize, addr, port, server=False):
+ #init hier block
+ gr.hier_block2.__init__(
+ self, 'tcp_sink',
+ gr.io_signature(1, 1, itemsize),
+ gr.io_signature(0, 0, 0),
+ )
+ fd = _get_sock_fd(addr, port, server)
+ self.connect(self, blocks.file_descriptor_sink(itemsize, fd))
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index add32dbdac..71d62fc8f5 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -37,132 +37,132 @@ from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveIm
gobject.threads_init()
class ActionHandler:
- """
- The action handler will setup all the major window components,
- and handle button presses and flow graph operations from the GUI.
- """
-
- def __init__(self, file_paths, platform):
- """
- ActionHandler constructor.
- Create the main window, setup the message handler, import the preferences,
- and connect all of the action handlers. Finally, enter the gtk main loop and block.
-
- Args:
- file_paths: a list of flow graph file passed from command line
- platform: platform module
- """
- self.clipboard = None
- for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
- #setup the main window
- self.platform = platform;
- self.main_window = MainWindow(platform)
- self.main_window.connect('delete-event', self._quit)
- self.main_window.connect('key-press-event', self._handle_key_press)
- self.get_page = self.main_window.get_page
- self.get_flow_graph = self.main_window.get_flow_graph
- self.get_focus_flag = self.main_window.get_focus_flag
- #setup the messages
- Messages.register_messenger(self.main_window.add_report_line)
- Messages.send_init(platform)
- #initialize
- self.init_file_paths = file_paths
- Actions.APPLICATION_INITIALIZE()
- #enter the mainloop
- gtk.main()
-
- def _handle_key_press(self, widget, event):
- """
- Handle key presses from the keyboard and translate key combinations into actions.
- This key press handler is called prior to the gtk key press handler.
- This handler bypasses built in accelerator key handling when in focus because
- * some keys are ignored by the accelerators like the direction keys,
- * some keys are not registered to any accelerators but are still used.
- When not in focus, gtk and the accelerators handle the the key press.
-
- Returns:
- false to let gtk handle the key action
- """
- if not self.get_focus_flag(): return False
- return Actions.handle_key_press(event)
-
- def _quit(self, window, event):
- """
- Handle the delete event from the main window.
- Generated by pressing X to close, alt+f4, or right click+close.
- This method in turns calls the state handler to quit.
-
- Returns:
- true
- """
- Actions.APPLICATION_QUIT()
- return True
-
- def _handle_action(self, action):
- #print action
- ##################################################
- # Initalize/Quit
- ##################################################
- if action == Actions.APPLICATION_INITIALIZE:
- for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled
- #enable a select few actions
- for action in (
- Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
- Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
- Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
- Actions.TYPES_WINDOW_DISPLAY,
- ): action.set_sensitive(True)
- if not self.init_file_paths:
- self.init_file_paths = Preferences.files_open()
- if not self.init_file_paths: self.init_file_paths = ['']
- for file_path in self.init_file_paths:
- if file_path: self.main_window.new_page(file_path) #load pages from file paths
- if Preferences.file_open() in self.init_file_paths:
- self.main_window.new_page(Preferences.file_open(), show=True)
- if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists
- elif action == Actions.APPLICATION_QUIT:
- if self.main_window.close_pages():
- gtk.main_quit()
- exit(0)
- ##################################################
- # Selections
- ##################################################
- elif action == Actions.ELEMENT_SELECT:
- pass #do nothing, update routines below
- elif action == Actions.NOTHING_SELECT:
- self.get_flow_graph().unselect()
- ##################################################
- # Enable/Disable
- ##################################################
- elif action == Actions.BLOCK_ENABLE:
- if self.get_flow_graph().enable_selected(True):
- 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)
- elif action == Actions.BLOCK_DISABLE:
- if self.get_flow_graph().enable_selected(False):
- 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)
- ##################################################
- # Cut/Copy/Paste
- ##################################################
- elif action == Actions.BLOCK_CUT:
- Actions.BLOCK_COPY()
- Actions.ELEMENT_DELETE()
- elif action == Actions.BLOCK_COPY:
- self.clipboard = self.get_flow_graph().copy_to_clipboard()
- elif action == Actions.BLOCK_PASTE:
- if self.clipboard:
- self.get_flow_graph().paste_from_clipboard(self.clipboard)
- 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)
+ """
+ The action handler will setup all the major window components,
+ and handle button presses and flow graph operations from the GUI.
+ """
+
+ def __init__(self, file_paths, platform):
+ """
+ ActionHandler constructor.
+ Create the main window, setup the message handler, import the preferences,
+ and connect all of the action handlers. Finally, enter the gtk main loop and block.
+
+ Args:
+ file_paths: a list of flow graph file passed from command line
+ platform: platform module
+ """
+ self.clipboard = None
+ for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
+ #setup the main window
+ self.platform = platform;
+ self.main_window = MainWindow(platform)
+ self.main_window.connect('delete-event', self._quit)
+ self.main_window.connect('key-press-event', self._handle_key_press)
+ self.get_page = self.main_window.get_page
+ self.get_flow_graph = self.main_window.get_flow_graph
+ self.get_focus_flag = self.main_window.get_focus_flag
+ #setup the messages
+ Messages.register_messenger(self.main_window.add_report_line)
+ Messages.send_init(platform)
+ #initialize
+ self.init_file_paths = file_paths
+ Actions.APPLICATION_INITIALIZE()
+ #enter the mainloop
+ gtk.main()
+
+ def _handle_key_press(self, widget, event):
+ """
+ Handle key presses from the keyboard and translate key combinations into actions.
+ This key press handler is called prior to the gtk key press handler.
+ This handler bypasses built in accelerator key handling when in focus because
+ * some keys are ignored by the accelerators like the direction keys,
+ * some keys are not registered to any accelerators but are still used.
+ When not in focus, gtk and the accelerators handle the the key press.
+
+ Returns:
+ false to let gtk handle the key action
+ """
+ if not self.get_focus_flag(): return False
+ return Actions.handle_key_press(event)
+
+ def _quit(self, window, event):
+ """
+ Handle the delete event from the main window.
+ Generated by pressing X to close, alt+f4, or right click+close.
+ This method in turns calls the state handler to quit.
+
+ Returns:
+ true
+ """
+ Actions.APPLICATION_QUIT()
+ return True
+
+ def _handle_action(self, action):
+ #print action
+ ##################################################
+ # Initalize/Quit
+ ##################################################
+ if action == Actions.APPLICATION_INITIALIZE:
+ for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled
+ #enable a select few actions
+ for action in (
+ Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
+ Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
+ Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
+ Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
+ Actions.TYPES_WINDOW_DISPLAY,
+ ): action.set_sensitive(True)
+ if not self.init_file_paths:
+ self.init_file_paths = Preferences.files_open()
+ if not self.init_file_paths: self.init_file_paths = ['']
+ for file_path in self.init_file_paths:
+ if file_path: self.main_window.new_page(file_path) #load pages from file paths
+ if Preferences.file_open() in self.init_file_paths:
+ self.main_window.new_page(Preferences.file_open(), show=True)
+ if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists
+ elif action == Actions.APPLICATION_QUIT:
+ if self.main_window.close_pages():
+ gtk.main_quit()
+ exit(0)
+ ##################################################
+ # Selections
+ ##################################################
+ elif action == Actions.ELEMENT_SELECT:
+ pass #do nothing, update routines below
+ elif action == Actions.NOTHING_SELECT:
+ self.get_flow_graph().unselect()
+ ##################################################
+ # Enable/Disable
+ ##################################################
+ elif action == Actions.BLOCK_ENABLE:
+ if self.get_flow_graph().enable_selected(True):
+ 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)
+ elif action == Actions.BLOCK_DISABLE:
+ if self.get_flow_graph().enable_selected(False):
+ 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)
+ ##################################################
+ # Cut/Copy/Paste
+ ##################################################
+ elif action == Actions.BLOCK_CUT:
+ Actions.BLOCK_COPY()
+ Actions.ELEMENT_DELETE()
+ elif action == Actions.BLOCK_COPY:
+ self.clipboard = self.get_flow_graph().copy_to_clipboard()
+ elif action == Actions.BLOCK_PASTE:
+ if self.clipboard:
+ self.get_flow_graph().paste_from_clipboard(self.clipboard)
+ 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:
+ elif action == Actions.BLOCK_CREATE_HIER:
# keeping track of coordinates for pasting later
coords = self.get_flow_graph().get_selected_blocks()[0].get_coordinate()
@@ -211,8 +211,8 @@ class ActionHandler:
# 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_COPY()
+ self.main_window.new_page()
Actions.BLOCK_PASTE()
coords = (x_min,y_min)
self.get_flow_graph().move_selected(coords)
@@ -284,255 +284,272 @@ class ActionHandler:
new_connection = self.get_flow_graph().connect(pad_source,sink)
# update the new heir block flow graph
- self.get_flow_graph().update()
+ self.get_flow_graph().update()
- ##################################################
- # Move/Rotate/Delete/Create
- ##################################################
- elif action == Actions.BLOCK_MOVE:
- self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
- self.get_page().set_saved(False)
- elif action == Actions.BLOCK_ROTATE_CCW:
- if self.get_flow_graph().rotate_selected(90):
- 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)
- elif action == Actions.BLOCK_ROTATE_CW:
- if self.get_flow_graph().rotate_selected(-90):
- 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)
- elif action == Actions.ELEMENT_DELETE:
- if self.get_flow_graph().remove_selected():
- self.get_flow_graph().update()
- self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
- Actions.NOTHING_SELECT()
- self.get_page().set_saved(False)
- elif action == Actions.ELEMENT_CREATE:
- self.get_flow_graph().update()
- self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
- Actions.NOTHING_SELECT()
- self.get_page().set_saved(False)
- elif action == Actions.BLOCK_INC_TYPE:
- if self.get_flow_graph().type_controller_modify_selected(1):
- 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)
- elif action == Actions.BLOCK_DEC_TYPE:
- if self.get_flow_graph().type_controller_modify_selected(-1):
- 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)
- elif action == Actions.PORT_CONTROLLER_INC:
- if self.get_flow_graph().port_controller_modify_selected(1):
- 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)
- elif action == Actions.PORT_CONTROLLER_DEC:
- if self.get_flow_graph().port_controller_modify_selected(-1):
- 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)
- ##################################################
- # Window stuff
- ##################################################
- elif action == Actions.ABOUT_WINDOW_DISPLAY:
- Dialogs.AboutDialog(self.get_flow_graph().get_parent())
- elif action == Actions.HELP_WINDOW_DISPLAY:
- Dialogs.HelpDialog()
- elif action == Actions.TYPES_WINDOW_DISPLAY:
- Dialogs.TypesDialog(self.get_flow_graph().get_parent())
- elif action == Actions.ERRORS_WINDOW_DISPLAY:
- Dialogs.ErrorsDialog(self.get_flow_graph())
- ##################################################
- # Param Modifications
- ##################################################
- elif action == Actions.BLOCK_PARAM_MODIFY:
- selected_block = self.get_flow_graph().get_selected_block()
- if selected_block:
- if PropsDialog(selected_block).run():
- #save the new state
- 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)
- else:
- #restore the current state
- n = self.get_page().get_state_cache().get_current_state()
- self.get_flow_graph().import_data(n)
- self.get_flow_graph().update()
- ##################################################
- # Undo/Redo
- ##################################################
- elif action == Actions.FLOW_GRAPH_UNDO:
- n = self.get_page().get_state_cache().get_prev_state()
- if n:
- self.get_flow_graph().unselect()
- self.get_flow_graph().import_data(n)
- self.get_flow_graph().update()
- self.get_page().set_saved(False)
- elif action == Actions.FLOW_GRAPH_REDO:
- n = self.get_page().get_state_cache().get_next_state()
- if n:
- self.get_flow_graph().unselect()
- self.get_flow_graph().import_data(n)
- self.get_flow_graph().update()
- self.get_page().set_saved(False)
- ##################################################
- # New/Open/Save/Close
- ##################################################
- elif action == Actions.FLOW_GRAPH_NEW:
- self.main_window.new_page()
- elif action == Actions.FLOW_GRAPH_OPEN:
- file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run()
- if file_paths: #open a new page for each file, show only the first
- for i,file_path in enumerate(file_paths):
- self.main_window.new_page(file_path, show=(i==0))
- elif action == Actions.FLOW_GRAPH_CLOSE:
- self.main_window.close_page()
- elif action == Actions.FLOW_GRAPH_SAVE:
- #read-only or undefined file path, do save-as
- if self.get_page().get_read_only() or not self.get_page().get_file_path():
- Actions.FLOW_GRAPH_SAVE_AS()
- #otherwise try to save
- 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())
- self.get_page().set_saved(False)
- elif action == Actions.FLOW_GRAPH_SAVE_AS:
- file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run()
- if file_path is not None:
- self.get_page().set_file_path(file_path)
- Actions.FLOW_GRAPH_SAVE()
- elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
- file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
- if file_path is not None:
- pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf()
- pixbuf.save(file_path, IMAGE_FILE_EXTENSION[1:])
- ##################################################
- # Gen/Exec/Stop
- ##################################################
- elif action == Actions.FLOW_GRAPH_GEN:
- if not self.get_page().get_proc():
- if not self.get_page().get_saved() or not self.get_page().get_file_path():
- Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved
- if self.get_page().get_saved() and self.get_page().get_file_path():
- generator = self.get_page().get_generator()
- try:
- Messages.send_start_gen(generator.get_file_path())
- generator.write()
- except Exception,e: Messages.send_fail_gen(e)
- else: self.generator = None
- elif action == Actions.FLOW_GRAPH_EXEC:
- if not self.get_page().get_proc():
- Actions.FLOW_GRAPH_GEN()
- if self.get_page().get_saved() and self.get_page().get_file_path():
- ExecFlowGraphThread(self)
- elif action == Actions.FLOW_GRAPH_KILL:
- if self.get_page().get_proc():
- try: self.get_page().get_proc().kill()
- except: print "could not kill process: %d"%self.get_page().get_proc().pid
- elif action == Actions.PAGE_CHANGE: #pass and run the global actions
- pass
- elif action == Actions.RELOAD_BLOCKS:
- self.platform.loadblocks()
- self.main_window.btwin.clear();
- self.platform.load_block_tree(self.main_window.btwin);
- elif action == Actions.OPEN_HIER:
- bn = [];
- for b in self.get_flow_graph().get_selected_blocks():
- if b._grc_source:
- self.main_window.new_page(b._grc_source, show=True);
- else: print '!!! Action "%s" not handled !!!'%action
- ##################################################
- # Global Actions for all States
- ##################################################
- #update general buttons
- Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid())
- Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
- Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block()))
- Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
- Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
- #update cut/copy/paste
- Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
- Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
- Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
- #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
- self.update_exec_stop()
- #saved status
- Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved())
- self.main_window.update()
- try: #set the size of the flow graph area (if changed)
- new_size = self.get_flow_graph().get_option('window_size')
- if self.get_flow_graph().get_size() != tuple(new_size):
- self.get_flow_graph().set_size(*new_size)
- except: pass
- #draw the flow graph
- self.get_flow_graph().update_selected()
- self.get_flow_graph().queue_draw()
- return True #action was handled
-
- def update_exec_stop(self):
- """
- Update the exec and stop buttons.
- Lock and unlock the mutex for race conditions with exec flow graph threads.
- """
- sensitive = self.get_flow_graph().is_valid() and not self.get_page().get_proc()
- Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_proc() != None)
+ ##################################################
+ # Move/Rotate/Delete/Create
+ ##################################################
+ elif action == Actions.BLOCK_MOVE:
+ self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+ self.get_page().set_saved(False)
+ elif action == Actions.BLOCK_ROTATE_CCW:
+ if self.get_flow_graph().rotate_selected(90):
+ 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)
+ elif action == Actions.BLOCK_ROTATE_CW:
+ if self.get_flow_graph().rotate_selected(-90):
+ 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)
+ elif action == Actions.ELEMENT_DELETE:
+ if self.get_flow_graph().remove_selected():
+ self.get_flow_graph().update()
+ self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+ Actions.NOTHING_SELECT()
+ self.get_page().set_saved(False)
+ elif action == Actions.ELEMENT_CREATE:
+ self.get_flow_graph().update()
+ self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+ Actions.NOTHING_SELECT()
+ self.get_page().set_saved(False)
+ elif action == Actions.BLOCK_INC_TYPE:
+ if self.get_flow_graph().type_controller_modify_selected(1):
+ 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)
+ elif action == Actions.BLOCK_DEC_TYPE:
+ if self.get_flow_graph().type_controller_modify_selected(-1):
+ 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)
+ elif action == Actions.PORT_CONTROLLER_INC:
+ if self.get_flow_graph().port_controller_modify_selected(1):
+ 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)
+ elif action == Actions.PORT_CONTROLLER_DEC:
+ if self.get_flow_graph().port_controller_modify_selected(-1):
+ 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)
+ ##################################################
+ # Window stuff
+ ##################################################
+ elif action == Actions.ABOUT_WINDOW_DISPLAY:
+ Dialogs.AboutDialog(self.get_flow_graph().get_parent())
+ elif action == Actions.HELP_WINDOW_DISPLAY:
+ Dialogs.HelpDialog()
+ elif action == Actions.TYPES_WINDOW_DISPLAY:
+ Dialogs.TypesDialog(self.get_flow_graph().get_parent())
+ elif action == Actions.ERRORS_WINDOW_DISPLAY:
+ Dialogs.ErrorsDialog(self.get_flow_graph())
+ ##################################################
+ # Param Modifications
+ ##################################################
+ elif action == Actions.BLOCK_PARAM_MODIFY:
+ selected_block = self.get_flow_graph().get_selected_block()
+ if selected_block:
+ if PropsDialog(selected_block).run():
+ #save the new state
+ 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)
+ else:
+ #restore the current state
+ n = self.get_page().get_state_cache().get_current_state()
+ self.get_flow_graph().import_data(n)
+ self.get_flow_graph().update()
+ ##################################################
+ # Undo/Redo
+ ##################################################
+ elif action == Actions.FLOW_GRAPH_UNDO:
+ n = self.get_page().get_state_cache().get_prev_state()
+ if n:
+ self.get_flow_graph().unselect()
+ self.get_flow_graph().import_data(n)
+ self.get_flow_graph().update()
+ self.get_page().set_saved(False)
+ elif action == Actions.FLOW_GRAPH_REDO:
+ n = self.get_page().get_state_cache().get_next_state()
+ if n:
+ self.get_flow_graph().unselect()
+ self.get_flow_graph().import_data(n)
+ self.get_flow_graph().update()
+ self.get_page().set_saved(False)
+ ##################################################
+ # New/Open/Save/Close
+ ##################################################
+ elif action == Actions.FLOW_GRAPH_NEW:
+ self.main_window.new_page()
+ elif action == Actions.FLOW_GRAPH_OPEN:
+ file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run()
+ if file_paths: #open a new page for each file, show only the first
+ for i,file_path in enumerate(file_paths):
+ self.main_window.new_page(file_path, show=(i==0))
+ elif action == Actions.FLOW_GRAPH_CLOSE:
+ self.main_window.close_page()
+ elif action == Actions.FLOW_GRAPH_SAVE:
+ #read-only or undefined file path, do save-as
+ if self.get_page().get_read_only() or not self.get_page().get_file_path():
+ Actions.FLOW_GRAPH_SAVE_AS()
+ #otherwise try to save
+ 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())
+ self.get_page().set_saved(False)
+ elif action == Actions.FLOW_GRAPH_SAVE_AS:
+ file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run()
+ if file_path is not None:
+ self.get_page().set_file_path(file_path)
+ Actions.FLOW_GRAPH_SAVE()
+ elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
+ file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
+ if file_path is not None:
+ pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf()
+ pixbuf.save(file_path, IMAGE_FILE_EXTENSION[1:])
+ ##################################################
+ # Gen/Exec/Stop
+ ##################################################
+ elif action == Actions.FLOW_GRAPH_GEN:
+ if not self.get_page().get_proc():
+ if not self.get_page().get_saved() or not self.get_page().get_file_path():
+ Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved
+ if self.get_page().get_saved() and self.get_page().get_file_path():
+ generator = self.get_page().get_generator()
+ try:
+ Messages.send_start_gen(generator.get_file_path())
+ generator.write()
+ except Exception,e: Messages.send_fail_gen(e)
+ else: self.generator = None
+ elif action == Actions.FLOW_GRAPH_EXEC:
+ if not self.get_page().get_proc():
+ Actions.FLOW_GRAPH_GEN()
+ if self.get_page().get_saved() and self.get_page().get_file_path():
+ ExecFlowGraphThread(self)
+ elif action == Actions.FLOW_GRAPH_KILL:
+ if self.get_page().get_proc():
+ try: self.get_page().get_proc().kill()
+ except: print "could not kill process: %d"%self.get_page().get_proc().pid
+ elif action == Actions.PAGE_CHANGE: #pass and run the global actions
+ pass
+ elif action == Actions.RELOAD_BLOCKS:
+ self.platform.loadblocks()
+ self.main_window.btwin.clear();
+ self.platform.load_block_tree(self.main_window.btwin);
+ elif action == Actions.OPEN_HIER:
+ bn = [];
+ for b in self.get_flow_graph().get_selected_blocks():
+ if b._grc_source:
+ self.main_window.new_page(b._grc_source, show=True);
+ elif action == Actions.BUSSIFY_SOURCES:
+ n = {'name':'bus', 'type':'bus'}
+ for b in self.get_flow_graph().get_selected_blocks():
+ b.bussify(n, 'source');
+ self.get_flow_graph()._old_selected_port = None;
+ self.get_flow_graph()._new_selected_port = None;
+ Actions.ELEMENT_CREATE();
+
+ elif action == Actions.BUSSIFY_SINKS:
+ n = {'name':'bus', 'type':'bus'}
+ for b in self.get_flow_graph().get_selected_blocks():
+ b.bussify(n, 'sink')
+ self.get_flow_graph()._old_selected_port = None;
+ self.get_flow_graph()._new_selected_port = None;
+ Actions.ELEMENT_CREATE();
+ else: print '!!! Action "%s" not handled !!!'%action
+ ##################################################
+ # Global Actions for all States
+ ##################################################
+ #update general buttons
+ Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid())
+ Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
+ Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block()))
+ Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ #update cut/copy/paste
+ Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
+ #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.BUSSIFY_SOURCES.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.BUSSIFY_SINKS.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+ Actions.RELOAD_BLOCKS.set_sensitive(True)
+ #set the exec and stop buttons
+ self.update_exec_stop()
+ #saved status
+ Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved())
+ self.main_window.update()
+ try: #set the size of the flow graph area (if changed)
+ new_size = self.get_flow_graph().get_option('window_size')
+ if self.get_flow_graph().get_size() != tuple(new_size):
+ self.get_flow_graph().set_size(*new_size)
+ except: pass
+ #draw the flow graph
+ self.get_flow_graph().update_selected()
+ self.get_flow_graph().queue_draw()
+ return True #action was handled
+
+ def update_exec_stop(self):
+ """
+ Update the exec and stop buttons.
+ Lock and unlock the mutex for race conditions with exec flow graph threads.
+ """
+ sensitive = self.get_flow_graph().is_valid() and not self.get_page().get_proc()
+ Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
+ Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
+ Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_proc() != None)
class ExecFlowGraphThread(Thread):
- """Execute the flow graph as a new process and wait on it to finish."""
-
- def __init__ (self, action_handler):
- """
- ExecFlowGraphThread constructor.
-
- Args:
- action_handler: an instance of an ActionHandler
- """
- Thread.__init__(self)
- self.update_exec_stop = action_handler.update_exec_stop
- self.flow_graph = action_handler.get_flow_graph()
- #store page and dont use main window calls in run
- self.page = action_handler.get_page()
- Messages.send_start_exec(self.page.get_generator().get_file_path())
- #get the popen
- try:
- self.p = self.page.get_generator().get_popen()
- self.page.set_proc(self.p)
- #update
- self.update_exec_stop()
- self.start()
- except Exception, e:
- Messages.send_verbose_exec(str(e))
- Messages.send_end_exec()
-
- def run(self):
- """
- Wait on the executing process by reading from its stdout.
- Use gobject.idle_add when calling functions that modify gtk objects.
- """
- #handle completion
- r = "\n"
- while(r):
- gobject.idle_add(Messages.send_verbose_exec, r)
- r = os.read(self.p.stdout.fileno(), 1024)
- gobject.idle_add(self.done)
-
- def done(self):
- """Perform end of execution tasks."""
- Messages.send_end_exec()
- self.page.set_proc(None)
- self.update_exec_stop()
+ """Execute the flow graph as a new process and wait on it to finish."""
+
+ def __init__ (self, action_handler):
+ """
+ ExecFlowGraphThread constructor.
+
+ Args:
+ action_handler: an instance of an ActionHandler
+ """
+ Thread.__init__(self)
+ self.update_exec_stop = action_handler.update_exec_stop
+ self.flow_graph = action_handler.get_flow_graph()
+ #store page and dont use main window calls in run
+ self.page = action_handler.get_page()
+ Messages.send_start_exec(self.page.get_generator().get_file_path())
+ #get the popen
+ try:
+ self.p = self.page.get_generator().get_popen()
+ self.page.set_proc(self.p)
+ #update
+ self.update_exec_stop()
+ self.start()
+ except Exception, e:
+ Messages.send_verbose_exec(str(e))
+ Messages.send_end_exec()
+
+ def run(self):
+ """
+ Wait on the executing process by reading from its stdout.
+ Use gobject.idle_add when calling functions that modify gtk objects.
+ """
+ #handle completion
+ r = "\n"
+ while(r):
+ gobject.idle_add(Messages.send_verbose_exec, r)
+ r = os.read(self.p.stdout.fileno(), 1024)
+ gobject.idle_add(self.done)
+
+ def done(self):
+ """Perform end of execution tasks."""
+ Messages.send_end_exec()
+ self.page.set_proc(None)
+ self.update_exec_stop()
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 9225b0bd52..a70109c021 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -30,26 +30,26 @@ _actions_keypress_dict = dict()
_keymap = gtk.gdk.keymap_get_default()
_used_mods_mask = NO_MODS_MASK
def handle_key_press(event):
- """
- Call the action associated with the key press event.
- Both the key value and the mask must have a match.
-
- Args:
- event: a gtk key press event
-
- Returns:
- true if handled
- """
- _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK)
- #extract the key value and the consumed modifiers
- keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
- event.hardware_keycode, event.state, event.group)
- #get the modifier mask and ignore irrelevant modifiers
- mod_mask = event.state & ~consumed & _used_mods_mask
- #look up the keypress and call the action
- try: _actions_keypress_dict[(keyval, mod_mask)]()
- except KeyError: return False #not handled
- return True #handled here
+ """
+ Call the action associated with the key press event.
+ Both the key value and the mask must have a match.
+
+ Args:
+ event: a gtk key press event
+
+ Returns:
+ true if handled
+ """
+ _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK)
+ #extract the key value and the consumed modifiers
+ keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
+ event.hardware_keycode, event.state, event.group)
+ #get the modifier mask and ignore irrelevant modifiers
+ mod_mask = event.state & ~consumed & _used_mods_mask
+ #look up the keypress and call the action
+ try: _actions_keypress_dict[(keyval, mod_mask)]()
+ except KeyError: return False #not handled
+ return True #handled here
_all_actions_list = list()
def get_all_actions(): return _all_actions_list
@@ -58,240 +58,250 @@ _accel_group = gtk.AccelGroup()
def get_accel_group(): return _accel_group
class Action(gtk.Action):
- """
- A custom Action class based on gtk.Action.
- Pass additional arguments such as keypresses.
- Register actions and keypresses with this module.
- """
+ """
+ A custom Action class based on gtk.Action.
+ Pass additional arguments such as keypresses.
+ Register actions and keypresses with this module.
+ """
- def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None):
- """
- Create a new Action instance.
-
- Args:
- key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
- the: regular gtk.Action parameters (defaults to None)
- """
- if name is None: name = label
- gtk.Action.__init__(self,
- name=name, label=label,
- tooltip=tooltip, stock_id=stock_id,
- )
- #register this action
- _all_actions_list.append(self)
- for i in range(len(keypresses)/2):
- keyval, mod_mask = keypresses[i*2:(i+1)*2]
- #register this keypress
- if _actions_keypress_dict.has_key((keyval, mod_mask)):
- raise KeyError('keyval/mod_mask pair already registered "%s"'%str((keyval, mod_mask)))
- _actions_keypress_dict[(keyval, mod_mask)] = self
- #set the accelerator group, and accelerator path
- #register the key name and mod mask with the accelerator path
- if label is None: continue #dont register accel
- accel_path = '<main>/'+self.get_name()
- self.set_accel_group(get_accel_group())
- self.set_accel_path(accel_path)
- gtk.accel_map_add_entry(accel_path, keyval, mod_mask)
+ def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None):
+ """
+ Create a new Action instance.
+
+ Args:
+ key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
+ the: regular gtk.Action parameters (defaults to None)
+ """
+ if name is None: name = label
+ gtk.Action.__init__(self,
+ name=name, label=label,
+ tooltip=tooltip, stock_id=stock_id,
+ )
+ #register this action
+ _all_actions_list.append(self)
+ for i in range(len(keypresses)/2):
+ keyval, mod_mask = keypresses[i*2:(i+1)*2]
+ #register this keypress
+ if _actions_keypress_dict.has_key((keyval, mod_mask)):
+ raise KeyError('keyval/mod_mask pair already registered "%s"'%str((keyval, mod_mask)))
+ _actions_keypress_dict[(keyval, mod_mask)] = self
+ #set the accelerator group, and accelerator path
+ #register the key name and mod mask with the accelerator path
+ if label is None: continue #dont register accel
+ accel_path = '<main>/'+self.get_name()
+ self.set_accel_group(get_accel_group())
+ self.set_accel_path(accel_path)
+ gtk.accel_map_add_entry(accel_path, keyval, mod_mask)
- def __str__(self):
- """
- The string representation should be the name of the action id.
- Try to find the action id for this action by searching this module.
- """
- try:
- import Actions
- return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0]
- except: return self.get_name()
+ def __str__(self):
+ """
+ The string representation should be the name of the action id.
+ Try to find the action id for this action by searching this module.
+ """
+ try:
+ import Actions
+ return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0]
+ except: return self.get_name()
- def __repr__(self): return str(self)
+ def __repr__(self): return str(self)
- def __call__(self):
- """
- Emit the activate signal when called with ().
- """
- self.emit('activate')
+ def __call__(self):
+ """
+ Emit the activate signal when called with ().
+ """
+ self.emit('activate')
########################################################################
# Actions
########################################################################
PAGE_CHANGE = Action()
FLOW_GRAPH_NEW = Action(
- label='_New',
- tooltip='Create a new flow graph',
- stock_id=gtk.STOCK_NEW,
- keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK),
+ label='_New',
+ tooltip='Create a new flow graph',
+ stock_id=gtk.STOCK_NEW,
+ keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK),
)
FLOW_GRAPH_OPEN = Action(
- label='_Open',
- tooltip='Open an existing flow graph',
- stock_id=gtk.STOCK_OPEN,
- keypresses=(gtk.keysyms.o, gtk.gdk.CONTROL_MASK),
+ label='_Open',
+ tooltip='Open an existing flow graph',
+ stock_id=gtk.STOCK_OPEN,
+ keypresses=(gtk.keysyms.o, gtk.gdk.CONTROL_MASK),
)
FLOW_GRAPH_SAVE = Action(
- label='_Save',
- tooltip='Save the current flow graph',
- stock_id=gtk.STOCK_SAVE,
- keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK),
+ label='_Save',
+ tooltip='Save the current flow graph',
+ stock_id=gtk.STOCK_SAVE,
+ keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK),
)
FLOW_GRAPH_SAVE_AS = Action(
- label='Save _As',
- tooltip='Save the current flow graph as...',
- stock_id=gtk.STOCK_SAVE_AS,
- keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK),
+ label='Save _As',
+ tooltip='Save the current flow graph as...',
+ stock_id=gtk.STOCK_SAVE_AS,
+ keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK),
)
FLOW_GRAPH_CLOSE = Action(
- label='_Close',
- tooltip='Close the current flow graph',
- stock_id=gtk.STOCK_CLOSE,
- keypresses=(gtk.keysyms.w, gtk.gdk.CONTROL_MASK),
+ label='_Close',
+ tooltip='Close the current flow graph',
+ stock_id=gtk.STOCK_CLOSE,
+ keypresses=(gtk.keysyms.w, gtk.gdk.CONTROL_MASK),
)
APPLICATION_INITIALIZE = Action()
APPLICATION_QUIT = Action(
- label='_Quit',
- tooltip='Quit program',
- stock_id=gtk.STOCK_QUIT,
- keypresses=(gtk.keysyms.q, gtk.gdk.CONTROL_MASK),
+ label='_Quit',
+ tooltip='Quit program',
+ stock_id=gtk.STOCK_QUIT,
+ keypresses=(gtk.keysyms.q, gtk.gdk.CONTROL_MASK),
)
FLOW_GRAPH_UNDO = Action(
- label='_Undo',
- tooltip='Undo a change to the flow graph',
- stock_id=gtk.STOCK_UNDO,
- keypresses=(gtk.keysyms.z, gtk.gdk.CONTROL_MASK),
+ label='_Undo',
+ tooltip='Undo a change to the flow graph',
+ stock_id=gtk.STOCK_UNDO,
+ keypresses=(gtk.keysyms.z, gtk.gdk.CONTROL_MASK),
)
FLOW_GRAPH_REDO = Action(
- label='_Redo',
- tooltip='Redo a change to the flow graph',
- stock_id=gtk.STOCK_REDO,
- keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK),
+ label='_Redo',
+ tooltip='Redo a change to the flow graph',
+ stock_id=gtk.STOCK_REDO,
+ keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK),
)
NOTHING_SELECT = Action()
ELEMENT_SELECT = Action()
ELEMENT_CREATE = Action()
ELEMENT_DELETE = Action(
- label='_Delete',
- tooltip='Delete the selected blocks',
- stock_id=gtk.STOCK_DELETE,
- keypresses=(gtk.keysyms.Delete, NO_MODS_MASK),
+ label='_Delete',
+ tooltip='Delete the selected blocks',
+ stock_id=gtk.STOCK_DELETE,
+ keypresses=(gtk.keysyms.Delete, NO_MODS_MASK),
)
BLOCK_MOVE = Action()
BLOCK_ROTATE_CCW = Action(
- label='Rotate Counterclockwise',
- tooltip='Rotate the selected blocks 90 degrees to the left',
- stock_id=gtk.STOCK_GO_BACK,
- keypresses=(gtk.keysyms.Left, NO_MODS_MASK),
+ label='Rotate Counterclockwise',
+ tooltip='Rotate the selected blocks 90 degrees to the left',
+ stock_id=gtk.STOCK_GO_BACK,
+ keypresses=(gtk.keysyms.Left, NO_MODS_MASK),
)
BLOCK_ROTATE_CW = Action(
- label='Rotate Clockwise',
- tooltip='Rotate the selected blocks 90 degrees to the right',
- stock_id=gtk.STOCK_GO_FORWARD,
- keypresses=(gtk.keysyms.Right, NO_MODS_MASK),
+ label='Rotate Clockwise',
+ tooltip='Rotate the selected blocks 90 degrees to the right',
+ stock_id=gtk.STOCK_GO_FORWARD,
+ keypresses=(gtk.keysyms.Right, NO_MODS_MASK),
)
BLOCK_PARAM_MODIFY = Action(
- label='_Properties',
- tooltip='Modify params for the selected block',
- stock_id=gtk.STOCK_PROPERTIES,
- keypresses=(gtk.keysyms.Return, NO_MODS_MASK),
+ label='_Properties',
+ tooltip='Modify params for the selected block',
+ stock_id=gtk.STOCK_PROPERTIES,
+ keypresses=(gtk.keysyms.Return, NO_MODS_MASK),
)
BLOCK_ENABLE = Action(
- label='E_nable',
- tooltip='Enable the selected blocks',
- stock_id=gtk.STOCK_CONNECT,
- keypresses=(gtk.keysyms.e, NO_MODS_MASK),
+ label='E_nable',
+ tooltip='Enable the selected blocks',
+ stock_id=gtk.STOCK_CONNECT,
+ keypresses=(gtk.keysyms.e, NO_MODS_MASK),
)
BLOCK_DISABLE = Action(
- label='D_isable',
- tooltip='Disable the selected blocks',
- stock_id=gtk.STOCK_DISCONNECT,
- keypresses=(gtk.keysyms.d, NO_MODS_MASK),
+ label='D_isable',
+ tooltip='Disable the selected blocks',
+ 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),
+ 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',
- stock_id=gtk.STOCK_CUT,
- keypresses=(gtk.keysyms.x, gtk.gdk.CONTROL_MASK),
+ label='Cu_t',
+ tooltip='Cut',
+ stock_id=gtk.STOCK_CUT,
+ keypresses=(gtk.keysyms.x, gtk.gdk.CONTROL_MASK),
)
BLOCK_COPY = Action(
- label='_Copy',
- tooltip='Copy',
- stock_id=gtk.STOCK_COPY,
- keypresses=(gtk.keysyms.c, gtk.gdk.CONTROL_MASK),
+ label='_Copy',
+ tooltip='Copy',
+ stock_id=gtk.STOCK_COPY,
+ keypresses=(gtk.keysyms.c, gtk.gdk.CONTROL_MASK),
)
BLOCK_PASTE = Action(
- label='_Paste',
- tooltip='Paste',
- stock_id=gtk.STOCK_PASTE,
- keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK),
+ label='_Paste',
+ tooltip='Paste',
+ stock_id=gtk.STOCK_PASTE,
+ keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK),
)
ERRORS_WINDOW_DISPLAY = Action(
- label='_Errors',
- tooltip='View flow graph errors',
- stock_id=gtk.STOCK_DIALOG_ERROR,
+ label='_Errors',
+ tooltip='View flow graph errors',
+ stock_id=gtk.STOCK_DIALOG_ERROR,
)
ABOUT_WINDOW_DISPLAY = Action(
- label='_About',
- tooltip='About this program',
- stock_id=gtk.STOCK_ABOUT,
+ label='_About',
+ tooltip='About this program',
+ stock_id=gtk.STOCK_ABOUT,
)
HELP_WINDOW_DISPLAY = Action(
- label='_Help',
- tooltip='Usage tips',
- stock_id=gtk.STOCK_HELP,
- keypresses=(gtk.keysyms.F1, NO_MODS_MASK),
+ label='_Help',
+ tooltip='Usage tips',
+ stock_id=gtk.STOCK_HELP,
+ keypresses=(gtk.keysyms.F1, NO_MODS_MASK),
)
TYPES_WINDOW_DISPLAY = Action(
- label='_Types',
- tooltip='Types color mapping',
- stock_id=gtk.STOCK_DIALOG_INFO,
+ label='_Types',
+ tooltip='Types color mapping',
+ stock_id=gtk.STOCK_DIALOG_INFO,
)
FLOW_GRAPH_GEN = Action(
- label='_Generate',
- tooltip='Generate the flow graph',
- stock_id=gtk.STOCK_CONVERT,
- keypresses=(gtk.keysyms.F5, NO_MODS_MASK),
+ label='_Generate',
+ tooltip='Generate the flow graph',
+ stock_id=gtk.STOCK_CONVERT,
+ keypresses=(gtk.keysyms.F5, NO_MODS_MASK),
)
FLOW_GRAPH_EXEC = Action(
- label='_Execute',
- tooltip='Execute the flow graph',
- stock_id=gtk.STOCK_EXECUTE,
- keypresses=(gtk.keysyms.F6, NO_MODS_MASK),
+ label='_Execute',
+ tooltip='Execute the flow graph',
+ stock_id=gtk.STOCK_EXECUTE,
+ keypresses=(gtk.keysyms.F6, NO_MODS_MASK),
)
FLOW_GRAPH_KILL = Action(
- label='_Kill',
- tooltip='Kill the flow graph',
- stock_id=gtk.STOCK_STOP,
- keypresses=(gtk.keysyms.F7, NO_MODS_MASK),
+ label='_Kill',
+ tooltip='Kill the flow graph',
+ stock_id=gtk.STOCK_STOP,
+ keypresses=(gtk.keysyms.F7, NO_MODS_MASK),
)
FLOW_GRAPH_SCREEN_CAPTURE = Action(
- label='S_creen Capture',
- tooltip='Create a screen capture of the flow graph',
- stock_id=gtk.STOCK_PRINT,
- keypresses=(gtk.keysyms.Print, NO_MODS_MASK),
+ label='S_creen Capture',
+ tooltip='Create a screen capture of the flow graph',
+ stock_id=gtk.STOCK_PRINT,
+ keypresses=(gtk.keysyms.Print, NO_MODS_MASK),
)
PORT_CONTROLLER_DEC = Action(
- keypresses=(gtk.keysyms.minus, NO_MODS_MASK, gtk.keysyms.KP_Subtract, NO_MODS_MASK),
+ keypresses=(gtk.keysyms.minus, NO_MODS_MASK, gtk.keysyms.KP_Subtract, NO_MODS_MASK),
)
PORT_CONTROLLER_INC = Action(
- keypresses=(gtk.keysyms.plus, NO_MODS_MASK, gtk.keysyms.KP_Add, NO_MODS_MASK),
+ keypresses=(gtk.keysyms.plus, NO_MODS_MASK, gtk.keysyms.KP_Add, NO_MODS_MASK),
)
BLOCK_INC_TYPE = Action(
- keypresses=(gtk.keysyms.Down, NO_MODS_MASK),
+ keypresses=(gtk.keysyms.Down, NO_MODS_MASK),
)
BLOCK_DEC_TYPE = Action(
- keypresses=(gtk.keysyms.Up, NO_MODS_MASK),
+ keypresses=(gtk.keysyms.Up, NO_MODS_MASK),
)
RELOAD_BLOCKS = Action(
- label='Reload _Blocks',
- tooltip='Reload Blocks',
- stock_id=gtk.STOCK_REFRESH
+ label='Reload _Blocks',
+ tooltip='Reload Blocks',
+ stock_id=gtk.STOCK_REFRESH
)
OPEN_HIER = Action(
- label='Open H_ier',
- tooltip='Open the source of the selected hierarchical block',
- stock_id=gtk.STOCK_JUMP_TO,
+ label='Open H_ier',
+ tooltip='Open the source of the selected hierarchical block',
+ stock_id=gtk.STOCK_JUMP_TO,
+)
+BUSSIFY_SOURCES = Action(
+ label='Toggle So_urce Bus',
+ tooltip='Gang source ports into a single bus port',
+ stock_id=gtk.STOCK_JUMP_TO,
+)
+BUSSIFY_SINKS = Action(
+ label='Toggle S_ink Bus',
+ tooltip='Gang sink ports into a single bus port',
+ stock_id=gtk.STOCK_JUMP_TO,
)
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index d95d23f1fe..e2b7f4f9bc 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -24,120 +24,121 @@ import gtk
##The list of actions for the toolbar.
TOOLBAR_LIST = (
- Actions.FLOW_GRAPH_NEW,
- Actions.FLOW_GRAPH_OPEN,
- Actions.FLOW_GRAPH_SAVE,
- Actions.FLOW_GRAPH_CLOSE,
- None,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE,
- None,
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- None,
- Actions.FLOW_GRAPH_UNDO,
- Actions.FLOW_GRAPH_REDO,
- None,
- Actions.ERRORS_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_GEN,
- Actions.FLOW_GRAPH_EXEC,
- Actions.FLOW_GRAPH_KILL,
- None,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- None,
- Actions.BLOCK_ENABLE,
- Actions.BLOCK_DISABLE,
+ Actions.FLOW_GRAPH_NEW,
+ Actions.FLOW_GRAPH_OPEN,
+ Actions.FLOW_GRAPH_SAVE,
+ Actions.FLOW_GRAPH_CLOSE,
+ None,
+ Actions.FLOW_GRAPH_SCREEN_CAPTURE,
+ None,
+ Actions.BLOCK_CUT,
+ Actions.BLOCK_COPY,
+ Actions.BLOCK_PASTE,
+ Actions.ELEMENT_DELETE,
+ None,
+ Actions.FLOW_GRAPH_UNDO,
+ Actions.FLOW_GRAPH_REDO,
+ None,
+ Actions.ERRORS_WINDOW_DISPLAY,
+ Actions.FLOW_GRAPH_GEN,
+ Actions.FLOW_GRAPH_EXEC,
+ Actions.FLOW_GRAPH_KILL,
+ None,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
+ None,
+ Actions.BLOCK_ENABLE,
+ Actions.BLOCK_DISABLE,
None,
Actions.RELOAD_BLOCKS,
Actions.OPEN_HIER,
+ Actions.BUSSIFY_SOURCES,
)
##The list of actions and categories for the menu bar.
MENU_BAR_LIST = (
- (gtk.Action('File', '_File', None, None), [
- Actions.FLOW_GRAPH_NEW,
- Actions.FLOW_GRAPH_OPEN,
- None,
- Actions.FLOW_GRAPH_SAVE,
- Actions.FLOW_GRAPH_SAVE_AS,
- None,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE,
- None,
- Actions.FLOW_GRAPH_CLOSE,
- Actions.APPLICATION_QUIT,
- ]),
- (gtk.Action('Edit', '_Edit', None, None), [
- Actions.FLOW_GRAPH_UNDO,
- Actions.FLOW_GRAPH_REDO,
- None,
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- None,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- None,
- Actions.BLOCK_ENABLE,
- Actions.BLOCK_DISABLE,
- None,
- Actions.BLOCK_PARAM_MODIFY,
- ]),
- (gtk.Action('View', '_View', None, None), [
- Actions.ERRORS_WINDOW_DISPLAY,
- ]),
- (gtk.Action('Build', '_Build', None, None), [
- Actions.FLOW_GRAPH_GEN,
- Actions.FLOW_GRAPH_EXEC,
- Actions.FLOW_GRAPH_KILL,
- ]),
- (gtk.Action('Help', '_Help', None, None), [
- Actions.HELP_WINDOW_DISPLAY,
- Actions.TYPES_WINDOW_DISPLAY,
- None,
- Actions.ABOUT_WINDOW_DISPLAY,
- ]),
+ (gtk.Action('File', '_File', None, None), [
+ Actions.FLOW_GRAPH_NEW,
+ Actions.FLOW_GRAPH_OPEN,
+ None,
+ Actions.FLOW_GRAPH_SAVE,
+ Actions.FLOW_GRAPH_SAVE_AS,
+ None,
+ Actions.FLOW_GRAPH_SCREEN_CAPTURE,
+ None,
+ Actions.FLOW_GRAPH_CLOSE,
+ Actions.APPLICATION_QUIT,
+ ]),
+ (gtk.Action('Edit', '_Edit', None, None), [
+ Actions.FLOW_GRAPH_UNDO,
+ Actions.FLOW_GRAPH_REDO,
+ None,
+ Actions.BLOCK_CUT,
+ Actions.BLOCK_COPY,
+ Actions.BLOCK_PASTE,
+ Actions.ELEMENT_DELETE,
+ None,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
+ None,
+ Actions.BLOCK_ENABLE,
+ Actions.BLOCK_DISABLE,
+ None,
+ Actions.BLOCK_PARAM_MODIFY,
+ ]),
+ (gtk.Action('View', '_View', None, None), [
+ Actions.ERRORS_WINDOW_DISPLAY,
+ ]),
+ (gtk.Action('Build', '_Build', None, None), [
+ Actions.FLOW_GRAPH_GEN,
+ Actions.FLOW_GRAPH_EXEC,
+ Actions.FLOW_GRAPH_KILL,
+ ]),
+ (gtk.Action('Help', '_Help', None, None), [
+ Actions.HELP_WINDOW_DISPLAY,
+ Actions.TYPES_WINDOW_DISPLAY,
+ None,
+ Actions.ABOUT_WINDOW_DISPLAY,
+ ]),
)
class Toolbar(gtk.Toolbar):
- """The gtk toolbar with actions added from the toolbar list."""
+ """The gtk toolbar with actions added from the toolbar list."""
- def __init__(self):
- """
- Parse the list of action names in the toolbar list.
- Look up the action for each name in the action list and add it to the toolbar.
- """
- gtk.Toolbar.__init__(self)
- self.set_style(gtk.TOOLBAR_ICONS)
- for action in TOOLBAR_LIST:
- if action: #add a tool item
- self.add(action.create_tool_item())
- #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show
- action.set_property('tooltip', action.get_property('tooltip'))
- else: self.add(gtk.SeparatorToolItem())
+ def __init__(self):
+ """
+ Parse the list of action names in the toolbar list.
+ Look up the action for each name in the action list and add it to the toolbar.
+ """
+ gtk.Toolbar.__init__(self)
+ self.set_style(gtk.TOOLBAR_ICONS)
+ for action in TOOLBAR_LIST:
+ if action: #add a tool item
+ self.add(action.create_tool_item())
+ #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show
+ action.set_property('tooltip', action.get_property('tooltip'))
+ else: self.add(gtk.SeparatorToolItem())
class MenuBar(gtk.MenuBar):
- """The gtk menu bar with actions added from the menu bar list."""
+ """The gtk menu bar with actions added from the menu bar list."""
- def __init__(self):
- """
- Parse the list of submenus from the menubar list.
- For each submenu, get a list of action names.
- Look up the action for each name in the action list and add it to the submenu.
- Add the submenu to the menu bar.
- """
- gtk.MenuBar.__init__(self)
- for main_action, actions in MENU_BAR_LIST:
- #create the main menu item
- main_menu_item = main_action.create_menu_item()
- self.append(main_menu_item)
- #create the menu
- main_menu = gtk.Menu()
- main_menu_item.set_submenu(main_menu)
- for action in actions:
- if action: #append a menu item
- main_menu.append(action.create_menu_item())
- else: main_menu.append(gtk.SeparatorMenuItem())
- main_menu.show_all() #this show all is required for the separators to show
+ def __init__(self):
+ """
+ Parse the list of submenus from the menubar list.
+ For each submenu, get a list of action names.
+ Look up the action for each name in the action list and add it to the submenu.
+ Add the submenu to the menu bar.
+ """
+ gtk.MenuBar.__init__(self)
+ for main_action, actions in MENU_BAR_LIST:
+ #create the main menu item
+ main_menu_item = main_action.create_menu_item()
+ self.append(main_menu_item)
+ #create the menu
+ main_menu = gtk.Menu()
+ main_menu_item.set_submenu(main_menu)
+ for action in actions:
+ if action: #append a menu item
+ main_menu.append(action.create_menu_item())
+ else: main_menu.append(gtk.SeparatorMenuItem())
+ main_menu.show_all() #this show all is required for the separators to show
diff --git a/grc/gui/Block.py b/grc/gui/Block.py
index 11e66bff85..30031866c0 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -23,9 +23,9 @@ import Colors
from .. base import odict
from Constants import BORDER_PROXIMITY_SENSITIVITY
from Constants import \
- BLOCK_LABEL_PADDING, \
- PORT_SEPARATION, LABEL_SEPARATION, \
- PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS
+ BLOCK_LABEL_PADDING, \
+ PORT_SEPARATION, LABEL_SEPARATION, \
+ PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS
import pygtk
pygtk.require('2.0')
import gtk
@@ -36,180 +36,184 @@ BLOCK_MARKUP_TMPL="""\
<span foreground="$foreground" font_desc="Sans 8"><b>$encode($block.get_name())</b></span>"""
class Block(Element):
- """The graphical signal block."""
+ """The graphical signal block."""
- def __init__(self):
- """
- Block contructor.
- Add graphics related params to the block.
- """
- #add the position param
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({
- 'name': 'GUI Coordinate',
- 'key': '_coordinate',
- 'type': 'raw',
- 'value': '(0, 0)',
- 'hide': 'all',
- })
- ))
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({
- 'name': 'GUI Rotation',
- 'key': '_rotation',
- 'type': 'raw',
- 'value': '0',
- 'hide': 'all',
- })
- ))
- Element.__init__(self)
+ def __init__(self):
+ """
+ Block contructor.
+ Add graphics related params to the block.
+ """
+ #add the position param
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({
+ 'name': 'GUI Coordinate',
+ 'key': '_coordinate',
+ 'type': 'raw',
+ 'value': '(0, 0)',
+ 'hide': 'all',
+ })
+ ))
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({
+ 'name': 'GUI Rotation',
+ 'key': '_rotation',
+ 'type': 'raw',
+ 'value': '0',
+ 'hide': 'all',
+ })
+ ))
+ Element.__init__(self)
- def get_coordinate(self):
- """
- Get the coordinate from the position param.
-
- Returns:
- the coordinate tuple (x, y) or (0, 0) if failure
- """
- try: #should evaluate to tuple
- coor = eval(self.get_param('_coordinate').get_value())
- x, y = map(int, coor)
- fgW,fgH = self.get_parent().get_size()
- if x <= 0:
- x = 0
- elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
- x = fgW - BORDER_PROXIMITY_SENSITIVITY
- if y <= 0:
- y = 0
- elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
- y = fgH - BORDER_PROXIMITY_SENSITIVITY
- return (x, y)
- except:
- self.set_coordinate((0, 0))
- return (0, 0)
+ def get_coordinate(self):
+ """
+ Get the coordinate from the position param.
+
+ Returns:
+ the coordinate tuple (x, y) or (0, 0) if failure
+ """
+ try: #should evaluate to tuple
+ coor = eval(self.get_param('_coordinate').get_value())
+ x, y = map(int, coor)
+ fgW,fgH = self.get_parent().get_size()
+ if x <= 0:
+ x = 0
+ elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
+ x = fgW - BORDER_PROXIMITY_SENSITIVITY
+ if y <= 0:
+ y = 0
+ elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
+ y = fgH - BORDER_PROXIMITY_SENSITIVITY
+ return (x, y)
+ except:
+ self.set_coordinate((0, 0))
+ return (0, 0)
- def set_coordinate(self, coor):
- """
- Set the coordinate into the position param.
-
- Args:
- coor: the coordinate tuple (x, y)
- """
- self.get_param('_coordinate').set_value(str(coor))
+ def set_coordinate(self, coor):
+ """
+ Set the coordinate into the position param.
+
+ Args:
+ coor: the coordinate tuple (x, y)
+ """
+ self.get_param('_coordinate').set_value(str(coor))
- def get_rotation(self):
- """
- Get the rotation from the position param.
-
- Returns:
- the rotation in degrees or 0 if failure
- """
- try: #should evaluate to dict
- rotation = eval(self.get_param('_rotation').get_value())
- return int(rotation)
- except:
- self.set_rotation(POSSIBLE_ROTATIONS[0])
- return POSSIBLE_ROTATIONS[0]
+ def get_rotation(self):
+ """
+ Get the rotation from the position param.
+
+ Returns:
+ the rotation in degrees or 0 if failure
+ """
+ try: #should evaluate to dict
+ rotation = eval(self.get_param('_rotation').get_value())
+ return int(rotation)
+ except:
+ self.set_rotation(POSSIBLE_ROTATIONS[0])
+ return POSSIBLE_ROTATIONS[0]
- def set_rotation(self, rot):
- """
- Set the rotation into the position param.
-
- Args:
- rot: the rotation in degrees
- """
- self.get_param('_rotation').set_value(str(rot))
+ def set_rotation(self, rot):
+ """
+ Set the rotation into the position param.
+
+ Args:
+ rot: the rotation in degrees
+ """
+ self.get_param('_rotation').set_value(str(rot))
- def create_shapes(self):
- """Update the block, parameters, and ports when a change occurs."""
- Element.create_shapes(self)
- if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H))
- elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W))
+ def create_shapes(self):
+ """Update the block, parameters, and ports when a change occurs."""
+ Element.create_shapes(self)
+ if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H))
+ elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W))
- def create_labels(self):
- """Create the labels for the signal block."""
- Element.create_labels(self)
- self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
- layouts = list()
- #create the main layout
- layout = gtk.DrawingArea().create_pango_layout('')
- layouts.append(layout)
- layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self))
- self.label_width, self.label_height = layout.get_pixel_size()
- #display the params
- markups = [param.get_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')]
- if markups:
- layout = gtk.DrawingArea().create_pango_layout('')
- layout.set_spacing(LABEL_SEPARATION*pango.SCALE)
- layout.set_markup('\n'.join(markups))
- layouts.append(layout)
- w,h = layout.get_pixel_size()
- self.label_width = max(w, self.label_width)
- self.label_height += h + LABEL_SEPARATION
- width = self.label_width
- height = self.label_height
- #setup the pixmap
- pixmap = self.get_parent().new_pixmap(width, height)
- gc = pixmap.new_gc()
- gc.set_foreground(self._bg_color)
- pixmap.draw_rectangle(gc, True, 0, 0, width, height)
- #draw the layouts
- h_off = 0
- for i,layout in enumerate(layouts):
- w,h = layout.get_pixel_size()
- if i == 0: w_off = (width-w)/2
- else: w_off = 0
- pixmap.draw_layout(gc, w_off, h_off, layout)
- h_off = h + h_off + LABEL_SEPARATION
- #create vertical and horizontal pixmaps
- self.horizontal_label = pixmap
- if self.is_vertical():
- self.vertical_label = self.get_parent().new_pixmap(height, width)
- Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
- #calculate width and height needed
- self.W = self.label_width + 2*BLOCK_LABEL_PADDING
- self.H = max(*(
- [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
- sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
- for ports in (self.get_sources(), self.get_sinks())]
- ))
+ def create_labels(self):
+ """Create the labels for the signal block."""
+ Element.create_labels(self)
+ self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
+ layouts = list()
+ #create the main layout
+ layout = gtk.DrawingArea().create_pango_layout('')
+ layouts.append(layout)
+ layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self))
+ self.label_width, self.label_height = layout.get_pixel_size()
+ #display the params
+ markups = [param.get_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')]
+ if markups:
+ layout = gtk.DrawingArea().create_pango_layout('')
+ layout.set_spacing(LABEL_SEPARATION*pango.SCALE)
+ layout.set_markup('\n'.join(markups))
+ layouts.append(layout)
+ w,h = layout.get_pixel_size()
+ self.label_width = max(w, self.label_width)
+ self.label_height += h + LABEL_SEPARATION
+ width = self.label_width
+ height = self.label_height
+ #setup the pixmap
+ pixmap = self.get_parent().new_pixmap(width, height)
+ gc = pixmap.new_gc()
+ gc.set_foreground(self._bg_color)
+ pixmap.draw_rectangle(gc, True, 0, 0, width, height)
+ #draw the layouts
+ h_off = 0
+ for i,layout in enumerate(layouts):
+ w,h = layout.get_pixel_size()
+ if i == 0: w_off = (width-w)/2
+ else: w_off = 0
+ pixmap.draw_layout(gc, w_off, h_off, layout)
+ h_off = h + h_off + LABEL_SEPARATION
+ #create vertical and horizontal pixmaps
+ self.horizontal_label = pixmap
+ if self.is_vertical():
+ self.vertical_label = self.get_parent().new_pixmap(height, width)
+ Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
+ #calculate width and height needed
+ self.W = self.label_width + 2*BLOCK_LABEL_PADDING
+ self.H = max(*(
+ [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
+ sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
+ for ports in (self.get_sources_gui(), self.get_sinks_gui())] +
+ [4*PORT_BORDER_SEPARATION + \
+ sum([(port.H) + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
+ for ports in ([i for i in self.get_sources_gui() if i.get_type() == 'bus'], [i for i in self.get_sinks_gui() if i.get_type() == 'bus'])]
+ ))
- def draw(self, gc, window):
- """
- Draw the signal block with label and inputs/outputs.
-
- Args:
- gc: the graphics context
- window: the gtk window to draw on
- """
- x, y = self.get_coordinate()
- #draw main block
- Element.draw(
- self, gc, window, bg_color=self._bg_color,
- border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
- )
- #draw label image
- if self.is_horizontal():
- window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1)
- elif self.is_vertical():
- window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1)
- #draw ports
- for port in self.get_ports(): port.draw(gc, window)
+ def draw(self, gc, window):
+ """
+ Draw the signal block with label and inputs/outputs.
+
+ Args:
+ gc: the graphics context
+ window: the gtk window to draw on
+ """
+ x, y = self.get_coordinate()
+ #draw main block
+ Element.draw(
+ self, gc, window, bg_color=self._bg_color,
+ border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
+ )
+ #draw label image
+ if self.is_horizontal():
+ window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1)
+ elif self.is_vertical():
+ window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1)
+ #draw ports
+ for port in self.get_ports_gui():
+ port.draw(gc, window)
- def what_is_selected(self, coor, coor_m=None):
- """
- Get the element that is selected.
-
- Args:
- coor: the (x,y) tuple
- coor_m: the (x_m, y_m) tuple
-
- Returns:
- this block, a port, or None
- """
- for port in self.get_ports():
- port_selected = port.what_is_selected(coor, coor_m)
- if port_selected: return port_selected
- return Element.what_is_selected(self, coor, coor_m)
+ def what_is_selected(self, coor, coor_m=None):
+ """
+ Get the element that is selected.
+
+ Args:
+ coor: the (x,y) tuple
+ coor_m: the (x_m, y_m) tuple
+
+ Returns:
+ this block, a port, or None
+ """
+ for port in self.get_ports_gui():
+ port_selected = port.what_is_selected(coor, coor_m)
+ if port_selected: return port_selected
+ return Element.what_is_selected(self, coor, coor_m)
diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py
index 28867dce7c..ced6429c62 100644
--- a/grc/gui/BlockTreeWindow.py
+++ b/grc/gui/BlockTreeWindow.py
@@ -38,172 +38,173 @@ undocumented#slurp
CAT_MARKUP_TMPL="""Category: $cat"""
class BlockTreeWindow(gtk.VBox):
- """The block selection panel."""
-
- def __init__(self, platform, get_flow_graph):
- """
- BlockTreeWindow constructor.
- Create a tree view of the possible blocks in the platform.
- The tree view nodes will be category names, the leaves will be block names.
- A mouse double click or button press action will trigger the add block event.
-
- Args:
- platform: the particular platform will all block prototypes
- get_flow_graph: get the selected flow graph
- """
- gtk.VBox.__init__(self)
- self.platform = platform
- self.get_flow_graph = get_flow_graph
- #make the tree model for holding blocks
- self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
- self.treeview = gtk.TreeView(self.treestore)
- self.treeview.set_enable_search(False) #disable pop up search box
- self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
- self.treeview.connect('button-press-event', self._handle_mouse_button_press)
- selection = self.treeview.get_selection()
- selection.set_mode('single')
- selection.connect('changed', self._handle_selection_change)
- renderer = gtk.CellRendererText()
- column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
- self.treeview.append_column(column)
- #setup the search
- self.treeview.set_enable_search(True)
- self.treeview.set_search_equal_func(self._handle_search)
- #try to enable the tooltips (available in pygtk 2.12 and above)
- try: self.treeview.set_tooltip_column(DOC_INDEX)
- except: pass
- #setup sort order
- column.set_sort_column_id(0)
- #setup drag and drop
- self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY)
- self.treeview.connect('drag-data-get', self._handle_drag_get_data)
- #make the scrolled window to hold the tree view
- scrolled_window = gtk.ScrolledWindow()
- scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- scrolled_window.add_with_viewport(self.treeview)
- scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
- self.pack_start(scrolled_window)
- #add button
- self.add_button = gtk.Button(None, gtk.STOCK_ADD)
- self.add_button.connect('clicked', self._handle_add_button)
- self.pack_start(self.add_button, False)
- #map categories to iters, automatic mapping for root
- self._categories = {tuple(): None}
- #add blocks and categories
- self.platform.load_block_tree(self)
- #initialize
- self._update_add_button()
-
- def clear(self):
- self.treestore.clear();
- self._categories = {tuple(): None}
-
-
- ############################################################
- ## Block Tree Methods
- ############################################################
- def add_block(self, category, block=None):
- """
- Add a block with category to this selection window.
- Add only the category when block is None.
-
- Args:
- category: the category list or path string
- block: the block object or None
- """
- if isinstance(category, str): category = category.split('/')
- category = tuple(filter(lambda x: x, category)) #tuple is hashable
- #add category and all sub categories
- for i, cat_name in enumerate(category):
- sub_category = category[:i+1]
- if sub_category not in self._categories:
- iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
- self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
- self.treestore.set_value(iter, KEY_INDEX, '')
- self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
- self._categories[sub_category] = iter
- #add block
- if block is None: return
- iter = self.treestore.insert_before(self._categories[category], None)
- self.treestore.set_value(iter, NAME_INDEX, block.get_name())
- self.treestore.set_value(iter, KEY_INDEX, block.get_key())
- self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
-
- ############################################################
- ## Helper Methods
- ############################################################
- def _get_selected_block_key(self):
- """
- Get the currently selected block key.
-
- Returns:
- the key of the selected block or a empty string
- """
- selection = self.treeview.get_selection()
- treestore, iter = selection.get_selected()
- return iter and treestore.get_value(iter, KEY_INDEX) or ''
-
- def _update_add_button(self):
- """
- Update the add button's sensitivity.
- The button should be active only if a block is selected.
- """
- key = self._get_selected_block_key()
- self.add_button.set_sensitive(bool(key))
-
- def _add_selected_block(self):
- """
- Add the selected block with the given key to the flow graph.
- """
- key = self._get_selected_block_key()
- if key: self.get_flow_graph().add_new_block(key)
-
- ############################################################
- ## Event Handlers
- ############################################################
- def _handle_search(self, model, column, key, iter):
- #determine which blocks match the search key
- blocks = self.get_flow_graph().get_parent().get_blocks()
- matching_blocks = filter(lambda b: key in b.get_key() or key in b.get_name().lower(), blocks)
- #remove the old search category
- try: self.treestore.remove(self._categories.pop((self._search_category, )))
- except (KeyError, AttributeError): pass #nothing to remove
- #create a search category
- if not matching_blocks: return
- self._search_category = 'Search: %s'%key
- for block in matching_blocks: self.add_block(self._search_category, block)
- #expand the search category
- path = self.treestore.get_path(self._categories[(self._search_category, )])
- self.treeview.collapse_all()
- self.treeview.expand_row(path, open_all=False)
-
- def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time):
- """
- Handle a drag and drop by setting the key to the selection object.
- This will call the destination handler for drag and drop.
- Only call set when the key is valid to ignore DND from categories.
- """
- key = self._get_selected_block_key()
- if key: selection_data.set(selection_data.target, 8, key)
-
- def _handle_mouse_button_press(self, widget, event):
- """
- Handle the mouse button press.
- If a left double click is detected, call add selected block.
- """
- if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
- self._add_selected_block()
-
- def _handle_selection_change(self, selection):
- """
- Handle a selection change in the tree view.
- If a selection changes, set the add button sensitive.
- """
- self._update_add_button()
-
- def _handle_add_button(self, widget):
- """
- Handle the add button clicked signal.
- Call add selected block.
- """
- self._add_selected_block()
+ """The block selection panel."""
+
+ def __init__(self, platform, get_flow_graph):
+ """
+ BlockTreeWindow constructor.
+ Create a tree view of the possible blocks in the platform.
+ The tree view nodes will be category names, the leaves will be block names.
+ A mouse double click or button press action will trigger the add block event.
+
+ Args:
+ platform: the particular platform will all block prototypes
+ get_flow_graph: get the selected flow graph
+ """
+ gtk.VBox.__init__(self)
+ self.platform = platform
+ self.get_flow_graph = get_flow_graph
+ #make the tree model for holding blocks
+ self.treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.treeview = gtk.TreeView(self.treestore)
+ self.treeview.set_enable_search(False) #disable pop up search box
+ self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
+ self.treeview.connect('button-press-event', self._handle_mouse_button_press)
+ selection = self.treeview.get_selection()
+ selection.set_mode('single')
+ selection.connect('changed', self._handle_selection_change)
+ renderer = gtk.CellRendererText()
+ column = gtk.TreeViewColumn('Blocks', renderer, text=NAME_INDEX)
+ self.treeview.append_column(column)
+ #setup the search
+ self.treeview.set_enable_search(True)
+ self.treeview.set_search_equal_func(self._handle_search)
+ #try to enable the tooltips (available in pygtk 2.12 and above)
+ try: self.treeview.set_tooltip_column(DOC_INDEX)
+ except: pass
+ #setup sort order
+ column.set_sort_column_id(0)
+ self.treestore.set_sort_column_id(0, gtk.SORT_ASCENDING)
+ #setup drag and drop
+ self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, DND_TARGETS, gtk.gdk.ACTION_COPY)
+ self.treeview.connect('drag-data-get', self._handle_drag_get_data)
+ #make the scrolled window to hold the tree view
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(self.treeview)
+ scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
+ self.pack_start(scrolled_window)
+ #add button
+ self.add_button = gtk.Button(None, gtk.STOCK_ADD)
+ self.add_button.connect('clicked', self._handle_add_button)
+ self.pack_start(self.add_button, False)
+ #map categories to iters, automatic mapping for root
+ self._categories = {tuple(): None}
+ #add blocks and categories
+ self.platform.load_block_tree(self)
+ #initialize
+ self._update_add_button()
+
+ def clear(self):
+ self.treestore.clear();
+ self._categories = {tuple(): None}
+
+
+ ############################################################
+ ## Block Tree Methods
+ ############################################################
+ def add_block(self, category, block=None):
+ """
+ Add a block with category to this selection window.
+ Add only the category when block is None.
+
+ Args:
+ category: the category list or path string
+ block: the block object or None
+ """
+ if isinstance(category, str): category = category.split('/')
+ category = tuple(filter(lambda x: x, category)) #tuple is hashable
+ #add category and all sub categories
+ for i, cat_name in enumerate(category):
+ sub_category = category[:i+1]
+ if sub_category not in self._categories:
+ iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
+ self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
+ self.treestore.set_value(iter, KEY_INDEX, '')
+ self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
+ self._categories[sub_category] = iter
+ #add block
+ if block is None: return
+ iter = self.treestore.insert_before(self._categories[category], None)
+ self.treestore.set_value(iter, NAME_INDEX, block.get_name())
+ self.treestore.set_value(iter, KEY_INDEX, block.get_key())
+ self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
+
+ ############################################################
+ ## Helper Methods
+ ############################################################
+ def _get_selected_block_key(self):
+ """
+ Get the currently selected block key.
+
+ Returns:
+ the key of the selected block or a empty string
+ """
+ selection = self.treeview.get_selection()
+ treestore, iter = selection.get_selected()
+ return iter and treestore.get_value(iter, KEY_INDEX) or ''
+
+ def _update_add_button(self):
+ """
+ Update the add button's sensitivity.
+ The button should be active only if a block is selected.
+ """
+ key = self._get_selected_block_key()
+ self.add_button.set_sensitive(bool(key))
+
+ def _add_selected_block(self):
+ """
+ Add the selected block with the given key to the flow graph.
+ """
+ key = self._get_selected_block_key()
+ if key: self.get_flow_graph().add_new_block(key)
+
+ ############################################################
+ ## Event Handlers
+ ############################################################
+ def _handle_search(self, model, column, key, iter):
+ #determine which blocks match the search key
+ blocks = self.get_flow_graph().get_parent().get_blocks()
+ matching_blocks = filter(lambda b: key in b.get_key() or key in b.get_name().lower(), blocks)
+ #remove the old search category
+ try: self.treestore.remove(self._categories.pop((self._search_category, )))
+ except (KeyError, AttributeError): pass #nothing to remove
+ #create a search category
+ if not matching_blocks: return
+ self._search_category = 'Search: %s'%key
+ for block in matching_blocks: self.add_block(self._search_category, block)
+ #expand the search category
+ path = self.treestore.get_path(self._categories[(self._search_category, )])
+ self.treeview.collapse_all()
+ self.treeview.expand_row(path, open_all=False)
+
+ def _handle_drag_get_data(self, widget, drag_context, selection_data, info, time):
+ """
+ Handle a drag and drop by setting the key to the selection object.
+ This will call the destination handler for drag and drop.
+ Only call set when the key is valid to ignore DND from categories.
+ """
+ key = self._get_selected_block_key()
+ if key: selection_data.set(selection_data.target, 8, key)
+
+ def _handle_mouse_button_press(self, widget, event):
+ """
+ Handle the mouse button press.
+ If a left double click is detected, call add selected block.
+ """
+ if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
+ self._add_selected_block()
+
+ def _handle_selection_change(self, selection):
+ """
+ Handle a selection change in the tree view.
+ If a selection changes, set the add button sensitive.
+ """
+ self._update_add_button()
+
+ def _handle_add_button(self, widget):
+ """
+ Handle the add button clicked signal.
+ Call add selected block.
+ """
+ self._add_selected_block()
diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py
index 5d24fefded..0f631791db 100644
--- a/grc/gui/Connection.py
+++ b/grc/gui/Connection.py
@@ -23,127 +23,137 @@ import Colors
from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT
class Connection(Element):
- """
- A graphical connection for ports.
- The connection has 2 parts, the arrow and the wire.
- The coloring of the arrow and wire exposes the status of 3 states:
- enabled/disabled, valid/invalid, highlighted/non-highlighted.
- The wire coloring exposes the enabled and highlighted states.
- The arrow coloring exposes the enabled and valid states.
- """
+ """
+ A graphical connection for ports.
+ The connection has 2 parts, the arrow and the wire.
+ The coloring of the arrow and wire exposes the status of 3 states:
+ enabled/disabled, valid/invalid, highlighted/non-highlighted.
+ The wire coloring exposes the enabled and highlighted states.
+ The arrow coloring exposes the enabled and valid states.
+ """
- def __init__(self): Element.__init__(self)
+ def __init__(self): Element.__init__(self)
- def get_coordinate(self):
- """
- Get the 0,0 coordinate.
- Coordinates are irrelevant in connection.
-
- Returns:
- 0, 0
- """
- return (0, 0)
+ def get_coordinate(self):
+ """
+ Get the 0,0 coordinate.
+ Coordinates are irrelevant in connection.
+
+ Returns:
+ 0, 0
+ """
+ return (0, 0)
- def get_rotation(self):
- """
- Get the 0 degree rotation.
- Rotations are irrelevant in connection.
-
- Returns:
- 0
- """
- return 0
+ def get_rotation(self):
+ """
+ Get the 0 degree rotation.
+ Rotations are irrelevant in connection.
+
+ Returns:
+ 0
+ """
+ return 0
- def create_shapes(self):
- """Precalculate relative coordinates."""
- Element.create_shapes(self)
- self._sink_rot = None
- self._source_rot = None
- self._sink_coor = None
- self._source_coor = None
- #get the source coordinate
- connector_length = self.get_source().get_connector_length()
- self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation())
- #get the sink coordinate
- connector_length = self.get_sink().get_connector_length() + CONNECTOR_ARROW_HEIGHT
- self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.get_sink().get_rotation())
- #build the arrow
- self.arrow = [(0, 0),
- Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
- Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
- ]
- self._update_after_move()
- if not self.get_enabled(): self._arrow_color = Colors.CONNECTION_DISABLED_COLOR
- elif not self.is_valid(): self._arrow_color = Colors.CONNECTION_ERROR_COLOR
- else: self._arrow_color = Colors.CONNECTION_ENABLED_COLOR
+ def create_shapes(self):
+ """Precalculate relative coordinates."""
+ Element.create_shapes(self)
+ self._sink_rot = None
+ self._source_rot = None
+ self._sink_coor = None
+ self._source_coor = None
+ #get the source coordinate
+ try:
+ connector_length = self.get_source().get_connector_length()
+ except:
+ return
+ self.x1, self.y1 = Utils.get_rotated_coordinate((connector_length, 0), self.get_source().get_rotation())
+ #get the sink coordinate
+ connector_length = self.get_sink().get_connector_length() + CONNECTOR_ARROW_HEIGHT
+ self.x2, self.y2 = Utils.get_rotated_coordinate((-connector_length, 0), self.get_sink().get_rotation())
+ #build the arrow
+ self.arrow = [(0, 0),
+ Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, -CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
+ Utils.get_rotated_coordinate((-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE/2), self.get_sink().get_rotation()),
+ ]
+ self._update_after_move()
+ if not self.get_enabled(): self._arrow_color = Colors.CONNECTION_DISABLED_COLOR
+ elif not self.is_valid(): self._arrow_color = Colors.CONNECTION_ERROR_COLOR
+ else: self._arrow_color = Colors.CONNECTION_ENABLED_COLOR
- def _update_after_move(self):
- """Calculate coordinates."""
- self.clear() #FIXME do i want this here?
- #source connector
- source = self.get_source()
- X, Y = source.get_connector_coordinate()
- x1, y1 = self.x1 + X, self.y1 + Y
- self.add_line((x1, y1), (X, Y))
- #sink connector
- sink = self.get_sink()
- X, Y = sink.get_connector_coordinate()
- x2, y2 = self.x2 + X, self.y2 + Y
- self.add_line((x2, y2), (X, Y))
- #adjust arrow
- self._arrow = [(x+X, y+Y) for x,y in self.arrow]
- #add the horizontal and vertical lines in this connection
- if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180:
- #2 possible point sets to create a 3-line connector
- mid_x, mid_y = (x1 + x2)/2.0, (y1 + y2)/2.0
- points = [((mid_x, y1), (mid_x, y2)), ((x1, mid_y), (x2, mid_y))]
- #source connector -> points[0][0] should be in the direction of source (if possible)
- if Utils.get_angle_from_coordinates((x1, y1), points[0][0]) != source.get_connector_direction(): points.reverse()
- #points[0][0] -> sink connector should not be in the direction of sink
- if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
- #points[0][0] -> source connector should not be in the direction of source
- if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse()
- #create 3-line connector
- p1, p2 = map(int, points[0][0]), map(int, points[0][1])
- self.add_line((x1, y1), p1)
- self.add_line(p1, p2)
- self.add_line((x2, y2), p2)
- else:
- #2 possible points to create a right-angled connector
- points = [(x1, y2), (x2, y1)]
- #source connector -> points[0] should be in the direction of source (if possible)
- if Utils.get_angle_from_coordinates((x1, y1), points[0]) != source.get_connector_direction(): points.reverse()
- #points[0] -> sink connector should not be in the direction of sink
- if Utils.get_angle_from_coordinates(points[0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
- #points[0] -> source connector should not be in the direction of source
- if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse()
- #create right-angled connector
- self.add_line((x1, y1), points[0])
- self.add_line((x2, y2), points[0])
+ def _update_after_move(self):
+ """Calculate coordinates."""
+ self.clear() #FIXME do i want this here?
+ #source connector
+ source = self.get_source()
+ X, Y = source.get_connector_coordinate()
+ x1, y1 = self.x1 + X, self.y1 + Y
+ self.add_line((x1, y1), (X, Y))
+ #sink connector
+ sink = self.get_sink()
+ X, Y = sink.get_connector_coordinate()
+ x2, y2 = self.x2 + X, self.y2 + Y
+ self.add_line((x2, y2), (X, Y))
+ #adjust arrow
+ self._arrow = [(x+X, y+Y) for x,y in self.arrow]
+ #add the horizontal and vertical lines in this connection
+ if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180:
+ #2 possible point sets to create a 3-line connector
+ mid_x, mid_y = (x1 + x2)/2.0, (y1 + y2)/2.0
+ points = [((mid_x, y1), (mid_x, y2)), ((x1, mid_y), (x2, mid_y))]
+ #source connector -> points[0][0] should be in the direction of source (if possible)
+ if Utils.get_angle_from_coordinates((x1, y1), points[0][0]) != source.get_connector_direction(): points.reverse()
+ #points[0][0] -> sink connector should not be in the direction of sink
+ if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
+ #points[0][0] -> source connector should not be in the direction of source
+ if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse()
+ #create 3-line connector
+ p1, p2 = map(int, points[0][0]), map(int, points[0][1])
+ self.add_line((x1, y1), p1)
+ self.add_line(p1, p2)
+ self.add_line((x2, y2), p2)
+ else:
+ #2 possible points to create a right-angled connector
+ points = [(x1, y2), (x2, y1)]
+ #source connector -> points[0] should be in the direction of source (if possible)
+ if Utils.get_angle_from_coordinates((x1, y1), points[0]) != source.get_connector_direction(): points.reverse()
+ #points[0] -> sink connector should not be in the direction of sink
+ if Utils.get_angle_from_coordinates(points[0], (x2, y2)) == sink.get_connector_direction(): points.reverse()
+ #points[0] -> source connector should not be in the direction of source
+ if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse()
+ #create right-angled connector
+ self.add_line((x1, y1), points[0])
+ self.add_line((x2, y2), points[0])
- def draw(self, gc, window):
- """
- Draw the connection.
-
- Args:
- gc: the graphics context
- window: the gtk window to draw on
- """
- sink = self.get_sink()
- source = self.get_source()
- #check for changes
- if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes()
- elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move()
- #cache values
- self._sink_rot = sink.get_rotation()
- self._source_rot = source.get_rotation()
- self._sink_coor = sink.get_coordinate()
- self._source_coor = source.get_coordinate()
- #draw
- if self.is_highlighted(): border_color = Colors.HIGHLIGHT_COLOR
- elif self.get_enabled(): border_color = Colors.CONNECTION_ENABLED_COLOR
- else: border_color = Colors.CONNECTION_DISABLED_COLOR
- Element.draw(self, gc, window, bg_color=None, border_color=border_color)
- #draw arrow on sink port
- gc.set_foreground(self._arrow_color)
- window.draw_polygon(gc, True, self._arrow)
+ def draw(self, gc, window):
+ """
+ Draw the connection.
+
+ Args:
+ gc: the graphics context
+ window: the gtk window to draw on
+ """
+ sink = self.get_sink()
+ source = self.get_source()
+ #check for changes
+ if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes()
+ elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate():
+ try:
+ self._update_after_move()
+ except:
+ return
+ #cache values
+ self._sink_rot = sink.get_rotation()
+ self._source_rot = source.get_rotation()
+ self._sink_coor = sink.get_coordinate()
+ self._source_coor = source.get_coordinate()
+ #draw
+ if self.is_highlighted(): border_color = Colors.HIGHLIGHT_COLOR
+ elif self.get_enabled(): border_color = Colors.CONNECTION_ENABLED_COLOR
+ else: border_color = Colors.CONNECTION_DISABLED_COLOR
+ Element.draw(self, gc, window, bg_color=None, border_color=border_color)
+ #draw arrow on sink port
+ try:
+ gc.set_foreground(self._arrow_color)
+ window.draw_polygon(gc, True, self._arrow)
+ except:
+ return
diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py
index df424750b9..5b3b420d3b 100644
--- a/grc/gui/Dialogs.py
+++ b/grc/gui/Dialogs.py
@@ -23,46 +23,46 @@ import gtk
import Utils
class TextDisplay(gtk.TextView):
- """A non editable gtk text view."""
-
- def __init__(self, text=''):
- """
- TextDisplay constructor.
-
- Args:
- text: the text to display (string)
- """
- text_buffer = gtk.TextBuffer()
- text_buffer.set_text(text)
- self.set_text = text_buffer.set_text
- self.insert = lambda line: text_buffer.insert(text_buffer.get_end_iter(), line)
- gtk.TextView.__init__(self, text_buffer)
- self.set_editable(False)
- self.set_cursor_visible(False)
- self.set_wrap_mode(gtk.WRAP_WORD_CHAR)
+ """A non editable gtk text view."""
+
+ def __init__(self, text=''):
+ """
+ TextDisplay constructor.
+
+ Args:
+ text: the text to display (string)
+ """
+ text_buffer = gtk.TextBuffer()
+ text_buffer.set_text(text)
+ self.set_text = text_buffer.set_text
+ self.insert = lambda line: text_buffer.insert(text_buffer.get_end_iter(), line)
+ gtk.TextView.__init__(self, text_buffer)
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+ self.set_wrap_mode(gtk.WRAP_WORD_CHAR)
def MessageDialogHelper(type, buttons, title=None, markup=None):
- """
- Create a modal message dialog and run it.
-
- Args:
- type: the type of message: gtk.MESSAGE_INFO, gtk.MESSAGE_WARNING, gtk.MESSAGE_QUESTION or gtk.MESSAGE_ERROR
- buttons: the predefined set of buttons to use:
- gtk.BUTTONS_NONE, gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL
-
- Args:
- tittle: the title of the window (string)
- markup: the message text with pango markup
-
- Returns:
- the gtk response from run()
- """
- message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, type, buttons)
- if title: message_dialog.set_title(title)
- if markup: message_dialog.set_markup(markup)
- response = message_dialog.run()
- message_dialog.destroy()
- return response
+ """
+ Create a modal message dialog and run it.
+
+ Args:
+ type: the type of message: gtk.MESSAGE_INFO, gtk.MESSAGE_WARNING, gtk.MESSAGE_QUESTION or gtk.MESSAGE_ERROR
+ buttons: the predefined set of buttons to use:
+ gtk.BUTTONS_NONE, gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL
+
+ Args:
+ tittle: the title of the window (string)
+ markup: the message text with pango markup
+
+ Returns:
+ the gtk response from run()
+ """
+ message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, type, buttons)
+ if title: message_dialog.set_title(title)
+ if markup: message_dialog.set_markup(markup)
+ response = message_dialog.run()
+ message_dialog.destroy()
+ return response
ERRORS_MARKUP_TMPL="""\
@@ -72,31 +72,31 @@ $encode($err_msg.replace('\t', ' '))
#end for"""
def ErrorsDialog(flowgraph): MessageDialogHelper(
- type=gtk.MESSAGE_ERROR,
- buttons=gtk.BUTTONS_CLOSE,
- title='Flow Graph Errors',
- markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()),
+ type=gtk.MESSAGE_ERROR,
+ buttons=gtk.BUTTONS_CLOSE,
+ title='Flow Graph Errors',
+ markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()),
)
class AboutDialog(gtk.AboutDialog):
- """A cute little about dialog."""
-
- def __init__(self, platform):
- """AboutDialog constructor."""
- gtk.AboutDialog.__init__(self)
- self.set_name(platform.get_name())
- self.set_version(platform.get_version())
- self.set_license(platform.get_license())
- self.set_copyright(platform.get_license().splitlines()[0])
- self.set_website(platform.get_website())
- self.run()
- self.destroy()
+ """A cute little about dialog."""
+
+ def __init__(self, platform):
+ """AboutDialog constructor."""
+ gtk.AboutDialog.__init__(self)
+ self.set_name(platform.get_name())
+ self.set_version(platform.get_version())
+ self.set_license(platform.get_license())
+ self.set_copyright(platform.get_license().splitlines()[0])
+ self.set_website(platform.get_website())
+ self.run()
+ self.destroy()
def HelpDialog(): MessageDialogHelper(
- type=gtk.MESSAGE_INFO,
- buttons=gtk.BUTTONS_CLOSE,
- title='Help',
- markup="""\
+ type=gtk.MESSAGE_INFO,
+ buttons=gtk.BUTTONS_CLOSE,
+ title='Help',
+ markup="""\
<b>Usage Tips</b>
<u>Add block</u>: drag and drop or double click a block in the block selection window.
@@ -112,15 +112,15 @@ COLORS_DIALOG_MARKUP_TMPL = """\
<b>Color Mapping</b>
#if $colors
- #set $max_len = max([len(color[0]) for color in $colors]) + 10
- #for $title, $color_spec in $colors
+ #set $max_len = max([len(color[0]) for color in $colors]) + 10
+ #for $title, $color_spec in $colors
<span background="$color_spec"><tt>$($encode($title).center($max_len))</tt></span>
- #end for
+ #end for
#end if
"""
def TypesDialog(platform): MessageDialogHelper(
- type=gtk.MESSAGE_INFO,
- buttons=gtk.BUTTONS_CLOSE,
- title='Types',
- markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors()))
+ type=gtk.MESSAGE_INFO,
+ buttons=gtk.BUTTONS_CLOSE,
+ title='Types',
+ markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors()))
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py
index da16eb7cf2..64be4d3ea6 100644
--- a/grc/gui/DrawingArea.py
+++ b/grc/gui/DrawingArea.py
@@ -23,113 +23,113 @@ import gtk
from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS
class DrawingArea(gtk.DrawingArea):
- """
- DrawingArea is the gtk pixel map that graphical elements may draw themselves on.
- The drawing area also responds to mouse and key events.
- """
+ """
+ DrawingArea is the gtk pixel map that graphical elements may draw themselves on.
+ The drawing area also responds to mouse and key events.
+ """
- def __init__(self, flow_graph):
- """
- DrawingArea contructor.
- Connect event handlers.
-
- Args:
- main_window: the main_window containing all flow graphs
- """
- self.ctrl_mask = False
- self._flow_graph = flow_graph
- gtk.DrawingArea.__init__(self)
- self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
- self.connect('realize', self._handle_window_realize)
- self.connect('configure-event', self._handle_window_configure)
- self.connect('expose-event', self._handle_window_expose)
- self.connect('motion-notify-event', self._handle_mouse_motion)
- self.connect('button-press-event', self._handle_mouse_button_press)
- self.connect('button-release-event', self._handle_mouse_button_release)
- self.add_events(
- gtk.gdk.BUTTON_PRESS_MASK | \
- gtk.gdk.POINTER_MOTION_MASK | \
- gtk.gdk.BUTTON_RELEASE_MASK | \
- gtk.gdk.LEAVE_NOTIFY_MASK | \
- gtk.gdk.ENTER_NOTIFY_MASK
- )
- #setup drag and drop
- self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY)
- self.connect('drag-data-received', self._handle_drag_data_received)
- #setup the focus flag
- self._focus_flag = False
- self.get_focus_flag = lambda: self._focus_flag
- def _handle_focus_event(widget, event, focus_flag): self._focus_flag = focus_flag
- self.connect('leave-notify-event', _handle_focus_event, False)
- self.connect('enter-notify-event', _handle_focus_event, True)
+ def __init__(self, flow_graph):
+ """
+ DrawingArea contructor.
+ Connect event handlers.
+
+ Args:
+ main_window: the main_window containing all flow graphs
+ """
+ self.ctrl_mask = False
+ self._flow_graph = flow_graph
+ gtk.DrawingArea.__init__(self)
+ self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
+ self.connect('realize', self._handle_window_realize)
+ self.connect('configure-event', self._handle_window_configure)
+ self.connect('expose-event', self._handle_window_expose)
+ self.connect('motion-notify-event', self._handle_mouse_motion)
+ self.connect('button-press-event', self._handle_mouse_button_press)
+ self.connect('button-release-event', self._handle_mouse_button_release)
+ self.add_events(
+ gtk.gdk.BUTTON_PRESS_MASK | \
+ gtk.gdk.POINTER_MOTION_MASK | \
+ gtk.gdk.BUTTON_RELEASE_MASK | \
+ gtk.gdk.LEAVE_NOTIFY_MASK | \
+ gtk.gdk.ENTER_NOTIFY_MASK
+ )
+ #setup drag and drop
+ self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY)
+ self.connect('drag-data-received', self._handle_drag_data_received)
+ #setup the focus flag
+ self._focus_flag = False
+ self.get_focus_flag = lambda: self._focus_flag
+ def _handle_focus_event(widget, event, focus_flag): self._focus_flag = focus_flag
+ self.connect('leave-notify-event', _handle_focus_event, False)
+ self.connect('enter-notify-event', _handle_focus_event, True)
- def new_pixmap(self, width, height): return gtk.gdk.Pixmap(self.window, width, height, -1)
- def get_pixbuf(self):
- width, height = self._pixmap.get_size()
- pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height)
- pixbuf.get_from_drawable(self._pixmap, self._pixmap.get_colormap(), 0, 0, 0, 0, width, height)
- return pixbuf
+ def new_pixmap(self, width, height): return gtk.gdk.Pixmap(self.window, width, height, -1)
+ def get_pixbuf(self):
+ width, height = self._pixmap.get_size()
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height)
+ pixbuf.get_from_drawable(self._pixmap, self._pixmap.get_colormap(), 0, 0, 0, 0, width, height)
+ return pixbuf
- ##########################################################################
- ## Handlers
- ##########################################################################
- def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time):
- """
- Handle a drag and drop by adding a block at the given coordinate.
- """
- self._flow_graph.add_new_block(selection_data.data, (x, y))
+ ##########################################################################
+ ## Handlers
+ ##########################################################################
+ def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time):
+ """
+ Handle a drag and drop by adding a block at the given coordinate.
+ """
+ self._flow_graph.add_new_block(selection_data.data, (x, y))
- def _handle_mouse_button_press(self, widget, event):
- """
- Forward button click information to the flow graph.
- """
- self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
- if event.button == 1: self._flow_graph.handle_mouse_selector_press(
- double_click=(event.type == gtk.gdk._2BUTTON_PRESS),
- coordinate=(event.x, event.y),
- )
- if event.button == 3: self._flow_graph.handle_mouse_context_press(
- coordinate=(event.x, event.y),
- event=event,
- )
+ def _handle_mouse_button_press(self, widget, event):
+ """
+ Forward button click information to the flow graph.
+ """
+ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
+ if event.button == 1: self._flow_graph.handle_mouse_selector_press(
+ double_click=(event.type == gtk.gdk._2BUTTON_PRESS),
+ coordinate=(event.x, event.y),
+ )
+ if event.button == 3: self._flow_graph.handle_mouse_context_press(
+ coordinate=(event.x, event.y),
+ event=event,
+ )
- def _handle_mouse_button_release(self, widget, event):
- """
- Forward button release information to the flow graph.
- """
- self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
- if event.button == 1: self._flow_graph.handle_mouse_selector_release(
- coordinate=(event.x, event.y),
- )
+ def _handle_mouse_button_release(self, widget, event):
+ """
+ Forward button release information to the flow graph.
+ """
+ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
+ if event.button == 1: self._flow_graph.handle_mouse_selector_release(
+ coordinate=(event.x, event.y),
+ )
- def _handle_mouse_motion(self, widget, event):
- """
- Forward mouse motion information to the flow graph.
- """
- self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
- self._flow_graph.handle_mouse_motion(
- coordinate=(event.x, event.y),
- )
+ def _handle_mouse_motion(self, widget, event):
+ """
+ Forward mouse motion information to the flow graph.
+ """
+ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
+ self._flow_graph.handle_mouse_motion(
+ coordinate=(event.x, event.y),
+ )
- def _handle_window_realize(self, widget):
- """
- Called when the window is realized.
- Update the flowgraph, which calls new pixmap.
- """
- self._flow_graph.update()
+ def _handle_window_realize(self, widget):
+ """
+ Called when the window is realized.
+ Update the flowgraph, which calls new pixmap.
+ """
+ self._flow_graph.update()
- def _handle_window_configure(self, widget, event):
- """
- Called when the window is resized.
- Create a new pixmap for background buffer.
- """
- self._pixmap = self.new_pixmap(*self.get_size_request())
+ def _handle_window_configure(self, widget, event):
+ """
+ Called when the window is resized.
+ Create a new pixmap for background buffer.
+ """
+ self._pixmap = self.new_pixmap(*self.get_size_request())
- def _handle_window_expose(self, widget, event):
- """
- Called when window is exposed, or queue_draw is called.
- Double buffering: draw to pixmap, then draw pixmap to window.
- """
- gc = self.window.new_gc()
- self._flow_graph.draw(gc, self._pixmap)
- self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1)
+ def _handle_window_expose(self, widget, event):
+ """
+ Called when window is exposed, or queue_draw is called.
+ Double buffering: draw to pixmap, then draw pixmap to window.
+ """
+ gc = self.window.new_gc()
+ self._flow_graph.draw(gc, self._pixmap)
+ self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1)
diff --git a/grc/gui/Element.py b/grc/gui/Element.py
index eac59d88eb..915bdfb915 100644
--- a/grc/gui/Element.py
+++ b/grc/gui/Element.py
@@ -21,244 +21,244 @@ from Constants import LINE_SELECT_SENSITIVITY
from Constants import POSSIBLE_ROTATIONS
class Element(object):
- """
- GraphicalElement is the base class for all graphical elements.
- It contains an X,Y coordinate, a list of rectangular areas that the element occupies,
- and methods to detect selection of those areas.
- """
+ """
+ GraphicalElement is the base class for all graphical elements.
+ It contains an X,Y coordinate, a list of rectangular areas that the element occupies,
+ and methods to detect selection of those areas.
+ """
- def __init__(self):
- """
- Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
- """
- self.set_rotation(POSSIBLE_ROTATIONS[0])
- self.set_coordinate((0, 0))
- self.clear()
- self.set_highlighted(False)
+ def __init__(self):
+ """
+ Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
+ """
+ self.set_rotation(POSSIBLE_ROTATIONS[0])
+ self.set_coordinate((0, 0))
+ self.clear()
+ self.set_highlighted(False)
- def is_horizontal(self, rotation=None):
- """
- Is this element horizontal?
- If rotation is None, use this element's rotation.
-
- Args:
- rotation: the optional rotation
-
- Returns:
- true if rotation is horizontal
- """
- rotation = rotation or self.get_rotation()
- return rotation in (0, 180)
+ def is_horizontal(self, rotation=None):
+ """
+ Is this element horizontal?
+ If rotation is None, use this element's rotation.
+
+ Args:
+ rotation: the optional rotation
+
+ Returns:
+ true if rotation is horizontal
+ """
+ rotation = rotation or self.get_rotation()
+ return rotation in (0, 180)
- def is_vertical(self, rotation=None):
- """
- Is this element vertical?
- If rotation is None, use this element's rotation.
-
- Args:
- rotation: the optional rotation
-
- Returns:
- true if rotation is vertical
- """
- rotation = rotation or self.get_rotation()
- return rotation in (90, 270)
+ def is_vertical(self, rotation=None):
+ """
+ Is this element vertical?
+ If rotation is None, use this element's rotation.
+
+ Args:
+ rotation: the optional rotation
+
+ Returns:
+ true if rotation is vertical
+ """
+ rotation = rotation or self.get_rotation()
+ return rotation in (90, 270)
- def create_labels(self):
- """
- Create labels (if applicable) and call on all children.
- Call this base method before creating labels in the element.
- """
- for child in self.get_children(): child.create_labels()
+ def create_labels(self):
+ """
+ Create labels (if applicable) and call on all children.
+ Call this base method before creating labels in the element.
+ """
+ for child in self.get_children():child.create_labels()
- def create_shapes(self):
- """
- Create shapes (if applicable) and call on all children.
- Call this base method before creating shapes in the element.
- """
- self.clear()
- for child in self.get_children(): child.create_shapes()
+ def create_shapes(self):
+ """
+ Create shapes (if applicable) and call on all children.
+ Call this base method before creating shapes in the element.
+ """
+ self.clear()
+ for child in self.get_children(): child.create_shapes()
- def draw(self, gc, window, border_color, bg_color):
- """
- Draw in the given window.
-
- Args:
- gc: the graphics context
- window: the gtk window to draw on
- border_color: the color for lines and rectangle borders
- bg_color: the color for the inside of the rectangle
- """
- X,Y = self.get_coordinate()
- for (rX,rY),(W,H) in self._areas_list:
- aX = X + rX
- aY = Y + rY
- gc.set_foreground(bg_color)
- window.draw_rectangle(gc, True, aX, aY, W, H)
- gc.set_foreground(border_color)
- window.draw_rectangle(gc, False, aX, aY, W, H)
- for (x1, y1),(x2, y2) in self._lines_list:
- gc.set_foreground(border_color)
- window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
+ def draw(self, gc, window, border_color, bg_color):
+ """
+ Draw in the given window.
+
+ Args:
+ gc: the graphics context
+ window: the gtk window to draw on
+ border_color: the color for lines and rectangle borders
+ bg_color: the color for the inside of the rectangle
+ """
+ X,Y = self.get_coordinate()
+ for (rX,rY),(W,H) in self._areas_list:
+ aX = X + rX
+ aY = Y + rY
+ gc.set_foreground(bg_color)
+ window.draw_rectangle(gc, True, aX, aY, W, H)
+ gc.set_foreground(border_color)
+ window.draw_rectangle(gc, False, aX, aY, W, H)
+ for (x1, y1),(x2, y2) in self._lines_list:
+ gc.set_foreground(border_color)
+ window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
- def rotate(self, rotation):
- """
- Rotate all of the areas by 90 degrees.
-
- Args:
- rotation: multiple of 90 degrees
- """
- self.set_rotation((self.get_rotation() + rotation)%360)
+ def rotate(self, rotation):
+ """
+ Rotate all of the areas by 90 degrees.
+
+ Args:
+ rotation: multiple of 90 degrees
+ """
+ self.set_rotation((self.get_rotation() + rotation)%360)
- def clear(self):
- """Empty the lines and areas."""
- self._areas_list = list()
- self._lines_list = list()
+ def clear(self):
+ """Empty the lines and areas."""
+ self._areas_list = list()
+ self._lines_list = list()
- def set_coordinate(self, coor):
- """
- Set the reference coordinate.
-
- Args:
- coor: the coordinate tuple (x,y)
- """
- self.coor = coor
+ def set_coordinate(self, coor):
+ """
+ Set the reference coordinate.
+
+ Args:
+ coor: the coordinate tuple (x,y)
+ """
+ self.coor = coor
- def get_parent(self):
- """
- Get the parent of this element.
-
- Returns:
- the parent
- """
- return self.parent
+ def get_parent(self):
+ """
+ Get the parent of this element.
+
+ Returns:
+ the parent
+ """
+ return self.parent
- def set_highlighted(self, highlighted):
- """
- Set the highlight status.
-
- Args:
- highlighted: true to enable highlighting
- """
- self.highlighted = highlighted
+ def set_highlighted(self, highlighted):
+ """
+ Set the highlight status.
+
+ Args:
+ highlighted: true to enable highlighting
+ """
+ self.highlighted = highlighted
- def is_highlighted(self):
- """
- Get the highlight status.
-
- Returns:
- true if highlighted
- """
- return self.highlighted
+ def is_highlighted(self):
+ """
+ Get the highlight status.
+
+ Returns:
+ true if highlighted
+ """
+ return self.highlighted
- def get_coordinate(self):
- """Get the coordinate.
-
- Returns:
- the coordinate tuple (x,y)
- """
- return self.coor
+ def get_coordinate(self):
+ """Get the coordinate.
+
+ Returns:
+ the coordinate tuple (x,y)
+ """
+ return self.coor
- def move(self, delta_coor):
- """
- Move the element by adding the delta_coor to the current coordinate.
-
- Args:
- delta_coor: (delta_x,delta_y) tuple
- """
- deltaX, deltaY = delta_coor
- X, Y = self.get_coordinate()
- self.set_coordinate((X+deltaX, Y+deltaY))
+ def move(self, delta_coor):
+ """
+ Move the element by adding the delta_coor to the current coordinate.
+
+ Args:
+ delta_coor: (delta_x,delta_y) tuple
+ """
+ deltaX, deltaY = delta_coor
+ X, Y = self.get_coordinate()
+ self.set_coordinate((X+deltaX, Y+deltaY))
- def add_area(self, rel_coor, area):
- """
- Add an area to the area list.
- An area is actually a coordinate relative to the main coordinate
- with a width/height pair relative to the area coordinate.
- A positive width is to the right of the coordinate.
- A positive height is above the coordinate.
- The area is associated with a rotation.
-
- Args:
- rel_coor: (x,y) offset from this element's coordinate
- area: (width,height) tuple
- """
- self._areas_list.append((rel_coor, area))
+ def add_area(self, rel_coor, area):
+ """
+ Add an area to the area list.
+ An area is actually a coordinate relative to the main coordinate
+ with a width/height pair relative to the area coordinate.
+ A positive width is to the right of the coordinate.
+ A positive height is above the coordinate.
+ The area is associated with a rotation.
+
+ Args:
+ rel_coor: (x,y) offset from this element's coordinate
+ area: (width,height) tuple
+ """
+ self._areas_list.append((rel_coor, area))
- def add_line(self, rel_coor1, rel_coor2):
- """
- Add a line to the line list.
- A line is defined by 2 relative coordinates.
- Lines must be horizontal or vertical.
- The line is associated with a rotation.
-
- Args:
- rel_coor1: relative (x1,y1) tuple
- rel_coor2: relative (x2,y2) tuple
- """
- self._lines_list.append((rel_coor1, rel_coor2))
+ def add_line(self, rel_coor1, rel_coor2):
+ """
+ Add a line to the line list.
+ A line is defined by 2 relative coordinates.
+ Lines must be horizontal or vertical.
+ The line is associated with a rotation.
+
+ Args:
+ rel_coor1: relative (x1,y1) tuple
+ rel_coor2: relative (x2,y2) tuple
+ """
+ self._lines_list.append((rel_coor1, rel_coor2))
- def what_is_selected(self, coor, coor_m=None):
- """
- One coordinate specified:
- Is this element selected at given coordinate?
- ie: is the coordinate encompassed by one of the areas or lines?
- Both coordinates specified:
- Is this element within the rectangular region defined by both coordinates?
- ie: do any area corners or line endpoints fall within the region?
-
- Args:
- coor: the selection coordinate, tuple x, y
- coor_m: an additional selection coordinate.
-
- Returns:
- self if one of the areas/lines encompasses coor, else None.
- """
- #function to test if p is between a and b (inclusive)
- in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b)
- #relative coordinate
- x, y = [a-b for a,b in zip(coor, self.get_coordinate())]
- if coor_m:
- x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
- #handle rectangular areas
- for (x1,y1), (w,h) in self._areas_list:
- if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
- in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
- return self
- #handle horizontal or vertical lines
- for (x1, y1), (x2, y2) in self._lines_list:
- if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
- in_between(x2, x, x_m) and in_between(y2, y, y_m):
- return self
- return None
- else:
- #handle rectangular areas
- for (x1,y1), (w,h) in self._areas_list:
- if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
- #handle horizontal or vertical lines
- for (x1, y1), (x2, y2) in self._lines_list:
- if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY
- if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY
- if in_between(x, x1, x2) and in_between(y, y1, y2): return self
- return None
+ def what_is_selected(self, coor, coor_m=None):
+ """
+ One coordinate specified:
+ Is this element selected at given coordinate?
+ ie: is the coordinate encompassed by one of the areas or lines?
+ Both coordinates specified:
+ Is this element within the rectangular region defined by both coordinates?
+ ie: do any area corners or line endpoints fall within the region?
+
+ Args:
+ coor: the selection coordinate, tuple x, y
+ coor_m: an additional selection coordinate.
+
+ Returns:
+ self if one of the areas/lines encompasses coor, else None.
+ """
+ #function to test if p is between a and b (inclusive)
+ in_between = lambda p, a, b: p >= min(a, b) and p <= max(a, b)
+ #relative coordinate
+ x, y = [a-b for a,b in zip(coor, self.get_coordinate())]
+ if coor_m:
+ x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
+ #handle rectangular areas
+ for (x1,y1), (w,h) in self._areas_list:
+ if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
+ in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
+ in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
+ in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
+ return self
+ #handle horizontal or vertical lines
+ for (x1, y1), (x2, y2) in self._lines_list:
+ if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
+ in_between(x2, x, x_m) and in_between(y2, y, y_m):
+ return self
+ return None
+ else:
+ #handle rectangular areas
+ for (x1,y1), (w,h) in self._areas_list:
+ if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
+ #handle horizontal or vertical lines
+ for (x1, y1), (x2, y2) in self._lines_list:
+ if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY
+ if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY
+ if in_between(x, x1, x2) and in_between(y, y1, y2): return self
+ return None
- def get_rotation(self):
- """
- Get the rotation in degrees.
-
- Returns:
- the rotation
- """
- return self.rotation
+ def get_rotation(self):
+ """
+ Get the rotation in degrees.
+
+ Returns:
+ the rotation
+ """
+ return self.rotation
- def set_rotation(self, rotation):
- """
- Set the rotation in degrees.
-
- Args:
- rotation: the rotation"""
- if rotation not in POSSIBLE_ROTATIONS:
- raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
- self.rotation = rotation
+ def set_rotation(self, rotation):
+ """
+ Set the rotation in degrees.
+
+ Args:
+ rotation: the rotation"""
+ if rotation not in POSSIBLE_ROTATIONS:
+ raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
+ self.rotation = rotation
diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py
index 20172a7418..e8e859dc60 100644
--- a/grc/gui/FileDialogs.py
+++ b/grc/gui/FileDialogs.py
@@ -22,8 +22,8 @@ pygtk.require('2.0')
import gtk
from Dialogs import MessageDialogHelper
from Constants import \
- DEFAULT_FILE_PATH, IMAGE_FILE_EXTENSION, \
- NEW_FLOGRAPH_TITLE
+ DEFAULT_FILE_PATH, IMAGE_FILE_EXTENSION, \
+ NEW_FLOGRAPH_TITLE
import Preferences
from os import path
import Utils
@@ -46,139 +46,139 @@ File <b>$encode($filename)</b> Does not Exist!"""
##################################################
##the filter for flow graph files
def get_flow_graph_files_filter():
- filter = gtk.FileFilter()
- filter.set_name('Flow Graph Files')
- filter.add_pattern('*'+Preferences.file_extension())
- return filter
+ filter = gtk.FileFilter()
+ filter.set_name('Flow Graph Files')
+ filter.add_pattern('*'+Preferences.file_extension())
+ return filter
##the filter for image files
def get_image_files_filter():
- filter = gtk.FileFilter()
- filter.set_name('Image Files')
- filter.add_pattern('*'+IMAGE_FILE_EXTENSION)
- return filter
+ filter = gtk.FileFilter()
+ filter.set_name('Image Files')
+ filter.add_pattern('*'+IMAGE_FILE_EXTENSION)
+ return filter
##the filter for all files
def get_all_files_filter():
- filter = gtk.FileFilter()
- filter.set_name('All Files')
- filter.add_pattern('*')
- return filter
+ filter = gtk.FileFilter()
+ filter.set_name('All Files')
+ filter.add_pattern('*')
+ return filter
##################################################
# File Dialogs
##################################################
class FileDialogHelper(gtk.FileChooserDialog):
- """
- A wrapper class for the gtk file chooser dialog.
- Implement a file chooser dialog with only necessary parameters.
- """
-
- def __init__(self, action, title):
- """
- FileDialogHelper contructor.
- Create a save or open dialog with cancel and ok buttons.
- Use standard settings: no multiple selection, local files only, and the * filter.
-
- Args:
- action: gtk.FILE_CHOOSER_ACTION_OPEN or gtk.FILE_CHOOSER_ACTION_SAVE
- title: the title of the dialog (string)
- """
- ok_stock = {gtk.FILE_CHOOSER_ACTION_OPEN : 'gtk-open', gtk.FILE_CHOOSER_ACTION_SAVE : 'gtk-save'}[action]
- gtk.FileChooserDialog.__init__(self, title, None, action, ('gtk-cancel', gtk.RESPONSE_CANCEL, ok_stock, gtk.RESPONSE_OK))
- self.set_select_multiple(False)
- self.set_local_only(True)
- self.add_filter(get_all_files_filter())
+ """
+ A wrapper class for the gtk file chooser dialog.
+ Implement a file chooser dialog with only necessary parameters.
+ """
+
+ def __init__(self, action, title):
+ """
+ FileDialogHelper contructor.
+ Create a save or open dialog with cancel and ok buttons.
+ Use standard settings: no multiple selection, local files only, and the * filter.
+
+ Args:
+ action: gtk.FILE_CHOOSER_ACTION_OPEN or gtk.FILE_CHOOSER_ACTION_SAVE
+ title: the title of the dialog (string)
+ """
+ ok_stock = {gtk.FILE_CHOOSER_ACTION_OPEN : 'gtk-open', gtk.FILE_CHOOSER_ACTION_SAVE : 'gtk-save'}[action]
+ gtk.FileChooserDialog.__init__(self, title, None, action, ('gtk-cancel', gtk.RESPONSE_CANCEL, ok_stock, gtk.RESPONSE_OK))
+ self.set_select_multiple(False)
+ self.set_local_only(True)
+ self.add_filter(get_all_files_filter())
class FileDialog(FileDialogHelper):
- """A dialog box to save or open flow graph files. This is a base class, do not use."""
-
- def __init__(self, current_file_path=''):
- """
- FileDialog constructor.
-
- Args:
- current_file_path: the current directory or path to the open flow graph
- """
- if not current_file_path: current_file_path = path.join(DEFAULT_FILE_PATH, NEW_FLOGRAPH_TITLE + Preferences.file_extension())
- if self.type == OPEN_FLOW_GRAPH:
- FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_OPEN, 'Open a Flow Graph from a File...')
- self.add_and_set_filter(get_flow_graph_files_filter())
- self.set_select_multiple(True)
- elif self.type == SAVE_FLOW_GRAPH:
- FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph to a File...')
- self.add_and_set_filter(get_flow_graph_files_filter())
- self.set_current_name(path.basename(current_file_path)) #show the current filename
- elif self.type == SAVE_IMAGE:
- FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph Screen Shot...')
- self.add_and_set_filter(get_image_files_filter())
- current_file_path = current_file_path + IMAGE_FILE_EXTENSION
- self.set_current_name(path.basename(current_file_path)) #show the current filename
- self.set_current_folder(path.dirname(current_file_path)) #current directory
-
- def add_and_set_filter(self, filter):
- """
- Add the gtk file filter to the list of filters and set it as the default file filter.
-
- Args:
- filter: a gtk file filter.
- """
- self.add_filter(filter)
- self.set_filter(filter)
-
- def get_rectified_filename(self):
- """
- Run the dialog and get the filename.
- If this is a save dialog and the file name is missing the extension, append the file extension.
- If the file name with the extension already exists, show a overwrite dialog.
- If this is an open dialog, return a list of filenames.
-
- Returns:
- the complete file path
- """
- if gtk.FileChooserDialog.run(self) != gtk.RESPONSE_OK: return None #response was cancel
- #############################################
- # Handle Save Dialogs
- #############################################
- if self.type in (SAVE_FLOW_GRAPH, SAVE_IMAGE):
- filename = self.get_filename()
- extension = {
- SAVE_FLOW_GRAPH: Preferences.file_extension(),
- SAVE_IMAGE: IMAGE_FILE_EXTENSION,
- }[self.type]
- #append the missing file extension if the filter matches
- if path.splitext(filename)[1].lower() != extension: filename += extension
- self.set_current_name(path.basename(filename)) #show the filename with extension
- if path.exists(filename): #ask the user to confirm overwrite
- if MessageDialogHelper(
- gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Confirm Overwrite!',
- Utils.parse_template(FILE_OVERWRITE_MARKUP_TMPL, filename=filename),
- ) == gtk.RESPONSE_NO: return self.get_rectified_filename()
- return filename
- #############################################
- # Handle Open Dialogs
- #############################################
- elif self.type in (OPEN_FLOW_GRAPH,):
- filenames = self.get_filenames()
- for filename in filenames:
- if not path.exists(filename): #show a warning and re-run
- MessageDialogHelper(
- gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, 'Cannot Open!',
- Utils.parse_template(FILE_DNE_MARKUP_TMPL, filename=filename),
- )
- return self.get_rectified_filename()
- return filenames
-
- def run(self):
- """
- Get the filename and destroy the dialog.
-
- Returns:
- the filename or None if a close/cancel occured.
- """
- filename = self.get_rectified_filename()
- self.destroy()
- return filename
+ """A dialog box to save or open flow graph files. This is a base class, do not use."""
+
+ def __init__(self, current_file_path=''):
+ """
+ FileDialog constructor.
+
+ Args:
+ current_file_path: the current directory or path to the open flow graph
+ """
+ if not current_file_path: current_file_path = path.join(DEFAULT_FILE_PATH, NEW_FLOGRAPH_TITLE + Preferences.file_extension())
+ if self.type == OPEN_FLOW_GRAPH:
+ FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_OPEN, 'Open a Flow Graph from a File...')
+ self.add_and_set_filter(get_flow_graph_files_filter())
+ self.set_select_multiple(True)
+ elif self.type == SAVE_FLOW_GRAPH:
+ FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph to a File...')
+ self.add_and_set_filter(get_flow_graph_files_filter())
+ self.set_current_name(path.basename(current_file_path)) #show the current filename
+ elif self.type == SAVE_IMAGE:
+ FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save a Flow Graph Screen Shot...')
+ self.add_and_set_filter(get_image_files_filter())
+ current_file_path = current_file_path + IMAGE_FILE_EXTENSION
+ self.set_current_name(path.basename(current_file_path)) #show the current filename
+ self.set_current_folder(path.dirname(current_file_path)) #current directory
+
+ def add_and_set_filter(self, filter):
+ """
+ Add the gtk file filter to the list of filters and set it as the default file filter.
+
+ Args:
+ filter: a gtk file filter.
+ """
+ self.add_filter(filter)
+ self.set_filter(filter)
+
+ def get_rectified_filename(self):
+ """
+ Run the dialog and get the filename.
+ If this is a save dialog and the file name is missing the extension, append the file extension.
+ If the file name with the extension already exists, show a overwrite dialog.
+ If this is an open dialog, return a list of filenames.
+
+ Returns:
+ the complete file path
+ """
+ if gtk.FileChooserDialog.run(self) != gtk.RESPONSE_OK: return None #response was cancel
+ #############################################
+ # Handle Save Dialogs
+ #############################################
+ if self.type in (SAVE_FLOW_GRAPH, SAVE_IMAGE):
+ filename = self.get_filename()
+ extension = {
+ SAVE_FLOW_GRAPH: Preferences.file_extension(),
+ SAVE_IMAGE: IMAGE_FILE_EXTENSION,
+ }[self.type]
+ #append the missing file extension if the filter matches
+ if path.splitext(filename)[1].lower() != extension: filename += extension
+ self.set_current_name(path.basename(filename)) #show the filename with extension
+ if path.exists(filename): #ask the user to confirm overwrite
+ if MessageDialogHelper(
+ gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Confirm Overwrite!',
+ Utils.parse_template(FILE_OVERWRITE_MARKUP_TMPL, filename=filename),
+ ) == gtk.RESPONSE_NO: return self.get_rectified_filename()
+ return filename
+ #############################################
+ # Handle Open Dialogs
+ #############################################
+ elif self.type in (OPEN_FLOW_GRAPH,):
+ filenames = self.get_filenames()
+ for filename in filenames:
+ if not path.exists(filename): #show a warning and re-run
+ MessageDialogHelper(
+ gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, 'Cannot Open!',
+ Utils.parse_template(FILE_DNE_MARKUP_TMPL, filename=filename),
+ )
+ return self.get_rectified_filename()
+ return filenames
+
+ def run(self):
+ """
+ Get the filename and destroy the dialog.
+
+ Returns:
+ the filename or None if a close/cancel occured.
+ """
+ filename = self.get_rectified_filename()
+ self.destroy()
+ return filename
class OpenFlowGraphFileDialog(FileDialog): type = OPEN_FLOW_GRAPH
class SaveFlowGraphFileDialog(FileDialog): type = SAVE_FLOW_GRAPH
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 3f17c47bc8..4dff675afb 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -29,536 +29,537 @@ import random
import Messages
class FlowGraph(Element):
- """
- FlowGraph is the data structure to store graphical signal blocks,
- graphical inputs and outputs,
- and the connections between inputs and outputs.
- """
-
- def __init__(self):
- """
- FlowGraph contructor.
- Create a list for signal blocks and connections. Connect mouse handlers.
- """
- Element.__init__(self)
- #when is the flow graph selected? (used by keyboard event handler)
- self.is_selected = lambda: bool(self.get_selected_elements())
- #important vars dealing with mouse event tracking
- self.element_moved = False
- self.mouse_pressed = False
- self.unselect()
- self.press_coor = (0, 0)
- #selected ports
- self._old_selected_port = None
- self._new_selected_port = None
- #context menu
- self._context_menu = gtk.Menu()
- for action in [
- Actions.BLOCK_CUT,
- Actions.BLOCK_COPY,
- Actions.BLOCK_PASTE,
- Actions.ELEMENT_DELETE,
- Actions.BLOCK_ROTATE_CCW,
- Actions.BLOCK_ROTATE_CW,
- 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())
-
- ###########################################################################
- # Access Drawing Area
- ###########################################################################
- def get_drawing_area(self): return self.drawing_area
- def queue_draw(self): self.get_drawing_area().queue_draw()
- def get_size(self): return self.get_drawing_area().get_size_request()
- def set_size(self, *args): self.get_drawing_area().set_size_request(*args)
- def get_scroll_pane(self): return self.drawing_area.get_parent()
- def get_ctrl_mask(self): return self.drawing_area.ctrl_mask
- def new_pixmap(self, *args): return self.get_drawing_area().new_pixmap(*args)
-
- def add_new_block(self, key, coor=None):
- """
- Add a block of the given key to this flow graph.
-
- Args:
- key: the block key
- coor: an optional coordinate or None for random
- """
- id = self._get_unique_id(key)
- #calculate the position coordinate
- h_adj = self.get_scroll_pane().get_hadjustment()
- v_adj = self.get_scroll_pane().get_vadjustment()
- if coor is None: coor = (
- int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()),
- int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()),
- )
- #get the new block
- block = self.get_new_block(key)
- block.set_coordinate(coor)
- block.set_rotation(0)
- block.get_param('id').set_value(id)
- Actions.ELEMENT_CREATE()
-
- return id
-
- ###########################################################################
- # Copy Paste
- ###########################################################################
- def copy_to_clipboard(self):
- """
- Copy the selected blocks and connections into the clipboard.
-
- Returns:
- the clipboard
- """
- #get selected blocks
- blocks = self.get_selected_blocks()
- if not blocks: return None
- #calc x and y min
- x_min, y_min = blocks[0].get_coordinate()
- for block in blocks:
- x, y = block.get_coordinate()
- x_min = min(x, x_min)
- y_min = min(y, y_min)
- #get connections between selected blocks
- connections = filter(
- lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks,
- self.get_connections(),
- )
- clipboard = (
- (x_min, y_min),
- [block.export_data() for block in blocks],
- [connection.export_data() for connection in connections],
- )
- return clipboard
-
- def paste_from_clipboard(self, clipboard):
- """
- Paste the blocks and connections from the clipboard.
-
- Args:
- clipboard: the nested data of blocks, connections
- """
- selected = set()
- (x_min, y_min), blocks_n, connections_n = clipboard
- old_id2block = dict()
- #recalc the position
- h_adj = self.get_scroll_pane().get_hadjustment()
- v_adj = self.get_scroll_pane().get_vadjustment()
- x_off = h_adj.get_value() - x_min + h_adj.page_size/4
- y_off = v_adj.get_value() - y_min + v_adj.page_size/4
- #create blocks
- for block_n in blocks_n:
- block_key = block_n.find('key')
- if block_key == 'options': continue
- block = self.get_new_block(block_key)
- selected.add(block)
- #set params
- params_n = block_n.findall('param')
- for param_n in params_n:
- param_key = param_n.find('key')
- param_value = param_n.find('value')
- #setup id parameter
- if param_key == 'id':
- old_id2block[param_value] = block
- #if the block id is not unique, get a new block id
- if param_value in [block.get_id() for block in self.get_blocks()]:
- param_value = self._get_unique_id(param_value)
- #set value to key
- block.get_param(param_key).set_value(param_value)
- #move block to offset coordinate
- block.move((x_off, y_off))
- #update before creating connections
- self.update()
- #create connections
- for connection_n in connections_n:
- source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key'))
- sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key'))
- self.connect(source, sink)
- #set all pasted elements selected
- for block in selected: selected = selected.union(set(block.get_connections()))
- self._selected_elements = list(selected)
-
- ###########################################################################
- # Modify Selected
- ###########################################################################
- def type_controller_modify_selected(self, direction):
- """
- Change the registered type controller for the selected signal blocks.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for change
- """
- return any([sb.type_controller_modify(direction) for sb in self.get_selected_blocks()])
-
- def port_controller_modify_selected(self, direction):
- """
- Change port controller for the selected signal blocks.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for changed
- """
- return any([sb.port_controller_modify(direction) for sb in self.get_selected_blocks()])
-
- def enable_selected(self, enable):
- """
- Enable/disable the selected blocks.
-
- Args:
- enable: true to enable
-
- Returns:
- true if changed
- """
- changed = False
- for selected_block in self.get_selected_blocks():
- if selected_block.get_enabled() != enable:
- selected_block.set_enabled(enable)
- changed = True
- return changed
-
- def move_selected(self, delta_coordinate):
- """
- Move the element and by the change in coordinates.
-
- Args:
- delta_coordinate: the change in coordinates
- """
- for selected_block in self.get_selected_blocks():
- selected_block.move(delta_coordinate)
- self.element_moved = True
-
- def rotate_selected(self, rotation):
- """
- Rotate the selected blocks by multiples of 90 degrees.
-
- Args:
- rotation: the rotation in degrees
-
- Returns:
- true if changed, otherwise false.
- """
- if not self.get_selected_blocks(): return False
- #initialize min and max coordinates
- min_x, min_y = self.get_selected_block().get_coordinate()
- max_x, max_y = self.get_selected_block().get_coordinate()
- #rotate each selected block, and find min/max coordinate
- for selected_block in self.get_selected_blocks():
- selected_block.rotate(rotation)
- #update the min/max coordinate
- x, y = selected_block.get_coordinate()
- min_x, min_y = min(min_x, x), min(min_y, y)
- max_x, max_y = max(max_x, x), max(max_y, y)
- #calculate center point of slected blocks
- ctr_x, ctr_y = (max_x + min_x)/2, (max_y + min_y)/2
- #rotate the blocks around the center point
- for selected_block in self.get_selected_blocks():
- x, y = selected_block.get_coordinate()
- x, y = Utils.get_rotated_coordinate((x - ctr_x, y - ctr_y), rotation)
- selected_block.set_coordinate((x + ctr_x, y + ctr_y))
- return True
-
- def remove_selected(self):
- """
- Remove selected elements
-
- Returns:
- true if changed.
- """
- changed = False
- for selected_element in self.get_selected_elements():
- self.remove_element(selected_element)
- changed = True
- return changed
-
- def draw(self, gc, window):
- """
- Draw the background and grid if enabled.
- Draw all of the elements in this flow graph onto the pixmap.
- Draw the pixmap to the drawable window of this flow graph.
- """
- W,H = self.get_size()
- #draw the background
- gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR)
- window.draw_rectangle(gc, True, 0, 0, W, H)
- #draw multi select rectangle
- if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()):
- #coordinates
- x1, y1 = self.press_coor
- x2, y2 = self.get_coordinate()
- #calculate top-left coordinate and width/height
- x, y = int(min(x1, x2)), int(min(y1, y2))
- w, h = int(abs(x1 - x2)), int(abs(y1 - y2))
- #draw
- gc.set_foreground(Colors.HIGHLIGHT_COLOR)
- window.draw_rectangle(gc, True, x, y, w, h)
- gc.set_foreground(Colors.BORDER_COLOR)
- window.draw_rectangle(gc, False, x, y, w, h)
- #draw blocks on top of connections
- for element in self.get_connections() + self.get_blocks():
- element.draw(gc, window)
- #draw selected blocks on top of selected connections
- for selected_element in self.get_selected_connections() + self.get_selected_blocks():
- selected_element.draw(gc, window)
-
- def update_selected(self):
- """
- Remove deleted elements from the selected elements list.
- Update highlighting so only the selected are highlighted.
- """
- selected_elements = self.get_selected_elements()
- elements = self.get_elements()
- #remove deleted elements
- for selected in selected_elements:
- if selected in elements: continue
- selected_elements.remove(selected)
- if self._old_selected_port and self._old_selected_port.get_parent() not in elements:
- self._old_selected_port = None
- if self._new_selected_port and self._new_selected_port.get_parent() not in elements:
- self._new_selected_port = None
- #update highlighting
- for element in elements:
- element.set_highlighted(element in selected_elements)
-
- def update(self):
- """
- Call the top level rewrite and validate.
- Call the top level create labels and shapes.
- """
- self.rewrite()
- self.validate()
- self.create_labels()
- self.create_shapes()
-
- ##########################################################################
- ## Get Selected
- ##########################################################################
- def unselect(self):
- """
- Set selected elements to an empty set.
- """
- self._selected_elements = []
-
- def what_is_selected(self, coor, coor_m=None):
- """
- What is selected?
- At the given coordinate, return the elements found to be selected.
- If coor_m is unspecified, return a list of only the first element found to be selected:
- Iterate though the elements backwards since top elements are at the end of the list.
- If an element is selected, place it at the end of the list so that is is drawn last,
- and hence on top. Update the selected port information.
-
- Args:
- coor: the coordinate of the mouse click
- coor_m: the coordinate for multi select
-
- Returns:
- the selected blocks and connections or an empty list
- """
- selected_port = None
- selected = set()
- #check the elements
- for element in reversed(self.get_elements()):
- selected_element = element.what_is_selected(coor, coor_m)
- if not selected_element: continue
- #update the selected port information
- if selected_element.is_port():
- if not coor_m: selected_port = selected_element
- selected_element = selected_element.get_parent()
- selected.add(selected_element)
- #place at the end of the list
- self.get_elements().remove(element)
- self.get_elements().append(element)
- #single select mode, break
- if not coor_m: break
- #update selected ports
- self._old_selected_port = self._new_selected_port
- self._new_selected_port = selected_port
- return list(selected)
-
- def get_selected_connections(self):
- """
- Get a group of selected connections.
-
- Returns:
- sub set of connections in this flow graph
- """
- selected = set()
- for selected_element in self.get_selected_elements():
- if selected_element.is_connection(): selected.add(selected_element)
- return list(selected)
-
- def get_selected_blocks(self):
- """
- Get a group of selected blocks.
-
- Returns:
- sub set of blocks in this flow graph
- """
- selected = set()
- for selected_element in self.get_selected_elements():
- if selected_element.is_block(): selected.add(selected_element)
- return list(selected)
-
- def get_selected_block(self):
- """
- Get the selected block when a block or port is selected.
-
- Returns:
- a block or None
- """
- return self.get_selected_blocks() and self.get_selected_blocks()[0] or None
-
- def get_selected_elements(self):
- """
- Get the group of selected elements.
-
- Returns:
- sub set of elements in this flow graph
- """
- return self._selected_elements
-
- def get_selected_element(self):
- """
- Get the selected element.
-
- Returns:
- a block, port, or connection or None
- """
- return self.get_selected_elements() and self.get_selected_elements()[0] or None
-
- def update_selected_elements(self):
- """
- Update the selected elements.
- The update behavior depends on the state of the mouse button.
- When the mouse button pressed the selection will change when
- the control mask is set or the new selection is not in the current group.
- When the mouse button is released the selection will change when
- the mouse has moved and the control mask is set or the current group is empty.
- Attempt to make a new connection if the old and ports are filled.
- If the control mask is set, merge with the current elements.
- """
- selected_elements = None
- if self.mouse_pressed:
- new_selections = self.what_is_selected(self.get_coordinate())
- #update the selections if the new selection is not in the current selections
- #allows us to move entire selected groups of elements
- if self.get_ctrl_mask() or not (
- new_selections and new_selections[0] in self.get_selected_elements()
- ): selected_elements = new_selections
- else: #called from a mouse release
- if not self.element_moved and (not self.get_selected_elements() or self.get_ctrl_mask()):
- selected_elements = self.what_is_selected(self.get_coordinate(), self.press_coor)
- #this selection and the last were ports, try to connect them
- if self._old_selected_port and self._new_selected_port and \
- self._old_selected_port is not self._new_selected_port:
- try:
- self.connect(self._old_selected_port, self._new_selected_port)
- Actions.ELEMENT_CREATE()
- except: Messages.send_fail_connection()
- self._old_selected_port = None
- self._new_selected_port = None
- return
- #update selected elements
- if selected_elements is None: return
- old_elements = set(self.get_selected_elements())
- self._selected_elements = list(set(selected_elements))
- new_elements = set(self.get_selected_elements())
- #if ctrl, set the selected elements to the union - intersection of old and new
- if self.get_ctrl_mask():
- self._selected_elements = list(
- set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements)
- )
- Actions.ELEMENT_SELECT()
-
- ##########################################################################
- ## Event Handlers
- ##########################################################################
- def handle_mouse_context_press(self, coordinate, event):
- """
- The context mouse button was pressed:
- If no elements were selected, perform re-selection at this coordinate.
- Then, show the context menu at the mouse click location.
- """
- selections = self.what_is_selected(coordinate)
- if not set(selections).intersection(self.get_selected_elements()):
- self.set_coordinate(coordinate)
- self.mouse_pressed = True
- self.update_selected_elements()
- self.mouse_pressed = False
- self._context_menu.popup(None, None, None, event.button, event.time)
-
- def handle_mouse_selector_press(self, double_click, coordinate):
- """
- The selector mouse button was pressed:
- Find the selected element. Attempt a new connection if possible.
- Open the block params window on a double click.
- Update the selection state of the flow graph.
- """
- self.press_coor = coordinate
- self.set_coordinate(coordinate)
- self.time = 0
- self.mouse_pressed = True
- if double_click: self.unselect()
- self.update_selected_elements()
- #double click detected, bring up params dialog if possible
- if double_click and self.get_selected_block():
- self.mouse_pressed = False
- Actions.BLOCK_PARAM_MODIFY()
-
- def handle_mouse_selector_release(self, coordinate):
- """
- The selector mouse button was released:
- Update the state, handle motion (dragging).
- And update the selected flowgraph elements.
- """
- self.set_coordinate(coordinate)
- self.time = 0
- self.mouse_pressed = False
- if self.element_moved:
- Actions.BLOCK_MOVE()
- self.element_moved = False
- self.update_selected_elements()
-
- def handle_mouse_motion(self, coordinate):
- """
- The mouse has moved, respond to mouse dragging.
- Move a selected element to the new coordinate.
- Auto-scroll the scroll bars at the boundaries.
- """
- #to perform a movement, the mouse must be pressed
- # (no longer checking pending events via gtk.events_pending() - always true in Windows)
- if not self.mouse_pressed: return
- #perform autoscrolling
- width, height = self.get_size()
- x, y = coordinate
- h_adj = self.get_scroll_pane().get_hadjustment()
- v_adj = self.get_scroll_pane().get_vadjustment()
- for pos, length, adj, adj_val, adj_len in (
- (x, width, h_adj, h_adj.get_value(), h_adj.page_size),
- (y, height, v_adj, v_adj.get_value(), v_adj.page_size),
- ):
- #scroll if we moved near the border
- if pos-adj_val > adj_len-SCROLL_PROXIMITY_SENSITIVITY and adj_val+SCROLL_DISTANCE < length-adj_len:
- adj.set_value(adj_val+SCROLL_DISTANCE)
- adj.emit('changed')
- elif pos-adj_val < SCROLL_PROXIMITY_SENSITIVITY:
- adj.set_value(adj_val-SCROLL_DISTANCE)
- adj.emit('changed')
- #remove the connection if selected in drag event
- if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection():
- Actions.ELEMENT_DELETE()
- #move the selected elements and record the new coordinate
- X, Y = self.get_coordinate()
- if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y)))
- self.set_coordinate((x, y))
- #queue draw for animation
- self.queue_draw()
+ """
+ FlowGraph is the data structure to store graphical signal blocks,
+ graphical inputs and outputs,
+ and the connections between inputs and outputs.
+ """
+
+ def __init__(self):
+ """
+ FlowGraph contructor.
+ Create a list for signal blocks and connections. Connect mouse handlers.
+ """
+ Element.__init__(self)
+ #when is the flow graph selected? (used by keyboard event handler)
+ self.is_selected = lambda: bool(self.get_selected_elements())
+ #important vars dealing with mouse event tracking
+ self.element_moved = False
+ self.mouse_pressed = False
+ self.unselect()
+ self.press_coor = (0, 0)
+ #selected ports
+ self._old_selected_port = None
+ self._new_selected_port = None
+ #context menu
+ self._context_menu = gtk.Menu()
+ for action in [
+ Actions.BLOCK_CUT,
+ Actions.BLOCK_COPY,
+ Actions.BLOCK_PASTE,
+ Actions.ELEMENT_DELETE,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
+ Actions.BLOCK_ENABLE,
+ Actions.BLOCK_DISABLE,
+ Actions.BLOCK_PARAM_MODIFY,
+ Actions.BLOCK_CREATE_HIER,
+ Actions.OPEN_HIER,
+ Actions.BUSSIFY_SOURCES,
+ Actions.BUSSIFY_SINKS,
+ ]: self._context_menu.append(action.create_menu_item())
+
+ ###########################################################################
+ # Access Drawing Area
+ ###########################################################################
+ def get_drawing_area(self): return self.drawing_area
+ def queue_draw(self): self.get_drawing_area().queue_draw()
+ def get_size(self): return self.get_drawing_area().get_size_request()
+ def set_size(self, *args): self.get_drawing_area().set_size_request(*args)
+ def get_scroll_pane(self): return self.drawing_area.get_parent()
+ def get_ctrl_mask(self): return self.drawing_area.ctrl_mask
+ def new_pixmap(self, *args): return self.get_drawing_area().new_pixmap(*args)
+
+ def add_new_block(self, key, coor=None):
+ """
+ Add a block of the given key to this flow graph.
+
+ Args:
+ key: the block key
+ coor: an optional coordinate or None for random
+ """
+ id = self._get_unique_id(key)
+ #calculate the position coordinate
+ h_adj = self.get_scroll_pane().get_hadjustment()
+ v_adj = self.get_scroll_pane().get_vadjustment()
+ if coor is None: coor = (
+ int(random.uniform(.25, .75)*h_adj.page_size + h_adj.get_value()),
+ int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()),
+ )
+ #get the new block
+ block = self.get_new_block(key)
+ block.set_coordinate(coor)
+ block.set_rotation(0)
+ block.get_param('id').set_value(id)
+ Actions.ELEMENT_CREATE()
+ return id
+
+ ###########################################################################
+ # Copy Paste
+ ###########################################################################
+ def copy_to_clipboard(self):
+ """
+ Copy the selected blocks and connections into the clipboard.
+
+ Returns:
+ the clipboard
+ """
+ #get selected blocks
+ blocks = self.get_selected_blocks()
+ if not blocks: return None
+ #calc x and y min
+ x_min, y_min = blocks[0].get_coordinate()
+ for block in blocks:
+ x, y = block.get_coordinate()
+ x_min = min(x, x_min)
+ y_min = min(y, y_min)
+ #get connections between selected blocks
+ connections = filter(
+ lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks,
+ self.get_connections(),
+ )
+ clipboard = (
+ (x_min, y_min),
+ [block.export_data() for block in blocks],
+ [connection.export_data() for connection in connections],
+ )
+ return clipboard
+
+ def paste_from_clipboard(self, clipboard):
+ """
+ Paste the blocks and connections from the clipboard.
+
+ Args:
+ clipboard: the nested data of blocks, connections
+ """
+ selected = set()
+ (x_min, y_min), blocks_n, connections_n = clipboard
+ old_id2block = dict()
+ #recalc the position
+ h_adj = self.get_scroll_pane().get_hadjustment()
+ v_adj = self.get_scroll_pane().get_vadjustment()
+ x_off = h_adj.get_value() - x_min + h_adj.page_size/4
+ y_off = v_adj.get_value() - y_min + v_adj.page_size/4
+ #create blocks
+ for block_n in blocks_n:
+ block_key = block_n.find('key')
+ if block_key == 'options': continue
+ block = self.get_new_block(block_key)
+ selected.add(block)
+ #set params
+ params_n = block_n.findall('param')
+ for param_n in params_n:
+ param_key = param_n.find('key')
+ param_value = param_n.find('value')
+ #setup id parameter
+ if param_key == 'id':
+ old_id2block[param_value] = block
+ #if the block id is not unique, get a new block id
+ if param_value in [bluck.get_id() for bluck in self.get_blocks()]:
+ param_value = self._get_unique_id(param_value)
+ #set value to key
+ block.get_param(param_key).set_value(param_value)
+ #move block to offset coordinate
+ block.move((x_off, y_off))
+ #update before creating connections
+ self.update()
+ #create connections
+ for connection_n in connections_n:
+ source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key'))
+ sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key'))
+ self.connect(source, sink)
+ #set all pasted elements selected
+ for block in selected: selected = selected.union(set(block.get_connections()))
+ self._selected_elements = list(selected)
+
+ ###########################################################################
+ # Modify Selected
+ ###########################################################################
+ def type_controller_modify_selected(self, direction):
+ """
+ Change the registered type controller for the selected signal blocks.
+
+ Args:
+ direction: +1 or -1
+
+ Returns:
+ true for change
+ """
+ return any([sb.type_controller_modify(direction) for sb in self.get_selected_blocks()])
+
+ def port_controller_modify_selected(self, direction):
+ """
+ Change port controller for the selected signal blocks.
+
+ Args:
+ direction: +1 or -1
+
+ Returns:
+ true for changed
+ """
+ return any([sb.port_controller_modify(direction) for sb in self.get_selected_blocks()])
+
+ def enable_selected(self, enable):
+ """
+ Enable/disable the selected blocks.
+
+ Args:
+ enable: true to enable
+
+ Returns:
+ true if changed
+ """
+ changed = False
+ for selected_block in self.get_selected_blocks():
+ if selected_block.get_enabled() != enable:
+ selected_block.set_enabled(enable)
+ changed = True
+ return changed
+
+ def move_selected(self, delta_coordinate):
+ """
+ Move the element and by the change in coordinates.
+
+ Args:
+ delta_coordinate: the change in coordinates
+ """
+ for selected_block in self.get_selected_blocks():
+ selected_block.move(delta_coordinate)
+ self.element_moved = True
+
+ def rotate_selected(self, rotation):
+ """
+ Rotate the selected blocks by multiples of 90 degrees.
+
+ Args:
+ rotation: the rotation in degrees
+
+ Returns:
+ true if changed, otherwise false.
+ """
+ if not self.get_selected_blocks(): return False
+ #initialize min and max coordinates
+ min_x, min_y = self.get_selected_block().get_coordinate()
+ max_x, max_y = self.get_selected_block().get_coordinate()
+ #rotate each selected block, and find min/max coordinate
+ for selected_block in self.get_selected_blocks():
+ selected_block.rotate(rotation)
+ #update the min/max coordinate
+ x, y = selected_block.get_coordinate()
+ min_x, min_y = min(min_x, x), min(min_y, y)
+ max_x, max_y = max(max_x, x), max(max_y, y)
+ #calculate center point of slected blocks
+ ctr_x, ctr_y = (max_x + min_x)/2, (max_y + min_y)/2
+ #rotate the blocks around the center point
+ for selected_block in self.get_selected_blocks():
+ x, y = selected_block.get_coordinate()
+ x, y = Utils.get_rotated_coordinate((x - ctr_x, y - ctr_y), rotation)
+ selected_block.set_coordinate((x + ctr_x, y + ctr_y))
+ return True
+
+ def remove_selected(self):
+ """
+ Remove selected elements
+
+ Returns:
+ true if changed.
+ """
+ changed = False
+ for selected_element in self.get_selected_elements():
+ self.remove_element(selected_element)
+ changed = True
+ return changed
+
+ def draw(self, gc, window):
+ """
+ Draw the background and grid if enabled.
+ Draw all of the elements in this flow graph onto the pixmap.
+ Draw the pixmap to the drawable window of this flow graph.
+ """
+ W,H = self.get_size()
+ #draw the background
+ gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR)
+ window.draw_rectangle(gc, True, 0, 0, W, H)
+ #draw multi select rectangle
+ if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()):
+ #coordinates
+ x1, y1 = self.press_coor
+ x2, y2 = self.get_coordinate()
+ #calculate top-left coordinate and width/height
+ x, y = int(min(x1, x2)), int(min(y1, y2))
+ w, h = int(abs(x1 - x2)), int(abs(y1 - y2))
+ #draw
+ gc.set_foreground(Colors.HIGHLIGHT_COLOR)
+ window.draw_rectangle(gc, True, x, y, w, h)
+ gc.set_foreground(Colors.BORDER_COLOR)
+ window.draw_rectangle(gc, False, x, y, w, h)
+ #draw blocks on top of connections
+ for element in self.get_connections() + self.get_blocks():
+ element.draw(gc, window)
+ #draw selected blocks on top of selected connections
+ for selected_element in self.get_selected_connections() + self.get_selected_blocks():
+ selected_element.draw(gc, window)
+
+ def update_selected(self):
+ """
+ Remove deleted elements from the selected elements list.
+ Update highlighting so only the selected are highlighted.
+ """
+ selected_elements = self.get_selected_elements()
+ elements = self.get_elements()
+ #remove deleted elements
+ for selected in selected_elements:
+ if selected in elements: continue
+ selected_elements.remove(selected)
+ if self._old_selected_port and self._old_selected_port.get_parent() not in elements:
+ self._old_selected_port = None
+ if self._new_selected_port and self._new_selected_port.get_parent() not in elements:
+ self._new_selected_port = None
+ #update highlighting
+ for element in elements:
+ element.set_highlighted(element in selected_elements)
+
+ def update(self):
+ """
+ Call the top level rewrite and validate.
+ Call the top level create labels and shapes.
+ """
+ self.rewrite()
+ self.validate()
+ self.create_labels()
+ self.create_shapes()
+
+ ##########################################################################
+ ## Get Selected
+ ##########################################################################
+ def unselect(self):
+ """
+ Set selected elements to an empty set.
+ """
+ self._selected_elements = []
+
+ def what_is_selected(self, coor, coor_m=None):
+ """
+ What is selected?
+ At the given coordinate, return the elements found to be selected.
+ If coor_m is unspecified, return a list of only the first element found to be selected:
+ Iterate though the elements backwards since top elements are at the end of the list.
+ If an element is selected, place it at the end of the list so that is is drawn last,
+ and hence on top. Update the selected port information.
+
+ Args:
+ coor: the coordinate of the mouse click
+ coor_m: the coordinate for multi select
+
+ Returns:
+ the selected blocks and connections or an empty list
+ """
+ selected_port = None
+ selected = set()
+ #check the elements
+ for element in reversed(self.get_elements()):
+ selected_element = element.what_is_selected(coor, coor_m)
+ if not selected_element: continue
+ #update the selected port information
+ if selected_element.is_port():
+ if not coor_m: selected_port = selected_element
+ selected_element = selected_element.get_parent()
+ selected.add(selected_element)
+ #place at the end of the list
+ self.get_elements().remove(element)
+ self.get_elements().append(element)
+ #single select mode, break
+ if not coor_m: break
+ #update selected ports
+ self._old_selected_port = self._new_selected_port
+ self._new_selected_port = selected_port
+ return list(selected)
+
+ def get_selected_connections(self):
+ """
+ Get a group of selected connections.
+
+ Returns:
+ sub set of connections in this flow graph
+ """
+ selected = set()
+ for selected_element in self.get_selected_elements():
+ if selected_element.is_connection(): selected.add(selected_element)
+ return list(selected)
+
+ def get_selected_blocks(self):
+ """
+ Get a group of selected blocks.
+
+ Returns:
+ sub set of blocks in this flow graph
+ """
+ selected = set()
+ for selected_element in self.get_selected_elements():
+ if selected_element.is_block(): selected.add(selected_element)
+ return list(selected)
+
+ def get_selected_block(self):
+ """
+ Get the selected block when a block or port is selected.
+
+ Returns:
+ a block or None
+ """
+ return self.get_selected_blocks() and self.get_selected_blocks()[0] or None
+
+ def get_selected_elements(self):
+ """
+ Get the group of selected elements.
+
+ Returns:
+ sub set of elements in this flow graph
+ """
+ return self._selected_elements
+
+ def get_selected_element(self):
+ """
+ Get the selected element.
+
+ Returns:
+ a block, port, or connection or None
+ """
+ return self.get_selected_elements() and self.get_selected_elements()[0] or None
+
+ def update_selected_elements(self):
+ """
+ Update the selected elements.
+ The update behavior depends on the state of the mouse button.
+ When the mouse button pressed the selection will change when
+ the control mask is set or the new selection is not in the current group.
+ When the mouse button is released the selection will change when
+ the mouse has moved and the control mask is set or the current group is empty.
+ Attempt to make a new connection if the old and ports are filled.
+ If the control mask is set, merge with the current elements.
+ """
+ selected_elements = None
+ if self.mouse_pressed:
+ new_selections = self.what_is_selected(self.get_coordinate())
+ #update the selections if the new selection is not in the current selections
+ #allows us to move entire selected groups of elements
+ if self.get_ctrl_mask() or not (
+ new_selections and new_selections[0] in self.get_selected_elements()
+ ): selected_elements = new_selections
+ else: #called from a mouse release
+ if not self.element_moved and (not self.get_selected_elements() or self.get_ctrl_mask()):
+ selected_elements = self.what_is_selected(self.get_coordinate(), self.press_coor)
+ #this selection and the last were ports, try to connect them
+ if self._old_selected_port and self._new_selected_port and \
+ self._old_selected_port is not self._new_selected_port:
+ try:
+ self.connect(self._old_selected_port, self._new_selected_port)
+ Actions.ELEMENT_CREATE()
+ except: Messages.send_fail_connection()
+ self._old_selected_port = None
+ self._new_selected_port = None
+ return
+ #update selected elements
+ if selected_elements is None: return
+ old_elements = set(self.get_selected_elements())
+ self._selected_elements = list(set(selected_elements))
+ new_elements = set(self.get_selected_elements())
+ #if ctrl, set the selected elements to the union - intersection of old and new
+ if self.get_ctrl_mask():
+ self._selected_elements = list(
+ set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements)
+ )
+ Actions.ELEMENT_SELECT()
+
+ ##########################################################################
+ ## Event Handlers
+ ##########################################################################
+ def handle_mouse_context_press(self, coordinate, event):
+ """
+ The context mouse button was pressed:
+ If no elements were selected, perform re-selection at this coordinate.
+ Then, show the context menu at the mouse click location.
+ """
+ selections = self.what_is_selected(coordinate)
+ if not set(selections).intersection(self.get_selected_elements()):
+ self.set_coordinate(coordinate)
+ self.mouse_pressed = True
+ self.update_selected_elements()
+ self.mouse_pressed = False
+ self._context_menu.popup(None, None, None, event.button, event.time)
+
+ def handle_mouse_selector_press(self, double_click, coordinate):
+ """
+ The selector mouse button was pressed:
+ Find the selected element. Attempt a new connection if possible.
+ Open the block params window on a double click.
+ Update the selection state of the flow graph.
+ """
+ self.press_coor = coordinate
+ self.set_coordinate(coordinate)
+ self.time = 0
+ self.mouse_pressed = True
+ if double_click: self.unselect()
+ self.update_selected_elements()
+ #double click detected, bring up params dialog if possible
+ if double_click and self.get_selected_block():
+ self.mouse_pressed = False
+ Actions.BLOCK_PARAM_MODIFY()
+
+ def handle_mouse_selector_release(self, coordinate):
+ """
+ The selector mouse button was released:
+ Update the state, handle motion (dragging).
+ And update the selected flowgraph elements.
+ """
+ self.set_coordinate(coordinate)
+ self.time = 0
+ self.mouse_pressed = False
+ if self.element_moved:
+ Actions.BLOCK_MOVE()
+ self.element_moved = False
+ self.update_selected_elements()
+
+ def handle_mouse_motion(self, coordinate):
+ """
+ The mouse has moved, respond to mouse dragging.
+ Move a selected element to the new coordinate.
+ Auto-scroll the scroll bars at the boundaries.
+ """
+ #to perform a movement, the mouse must be pressed
+ # (no longer checking pending events via gtk.events_pending() - always true in Windows)
+ if not self.mouse_pressed: return
+ #perform autoscrolling
+ width, height = self.get_size()
+ x, y = coordinate
+ h_adj = self.get_scroll_pane().get_hadjustment()
+ v_adj = self.get_scroll_pane().get_vadjustment()
+ for pos, length, adj, adj_val, adj_len in (
+ (x, width, h_adj, h_adj.get_value(), h_adj.page_size),
+ (y, height, v_adj, v_adj.get_value(), v_adj.page_size),
+ ):
+ #scroll if we moved near the border
+ if pos-adj_val > adj_len-SCROLL_PROXIMITY_SENSITIVITY and adj_val+SCROLL_DISTANCE < length-adj_len:
+ adj.set_value(adj_val+SCROLL_DISTANCE)
+ adj.emit('changed')
+ elif pos-adj_val < SCROLL_PROXIMITY_SENSITIVITY:
+ adj.set_value(adj_val-SCROLL_DISTANCE)
+ adj.emit('changed')
+ #remove the connection if selected in drag event
+ if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection():
+ Actions.ELEMENT_DELETE()
+ #move the selected elements and record the new coordinate
+ X, Y = self.get_coordinate()
+ if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y)))
+ self.set_coordinate((x, y))
+ #queue draw for animation
+ self.queue_draw()
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index c2d661c668..677f202e1f 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from Constants import \
- NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH
+ NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH
import Actions
import pygtk
pygtk.require('2.0')
@@ -63,293 +63,293 @@ PAGE_TITLE_MARKUP_TMPL = """\
############################################################
class MainWindow(gtk.Window):
- """The topmost window with menus, the tool bar, and other major windows."""
+ """The topmost window with menus, the tool bar, and other major windows."""
- def __init__(self, platform):
- """
- MainWindow contructor
- Setup the menu, toolbar, flowgraph editor notebook, block selection window...
- """
- self._platform = platform
- #setup window
- gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
- vbox = gtk.VBox()
- self.hpaned = gtk.HPaned()
- self.add(vbox)
- #create the menu bar and toolbar
- self.add_accel_group(Actions.get_accel_group())
- vbox.pack_start(Bars.MenuBar(), False)
- vbox.pack_start(Bars.Toolbar(), False)
- vbox.pack_start(self.hpaned)
- #create the notebook
- self.notebook = gtk.Notebook()
- self.page_to_be_closed = None
- self.current_page = None
- self.notebook.set_show_border(False)
- self.notebook.set_scrollable(True) #scroll arrows for page tabs
- self.notebook.connect('switch-page', self._handle_page_change)
- #setup containers
- self.flow_graph_vpaned = gtk.VPaned()
- #flow_graph_box.pack_start(self.scrolled_window)
- self.flow_graph_vpaned.pack1(self.notebook)
- self.hpaned.pack1(self.flow_graph_vpaned)
- self.btwin = BlockTreeWindow(platform, self.get_flow_graph);
- self.hpaned.pack2(self.btwin, False) #dont allow resize
- #create the reports window
- self.text_display = TextDisplay()
- #house the reports in a scrolled window
- self.reports_scrolled_window = gtk.ScrolledWindow()
- self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.reports_scrolled_window.add_with_viewport(self.text_display)
- self.reports_scrolled_window.set_size_request(-1, DEFAULT_REPORTS_WINDOW_WIDTH)
- self.flow_graph_vpaned.pack2(self.reports_scrolled_window, False) #dont allow resize
- #load preferences and show the main window
- Preferences.load(platform)
- self.resize(*Preferences.main_window_size())
- self.flow_graph_vpaned.set_position(Preferences.reports_window_position())
- self.hpaned.set_position(Preferences.blocks_window_position())
- self.show_all()
+ def __init__(self, platform):
+ """
+ MainWindow contructor
+ Setup the menu, toolbar, flowgraph editor notebook, block selection window...
+ """
+ self._platform = platform
+ #setup window
+ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+ vbox = gtk.VBox()
+ self.hpaned = gtk.HPaned()
+ self.add(vbox)
+ #create the menu bar and toolbar
+ self.add_accel_group(Actions.get_accel_group())
+ vbox.pack_start(Bars.MenuBar(), False)
+ vbox.pack_start(Bars.Toolbar(), False)
+ vbox.pack_start(self.hpaned)
+ #create the notebook
+ self.notebook = gtk.Notebook()
+ self.page_to_be_closed = None
+ self.current_page = None
+ self.notebook.set_show_border(False)
+ self.notebook.set_scrollable(True) #scroll arrows for page tabs
+ self.notebook.connect('switch-page', self._handle_page_change)
+ #setup containers
+ self.flow_graph_vpaned = gtk.VPaned()
+ #flow_graph_box.pack_start(self.scrolled_window)
+ self.flow_graph_vpaned.pack1(self.notebook)
+ self.hpaned.pack1(self.flow_graph_vpaned)
+ self.btwin = BlockTreeWindow(platform, self.get_flow_graph);
+ self.hpaned.pack2(self.btwin, False) #dont allow resize
+ #create the reports window
+ self.text_display = TextDisplay()
+ #house the reports in a scrolled window
+ self.reports_scrolled_window = gtk.ScrolledWindow()
+ self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.reports_scrolled_window.add_with_viewport(self.text_display)
+ self.reports_scrolled_window.set_size_request(-1, DEFAULT_REPORTS_WINDOW_WIDTH)
+ self.flow_graph_vpaned.pack2(self.reports_scrolled_window, False) #dont allow resize
+ #load preferences and show the main window
+ Preferences.load(platform)
+ self.resize(*Preferences.main_window_size())
+ self.flow_graph_vpaned.set_position(Preferences.reports_window_position())
+ self.hpaned.set_position(Preferences.blocks_window_position())
+ self.show_all()
- ############################################################
- # Event Handlers
- ############################################################
+ ############################################################
+ # Event Handlers
+ ############################################################
- def _quit(self, window, event):
- """
- Handle the delete event from the main window.
- Generated by pressing X to close, alt+f4, or right click+close.
- This method in turns calls the state handler to quit.
-
- Returns:
- true
- """
- Actions.APPLICATION_QUIT()
- return True
+ def _quit(self, window, event):
+ """
+ Handle the delete event from the main window.
+ Generated by pressing X to close, alt+f4, or right click+close.
+ This method in turns calls the state handler to quit.
+
+ Returns:
+ true
+ """
+ Actions.APPLICATION_QUIT()
+ return True
- def _handle_page_change(self, notebook, page, page_num):
- """
- Handle a page change. When the user clicks on a new tab,
- reload the flow graph to update the vars window and
- call handle states (select nothing) to update the buttons.
-
- Args:
- notebook: the notebook
- page: new page
- page_num: new page number
- """
- self.current_page = self.notebook.get_nth_page(page_num)
- Messages.send_page_switch(self.current_page.get_file_path())
- Actions.PAGE_CHANGE()
+ def _handle_page_change(self, notebook, page, page_num):
+ """
+ Handle a page change. When the user clicks on a new tab,
+ reload the flow graph to update the vars window and
+ call handle states (select nothing) to update the buttons.
+
+ Args:
+ notebook: the notebook
+ page: new page
+ page_num: new page number
+ """
+ self.current_page = self.notebook.get_nth_page(page_num)
+ Messages.send_page_switch(self.current_page.get_file_path())
+ Actions.PAGE_CHANGE()
- ############################################################
- # Report Window
- ############################################################
+ ############################################################
+ # Report Window
+ ############################################################
- def add_report_line(self, line):
- """
- Place line at the end of the text buffer, then scroll its window all the way down.
-
- Args:
- line: the new text
- """
- self.text_display.insert(line)
- vadj = self.reports_scrolled_window.get_vadjustment()
- vadj.set_value(vadj.upper)
- vadj.emit('changed')
+ def add_report_line(self, line):
+ """
+ Place line at the end of the text buffer, then scroll its window all the way down.
+
+ Args:
+ line: the new text
+ """
+ self.text_display.insert(line)
+ vadj = self.reports_scrolled_window.get_vadjustment()
+ vadj.set_value(vadj.upper)
+ vadj.emit('changed')
- ############################################################
- # Pages: create and close
- ############################################################
+ ############################################################
+ # Pages: create and close
+ ############################################################
- def new_page(self, file_path='', show=False):
- """
- Create a new notebook page.
- Set the tab to be selected.
-
- Args:
- file_path: optional file to load into the flow graph
- show: true if the page should be shown after loading
- """
- #if the file is already open, show the open page and return
- if file_path and file_path in self._get_files(): #already open
- page = self.notebook.get_nth_page(self._get_files().index(file_path))
- self._set_page(page)
- return
- try: #try to load from file
- if file_path: Messages.send_start_load(file_path)
- flow_graph = self._platform.get_new_flow_graph()
- flow_graph.grc_file_path = file_path;
- #print flow_graph
- page = NotebookPage(
- self,
- flow_graph=flow_graph,
- file_path=file_path,
- )
- if file_path: Messages.send_end_load()
- except Exception, e: #return on failure
- Messages.send_fail_load(e)
- if isinstance(e, KeyError) and str(e) == "'options'":
- # This error is unrecoverable, so crash gracefully
- exit(-1)
- return
- #add this page to the notebook
- self.notebook.append_page(page, page.get_tab())
- try: self.notebook.set_tab_reorderable(page, True)
- except: pass #gtk too old
- self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START)
- #only show if blank or manual
- if not file_path or show: self._set_page(page)
+ def new_page(self, file_path='', show=False):
+ """
+ Create a new notebook page.
+ Set the tab to be selected.
+
+ Args:
+ file_path: optional file to load into the flow graph
+ show: true if the page should be shown after loading
+ """
+ #if the file is already open, show the open page and return
+ if file_path and file_path in self._get_files(): #already open
+ page = self.notebook.get_nth_page(self._get_files().index(file_path))
+ self._set_page(page)
+ return
+ try: #try to load from file
+ if file_path: Messages.send_start_load(file_path)
+ flow_graph = self._platform.get_new_flow_graph()
+ flow_graph.grc_file_path = file_path;
+ #print flow_graph
+ page = NotebookPage(
+ self,
+ flow_graph=flow_graph,
+ file_path=file_path,
+ )
+ if file_path: Messages.send_end_load()
+ except Exception, e: #return on failure
+ Messages.send_fail_load(e)
+ if isinstance(e, KeyError) and str(e) == "'options'":
+ # This error is unrecoverable, so crash gracefully
+ exit(-1)
+ return
+ #add this page to the notebook
+ self.notebook.append_page(page, page.get_tab())
+ try: self.notebook.set_tab_reorderable(page, True)
+ except: pass #gtk too old
+ self.notebook.set_tab_label_packing(page, False, False, gtk.PACK_START)
+ #only show if blank or manual
+ if not file_path or show: self._set_page(page)
- def close_pages(self):
- """
- Close all the pages in this notebook.
-
- Returns:
- true if all closed
- """
- open_files = filter(lambda file: file, self._get_files()) #filter blank files
- open_file = self.get_page().get_file_path()
- #close each page
- for page in self._get_pages():
- self.page_to_be_closed = page
- self.close_page(False)
- if self.notebook.get_n_pages(): return False
- #save state before closing
- Preferences.files_open(open_files)
- Preferences.file_open(open_file)
- Preferences.main_window_size(self.get_size())
- Preferences.reports_window_position(self.flow_graph_vpaned.get_position())
- Preferences.blocks_window_position(self.hpaned.get_position())
- Preferences.save()
- return True
+ def close_pages(self):
+ """
+ Close all the pages in this notebook.
+
+ Returns:
+ true if all closed
+ """
+ open_files = filter(lambda file: file, self._get_files()) #filter blank files
+ open_file = self.get_page().get_file_path()
+ #close each page
+ for page in self._get_pages():
+ self.page_to_be_closed = page
+ self.close_page(False)
+ if self.notebook.get_n_pages(): return False
+ #save state before closing
+ Preferences.files_open(open_files)
+ Preferences.file_open(open_file)
+ Preferences.main_window_size(self.get_size())
+ Preferences.reports_window_position(self.flow_graph_vpaned.get_position())
+ Preferences.blocks_window_position(self.hpaned.get_position())
+ Preferences.save()
+ return True
- def close_page(self, ensure=True):
- """
- Close the current page.
- If the notebook becomes empty, and ensure is true,
- call new page upon exit to ensure that at least one page exists.
-
- Args:
- ensure: boolean
- """
- if not self.page_to_be_closed: self.page_to_be_closed = self.get_page()
- #show the page if it has an executing flow graph or is unsaved
- if self.page_to_be_closed.get_proc() or not self.page_to_be_closed.get_saved():
- self._set_page(self.page_to_be_closed)
- #unsaved? ask the user
- if not self.page_to_be_closed.get_saved() and self._save_changes():
- Actions.FLOW_GRAPH_SAVE() #try to save
- if not self.page_to_be_closed.get_saved(): #still unsaved?
- self.page_to_be_closed = None #set the page to be closed back to None
- return
- #stop the flow graph if executing
- if self.page_to_be_closed.get_proc(): Actions.FLOW_GRAPH_KILL()
- #remove the page
- self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
- if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one
- self.page_to_be_closed = None #set the page to be closed back to None
+ def close_page(self, ensure=True):
+ """
+ Close the current page.
+ If the notebook becomes empty, and ensure is true,
+ call new page upon exit to ensure that at least one page exists.
+
+ Args:
+ ensure: boolean
+ """
+ if not self.page_to_be_closed: self.page_to_be_closed = self.get_page()
+ #show the page if it has an executing flow graph or is unsaved
+ if self.page_to_be_closed.get_proc() or not self.page_to_be_closed.get_saved():
+ self._set_page(self.page_to_be_closed)
+ #unsaved? ask the user
+ if not self.page_to_be_closed.get_saved() and self._save_changes():
+ Actions.FLOW_GRAPH_SAVE() #try to save
+ if not self.page_to_be_closed.get_saved(): #still unsaved?
+ self.page_to_be_closed = None #set the page to be closed back to None
+ return
+ #stop the flow graph if executing
+ if self.page_to_be_closed.get_proc(): Actions.FLOW_GRAPH_KILL()
+ #remove the page
+ self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
+ if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one
+ self.page_to_be_closed = None #set the page to be closed back to None
- ############################################################
- # Misc
- ############################################################
+ ############################################################
+ # Misc
+ ############################################################
- def update(self):
- """
- Set the title of the main window.
- Set the titles on the page tabs.
- Show/hide the reports window.
-
- Args:
- title: the window title
- """
- gtk.Window.set_title(self, Utils.parse_template(MAIN_WINDOW_TITLE_TMPL,
- basename=os.path.basename(self.get_page().get_file_path()),
- dirname=os.path.dirname(self.get_page().get_file_path()),
- new_flowgraph_title=NEW_FLOGRAPH_TITLE,
- read_only=self.get_page().get_read_only(),
- saved=self.get_page().get_saved(),
- platform_name=self._platform.get_name(),
- )
- )
- #set tab titles
- for page in self._get_pages(): page.set_markup(
- Utils.parse_template(PAGE_TITLE_MARKUP_TMPL,
- #get filename and strip out file extension
- title=os.path.splitext(os.path.basename(page.get_file_path()))[0],
- read_only=page.get_read_only(), saved=page.get_saved(),
- new_flowgraph_title=NEW_FLOGRAPH_TITLE,
- )
- )
- #show/hide notebook tabs
- self.notebook.set_show_tabs(len(self._get_pages()) > 1)
+ def update(self):
+ """
+ Set the title of the main window.
+ Set the titles on the page tabs.
+ Show/hide the reports window.
+
+ Args:
+ title: the window title
+ """
+ gtk.Window.set_title(self, Utils.parse_template(MAIN_WINDOW_TITLE_TMPL,
+ basename=os.path.basename(self.get_page().get_file_path()),
+ dirname=os.path.dirname(self.get_page().get_file_path()),
+ new_flowgraph_title=NEW_FLOGRAPH_TITLE,
+ read_only=self.get_page().get_read_only(),
+ saved=self.get_page().get_saved(),
+ platform_name=self._platform.get_name(),
+ )
+ )
+ #set tab titles
+ for page in self._get_pages(): page.set_markup(
+ Utils.parse_template(PAGE_TITLE_MARKUP_TMPL,
+ #get filename and strip out file extension
+ title=os.path.splitext(os.path.basename(page.get_file_path()))[0],
+ read_only=page.get_read_only(), saved=page.get_saved(),
+ new_flowgraph_title=NEW_FLOGRAPH_TITLE,
+ )
+ )
+ #show/hide notebook tabs
+ self.notebook.set_show_tabs(len(self._get_pages()) > 1)
- def get_page(self):
- """
- Get the selected page.
-
- Returns:
- the selected page
- """
- return self.current_page
+ def get_page(self):
+ """
+ Get the selected page.
+
+ Returns:
+ the selected page
+ """
+ return self.current_page
- def get_flow_graph(self):
- """
- Get the selected flow graph.
-
- Returns:
- the selected flow graph
- """
- return self.get_page().get_flow_graph()
+ def get_flow_graph(self):
+ """
+ Get the selected flow graph.
+
+ Returns:
+ the selected flow graph
+ """
+ return self.get_page().get_flow_graph()
- def get_focus_flag(self):
- """
- Get the focus flag from the current page.
-
- Returns:
- the focus flag
- """
- return self.get_page().get_drawing_area().get_focus_flag()
+ def get_focus_flag(self):
+ """
+ Get the focus flag from the current page.
+
+ Returns:
+ the focus flag
+ """
+ return self.get_page().get_drawing_area().get_focus_flag()
- ############################################################
- # Helpers
- ############################################################
+ ############################################################
+ # Helpers
+ ############################################################
- def _set_page(self, page):
- """
- Set the current page.
-
- Args:
- page: the page widget
- """
- self.current_page = page
- self.notebook.set_current_page(self.notebook.page_num(self.current_page))
+ def _set_page(self, page):
+ """
+ Set the current page.
+
+ Args:
+ page: the page widget
+ """
+ self.current_page = page
+ self.notebook.set_current_page(self.notebook.page_num(self.current_page))
- def _save_changes(self):
- """
- Save changes to flow graph?
-
- Returns:
- true if yes
- """
- return MessageDialogHelper(
- gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!',
- 'Would you like to save changes before closing?'
- ) == gtk.RESPONSE_YES
+ def _save_changes(self):
+ """
+ Save changes to flow graph?
+
+ Returns:
+ true if yes
+ """
+ return MessageDialogHelper(
+ gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved Changes!',
+ 'Would you like to save changes before closing?'
+ ) == gtk.RESPONSE_YES
- def _get_files(self):
- """
- Get the file names for all the pages, in order.
-
- Returns:
- list of file paths
- """
- return map(lambda page: page.get_file_path(), self._get_pages())
+ def _get_files(self):
+ """
+ Get the file names for all the pages, in order.
+
+ Returns:
+ list of file paths
+ """
+ return map(lambda page: page.get_file_path(), self._get_pages())
- def _get_pages(self):
- """
- Get a list of all pages in the notebook.
-
- Returns:
- list of pages
- """
- return [self.notebook.get_nth_page(page_num) for page_num in range(self.notebook.get_n_pages())]
+ def _get_pages(self):
+ """
+ Get a list of all pages in the notebook.
+
+ Returns:
+ list of pages
+ """
+ return [self.notebook.get_nth_page(page_num) for page_num in range(self.notebook.get_n_pages())]
diff --git a/grc/gui/Messages.py b/grc/gui/Messages.py
index a9f0e36b85..d903e40a45 100644
--- a/grc/gui/Messages.py
+++ b/grc/gui/Messages.py
@@ -24,22 +24,22 @@ import sys
MESSENGERS_LIST = list()
def register_messenger(messenger):
- """
- Append the given messenger to the list of messengers.
-
- Args:
- messenger: a method thats takes a string
- """
- MESSENGERS_LIST.append(messenger)
+ """
+ Append the given messenger to the list of messengers.
+
+ Args:
+ messenger: a method thats takes a string
+ """
+ MESSENGERS_LIST.append(messenger)
def send(message):
- """
- Give the message to each of the messengers.
-
- Args:
- message: a message string
- """
- for messenger in MESSENGERS_LIST: messenger(message)
+ """
+ Give the message to each of the messengers.
+
+ Args:
+ message: a message string
+ """
+ for messenger in MESSENGERS_LIST: messenger(message)
#register stdout by default
register_messenger(sys.stdout.write)
@@ -48,61 +48,61 @@ register_messenger(sys.stdout.write)
# Special functions for specific program functionalities
###########################################################################
def send_init(platform):
- send("""<<< Welcome to %s %s >>>\n"""%(platform.get_name(), platform.get_version()))
+ send("""<<< Welcome to %s %s >>>\n"""%(platform.get_name(), platform.get_version()))
def send_page_switch(file_path):
- send('\nShowing: "%s"\n'%file_path)
+ send('\nShowing: "%s"\n'%file_path)
-################# functions for loading flow graphs ########################################
+################# functions for loading flow graphs ########################################
def send_start_load(file_path):
- send('\nLoading: "%s"'%file_path + '\n')
+ send('\nLoading: "%s"'%file_path + '\n')
def send_error_load(error):
- send('>>> Error: %s\n'%error)
- traceback.print_exc()
+ send('>>> Error: %s\n'%error)
+ traceback.print_exc()
def send_end_load():
- send('>>> Done\n')
+ send('>>> Done\n')
def send_fail_load(error):
- send('Error: %s\n'%error)
- send('>>> Failure\n')
- traceback.print_exc()
+ send('Error: %s\n'%error)
+ send('>>> Failure\n')
+ traceback.print_exc()
-################# functions for generating flow graphs ########################################
+################# functions for generating flow graphs ########################################
def send_start_gen(file_path):
- send('\nGenerating: "%s"'%file_path + '\n')
+ send('\nGenerating: "%s"'%file_path + '\n')
def send_fail_gen(error):
- send('Generate Error: %s\n'%error)
- send('>>> Failure\n')
- traceback.print_exc()
+ send('Generate Error: %s\n'%error)
+ send('>>> Failure\n')
+ traceback.print_exc()
-################# functions for executing flow graphs ########################################
+################# functions for executing flow graphs ########################################
def send_start_exec(file_path):
- send('\nExecuting: "%s"'%file_path + '\n')
+ send('\nExecuting: "%s"'%file_path + '\n')
def send_verbose_exec(verbose):
- send(verbose)
+ send(verbose)
def send_end_exec():
- send('\n>>> Done\n')
+ send('\n>>> Done\n')
-################# functions for saving flow graphs ########################################
+################# functions for saving flow graphs ########################################
def send_fail_save(file_path):
- send('>>> Error: Cannot save: %s\n'%file_path)
+ send('>>> Error: Cannot save: %s\n'%file_path)
-################# functions for connections ########################################
+################# functions for connections ########################################
def send_fail_connection():
- send('>>> Error: Cannot create connection.\n')
+ send('>>> Error: Cannot create connection.\n')
-################# functions for preferences ########################################
+################# functions for preferences ########################################
def send_fail_load_preferences(prefs_file_path):
- send('>>> Error: Cannot load preferences file: "%s"\n'%prefs_file_path)
+ send('>>> Error: Cannot load preferences file: "%s"\n'%prefs_file_path)
def send_fail_save_preferences(prefs_file_path):
- send('>>> Error: Cannot save preferences file: "%s"\n'%prefs_file_path)
+ send('>>> Error: Cannot save preferences file: "%s"\n'%prefs_file_path)
-################# functions for warning ########################################
+################# functions for warning ########################################
def send_warning(warning):
- send('>>> Warning: %s\n'%warning)
+ send('>>> Warning: %s\n'%warning)
diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py
index 095c045a66..10c5dde00d 100644
--- a/grc/gui/NotebookPage.py
+++ b/grc/gui/NotebookPage.py
@@ -31,185 +31,185 @@ import os
############################################################
class NotebookPage(gtk.HBox):
- """A page in the notebook."""
-
- def __init__(self, main_window, flow_graph, file_path=''):
- """
- Page constructor.
-
- Args:
- main_window: main window
- file_path: path to a flow graph file
- """
- self._flow_graph = flow_graph
- self.set_proc(None)
- #import the file
- self.main_window = main_window
- self.set_file_path(file_path)
- initial_state = flow_graph.get_parent().parse_flow_graph(file_path)
- self.state_cache = StateCache(initial_state)
- self.set_saved(True)
- #import the data to the flow graph
- self.get_flow_graph().import_data(initial_state)
- #initialize page gui
- gtk.HBox.__init__(self, False, 0)
- self.show()
- #tab box to hold label and close button
- self.tab = gtk.HBox(False, 0)
- #setup tab label
- self.label = gtk.Label()
- self.tab.pack_start(self.label, False)
- #setup button image
- image = gtk.Image()
- image.set_from_stock('gtk-close', gtk.ICON_SIZE_MENU)
- #setup image box
- image_box = gtk.HBox(False, 0)
- image_box.pack_start(image, True, False, 0)
- #setup the button
- button = gtk.Button()
- button.connect("clicked", self._handle_button)
- button.set_relief(gtk.RELIEF_NONE)
- button.add(image_box)
- #button size
- w, h = gtk.icon_size_lookup_for_settings(button.get_settings(), gtk.ICON_SIZE_MENU)
- button.set_size_request(w+6, h+6)
- self.tab.pack_start(button, False)
- self.tab.show_all()
- #setup scroll window and drawing area
- self.scrolled_window = gtk.ScrolledWindow()
- self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
- self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.drawing_area = DrawingArea(self.get_flow_graph())
- self.scrolled_window.add_with_viewport(self.get_drawing_area())
- self.pack_start(self.scrolled_window)
- #inject drawing area into flow graph
- self.get_flow_graph().drawing_area = self.get_drawing_area()
- self.show_all()
-
- def get_drawing_area(self): return self.drawing_area
-
- def get_generator(self):
- """
- Get the generator object for this flow graph.
-
- Returns:
- generator
- """
- return self.get_flow_graph().get_parent().get_generator()(
- self.get_flow_graph(),
- self.get_file_path(),
- )
-
- def _handle_button(self, button):
- """
- The button was clicked.
- Make the current page selected, then close.
-
- Args:
- the: button
- """
- self.main_window.page_to_be_closed = self
- Actions.FLOW_GRAPH_CLOSE()
-
- def set_markup(self, markup):
- """
- Set the markup in this label.
-
- Args:
- markup: the new markup text
- """
- self.label.set_markup(markup)
-
- def get_tab(self):
- """
- Get the gtk widget for this page's tab.
-
- Returns:
- gtk widget
- """
- return self.tab
-
- def get_proc(self):
- """
- Get the subprocess for the flow graph.
-
- Returns:
- the subprocess object
- """
- return self.process
-
- def set_proc(self, process):
- """
- Set the subprocess object.
-
- Args:
- process: the new subprocess
- """
- self.process = process
-
- def get_flow_graph(self):
- """
- Get the flow graph.
-
- Returns:
- the flow graph
- """
- return self._flow_graph
-
- def get_read_only(self):
- """
- Get the read-only state of the file.
- Always false for empty path.
-
- Returns:
- true for read-only
- """
- if not self.get_file_path(): return False
- return os.path.exists(self.get_file_path()) and \
- not os.access(self.get_file_path(), os.W_OK)
-
- def get_file_path(self):
- """
- Get the file path for the flow graph.
-
- Returns:
- the file path or ''
- """
- return self.file_path
-
- def set_file_path(self, file_path=''):
- """
- Set the file path, '' for no file path.
-
- Args:
- file_path: file path string
- """
- if file_path: self.file_path = os.path.abspath(file_path)
- else: self.file_path = ''
-
- def get_saved(self):
- """
- Get the saved status for the flow graph.
-
- Returns:
- true if saved
- """
- return self.saved
-
- def set_saved(self, saved=True):
- """
- Set the saved status.
-
- Args:
- saved: boolean status
- """
- self.saved = saved
-
- def get_state_cache(self):
- """
- Get the state cache for the flow graph.
-
- Returns:
- the state cache
- """
- return self.state_cache
+ """A page in the notebook."""
+
+ def __init__(self, main_window, flow_graph, file_path=''):
+ """
+ Page constructor.
+
+ Args:
+ main_window: main window
+ file_path: path to a flow graph file
+ """
+ self._flow_graph = flow_graph
+ self.set_proc(None)
+ #import the file
+ self.main_window = main_window
+ self.set_file_path(file_path)
+ initial_state = flow_graph.get_parent().parse_flow_graph(file_path)
+ self.state_cache = StateCache(initial_state)
+ self.set_saved(True)
+ #import the data to the flow graph
+ self.get_flow_graph().import_data(initial_state)
+ #initialize page gui
+ gtk.HBox.__init__(self, False, 0)
+ self.show()
+ #tab box to hold label and close button
+ self.tab = gtk.HBox(False, 0)
+ #setup tab label
+ self.label = gtk.Label()
+ self.tab.pack_start(self.label, False)
+ #setup button image
+ image = gtk.Image()
+ image.set_from_stock('gtk-close', gtk.ICON_SIZE_MENU)
+ #setup image box
+ image_box = gtk.HBox(False, 0)
+ image_box.pack_start(image, True, False, 0)
+ #setup the button
+ button = gtk.Button()
+ button.connect("clicked", self._handle_button)
+ button.set_relief(gtk.RELIEF_NONE)
+ button.add(image_box)
+ #button size
+ w, h = gtk.icon_size_lookup_for_settings(button.get_settings(), gtk.ICON_SIZE_MENU)
+ button.set_size_request(w+6, h+6)
+ self.tab.pack_start(button, False)
+ self.tab.show_all()
+ #setup scroll window and drawing area
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
+ self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.drawing_area = DrawingArea(self.get_flow_graph())
+ self.scrolled_window.add_with_viewport(self.get_drawing_area())
+ self.pack_start(self.scrolled_window)
+ #inject drawing area into flow graph
+ self.get_flow_graph().drawing_area = self.get_drawing_area()
+ self.show_all()
+
+ def get_drawing_area(self): return self.drawing_area
+
+ def get_generator(self):
+ """
+ Get the generator object for this flow graph.
+
+ Returns:
+ generator
+ """
+ return self.get_flow_graph().get_parent().get_generator()(
+ self.get_flow_graph(),
+ self.get_file_path(),
+ )
+
+ def _handle_button(self, button):
+ """
+ The button was clicked.
+ Make the current page selected, then close.
+
+ Args:
+ the: button
+ """
+ self.main_window.page_to_be_closed = self
+ Actions.FLOW_GRAPH_CLOSE()
+
+ def set_markup(self, markup):
+ """
+ Set the markup in this label.
+
+ Args:
+ markup: the new markup text
+ """
+ self.label.set_markup(markup)
+
+ def get_tab(self):
+ """
+ Get the gtk widget for this page's tab.
+
+ Returns:
+ gtk widget
+ """
+ return self.tab
+
+ def get_proc(self):
+ """
+ Get the subprocess for the flow graph.
+
+ Returns:
+ the subprocess object
+ """
+ return self.process
+
+ def set_proc(self, process):
+ """
+ Set the subprocess object.
+
+ Args:
+ process: the new subprocess
+ """
+ self.process = process
+
+ def get_flow_graph(self):
+ """
+ Get the flow graph.
+
+ Returns:
+ the flow graph
+ """
+ return self._flow_graph
+
+ def get_read_only(self):
+ """
+ Get the read-only state of the file.
+ Always false for empty path.
+
+ Returns:
+ true for read-only
+ """
+ if not self.get_file_path(): return False
+ return os.path.exists(self.get_file_path()) and \
+ not os.access(self.get_file_path(), os.W_OK)
+
+ def get_file_path(self):
+ """
+ Get the file path for the flow graph.
+
+ Returns:
+ the file path or ''
+ """
+ return self.file_path
+
+ def set_file_path(self, file_path=''):
+ """
+ Set the file path, '' for no file path.
+
+ Args:
+ file_path: file path string
+ """
+ if file_path: self.file_path = os.path.abspath(file_path)
+ else: self.file_path = ''
+
+ def get_saved(self):
+ """
+ Get the saved status for the flow graph.
+
+ Returns:
+ true if saved
+ """
+ return self.saved
+
+ def set_saved(self, saved=True):
+ """
+ Set the saved status.
+
+ Args:
+ saved: boolean status
+ """
+ self.saved = saved
+
+ def get_state_cache(self):
+ """
+ Get the state cache for the flow graph.
+
+ Returns:
+ the state cache
+ """
+ return self.state_cache
diff --git a/grc/gui/Param.py b/grc/gui/Param.py
index da76b6b82c..f0e5a2fcb2 100644
--- a/grc/gui/Param.py
+++ b/grc/gui/Param.py
@@ -25,110 +25,110 @@ import gtk
import Colors
class InputParam(gtk.HBox):
- """The base class for an input parameter inside the input parameters dialog."""
-
- def __init__(self, param, callback=None):
- gtk.HBox.__init__(self)
- self.param = param
- self._callback = callback
- self.label = gtk.Label() #no label, markup is added by set_markup
- self.label.set_size_request(150, -1)
- self.pack_start(self.label, False)
- self.set_markup = lambda m: self.label.set_markup(m)
- self.tp = None
- #connect events
- self.connect('show', self._update_gui)
- def set_color(self, color): pass
- def set_tooltip_text(self, text): pass
-
- def _update_gui(self, *args):
- """
- Set the markup, color, tooltip, show/hide.
- """
- #set the markup
- has_cb = \
- hasattr(self.param.get_parent(), 'get_callbacks') and \
- filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks)
- self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb))
- #set the color
- self.set_color(self.param.get_color())
- #set the tooltip
- self.set_tooltip_text(
- Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(),
- )
- #show/hide
- if self.param.get_hide() == 'all': self.hide_all()
- else: self.show_all()
-
- def _handle_changed(self, *args):
- """
- Handle a gui change by setting the new param value,
- calling the callback (if applicable), and updating.
- """
- #set the new value
- self.param.set_value(self.get_text())
- #call the callback
- if self._callback: self._callback(*args)
- else: self.param.validate()
- #gui update
- self._update_gui()
+ """The base class for an input parameter inside the input parameters dialog."""
+
+ def __init__(self, param, callback=None):
+ gtk.HBox.__init__(self)
+ self.param = param
+ self._callback = callback
+ self.label = gtk.Label() #no label, markup is added by set_markup
+ self.label.set_size_request(150, -1)
+ self.pack_start(self.label, False)
+ self.set_markup = lambda m: self.label.set_markup(m)
+ self.tp = None
+ #connect events
+ self.connect('show', self._update_gui)
+ def set_color(self, color): pass
+ def set_tooltip_text(self, text): pass
+
+ def _update_gui(self, *args):
+ """
+ Set the markup, color, tooltip, show/hide.
+ """
+ #set the markup
+ has_cb = \
+ hasattr(self.param.get_parent(), 'get_callbacks') and \
+ filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks)
+ self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb))
+ #set the color
+ self.set_color(self.param.get_color())
+ #set the tooltip
+ self.set_tooltip_text(
+ Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(),
+ )
+ #show/hide
+ if self.param.get_hide() == 'all': self.hide_all()
+ else: self.show_all()
+
+ def _handle_changed(self, *args):
+ """
+ Handle a gui change by setting the new param value,
+ calling the callback (if applicable), and updating.
+ """
+ #set the new value
+ self.param.set_value(self.get_text())
+ #call the callback
+ if self._callback: self._callback(*args)
+ else: self.param.validate()
+ #gui update
+ self._update_gui()
class EntryParam(InputParam):
- """Provide an entry box for strings and numbers."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.Entry()
- self._input.set_text(self.param.get_value())
- self._input.connect('changed', self._handle_changed)
- self.pack_start(self._input, True)
- def get_text(self): return self._input.get_text()
- def set_color(self, color):
- self._input.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
- self._input.modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
- def set_tooltip_text(self, text): self._input.set_tooltip_text(text)
+ """Provide an entry box for strings and numbers."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self._input = gtk.Entry()
+ self._input.set_text(self.param.get_value())
+ self._input.connect('changed', self._handle_changed)
+ self.pack_start(self._input, True)
+ def get_text(self): return self._input.get_text()
+ def set_color(self, color):
+ self._input.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+ self._input.modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
+ def set_tooltip_text(self, text): self._input.set_tooltip_text(text)
class EnumParam(InputParam):
- """Provide an entry box for Enum types with a drop down menu."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- self._input.connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
- def set_tooltip_text(self, text): self._input.set_tooltip_text(text)
+ """Provide an entry box for Enum types with a drop down menu."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self._input = gtk.combo_box_new_text()
+ for option in self.param.get_options(): self._input.append_text(option.get_name())
+ self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+ self._input.connect('changed', self._handle_changed)
+ self.pack_start(self._input, False)
+ def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
+ def set_tooltip_text(self, text): self._input.set_tooltip_text(text)
class EnumEntryParam(InputParam):
- """Provide an entry box and drop down menu for Raw Enum types."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_entry_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- except:
- self._input.set_active(-1)
- self._input.get_child().set_text(self.param.get_value())
- self._input.connect('changed', self._handle_changed)
- self._input.get_child().connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self):
- if self._input.get_active() == -1: return self._input.get_child().get_text()
- return self.param.get_option_keys()[self._input.get_active()]
- def set_tooltip_text(self, text):
- if self._input.get_active() == -1: #custom entry
- self._input.get_child().set_tooltip_text(text)
- else: self._input.set_tooltip_text(text)
- def set_color(self, color):
- if self._input.get_active() == -1: #custom entry, use color
- self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
- self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
- else: #from enum, make pale background
- self._input.get_child().modify_base(gtk.STATE_NORMAL, Colors.ENTRYENUM_CUSTOM_COLOR)
- self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
+ """Provide an entry box and drop down menu for Raw Enum types."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self._input = gtk.combo_box_entry_new_text()
+ for option in self.param.get_options(): self._input.append_text(option.get_name())
+ try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+ except:
+ self._input.set_active(-1)
+ self._input.get_child().set_text(self.param.get_value())
+ self._input.connect('changed', self._handle_changed)
+ self._input.get_child().connect('changed', self._handle_changed)
+ self.pack_start(self._input, False)
+ def get_text(self):
+ if self._input.get_active() == -1: return self._input.get_child().get_text()
+ return self.param.get_option_keys()[self._input.get_active()]
+ def set_tooltip_text(self, text):
+ if self._input.get_active() == -1: #custom entry
+ self._input.get_child().set_tooltip_text(text)
+ else: self._input.set_tooltip_text(text)
+ def set_color(self, color):
+ if self._input.get_active() == -1: #custom entry, use color
+ self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+ self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
+ else: #from enum, make pale background
+ self._input.get_child().modify_base(gtk.STATE_NORMAL, Colors.ENTRYENUM_CUSTOM_COLOR)
+ self._input.get_child().modify_text(gtk.STATE_NORMAL, Colors.PARAM_ENTRY_TEXT_COLOR)
PARAM_MARKUP_TMPL="""\
#set $foreground = $param.is_valid() and 'black' or 'red'
@@ -142,13 +142,13 @@ PARAM_LABEL_MARKUP_TMPL="""\
TIP_MARKUP_TMPL="""\
########################################
#def truncate(string)
- #set $max_len = 100
- #set $string = str($string)
- #if len($string) > $max_len
+ #set $max_len = 100
+ #set $string = str($string)
+ #if len($string) > $max_len
$('%s...%s'%($string[:$max_len/2], $string[-$max_len/2:]))#slurp
- #else
+ #else
$string#slurp
- #end if
+ #end if
#end def
########################################
Key: $param.get_key()
@@ -159,35 +159,35 @@ Value: $truncate($param.get_evaluated())
Error: $(param.get_error_messages()[0])
#else
Error:
- #for $error_msg in $param.get_error_messages()
+ #for $error_msg in $param.get_error_messages()
* $error_msg
- #end for
+ #end for
#end if"""
class Param(Element):
- """The graphical parameter."""
-
- def __init__(self): Element.__init__(self)
-
- def get_input(self, *args, **kwargs):
- """
- Get the graphical gtk class to represent this parameter.
- An enum requires and combo parameter.
- A non-enum with options gets a combined entry/combo parameter.
- All others get a standard entry parameter.
-
- Returns:
- gtk input class
- """
- if self.is_enum(): return EnumParam(self, *args, **kwargs)
- if self.get_options(): return EnumEntryParam(self, *args, **kwargs)
- return EntryParam(self, *args, **kwargs)
-
- def get_markup(self):
- """
- Get the markup for this param.
-
- Returns:
- a pango markup string
- """
- return Utils.parse_template(PARAM_MARKUP_TMPL, param=self)
+ """The graphical parameter."""
+
+ def __init__(self): Element.__init__(self)
+
+ def get_input(self, *args, **kwargs):
+ """
+ Get the graphical gtk class to represent this parameter.
+ An enum requires and combo parameter.
+ A non-enum with options gets a combined entry/combo parameter.
+ All others get a standard entry parameter.
+
+ Returns:
+ gtk input class
+ """
+ if self.is_enum(): return EnumParam(self, *args, **kwargs)
+ if self.get_options(): return EnumEntryParam(self, *args, **kwargs)
+ return EntryParam(self, *args, **kwargs)
+
+ def get_markup(self):
+ """
+ Get the markup for this param.
+
+ Returns:
+ a pango markup string
+ """
+ return Utils.parse_template(PARAM_MARKUP_TMPL, param=self)
diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py
index 8bbfaca232..6a8175b9fa 100644
--- a/grc/gui/Platform.py
+++ b/grc/gui/Platform.py
@@ -20,4 +20,4 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from Element import Element
class Platform(Element):
- def __init__(self): Element.__init__(self)
+ def __init__(self): Element.__init__(self)
diff --git a/grc/gui/Port.py b/grc/gui/Port.py
index 7b4c27dd5f..fe1dc5070a 100644
--- a/grc/gui/Port.py
+++ b/grc/gui/Port.py
@@ -19,9 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from Element import Element
from Constants import \
- PORT_SEPARATION, CONNECTOR_EXTENSION_MINIMAL, \
- CONNECTOR_EXTENSION_INCREMENT, \
- PORT_LABEL_PADDING, PORT_MIN_WIDTH
+ PORT_SEPARATION, CONNECTOR_EXTENSION_MINIMAL, \
+ CONNECTOR_EXTENSION_INCREMENT, \
+ PORT_LABEL_PADDING, PORT_MIN_WIDTH
import Utils
import Colors
import pygtk
@@ -32,179 +32,192 @@ PORT_MARKUP_TMPL="""\
<span foreground="black" font_desc="Sans 7.5">$encode($port.get_name())</span>"""
class Port(Element):
- """The graphical port."""
-
- def __init__(self):
- """
- Port contructor.
- Create list of connector coordinates.
- """
- Element.__init__(self)
- self.connector_coordinates = dict()
-
- def create_shapes(self):
- """Create new areas and labels for the port."""
- Element.create_shapes(self)
- #get current rotation
- rotation = self.get_rotation()
- #get all sibling ports
- if self.is_source(): ports = self.get_parent().get_sources()
- elif self.is_sink(): ports = self.get_parent().get_sinks()
- #get the max width
- self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH])
- #get a numeric index for this port relative to its sibling ports
- index = ports.index(self)
- length = len(ports)
- #reverse the order of ports for these rotations
- if rotation in (180, 270): index = length-index-1
- offset = (self.get_parent().H - length*self.H - (length-1)*PORT_SEPARATION)/2
- #create areas and connector coordinates
- if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180):
- x = -1*self.W
- y = (PORT_SEPARATION+self.H)*index+offset
- self.add_area((x, y), (self.W, self.H))
- self._connector_coordinate = (x-1, y+self.H/2)
- elif (self.is_source() and rotation == 0) or (self.is_sink() and rotation == 180):
- x = self.get_parent().W
- y = (PORT_SEPARATION+self.H)*index+offset
- self.add_area((x, y), (self.W, self.H))
- self._connector_coordinate = (x+1+self.W, y+self.H/2)
- elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270):
- y = -1*self.W
- x = (PORT_SEPARATION+self.H)*index+offset
- self.add_area((x, y), (self.H, self.W))
- self._connector_coordinate = (x+self.H/2, y-1)
- elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270):
- y = self.get_parent().W
- x = (PORT_SEPARATION+self.H)*index+offset
- self.add_area((x, y), (self.H, self.W))
- self._connector_coordinate = (x+self.H/2, y+1+self.W)
- #the connector length
- self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index
-
- def create_labels(self):
- """Create the labels for the socket."""
- Element.create_labels(self)
- self._bg_color = Colors.get_color(self.get_color())
- #create the layout
- layout = gtk.DrawingArea().create_pango_layout('')
- layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self))
- self.w, self.h = layout.get_pixel_size()
- self.W, self.H = 2*PORT_LABEL_PADDING+self.w, 2*PORT_LABEL_PADDING+self.h
- #create the pixmap
- pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h)
- gc = pixmap.new_gc()
- gc.set_foreground(self._bg_color)
- pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h)
- pixmap.draw_layout(gc, 0, 0, layout)
- #create vertical and horizontal pixmaps
- self.horizontal_label = pixmap
- if self.is_vertical():
- self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w)
- Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
-
- def draw(self, gc, window):
- """
- Draw the socket with a label.
-
- Args:
- gc: the graphics context
- window: the gtk window to draw on
- """
- Element.draw(
- self, gc, window, bg_color=self._bg_color,
- border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
- )
- X,Y = self.get_coordinate()
- (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels
- if self.is_horizontal():
- window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1)
- elif self.is_vertical():
- window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1)
-
- def get_connector_coordinate(self):
- """
- Get the coordinate where connections may attach to.
-
- Returns:
- the connector coordinate (x, y) tuple
- """
- x,y = self._connector_coordinate
- X,Y = self.get_coordinate()
- return (x+X, y+Y)
-
- def get_connector_direction(self):
- """
- Get the direction that the socket points: 0,90,180,270.
- This is the rotation degree if the socket is an output or
- the rotation degree + 180 if the socket is an input.
-
- Returns:
- the direction in degrees
- """
- if self.is_source(): return self.get_rotation()
- elif self.is_sink(): return (self.get_rotation() + 180)%360
-
- def get_connector_length(self):
- """
- Get the length of the connector.
- The connector length increases as the port index changes.
-
- Returns:
- the length in pixels
- """
- return self._connector_length
-
- def get_rotation(self):
- """
- Get the parent's rotation rather than self.
-
- Returns:
- the parent's rotation
- """
- return self.get_parent().get_rotation()
-
- def move(self, delta_coor):
- """
- Move the parent rather than self.
-
- Args:
- delta_corr: the (delta_x, delta_y) tuple
- """
- self.get_parent().move(delta_coor)
-
- def rotate(self, direction):
- """
- Rotate the parent rather than self.
-
- Args:
- direction: degrees to rotate
- """
- self.get_parent().rotate(direction)
-
- def get_coordinate(self):
- """
- Get the parent's coordinate rather than self.
-
- Returns:
- the parents coordinate
- """
- return self.get_parent().get_coordinate()
-
- def set_highlighted(self, highlight):
- """
- Set the parent highlight rather than self.
-
- Args:
- highlight: true to enable highlighting
- """
- self.get_parent().set_highlighted(highlight)
-
- def is_highlighted(self):
- """
- Get the parent's is highlight rather than self.
-
- Returns:
- the parent's highlighting status
- """
- return self.get_parent().is_highlighted()
+ """The graphical port."""
+
+ def __init__(self):
+ """
+ Port contructor.
+ Create list of connector coordinates.
+ """
+ Element.__init__(self)
+ self.connector_coordinates = dict()
+
+ def create_shapes(self):
+ """Create new areas and labels for the port."""
+ Element.create_shapes(self)
+ #get current rotation
+ rotation = self.get_rotation()
+ #get all sibling ports
+ if self.is_source(): ports = self.get_parent().get_sources_gui()
+ elif self.is_sink(): ports = self.get_parent().get_sinks_gui()
+ #get the max width
+ self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH])
+ #get a numeric index for this port relative to its sibling ports
+ try:
+ index = ports.index(self)
+ except:
+ if hasattr(self, '_connector_length'):
+ del self._connector_length;
+ return
+ length = len(ports)
+ #reverse the order of ports for these rotations
+ if rotation in (180, 270): index = length-index-1
+ offset = (self.get_parent().H - length*self.H - (length-1)*PORT_SEPARATION)/2
+ #create areas and connector coordinates
+ if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180):
+ x = -1*self.W
+ y = (PORT_SEPARATION+self.H)*index+offset
+ self.add_area((x, y), (self.W, self.H))
+ self._connector_coordinate = (x-1, y+self.H/2)
+ elif (self.is_source() and rotation == 0) or (self.is_sink() and rotation == 180):
+ x = self.get_parent().W
+ y = (PORT_SEPARATION+self.H)*index+offset
+ self.add_area((x, y), (self.W, self.H))
+ self._connector_coordinate = (x+1+self.W, y+self.H/2)
+ elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270):
+ y = -1*self.W
+ x = (PORT_SEPARATION+self.H)*index+offset
+ self.add_area((x, y), (self.H, self.W))
+ self._connector_coordinate = (x+self.H/2, y-1)
+ elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270):
+ y = self.get_parent().W
+ x = (PORT_SEPARATION+self.H)*index+offset
+ self.add_area((x, y), (self.H, self.W))
+ self._connector_coordinate = (x+self.H/2, y+1+self.W)
+ #the connector length
+ self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index
+ def modify_height(self, start_height):
+ type_dict = {'bus':(lambda a: a * 3)};
+
+ if self.get_type() in type_dict:
+ return type_dict[self.get_type()](start_height);
+ else:
+ return start_height;
+
+ def create_labels(self):
+ """Create the labels for the socket."""
+ Element.create_labels(self)
+ self._bg_color = Colors.get_color(self.get_color())
+ #create the layout
+ layout = gtk.DrawingArea().create_pango_layout('')
+ layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self))
+ self.w, self.h = layout.get_pixel_size()
+ self.W, self.H = 2*PORT_LABEL_PADDING+self.w, 2*PORT_LABEL_PADDING+self.h
+ self.H = self.modify_height(self.H);
+ #create the pixmap
+ pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h)
+ gc = pixmap.new_gc()
+ gc.set_foreground(self._bg_color)
+ pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h)
+ pixmap.draw_layout(gc, 0, 0, layout)
+ #create vertical and horizontal pixmaps
+ self.horizontal_label = pixmap
+ if self.is_vertical():
+ self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w)
+ Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label)
+
+ def draw(self, gc, window):
+ """
+ Draw the socket with a label.
+
+ Args:
+ gc: the graphics context
+ window: the gtk window to draw on
+ """
+ Element.draw(
+ self, gc, window, bg_color=self._bg_color,
+ border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
+ )
+ X,Y = self.get_coordinate()
+ (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels
+ if self.is_horizontal():
+ window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1)
+ elif self.is_vertical():
+ window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1)
+
+ def get_connector_coordinate(self):
+ """
+ Get the coordinate where connections may attach to.
+
+ Returns:
+ the connector coordinate (x, y) tuple
+ """
+ x,y = self._connector_coordinate
+ X,Y = self.get_coordinate()
+ return (x+X, y+Y)
+
+ def get_connector_direction(self):
+ """
+ Get the direction that the socket points: 0,90,180,270.
+ This is the rotation degree if the socket is an output or
+ the rotation degree + 180 if the socket is an input.
+
+ Returns:
+ the direction in degrees
+ """
+ if self.is_source(): return self.get_rotation()
+ elif self.is_sink(): return (self.get_rotation() + 180)%360
+
+ def get_connector_length(self):
+ """
+ Get the length of the connector.
+ The connector length increases as the port index changes.
+
+ Returns:
+ the length in pixels
+ """
+ return self._connector_length
+
+ def get_rotation(self):
+ """
+ Get the parent's rotation rather than self.
+
+ Returns:
+ the parent's rotation
+ """
+ return self.get_parent().get_rotation()
+
+ def move(self, delta_coor):
+ """
+ Move the parent rather than self.
+
+ Args:
+ delta_corr: the (delta_x, delta_y) tuple
+ """
+ self.get_parent().move(delta_coor)
+
+ def rotate(self, direction):
+ """
+ Rotate the parent rather than self.
+
+ Args:
+ direction: degrees to rotate
+ """
+ self.get_parent().rotate(direction)
+
+ def get_coordinate(self):
+ """
+ Get the parent's coordinate rather than self.
+
+ Returns:
+ the parents coordinate
+ """
+ return self.get_parent().get_coordinate()
+
+ def set_highlighted(self, highlight):
+ """
+ Set the parent highlight rather than self.
+
+ Args:
+ highlight: true to enable highlighting
+ """
+ self.get_parent().set_highlighted(highlight)
+
+ def is_highlighted(self):
+ """
+ Get the parent's is highlight rather than self.
+
+ Returns:
+ the parent's highlighting status
+ """
+ return self.get_parent().is_highlighted()
diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py
index 1d89920dd5..ce545cab6a 100644
--- a/grc/gui/Preferences.py
+++ b/grc/gui/Preferences.py
@@ -27,60 +27,60 @@ def file_extension(): return '.'+_platform.get_key()
def _prefs_file(): return os.path.join(os.path.expanduser('~'), file_extension())
def load(platform):
- global _platform
- _platform = platform
- #create sections
- _config_parser.add_section('main')
- _config_parser.add_section('files_open')
- try: _config_parser.read(_prefs_file())
- except: pass
+ global _platform
+ _platform = platform
+ #create sections
+ _config_parser.add_section('main')
+ _config_parser.add_section('files_open')
+ try: _config_parser.read(_prefs_file())
+ except: pass
def save():
- try: _config_parser.write(open(_prefs_file(), 'w'))
- except: pass
+ try: _config_parser.write(open(_prefs_file(), 'w'))
+ except: pass
###########################################################################
# Special methods for specific program functionalities
###########################################################################
def main_window_size(size=None):
- if size is not None:
- _config_parser.set('main', 'main_window_width', size[0])
- _config_parser.set('main', 'main_window_height', size[1])
- else:
- try: return (
- _config_parser.getint('main', 'main_window_width'),
- _config_parser.getint('main', 'main_window_height'),
- )
- except: return (1, 1)
+ if size is not None:
+ _config_parser.set('main', 'main_window_width', size[0])
+ _config_parser.set('main', 'main_window_height', size[1])
+ else:
+ try: return (
+ _config_parser.getint('main', 'main_window_width'),
+ _config_parser.getint('main', 'main_window_height'),
+ )
+ except: return (1, 1)
def file_open(file=None):
- if file is not None: _config_parser.set('main', 'file_open', file)
- else:
- try: return _config_parser.get('main', 'file_open')
- except: return ''
+ if file is not None: _config_parser.set('main', 'file_open', file)
+ else:
+ try: return _config_parser.get('main', 'file_open')
+ except: return ''
def files_open(files=None):
- if files is not None:
- _config_parser.remove_section('files_open') #clear section
- _config_parser.add_section('files_open')
- for i, file in enumerate(files):
- _config_parser.set('files_open', 'file_open_%d'%i, file)
- else:
- files = list()
- i = 0
- while True:
- try: files.append(_config_parser.get('files_open', 'file_open_%d'%i))
- except: return files
- i = i + 1
+ if files is not None:
+ _config_parser.remove_section('files_open') #clear section
+ _config_parser.add_section('files_open')
+ for i, file in enumerate(files):
+ _config_parser.set('files_open', 'file_open_%d'%i, file)
+ else:
+ files = list()
+ i = 0
+ while True:
+ try: files.append(_config_parser.get('files_open', 'file_open_%d'%i))
+ except: return files
+ i = i + 1
def reports_window_position(pos=None):
- if pos is not None: _config_parser.set('main', 'reports_window_position', pos)
- else:
- try: return _config_parser.getint('main', 'reports_window_position') or 1 #greater than 0
- except: return -1
+ if pos is not None: _config_parser.set('main', 'reports_window_position', pos)
+ else:
+ try: return _config_parser.getint('main', 'reports_window_position') or 1 #greater than 0
+ except: return -1
def blocks_window_position(pos=None):
- if pos is not None: _config_parser.set('main', 'blocks_window_position', pos)
- else:
- try: return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0
- except: return -1
+ if pos is not None: _config_parser.set('main', 'blocks_window_position', pos)
+ else:
+ try: return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0
+ except: return -1
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index 5264857fab..5c09f7cac1 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -25,158 +25,158 @@ from Dialogs import TextDisplay
from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
def get_title_label(title):
- """
- Get a title label for the params window.
- The title will be bold, underlined, and left justified.
-
- Args:
- title: the text of the title
-
- Returns:
- a gtk object
- """
- label = gtk.Label()
- label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title)
- hbox = gtk.HBox()
- hbox.pack_start(label, False, False, padding=11)
- return hbox
+ """
+ Get a title label for the params window.
+ The title will be bold, underlined, and left justified.
+
+ Args:
+ title: the text of the title
+
+ Returns:
+ a gtk object
+ """
+ label = gtk.Label()
+ label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title)
+ hbox = gtk.HBox()
+ hbox.pack_start(label, False, False, padding=11)
+ return hbox
class PropsDialog(gtk.Dialog):
- """
- A dialog to set block parameters, view errors, and view documentation.
- """
+ """
+ A dialog to set block parameters, view errors, and view documentation.
+ """
- def __init__(self, block):
- """
- Properties dialog contructor.
-
- Args:
- block: a block instance
- """
- self._hash = 0
- LABEL_SPACING = 7
- gtk.Dialog.__init__(self,
- title='Properties: %s'%block.get_name(),
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT),
- )
- self._block = block
- self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
- vbox = gtk.VBox()
- #Create the scrolled window to hold all the parameters
- scrolled_window = gtk.ScrolledWindow()
- scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- scrolled_window.add_with_viewport(vbox)
- self.vbox.pack_start(scrolled_window, True)
- #Params box for block parameters
- self._params_box = gtk.VBox()
- self._params_box.pack_start(get_title_label('Parameters'), False)
- self._input_object_params = list()
- #Error Messages for the block
- self._error_box = gtk.VBox()
- self._error_messages_text_display = TextDisplay()
- self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
- self._error_box.pack_start(get_title_label('Error Messages'), False)
- self._error_box.pack_start(self._error_messages_text_display, False)
- #Docs for the block
- self._docs_box = err_box = gtk.VBox()
- self._docs_text_display = TextDisplay()
- self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
- self._docs_box.pack_start(get_title_label('Documentation'), False)
- self._docs_box.pack_start(self._docs_text_display, False)
- #Add the boxes
- vbox.pack_start(self._params_box, False)
- vbox.pack_start(self._error_box, False)
- vbox.pack_start(self._docs_box, False)
- #connect events
- self.connect('key-press-event', self._handle_key_press)
- self.connect('show', self._update_gui)
- #show all (performs initial gui update)
- self.show_all()
+ def __init__(self, block):
+ """
+ Properties dialog contructor.
+
+ Args:
+ block: a block instance
+ """
+ self._hash = 0
+ LABEL_SPACING = 7
+ gtk.Dialog.__init__(self,
+ title='Properties: %s'%block.get_name(),
+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT),
+ )
+ self._block = block
+ self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ vbox = gtk.VBox()
+ #Create the scrolled window to hold all the parameters
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(vbox)
+ self.vbox.pack_start(scrolled_window, True)
+ #Params box for block parameters
+ self._params_box = gtk.VBox()
+ self._params_box.pack_start(get_title_label('Parameters'), False)
+ self._input_object_params = list()
+ #Error Messages for the block
+ self._error_box = gtk.VBox()
+ self._error_messages_text_display = TextDisplay()
+ self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
+ self._error_box.pack_start(get_title_label('Error Messages'), False)
+ self._error_box.pack_start(self._error_messages_text_display, False)
+ #Docs for the block
+ self._docs_box = err_box = gtk.VBox()
+ self._docs_text_display = TextDisplay()
+ self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
+ self._docs_box.pack_start(get_title_label('Documentation'), False)
+ self._docs_box.pack_start(self._docs_text_display, False)
+ #Add the boxes
+ vbox.pack_start(self._params_box, False)
+ vbox.pack_start(self._error_box, False)
+ vbox.pack_start(self._docs_box, False)
+ #connect events
+ self.connect('key-press-event', self._handle_key_press)
+ self.connect('show', self._update_gui)
+ #show all (performs initial gui update)
+ self.show_all()
- def _params_changed(self):
- """
- Have the params in this dialog changed?
- Ex: Added, removed, type change, hide change...
- To the props dialog, the hide setting of 'none' and 'part' are identical.
- Therfore, the props dialog only cares if the hide setting is/not 'all'.
- Make a hash that uniquely represents the params' state.
-
- Returns:
- true if changed
- """
- old_hash = self._hash
- #create a tuple of things from each param that affects the params box
- self._hash = hash(tuple([(
- hash(param), param.get_type(), param.get_hide() == 'all',
- ) for param in self._block.get_params()]))
- return self._hash != old_hash
+ def _params_changed(self):
+ """
+ Have the params in this dialog changed?
+ Ex: Added, removed, type change, hide change...
+ To the props dialog, the hide setting of 'none' and 'part' are identical.
+ Therfore, the props dialog only cares if the hide setting is/not 'all'.
+ Make a hash that uniquely represents the params' state.
+
+ Returns:
+ true if changed
+ """
+ old_hash = self._hash
+ #create a tuple of things from each param that affects the params box
+ self._hash = hash(tuple([(
+ hash(param), param.get_type(), param.get_hide() == 'all',
+ ) for param in self._block.get_params()]))
+ return self._hash != old_hash
- def _handle_changed(self, *args):
- """
- A change occured within a param:
- Rewrite/validate the block and update the gui.
- """
- #update for the block
- self._block.rewrite()
- self._block.validate()
- self._update_gui()
+ def _handle_changed(self, *args):
+ """
+ A change occured within a param:
+ Rewrite/validate the block and update the gui.
+ """
+ #update for the block
+ self._block.rewrite()
+ self._block.validate()
+ self._update_gui()
- def _update_gui(self, *args):
- """
- Repopulate the parameters box (if changed).
- Update all the input parameters.
- Update the error messages box.
- Hide the box if there are no errors.
- Update the documentation block.
- Hide the box if there are no docs.
- """
- #update the params box
- if self._params_changed():
- #hide params box before changing
- self._params_box.hide_all()
- #empty the params box
- for io_param in list(self._input_object_params):
- self._params_box.remove(io_param)
- self._input_object_params.remove(io_param)
- io_param.destroy()
- #repopulate the params box
- for param in self._block.get_params():
- if param.get_hide() == 'all': continue
- io_param = param.get_input(self._handle_changed)
- self._input_object_params.append(io_param)
- self._params_box.pack_start(io_param, False)
- #show params box with new params
- self._params_box.show_all()
- #update the errors box
- if self._block.is_valid(): self._error_box.hide()
- else: self._error_box.show()
- messages = '\n\n'.join(self._block.get_error_messages())
- self._error_messages_text_display.set_text(messages)
- #update the docs box
- if self._block.get_doc(): self._docs_box.show()
- else: self._docs_box.hide()
- self._docs_text_display.set_text(self._block.get_doc())
+ def _update_gui(self, *args):
+ """
+ Repopulate the parameters box (if changed).
+ Update all the input parameters.
+ Update the error messages box.
+ Hide the box if there are no errors.
+ Update the documentation block.
+ Hide the box if there are no docs.
+ """
+ #update the params box
+ if self._params_changed():
+ #hide params box before changing
+ self._params_box.hide_all()
+ #empty the params box
+ for io_param in list(self._input_object_params):
+ self._params_box.remove(io_param)
+ self._input_object_params.remove(io_param)
+ io_param.destroy()
+ #repopulate the params box
+ for param in self._block.get_params():
+ if param.get_hide() == 'all': continue
+ io_param = param.get_input(self._handle_changed)
+ self._input_object_params.append(io_param)
+ self._params_box.pack_start(io_param, False)
+ #show params box with new params
+ self._params_box.show_all()
+ #update the errors box
+ if self._block.is_valid(): self._error_box.hide()
+ else: self._error_box.show()
+ messages = '\n\n'.join(self._block.get_error_messages())
+ self._error_messages_text_display.set_text(messages)
+ #update the docs box
+ if self._block.get_doc(): self._docs_box.show()
+ else: self._docs_box.hide()
+ self._docs_text_display.set_text(self._block.get_doc())
- def _handle_key_press(self, widget, event):
- """
- Handle key presses from the keyboard.
- Call the ok response when enter is pressed.
-
- Returns:
- false to forward the keypress
- """
- if event.keyval == gtk.keysyms.Return:
- self.response(gtk.RESPONSE_ACCEPT)
- return True #handled here
- return False #forward the keypress
+ def _handle_key_press(self, widget, event):
+ """
+ Handle key presses from the keyboard.
+ Call the ok response when enter is pressed.
+
+ Returns:
+ false to forward the keypress
+ """
+ if event.keyval == gtk.keysyms.Return:
+ self.response(gtk.RESPONSE_ACCEPT)
+ return True #handled here
+ return False #forward the keypress
- def run(self):
- """
- Run the dialog and get its response.
-
- Returns:
- true if the response was accept
- """
- response = gtk.Dialog.run(self)
- self.destroy()
- return response == gtk.RESPONSE_ACCEPT
+ def run(self):
+ """
+ Run the dialog and get its response.
+
+ Returns:
+ true if the response was accept
+ """
+ response = gtk.Dialog.run(self)
+ self.destroy()
+ return response == gtk.RESPONSE_ACCEPT
diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py
index 50d85bf960..558f507716 100644
--- a/grc/gui/StateCache.py
+++ b/grc/gui/StateCache.py
@@ -21,82 +21,82 @@ import Actions
from Constants import STATE_CACHE_SIZE
class StateCache(object):
- """
- The state cache is an interface to a list to record data/states and to revert to previous states.
- States are recorded into the list in a circular fassion by using an index for the current state,
- and counters for the range where states are stored.
- """
+ """
+ The state cache is an interface to a list to record data/states and to revert to previous states.
+ States are recorded into the list in a circular fassion by using an index for the current state,
+ and counters for the range where states are stored.
+ """
- def __init__(self, initial_state):
- """
- StateCache constructor.
-
- Args:
- initial_state: the intial state (nested data)
- """
- self.states = [None] * STATE_CACHE_SIZE #fill states
- self.current_state_index = 0
- self.num_prev_states = 0
- self.num_next_states = 0
- self.states[0] = initial_state
- self.update_actions()
+ def __init__(self, initial_state):
+ """
+ StateCache constructor.
+
+ Args:
+ initial_state: the intial state (nested data)
+ """
+ self.states = [None] * STATE_CACHE_SIZE #fill states
+ self.current_state_index = 0
+ self.num_prev_states = 0
+ self.num_next_states = 0
+ self.states[0] = initial_state
+ self.update_actions()
- def save_new_state(self, state):
- """
- Save a new state.
- Place the new state at the next index and add one to the number of previous states.
-
- Args:
- state: the new state
- """
- self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE
- self.states[self.current_state_index] = state
- self.num_prev_states = self.num_prev_states + 1
- if self.num_prev_states == STATE_CACHE_SIZE: self.num_prev_states = STATE_CACHE_SIZE - 1
- self.num_next_states = 0
- self.update_actions()
+ def save_new_state(self, state):
+ """
+ Save a new state.
+ Place the new state at the next index and add one to the number of previous states.
+
+ Args:
+ state: the new state
+ """
+ self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE
+ self.states[self.current_state_index] = state
+ self.num_prev_states = self.num_prev_states + 1
+ if self.num_prev_states == STATE_CACHE_SIZE: self.num_prev_states = STATE_CACHE_SIZE - 1
+ self.num_next_states = 0
+ self.update_actions()
- def get_current_state(self):
- """
- Get the state at the current index.
-
- Returns:
- the current state (nested data)
- """
- self.update_actions()
- return self.states[self.current_state_index]
+ def get_current_state(self):
+ """
+ Get the state at the current index.
+
+ Returns:
+ the current state (nested data)
+ """
+ self.update_actions()
+ return self.states[self.current_state_index]
- def get_prev_state(self):
- """
- Get the previous state and decrement the current index.
-
- Returns:
- the previous state or None
- """
- if self.num_prev_states > 0:
- self.current_state_index = (self.current_state_index + STATE_CACHE_SIZE -1)%STATE_CACHE_SIZE
- self.num_next_states = self.num_next_states + 1
- self.num_prev_states = self.num_prev_states - 1
- return self.get_current_state()
- return None
+ def get_prev_state(self):
+ """
+ Get the previous state and decrement the current index.
+
+ Returns:
+ the previous state or None
+ """
+ if self.num_prev_states > 0:
+ self.current_state_index = (self.current_state_index + STATE_CACHE_SIZE -1)%STATE_CACHE_SIZE
+ self.num_next_states = self.num_next_states + 1
+ self.num_prev_states = self.num_prev_states - 1
+ return self.get_current_state()
+ return None
- def get_next_state(self):
- """
- Get the nest state and increment the current index.
-
- Returns:
- the next state or None
- """
- if self.num_next_states > 0:
- self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE
- self.num_next_states = self.num_next_states - 1
- self.num_prev_states = self.num_prev_states + 1
- return self.get_current_state()
- return None
+ def get_next_state(self):
+ """
+ Get the nest state and increment the current index.
+
+ Returns:
+ the next state or None
+ """
+ if self.num_next_states > 0:
+ self.current_state_index = (self.current_state_index + 1)%STATE_CACHE_SIZE
+ self.num_next_states = self.num_next_states - 1
+ self.num_prev_states = self.num_prev_states + 1
+ return self.get_current_state()
+ return None
- def update_actions(self):
- """
- Update the undo and redo actions based on the number of next and prev states.
- """
- Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0)
- Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0)
+ def update_actions(self):
+ """
+ Update the undo and redo actions based on the number of next and prev states.
+ """
+ Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0)
+ Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0)
diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py
index b68c19c4e1..cc1f8ceb12 100644
--- a/grc/gui/Utils.py
+++ b/grc/gui/Utils.py
@@ -25,80 +25,86 @@ import gtk
import gobject
def rotate_pixmap(gc, src_pixmap, dst_pixmap, angle=gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE):
- """
- Load the destination pixmap with a rotated version of the source pixmap.
- The source pixmap will be loaded into a pixbuf, rotated, and drawn to the destination pixmap.
- The pixbuf is a client-side drawable, where a pixmap is a server-side drawable.
-
- Args:
- gc: the graphics context
- src_pixmap: the source pixmap
- dst_pixmap: the destination pixmap
- angle: the angle to rotate by
- """
- width, height = src_pixmap.get_size()
- pixbuf = gtk.gdk.Pixbuf(
- colorspace=gtk.gdk.COLORSPACE_RGB,
- has_alpha=False, bits_per_sample=8,
- width=width, height=height,
- )
- pixbuf.get_from_drawable(src_pixmap, src_pixmap.get_colormap(), 0, 0, 0, 0, -1, -1)
- pixbuf = pixbuf.rotate_simple(angle)
- dst_pixmap.draw_pixbuf(gc, pixbuf, 0, 0, 0, 0)
+ """
+ Load the destination pixmap with a rotated version of the source pixmap.
+ The source pixmap will be loaded into a pixbuf, rotated, and drawn to the destination pixmap.
+ The pixbuf is a client-side drawable, where a pixmap is a server-side drawable.
+
+ Args:
+ gc: the graphics context
+ src_pixmap: the source pixmap
+ dst_pixmap: the destination pixmap
+ angle: the angle to rotate by
+ """
+ width, height = src_pixmap.get_size()
+ pixbuf = gtk.gdk.Pixbuf(
+ colorspace=gtk.gdk.COLORSPACE_RGB,
+ has_alpha=False, bits_per_sample=8,
+ width=width, height=height,
+ )
+ pixbuf.get_from_drawable(src_pixmap, src_pixmap.get_colormap(), 0, 0, 0, 0, -1, -1)
+ pixbuf = pixbuf.rotate_simple(angle)
+ dst_pixmap.draw_pixbuf(gc, pixbuf, 0, 0, 0, 0)
def get_rotated_coordinate(coor, rotation):
- """
- Rotate the coordinate by the given rotation.
-
- Args:
- coor: the coordinate x, y tuple
- rotation: the angle in degrees
-
- Returns:
- the rotated coordinates
- """
- #handles negative angles
- rotation = (rotation + 360)%360
- if rotation not in POSSIBLE_ROTATIONS:
- raise ValueError('unusable rotation angle "%s"'%str(rotation))
- #determine the number of degrees to rotate
- cos_r, sin_r = {
- 0: (1, 0),
- 90: (0, 1),
- 180: (-1, 0),
- 270: (0, -1),
- }[rotation]
- x, y = coor
- return (x*cos_r + y*sin_r, -x*sin_r + y*cos_r)
+ """
+ Rotate the coordinate by the given rotation.
+
+ Args:
+ coor: the coordinate x, y tuple
+ rotation: the angle in degrees
+
+ Returns:
+ the rotated coordinates
+ """
+ #handles negative angles
+ rotation = (rotation + 360)%360
+ if rotation not in POSSIBLE_ROTATIONS:
+ raise ValueError('unusable rotation angle "%s"'%str(rotation))
+ #determine the number of degrees to rotate
+ cos_r, sin_r = {
+ 0: (1, 0),
+ 90: (0, 1),
+ 180: (-1, 0),
+ 270: (0, -1),
+ }[rotation]
+ x, y = coor
+ return (x*cos_r + y*sin_r, -x*sin_r + y*cos_r)
def get_angle_from_coordinates((x1,y1), (x2,y2)):
- """
- Given two points, calculate the vector direction from point1 to point2, directions are multiples of 90 degrees.
-
- Args:
- (x1,y1): the coordinate of point 1
- (x2,y2): the coordinate of point 2
-
- Returns:
- the direction in degrees
- """
- if y1 == y2:#0 or 180
- if x2 > x1: return 0
- else: return 180
- else:#90 or 270
- if y2 > y1: return 270
- else: return 90
+ """
+ Given two points, calculate the vector direction from point1 to point2, directions are multiples of 90 degrees.
+
+ Args:
+ (x1,y1): the coordinate of point 1
+ (x2,y2): the coordinate of point 2
+
+ Returns:
+ the direction in degrees
+ """
+ if y1 == y2:#0 or 180
+ if x2 > x1: return 0
+ else: return 180
+ else:#90 or 270
+ if y2 > y1: return 270
+ else: return 90
def parse_template(tmpl_str, **kwargs):
- """
- Parse the template string with the given args.
- Pass in the xml encode method for pango escape chars.
-
- Args:
- tmpl_str: the template as a string
-
- Returns:
- a string of the parsed template
- """
- kwargs['encode'] = gobject.markup_escape_text
- return str(Template(tmpl_str, kwargs))
+ """
+ Parse the template string with the given args.
+ Pass in the xml encode method for pango escape chars.
+
+ Args:
+ tmpl_str: the template as a string
+
+ Returns:
+ a string of the parsed template
+ """
+ kwargs['encode'] = gobject.markup_escape_text
+ #try:
+ # cat = str(Template(tmpl_str, kwargs))
+ #except TypeError:
+ # print 'guppy'
+ # print tmpl_str
+ # print str(kwargs['param'].get_error_messages())
+ return str(Template(tmpl_str, kwargs))
diff --git a/grc/python/Block.py b/grc/python/Block.py
index 806de46724..e13b26c12f 100644
--- a/grc/python/Block.py
+++ b/grc/python/Block.py
@@ -23,170 +23,187 @@ import extract_docs
class Block(_Block, _GUIBlock):
- def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
- def is_virtual_source(self): return self.get_key() == 'virtual_source'
-
- ##for make source to keep track of indexes
- _source_count = 0
- ##for make sink to keep track of indexes
- _sink_count = 0
-
- def __init__(self, flow_graph, n):
- """
- Make a new block from nested data.
-
- Args:
- flow: graph the parent element
- n: the nested odict
-
- Returns:
- block a new block
- """
- #grab the data
- self._doc = n.find('doc') or ''
- self._imports = map(lambda i: i.strip(), n.findall('import'))
- self._make = n.find('make')
- self._var_make = n.find('var_make')
- self._checks = n.findall('check')
- self._callbacks = n.findall('callback')
- self._throttle = n.find('throttle') or ''
- #build the block
- _Block.__init__(
- self,
- flow_graph=flow_graph,
- n=n,
- )
- _GUIBlock.__init__(self)
-
- def throttle(self): return bool(self._throttle)
-
- def validate(self):
- """
- Validate this block.
- Call the base class validate.
- Evaluate the checks: each check must evaluate to True.
- """
- _Block.validate(self)
- #evaluate the checks
- for check in self._checks:
- check_res = self.resolve_dependencies(check)
- try:
- if not self.get_parent().evaluate(check_res):
- self.add_error_message('Check "%s" failed.'%check)
- except: self.add_error_message('Check "%s" did not evaluate.'%check)
-
- def rewrite(self):
- """
- Add and remove ports to adjust for the nports.
- """
- _Block.rewrite(self)
-
- def rectify(ports):
- #restore integer contiguity after insertion
- #rectify the port names with the index
- for i, port in enumerate(ports):
- port._key = str(i)
- port._name = port._n['name']
- if len(ports) > 1: port._name += str(i)
-
- def insert_port(get_ports, get_port, key):
- prev_port = get_port(str(int(key)-1))
- get_ports().insert(
- get_ports().index(prev_port)+1,
- prev_port.copy(new_key=key),
- )
- rectify(get_ports())
-
- def remove_port(get_ports, get_port, key):
- port = get_port(key)
- for connection in port.get_connections():
- self.get_parent().remove_element(connection)
- get_ports().remove(port)
- rectify(get_ports())
-
- #adjust nports
- for get_ports, get_port in (
- (self.get_sources, self.get_source),
- (self.get_sinks, self.get_sink),
- ):
- master_ports = filter(lambda p: p.get_nports(), get_ports())
- for i, master_port in enumerate(master_ports):
- nports = master_port.get_nports()
- index_first = get_ports().index(master_port)
- try: index_last = get_ports().index(master_ports[i+1])
- except IndexError: index_last = len(get_ports())
- num_ports = index_last - index_first
- #do nothing if nports is already num ports
- if nports == num_ports: continue
- #remove excess ports and connections
- if nports < num_ports:
- for key in reversed(map(str, range(index_first+nports, index_first+num_ports))):
- remove_port(get_ports, get_port, key)
- continue
- #add more ports
- if nports > num_ports:
- for key in map(str, range(index_first+num_ports, index_first+nports)):
- insert_port(get_ports, get_port, key)
- continue
-
- def port_controller_modify(self, direction):
- """
- Change the port controller.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for change
- """
- changed = False
- #concat the nports string from the private nports settings of all ports
- nports_str = ' '.join([port._nports for port in self.get_ports()])
- #modify all params whose keys appear in the nports string
- for param in self.get_params():
- if param.is_enum() or param.get_key() not in nports_str: continue
- #try to increment the port controller by direction
- try:
- value = param.get_evaluated()
- value = value + direction
- if 0 < value:
- param.set_value(value)
- changed = True
- except: pass
- return changed
-
- def get_doc(self):
- doc = self._doc.strip('\n').replace('\\\n', '')
- #merge custom doc with doxygen docs
- return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n')
-
- def get_category(self):
- return _Block.get_category(self)
-
- def get_imports(self):
- """
- Resolve all import statements.
- Split each import statement at newlines.
- Combine all import statments into a list.
- Filter empty imports.
-
- Returns:
- a list of import statements
- """
- return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), []))
-
- def get_make(self): return self.resolve_dependencies(self._make)
- def get_var_make(self): return self.resolve_dependencies(self._var_make)
-
- def get_callbacks(self):
- """
- Get a list of function callbacks for this block.
-
- Returns:
- a list of strings
- """
- def make_callback(callback):
- callback = self.resolve_dependencies(callback)
- if 'self.' in callback: return callback
- return 'self.%s.%s'%(self.get_id(), callback)
- return map(make_callback, self._callbacks)
+ def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
+ def is_virtual_source(self): return self.get_key() == 'virtual_source'
+
+ ##for make source to keep track of indexes
+ _source_count = 0
+ ##for make sink to keep track of indexes
+ _sink_count = 0
+
+ def __init__(self, flow_graph, n):
+ """
+ Make a new block from nested data.
+
+ Args:
+ flow: graph the parent element
+ n: the nested odict
+
+ Returns:
+ block a new block
+ """
+ #grab the data
+ self._doc = n.find('doc') or ''
+ self._imports = map(lambda i: i.strip(), n.findall('import'))
+ self._make = n.find('make')
+ self._var_make = n.find('var_make')
+ self._checks = n.findall('check')
+ self._callbacks = n.findall('callback')
+ self._throttle = n.find('throttle') or ''
+ self._bus_structure_source = n.find('bus_structure_source') or ''
+ self._bus_structure_sink = n.find('bus_structure_sink') or ''
+ #build the block
+ _Block.__init__(
+ self,
+ flow_graph=flow_graph,
+ n=n,
+ )
+ _GUIBlock.__init__(self)
+
+ def get_bus_structure(self, direction):
+ if direction == 'source':
+ bus_structure = self._bus_structure_source;
+ else:
+ bus_structure = self._bus_structure_sink;
+
+ bus_structure = self.resolve_dependencies(bus_structure);
+
+ if not bus_structure: return ''
+ try:
+ clean_bus_structure = self.get_parent().evaluate(bus_structure)
+ return clean_bus_structure
+
+ except: return ''
+ def throttle(self): return bool(self._throttle)
+
+ def validate(self):
+ """
+ Validate this block.
+ Call the base class validate.
+ Evaluate the checks: each check must evaluate to True.
+ """
+ _Block.validate(self)
+ #evaluate the checks
+ for check in self._checks:
+ check_res = self.resolve_dependencies(check)
+ try:
+ if not self.get_parent().evaluate(check_res):
+ self.add_error_message('Check "%s" failed.'%check)
+ except: self.add_error_message('Check "%s" did not evaluate.'%check)
+
+ def rewrite(self):
+ """
+ Add and remove ports to adjust for the nports.
+ """
+ _Block.rewrite(self)
+
+ def rectify(ports):
+ #restore integer contiguity after insertion
+ #rectify the port names with the index
+ self.back_ofthe_bus(ports);
+ for i, port in enumerate(ports):
+ port._key = str(i)
+ port._name = port._n['name']
+ if len(ports) > 1 and not port._type == 'bus': port._name += str(i)
+
+ def insert_port(get_ports, get_port, key):
+ prev_port = get_port(str(int(key)-1))
+ get_ports().insert(
+ get_ports().index(prev_port)+1,
+ prev_port.copy(new_key=key),
+ )
+ rectify(get_ports())
+
+ def remove_port(get_ports, get_port, key):
+ port = get_port(key)
+ for connection in port.get_connections():
+ self.get_parent().remove_element(connection)
+ get_ports().remove(port)
+ rectify(get_ports())
+
+ #adjust nports
+ for get_ports, get_port in (
+ (self.get_sources, self.get_source),
+ (self.get_sinks, self.get_sink),
+ ):
+ master_ports = filter(lambda p: p.get_nports(), get_ports())
+ for i, master_port in enumerate(master_ports):
+ nports = master_port.get_nports()
+ index_first = get_ports().index(master_port)
+ try: index_last = get_ports().index(master_ports[i+1])
+ except IndexError: index_last = len(get_ports())
+ num_ports = index_last - index_first
+ #do nothing if nports is already num ports
+ if nports == num_ports: continue
+ #remove excess ports and connections
+ if nports < num_ports:
+ for key in reversed(map(str, range(index_first+nports, index_first+num_ports))):
+ remove_port(get_ports, get_port, key);
+ continue
+ #add more ports
+ if nports > num_ports:
+ for key in map(str, range(index_first+num_ports, index_first+nports)):
+ insert_port(get_ports, get_port, key)
+ continue
+
+ def port_controller_modify(self, direction):
+ """
+ Change the port controller.
+
+ Args:
+ direction: +1 or -1
+
+ Returns:
+ true for change
+ """
+ changed = False
+ #concat the nports string from the private nports settings of all ports
+ nports_str = ' '.join([port._nports for port in self.get_ports()])
+ #modify all params whose keys appear in the nports string
+ for param in self.get_params():
+ if param.is_enum() or param.get_key() not in nports_str: continue
+ #try to increment the port controller by direction
+ try:
+ value = param.get_evaluated()
+ value = value + direction
+ if 0 < value:
+ param.set_value(value)
+ changed = True
+ except: pass
+ return changed
+
+ def get_doc(self):
+ doc = self._doc.strip('\n').replace('\\\n', '')
+ #merge custom doc with doxygen docs
+ return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n')
+
+ def get_category(self):
+ return _Block.get_category(self)
+
+ def get_imports(self):
+ """
+ Resolve all import statements.
+ Split each import statement at newlines.
+ Combine all import statments into a list.
+ Filter empty imports.
+
+ Returns:
+ a list of import statements
+ """
+ return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), []))
+
+ def get_make(self): return self.resolve_dependencies(self._make)
+ def get_var_make(self): return self.resolve_dependencies(self._var_make)
+
+ def get_callbacks(self):
+ """
+ Get a list of function callbacks for this block.
+
+ Returns:
+ a list of strings
+ """
+ def make_callback(callback):
+ callback = self.resolve_dependencies(callback)
+ if 'self.' in callback: return callback
+ return 'self.%s.%s'%(self.get_id(), callback)
+ return map(make_callback, self._callbacks)
diff --git a/grc/python/Connection.py b/grc/python/Connection.py
index 341dd2d821..7f235b190b 100644
--- a/grc/python/Connection.py
+++ b/grc/python/Connection.py
@@ -24,23 +24,26 @@ from .. gui.Connection import Connection as _GUIConnection
class Connection(_Connection, _GUIConnection):
- def __init__(self, **kwargs):
- _Connection.__init__(self, **kwargs)
- _GUIConnection.__init__(self)
-
- def is_msg(self):
- return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
-
- def is_message(self):
- return self.get_source().get_type() == self.get_sink().get_type() == 'message'
-
- def validate(self):
- """
- Validate the connections.
- The ports must match in io size.
- """
- Element.validate(self)
- source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen()
- sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen()
- if source_size != sink_size:
- self.add_error_message('Source IO size "%s" does not match sink IO size "%s".'%(source_size, sink_size))
+ def __init__(self, **kwargs):
+ _Connection.__init__(self, **kwargs)
+ _GUIConnection.__init__(self)
+
+ def is_msg(self):
+ return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
+
+ def is_message(self):
+ return self.get_source().get_type() == self.get_sink().get_type() == 'message'
+
+ def is_bus(self):
+ return self.get_source().get_type() == self.get_sink().get_type() == 'bus'
+
+ def validate(self):
+ """
+ Validate the connections.
+ The ports must match in io size.
+ """
+ Element.validate(self)
+ source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen()
+ sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen()
+ if source_size != sink_size:
+ self.add_error_message('Source IO size "%s" does not match sink IO size "%s".'%(source_size, sink_size))
diff --git a/grc/python/Constants.py b/grc/python/Constants.py
index b8dc9a96a1..15cc203b43 100644
--- a/grc/python/Constants.py
+++ b/grc/python/Constants.py
@@ -27,11 +27,11 @@ _gr_prefs = gr.prefs()
PATH_SEP = {'/':':', '\\':';'}[os.path.sep]
HIER_BLOCKS_LIB_DIR = os.path.join(os.path.expanduser('~'), '.grc_gnuradio')
BLOCKS_DIRS = filter( #filter blank strings
- lambda x: x, PATH_SEP.join([
- os.environ.get('GRC_BLOCKS_PATH', ''),
- _gr_prefs.get_string('grc', 'local_blocks_path', ''),
- _gr_prefs.get_string('grc', 'global_blocks_path', ''),
- ]).split(PATH_SEP),
+ lambda x: x, PATH_SEP.join([
+ os.environ.get('GRC_BLOCKS_PATH', ''),
+ _gr_prefs.get_string('grc', 'local_blocks_path', ''),
+ _gr_prefs.get_string('grc', 'global_blocks_path', ''),
+ ]).split(PATH_SEP),
) + [HIER_BLOCKS_LIB_DIR]
#file creation modes
@@ -45,39 +45,40 @@ BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd')
DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc')
CORE_TYPES = ( #name, key, sizeof, color
- ('Complex Float 64', 'fc64', 16, '#CC8C69'),
- ('Complex Float 32', 'fc32', 8, '#3399FF'),
- ('Complex Integer 64', 'sc64', 16, '#66CC00'),
- ('Complex Integer 32', 'sc32', 8, '#33cc66'),
- ('Complex Integer 16', 'sc16', 4, '#cccc00'),
- ('Complex Integer 8', 'sc8', 2, '#cc00cc'),
- ('Float 64', 'f64', 8, '#66CCCC'),
- ('Float 32', 'f32', 4, '#FF8C69'),
- ('Integer 64', 's64', 8, '#99FF33'),
- ('Integer 32', 's32', 4, '#00FF99'),
- ('Integer 16', 's16', 2, '#FFFF66'),
- ('Integer 8', 's8', 1, '#FF66FF'),
- ('Message Queue', 'msg', 0, '#777777'),
- ('Async Message', 'message', 0, '#C0C0C0'),
- ('Wildcard', '', 0, '#FFFFFF'),
+ ('Complex Float 64', 'fc64', 16, '#CC8C69'),
+ ('Complex Float 32', 'fc32', 8, '#3399FF'),
+ ('Complex Integer 64', 'sc64', 16, '#66CC00'),
+ ('Complex Integer 32', 'sc32', 8, '#33cc66'),
+ ('Complex Integer 16', 'sc16', 4, '#cccc00'),
+ ('Complex Integer 8', 'sc8', 2, '#cc00cc'),
+ ('Float 64', 'f64', 8, '#66CCCC'),
+ ('Float 32', 'f32', 4, '#FF8C69'),
+ ('Integer 64', 's64', 8, '#99FF33'),
+ ('Integer 32', 's32', 4, '#00FF99'),
+ ('Integer 16', 's16', 2, '#FFFF66'),
+ ('Integer 8', 's8', 1, '#FF66FF'),
+ ('Message Queue', 'msg', 0, '#777777'),
+ ('Async Message', 'message', 0, '#C0C0C0'),
+ ('Bus Connection', 'bus', 0, '#FFFFFF'),
+ ('Wildcard', '', 0, '#FFFFFF'),
)
ALIAS_TYPES = {
- 'complex' : (8, '#3399FF'),
- 'float' : (4, '#FF8C69'),
- 'int' : (4, '#00FF99'),
- 'short' : (2, '#FFFF66'),
- 'byte' : (1, '#FF66FF'),
+ 'complex' : (8, '#3399FF'),
+ 'float' : (4, '#FF8C69'),
+ 'int' : (4, '#00FF99'),
+ 'short' : (2, '#FFFF66'),
+ 'byte' : (1, '#FF66FF'),
}
TYPE_TO_COLOR = dict()
TYPE_TO_SIZEOF = dict()
for name, key, sizeof, color in CORE_TYPES:
- TYPE_TO_COLOR[key] = color
- TYPE_TO_SIZEOF[key] = sizeof
+ TYPE_TO_COLOR[key] = color
+ TYPE_TO_SIZEOF[key] = sizeof
for key, (sizeof, color) in ALIAS_TYPES.iteritems():
- TYPE_TO_COLOR[key] = color
- TYPE_TO_SIZEOF[key] = sizeof
+ TYPE_TO_COLOR[key] = color
+ TYPE_TO_SIZEOF[key] = sizeof
#coloring
COMPLEX_COLOR_SPEC = '#3399FF'
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
index 1080006cf5..180d605720 100644
--- a/grc/python/FlowGraph.py
+++ b/grc/python/FlowGraph.py
@@ -20,174 +20,237 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import expr_utils
from .. base.FlowGraph import FlowGraph as _FlowGraph
from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
+from .. base.odict import odict
import re
_variable_matcher = re.compile('^(variable\w*)$')
_parameter_matcher = re.compile('^(parameter)$')
_monitors_searcher = re.compile('(ctrlport_monitor)')
+_bussink_searcher = re.compile('^(bus_sink)$')
+_bussrc_searcher = re.compile('^(bus_source)$')
+_bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$')
+_bus_struct_src_searcher = re.compile('^(bus_structure_source)$')
class FlowGraph(_FlowGraph, _GUIFlowGraph):
- def __init__(self, **kwargs):
- _FlowGraph.__init__(self, **kwargs)
- _GUIFlowGraph.__init__(self)
- self._eval_cache = dict()
+ def __init__(self, **kwargs):
+ _FlowGraph.__init__(self, **kwargs)
+ _GUIFlowGraph.__init__(self)
+ self._eval_cache = dict()
- def _eval(self, code, namespace, namespace_hash):
- """
- Evaluate the code with the given namespace.
-
- Args:
- code: a string with python code
- namespace: a dict representing the namespace
- namespace_hash: a unique hash for the namespace
-
- Returns:
- the resultant object
- """
- if not code: raise Exception, 'Cannot evaluate empty statement.'
- my_hash = hash(code) ^ namespace_hash
- #cache if does not exist
- if not self._eval_cache.has_key(my_hash):
- self._eval_cache[my_hash] = eval(code, namespace, namespace)
- #return from cache
- return self._eval_cache[my_hash]
-
- def get_io_signaturev(self, direction):
- """
- Get a list of io signatures for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size
- """
- sorted_pads = {
- 'in': self.get_pad_sources(),
- 'out': self.get_pad_sinks(),
- }[direction]
+ def _eval(self, code, namespace, namespace_hash):
+ """
+ Evaluate the code with the given namespace.
+
+ Args:
+ code: a string with python code
+ namespace: a dict representing the namespace
+ namespace_hash: a unique hash for the namespace
+
+ Returns:
+ the resultant object
+ """
+ if not code: raise Exception, 'Cannot evaluate empty statement.'
+ my_hash = hash(code) ^ namespace_hash
+ #cache if does not exist
+ if not self._eval_cache.has_key(my_hash):
+ self._eval_cache[my_hash] = eval(code, namespace, namespace)
+ #return from cache
+ return self._eval_cache[my_hash]
+
+ def get_io_signaturev(self, direction):
+ """
+ Get a list of io signatures for this flow graph.
+
+ Args:
+ direction: a string of 'in' or 'out'
+
+ Returns:
+ a list of dicts with: type, label, vlen, size
+ """
+ sorted_pads = {
+ 'in': self.get_pad_sources(),
+ 'out': self.get_pad_sinks(),
+ }[direction]
# we only want stream ports
- sorted_pads = filter(lambda b: b.get_param('type').get_evaluated() != 'message', sorted_pads);
- #load io signature
- return [{
- 'label': str(pad.get_param('label').get_evaluated()),
- 'type': str(pad.get_param('type').get_evaluated()),
- 'vlen': str(pad.get_param('vlen').get_evaluated()),
- 'size': pad.get_param('type').get_opt('size'),
- 'optional': bool(pad.get_param('optional').get_evaluated()),
- } for pad in sorted_pads]
-
- def get_pad_sources(self):
- """
- Get a list of pad source blocks sorted by id order.
-
- Returns:
- a list of pad source blocks in this flow graph
- """
- pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks())
- return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
-
- def get_pad_sinks(self):
- """
- Get a list of pad sink blocks sorted by id order.
-
- Returns:
- a list of pad sink blocks in this flow graph
- """
- pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks())
- return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
-
- def get_msg_pad_sources(self):
- ps = self.get_pad_sources();
- return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps);
-
- def get_msg_pad_sinks(self):
- ps = self.get_pad_sinks();
- return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps);
-
- def get_imports(self):
- """
- Get a set of all import statments in this flow graph namespace.
+ sorted_pads = filter(lambda b: b.get_param('type').get_evaluated() != 'message', sorted_pads);
+ expanded_pads = [];
+ for i in sorted_pads:
+ for j in range(i.get_param('num_streams').get_evaluated()):
+ expanded_pads.append(i);
+ #load io signature
+ return [{
+ 'label': str(pad.get_param('label').get_evaluated()),
+ 'type': str(pad.get_param('type').get_evaluated()),
+ 'vlen': str(pad.get_param('vlen').get_evaluated()),
+ 'size': pad.get_param('type').get_opt('size'),
+ 'optional': bool(pad.get_param('optional').get_evaluated()),
+ } for pad in expanded_pads]
+
+ def get_pad_sources(self):
+ """
+ Get a list of pad source blocks sorted by id order.
+
+ Returns:
+ a list of pad source blocks in this flow graph
+ """
+ pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks())
+ return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
+
+ def get_pad_sinks(self):
+ """
+ Get a list of pad sink blocks sorted by id order.
+
+ Returns:
+ a list of pad sink blocks in this flow graph
+ """
+ pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks())
+ return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
+
+ def get_msg_pad_sources(self):
+ ps = self.get_pad_sources();
+ return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps);
+
+ def get_msg_pad_sinks(self):
+ ps = self.get_pad_sinks();
+ return filter(lambda b: b.get_param('type').get_evaluated() == 'message', ps);
+
+ def get_imports(self):
+ """
+ Get a set of all import statments in this flow graph namespace.
+
+ Returns:
+ a set of import statements
+ """
+ imports = sum([block.get_imports() for block in self.get_enabled_blocks()], [])
+ imports = sorted(set(imports))
+ return imports
+
+ def get_variables(self):
+ """
+ Get a list of all variables in this flow graph namespace.
+ Exclude paramterized variables.
+
+ Returns:
+ a sorted list of variable blocks in order of dependency (indep -> dep)
+ """
+ variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.get_enabled_blocks())
+ return expr_utils.sort_objects(variables, lambda v: v.get_id(), lambda v: v.get_var_make())
+
+ def get_parameters(self):
+ """
+ Get a list of all paramterized variables in this flow graph namespace.
+
+ Returns:
+ a list of paramterized variables
+ """
+ parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks())
+ return parameters
+
+ def get_monitors(self):
+ """
+ Get a list of all ControlPort monitors
+ """
+ monitors = filter(lambda b: _monitors_searcher.search(b.get_key()), self.get_enabled_blocks())
+ return monitors
+
+
+ def get_bussink(self):
+ bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks())
- Returns:
- a set of import statements
- """
- imports = sum([block.get_imports() for block in self.get_enabled_blocks()], [])
- imports = sorted(set(imports))
- return imports
-
- def get_variables(self):
- """
- Get a list of all variables in this flow graph namespace.
- Exclude paramterized variables.
+ for i in bussink:
+ for j in i.get_params():
+ if j.get_name() == 'On/Off' and j.get_value() == 'on':
+ return True;
+
+ return False
- Returns:
- a sorted list of variable blocks in order of dependency (indep -> dep)
- """
- variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.get_enabled_blocks())
- return expr_utils.sort_objects(variables, lambda v: v.get_id(), lambda v: v.get_var_make())
-
- def get_parameters(self):
- """
- Get a list of all paramterized variables in this flow graph namespace.
- Returns:
- a list of paramterized variables
- """
- parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks())
- return parameters
-
- def get_monitors(self):
- """
- Get a list of all ControlPort monitors
- """
- monitors = filter(lambda b: _monitors_searcher.search(b.get_key()), self.get_enabled_blocks())
- return monitors
-
- def rewrite(self):
- """
- Flag the namespace to be renewed.
- """
- self._renew_eval_ns = True
- _FlowGraph.rewrite(self)
-
- def evaluate(self, expr):
- """
- Evaluate the expression.
+
+ def get_bussrc(self):
+ bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), self.get_enabled_blocks())
+
+ for i in bussrc:
+ for j in i.get_params():
+ if j.get_name() == 'On/Off' and j.get_value() == 'on':
+ return True;
+
+ return False
+
+ def get_bus_structure_sink(self):
+ bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks())
+
+ return bussink
+
+ def get_bus_structure_src(self):
+ bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks())
- Args:
- expr: the string expression
- @throw Exception bad expression
+ return bussrc
- Returns:
- the evaluated data
- """
- if self._renew_eval_ns:
- self._renew_eval_ns = False
- #reload namespace
- n = dict()
- #load imports
- for imp in self.get_imports():
- try: exec imp in n
- except: pass
- #load parameters
- np = dict()
- for parameter in self.get_parameters():
- try:
- e = eval(parameter.get_param('value').to_code(), n, n)
- np[parameter.get_id()] = e
- except: pass
- n.update(np) #merge param namespace
- #load variables
- for variable in self.get_variables():
- try:
- e = eval(variable.get_param('value').to_code(), n, n)
- n[variable.get_id()] = e
- except: pass
- #make namespace public
- self.n = n
- self.n_hash = hash(str(n))
- #evaluate
- e = self._eval(expr, self.n, self.n_hash)
- return e
+
+ def rewrite(self):
+ """
+ Flag the namespace to be renewed.
+ """
+ def reconnect_bus_blocks():
+ for block in self.get_blocks():
+
+ if 'bus' in map(lambda a: a.get_type(), block.get_sources_gui()):
+
+
+ for i in range(len(block.get_sources_gui())):
+ if len(block.get_sources_gui()[i].get_connections()) > 0:
+ source = block.get_sources_gui()[i]
+ sink = []
+
+ for j in range(len(source.get_connections())):
+ sink.append(source.get_connections()[j].get_sink());
+
+
+ for elt in source.get_connections():
+ self.remove_element(elt);
+ for j in sink:
+ self.connect(source, j);
+ self._renew_eval_ns = True
+ _FlowGraph.rewrite(self);
+ reconnect_bus_blocks();
+
+ def evaluate(self, expr):
+ """
+ Evaluate the expression.
+
+ Args:
+ expr: the string expression
+ @throw Exception bad expression
+
+ Returns:
+ the evaluated data
+ """
+ if self._renew_eval_ns:
+ self._renew_eval_ns = False
+ #reload namespace
+ n = dict()
+ #load imports
+ for imp in self.get_imports():
+ try: exec imp in n
+ except: pass
+ #load parameters
+ np = dict()
+ for parameter in self.get_parameters():
+ try:
+ e = eval(parameter.get_param('value').to_code(), n, n)
+ np[parameter.get_id()] = e
+ except: pass
+ n.update(np) #merge param namespace
+ #load variables
+ for variable in self.get_variables():
+ try:
+ e = eval(variable.get_param('value').to_code(), n, n)
+ n[variable.get_id()] = e
+ except: pass
+ #make namespace public
+ self.n = n
+ self.n_hash = hash(str(n))
+ #evaluate
+ e = self._eval(expr, self.n, self.n_hash)
+ return e
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
index 77abc45281..005ed4c2b3 100644
--- a/grc/python/Generator.py
+++ b/grc/python/Generator.py
@@ -24,137 +24,137 @@ import tempfile
from Cheetah.Template import Template
import expr_utils
from Constants import \
- TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \
- HIER_BLOCKS_LIB_DIR, FLOW_GRAPH_TEMPLATE
+ TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \
+ HIER_BLOCKS_LIB_DIR, FLOW_GRAPH_TEMPLATE
import convert_hier
from .. gui import Messages
class Generator(object):
- def __init__(self, flow_graph, file_path):
- """
- Initialize the generator object.
- Determine the file to generate.
-
- Args:
- flow_graph: the flow graph object
- file_path: the path to write the file to
- """
- self._flow_graph = flow_graph
- self._generate_options = self._flow_graph.get_option('generate_options')
- if self._generate_options == 'hb':
- self._mode = HIER_BLOCK_FILE_MODE
- dirname = HIER_BLOCKS_LIB_DIR
- else:
- self._mode = TOP_BLOCK_FILE_MODE
- dirname = os.path.dirname(file_path)
- #handle the case where the directory is read-only
- #in this case, use the system's temp directory
- if not os.access(dirname, os.W_OK):
- dirname = tempfile.gettempdir()
- filename = self._flow_graph.get_option('id') + '.py'
- self._file_path = os.path.join(dirname, filename)
+ def __init__(self, flow_graph, file_path):
+ """
+ Initialize the generator object.
+ Determine the file to generate.
+
+ Args:
+ flow_graph: the flow graph object
+ file_path: the path to write the file to
+ """
+ self._flow_graph = flow_graph
+ self._generate_options = self._flow_graph.get_option('generate_options')
+ if self._generate_options == 'hb':
+ self._mode = HIER_BLOCK_FILE_MODE
+ dirname = HIER_BLOCKS_LIB_DIR
+ else:
+ self._mode = TOP_BLOCK_FILE_MODE
+ dirname = os.path.dirname(file_path)
+ #handle the case where the directory is read-only
+ #in this case, use the system's temp directory
+ if not os.access(dirname, os.W_OK):
+ dirname = tempfile.gettempdir()
+ filename = self._flow_graph.get_option('id') + '.py'
+ self._file_path = os.path.join(dirname, filename)
- def get_file_path(self): return self._file_path
+ def get_file_path(self): return self._file_path
- def write(self):
- #do throttle warning
- throttled = any(map(lambda b: b.throttle(), self._flow_graph.get_enabled_blocks()))
- if not throttled and self._generate_options != 'hb':
- Messages.send_warning('''\
+ def write(self):
+ #do throttle warning
+ throttled = any(map(lambda b: b.throttle(), self._flow_graph.get_enabled_blocks()))
+ if not throttled and self._generate_options != 'hb':
+ Messages.send_warning('''\
This flow graph may not have flow control: no audio or usrp blocks found. \
Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''')
- #generate
- open(self.get_file_path(), 'w').write(str(self))
- if self._generate_options == 'hb':
- #convert hier block to xml wrapper
- convert_hier.convert_hier(self._flow_graph, self.get_file_path())
- os.chmod(self.get_file_path(), self._mode)
+ #generate
+ open(self.get_file_path(), 'w').write(str(self))
+ if self._generate_options == 'hb':
+ #convert hier block to xml wrapper
+ convert_hier.convert_hier(self._flow_graph, self.get_file_path())
+ os.chmod(self.get_file_path(), self._mode)
- def get_popen(self):
- """
- Execute this python flow graph.
-
- Returns:
- a popen object
- """
- #extract the path to the python executable
- python_exe = sys.executable
+ def get_popen(self):
+ """
+ Execute this python flow graph.
+
+ Returns:
+ a popen object
+ """
+ #extract the path to the python executable
+ python_exe = sys.executable
- #when using wx gui on mac os, execute with pythonw
- #using pythonw is not necessary anymore, disabled below
- #if self._generate_options == 'wx_gui' and 'darwin' in sys.platform.lower():
- # python_exe = 'pythonw'
+ #when using wx gui on mac os, execute with pythonw
+ #using pythonw is not necessary anymore, disabled below
+ #if self._generate_options == 'wx_gui' and 'darwin' in sys.platform.lower():
+ # python_exe = 'pythonw'
- #setup the command args to run
- cmds = [python_exe, '-u', self.get_file_path()] #-u is unbuffered stdio
+ #setup the command args to run
+ cmds = [python_exe, '-u', self.get_file_path()] #-u is unbuffered stdio
- #when in no gui mode on linux, use an xterm (looks nice)
- if self._generate_options == 'no_gui' and 'linux' in sys.platform.lower():
- cmds = ['xterm', '-e'] + cmds
+ #when in no gui mode on linux, use an xterm (looks nice)
+ if self._generate_options == 'no_gui' and 'linux' in sys.platform.lower():
+ cmds = ['xterm', '-e'] + cmds
- p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True)
- return p
+ p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True)
+ return p
- def __str__(self):
- """
- Convert the flow graph to python code.
-
- Returns:
- a string of python code
- """
- title = self._flow_graph.get_option('title') or self._flow_graph.get_option('id').replace('_', ' ').title()
- imports = self._flow_graph.get_imports()
- variables = self._flow_graph.get_variables()
- parameters = self._flow_graph.get_parameters()
- monitors = self._flow_graph.get_monitors()
- #list of blocks not including variables and imports and parameters and disabled
- def _get_block_sort_text(block):
- code = block.get_make().replace(block.get_id(), ' ')
- try: code += block.get_param('notebook').get_value() #older gui markup w/ wxgui
- except: pass
- try: code += block.get_param('gui_hint').get_value() #newer gui markup w/ qtgui
- except: pass
- return code
- blocks = expr_utils.sort_objects(
- self._flow_graph.get_enabled_blocks(),
- lambda b: b.get_id(), _get_block_sort_text
- )
- #list of regular blocks (all blocks minus the special ones)
- blocks = filter(lambda b: b not in (imports + parameters), blocks)
- #list of connections where each endpoint is enabled
- connections = filter(lambda c: not (c.is_msg() or c.is_message()), self._flow_graph.get_enabled_connections())
- messages = filter(lambda c: c.is_msg(), self._flow_graph.get_enabled_connections())
- messages2 = filter(lambda c: c.is_message(), self._flow_graph.get_enabled_connections())
- #list of variable names
- var_ids = [var.get_id() for var in parameters + variables]
- #prepend self.
- replace_dict = dict([(var_id, 'self.%s'%var_id) for var_id in var_ids])
- #list of callbacks
- callbacks = [
- expr_utils.expr_replace(cb, replace_dict)
- for cb in sum([block.get_callbacks() for block in self._flow_graph.get_enabled_blocks()], [])
- ]
- #map var id to callbacks
- var_id2cbs = dict(
- [(var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks))
- for var_id in var_ids]
- )
- #load the namespace
- namespace = {
- 'title': title,
- 'imports': imports,
- 'flow_graph': self._flow_graph,
- 'variables': variables,
- 'parameters': parameters,
+ def __str__(self):
+ """
+ Convert the flow graph to python code.
+
+ Returns:
+ a string of python code
+ """
+ title = self._flow_graph.get_option('title') or self._flow_graph.get_option('id').replace('_', ' ').title()
+ imports = self._flow_graph.get_imports()
+ variables = self._flow_graph.get_variables()
+ parameters = self._flow_graph.get_parameters()
+ monitors = self._flow_graph.get_monitors()
+ #list of blocks not including variables and imports and parameters and disabled
+ def _get_block_sort_text(block):
+ code = block.get_make().replace(block.get_id(), ' ')
+ try: code += block.get_param('notebook').get_value() #older gui markup w/ wxgui
+ except: pass
+ try: code += block.get_param('gui_hint').get_value() #newer gui markup w/ qtgui
+ except: pass
+ return code
+ blocks = expr_utils.sort_objects(
+ self._flow_graph.get_enabled_blocks(),
+ lambda b: b.get_id(), _get_block_sort_text
+ )
+ #list of regular blocks (all blocks minus the special ones)
+ blocks = filter(lambda b: b not in (imports + parameters), blocks)
+ #list of connections where each endpoint is enabled
+ connections = filter(lambda c: not (c.is_bus() or c.is_msg() or c.is_message()), self._flow_graph.get_enabled_connections())
+ messages = filter(lambda c: c.is_msg(), self._flow_graph.get_enabled_connections())
+ messages2 = filter(lambda c: c.is_message(), self._flow_graph.get_enabled_connections())
+ #list of variable names
+ var_ids = [var.get_id() for var in parameters + variables]
+ #prepend self.
+ replace_dict = dict([(var_id, 'self.%s'%var_id) for var_id in var_ids])
+ #list of callbacks
+ callbacks = [
+ expr_utils.expr_replace(cb, replace_dict)
+ for cb in sum([block.get_callbacks() for block in self._flow_graph.get_enabled_blocks()], [])
+ ]
+ #map var id to callbacks
+ var_id2cbs = dict(
+ [(var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks))
+ for var_id in var_ids]
+ )
+ #load the namespace
+ namespace = {
+ 'title': title,
+ 'imports': imports,
+ 'flow_graph': self._flow_graph,
+ 'variables': variables,
+ 'parameters': parameters,
'monitors': monitors,
- 'blocks': blocks,
- 'connections': connections,
- 'messages': messages,
- 'messages2': messages2,
- 'generate_options': self._generate_options,
- 'var_id2cbs': var_id2cbs,
- }
- #build the template
- t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace)
- return str(t)
+ 'blocks': blocks,
+ 'connections': connections,
+ 'messages': messages,
+ 'messages2': messages2,
+ 'generate_options': self._generate_options,
+ 'var_id2cbs': var_id2cbs,
+ }
+ #build the template
+ t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace)
+ return str(t)
diff --git a/grc/python/Param.py b/grc/python/Param.py
index 696f16cc94..e603d6cdbe 100644
--- a/grc/python/Param.py
+++ b/grc/python/Param.py
@@ -34,51 +34,51 @@ _check_id_matcher = re.compile('^[a-z|A-Z]\w*$')
_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$')
class FileParam(EntryParam):
- """Provide an entry box for filename and a button to browse for a file."""
+ """Provide an entry box for filename and a button to browse for a file."""
- def __init__(self, *args, **kwargs):
- EntryParam.__init__(self, *args, **kwargs)
- input = gtk.Button('...')
- input.connect('clicked', self._handle_clicked)
- self.pack_start(input, False)
+ def __init__(self, *args, **kwargs):
+ EntryParam.__init__(self, *args, **kwargs)
+ input = gtk.Button('...')
+ input.connect('clicked', self._handle_clicked)
+ self.pack_start(input, False)
- def _handle_clicked(self, widget=None):
- """
- If the button was clicked, open a file dialog in open/save format.
- Replace the text in the entry with the new filename from the file dialog.
- """
- #get the paths
- file_path = self.param.is_valid() and self.param.get_evaluated() or ''
- (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '')
- if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths
- #build the dialog
- if self.param.get_type() == 'file_open':
- file_dialog = gtk.FileChooserDialog('Open a Data File...', None,
- gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK))
- elif self.param.get_type() == 'file_save':
- file_dialog = gtk.FileChooserDialog('Save a Data File...', None,
- gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
- file_dialog.set_do_overwrite_confirmation(True)
- file_dialog.set_current_name(basename) #show the current filename
- file_dialog.set_current_folder(dirname) #current directory
- file_dialog.set_select_multiple(False)
- file_dialog.set_local_only(True)
- if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog
- file_path = file_dialog.get_filename() #get the file path
- self._input.set_text(file_path)
- self._handle_changed()
- file_dialog.destroy() #destroy the dialog
+ def _handle_clicked(self, widget=None):
+ """
+ If the button was clicked, open a file dialog in open/save format.
+ Replace the text in the entry with the new filename from the file dialog.
+ """
+ #get the paths
+ file_path = self.param.is_valid() and self.param.get_evaluated() or ''
+ (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '')
+ if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths
+ #build the dialog
+ if self.param.get_type() == 'file_open':
+ file_dialog = gtk.FileChooserDialog('Open a Data File...', None,
+ gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK))
+ elif self.param.get_type() == 'file_save':
+ file_dialog = gtk.FileChooserDialog('Save a Data File...', None,
+ gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK))
+ file_dialog.set_do_overwrite_confirmation(True)
+ file_dialog.set_current_name(basename) #show the current filename
+ file_dialog.set_current_folder(dirname) #current directory
+ file_dialog.set_select_multiple(False)
+ file_dialog.set_local_only(True)
+ if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog
+ file_path = file_dialog.get_filename() #get the file path
+ self._input.set_text(file_path)
+ self._handle_changed()
+ file_dialog.destroy() #destroy the dialog
#blacklist certain ids, its not complete, but should help
import __builtin__
ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + \
- filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__)
+ filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__)
#define types, native python + numpy
VECTOR_TYPES = (tuple, list, set, numpy.ndarray)
COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128]
REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64]
INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64,
- numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]
+ numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]
#cast to tuple for isinstance, concat subtypes
COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
@@ -86,389 +86,389 @@ INT_TYPES = tuple(INT_TYPES)
class Param(_Param, _GUIParam):
- def __init__(self, **kwargs):
- _Param.__init__(self, **kwargs)
- _GUIParam.__init__(self)
- self._init = False
- self._hostage_cells = list()
+ def __init__(self, **kwargs):
+ _Param.__init__(self, **kwargs)
+ _GUIParam.__init__(self)
+ self._init = False
+ self._hostage_cells = list()
- def get_types(self): return (
- 'raw', 'enum',
- 'complex', 'real', 'float', 'int',
- 'complex_vector', 'real_vector', 'float_vector', 'int_vector',
- 'hex', 'string', 'bool',
- 'file_open', 'file_save',
- 'id', 'stream_id',
- 'grid_pos', 'notebook', 'gui_hint',
- 'import',
- )
+ def get_types(self): return (
+ 'raw', 'enum',
+ 'complex', 'real', 'float', 'int',
+ 'complex_vector', 'real_vector', 'float_vector', 'int_vector',
+ 'hex', 'string', 'bool',
+ 'file_open', 'file_save',
+ 'id', 'stream_id',
+ 'grid_pos', 'notebook', 'gui_hint',
+ 'import',
+ )
- def __repr__(self):
- """
- Get the repr (nice string format) for this param.
-
- Returns:
- the string representation
- """
- ##################################################
- # truncate helper method
- ##################################################
- def _truncate(string, style=0):
- max_len = max(27 - len(self.get_name()), 3)
- if len(string) > max_len:
- if style < 0: #front truncate
- string = '...' + string[3-max_len:]
- elif style == 0: #center truncate
- string = string[:max_len/2 -3] + '...' + string[-max_len/2:]
- elif style > 0: #rear truncate
- string = string[:max_len-3] + '...'
- return string
- ##################################################
- # simple conditions
- ##################################################
- if not self.is_valid(): return _truncate(self.get_value())
- if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name()
- ##################################################
- # display logic for numbers
- ##################################################
- def num_to_str(num):
- if isinstance(num, COMPLEX_TYPES):
- num = complex(num) #cast to python complex
- if num == 0: return '0' #value is zero
- elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real
- elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary
- elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag)))
- else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag))
- else: return str(num)
- ##################################################
- # split up formatting by type
- ##################################################
- truncate = 0 #default center truncate
- e = self.get_evaluated()
- t = self.get_type()
- if isinstance(e, bool): return str(e)
- elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e)
- elif isinstance(e, VECTOR_TYPES): #vector types
- if len(e) > 8:
- dt_str = self.get_value() #large vectors use code
- truncate = 1
- else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval
- elif t in ('file_open', 'file_save'):
- dt_str = self.get_value()
- truncate = -1
- else: dt_str = str(e) #other types
- ##################################################
- # done
- ##################################################
- return _truncate(dt_str, truncate)
+ def __repr__(self):
+ """
+ Get the repr (nice string format) for this param.
+
+ Returns:
+ the string representation
+ """
+ ##################################################
+ # truncate helper method
+ ##################################################
+ def _truncate(string, style=0):
+ max_len = max(27 - len(self.get_name()), 3)
+ if len(string) > max_len:
+ if style < 0: #front truncate
+ string = '...' + string[3-max_len:]
+ elif style == 0: #center truncate
+ string = string[:max_len/2 -3] + '...' + string[-max_len/2:]
+ elif style > 0: #rear truncate
+ string = string[:max_len-3] + '...'
+ return string
+ ##################################################
+ # simple conditions
+ ##################################################
+ if not self.is_valid(): return _truncate(self.get_value())
+ if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name()
+ ##################################################
+ # display logic for numbers
+ ##################################################
+ def num_to_str(num):
+ if isinstance(num, COMPLEX_TYPES):
+ num = complex(num) #cast to python complex
+ if num == 0: return '0' #value is zero
+ elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real
+ elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary
+ elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag)))
+ else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag))
+ else: return str(num)
+ ##################################################
+ # split up formatting by type
+ ##################################################
+ truncate = 0 #default center truncate
+ e = self.get_evaluated()
+ t = self.get_type()
+ if isinstance(e, bool): return str(e)
+ elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e)
+ elif isinstance(e, VECTOR_TYPES): #vector types
+ if len(e) > 8:
+ dt_str = self.get_value() #large vectors use code
+ truncate = 1
+ else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval
+ elif t in ('file_open', 'file_save'):
+ dt_str = self.get_value()
+ truncate = -1
+ else: dt_str = str(e) #other types
+ ##################################################
+ # done
+ ##################################################
+ return _truncate(dt_str, truncate)
- def get_input(self, *args, **kwargs):
- if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs)
- return _GUIParam.get_input(self, *args, **kwargs)
+ def get_input(self, *args, **kwargs):
+ if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs)
+ return _GUIParam.get_input(self, *args, **kwargs)
- def get_color(self):
- """
- Get the color that represents this param's type.
-
- Returns:
- a hex color code.
- """
- try:
- return {
- #number types
- 'complex': Constants.COMPLEX_COLOR_SPEC,
- 'real': Constants.FLOAT_COLOR_SPEC,
- 'float': Constants.FLOAT_COLOR_SPEC,
- 'int': Constants.INT_COLOR_SPEC,
- #vector types
- 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
- 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
+ def get_color(self):
+ """
+ Get the color that represents this param's type.
+
+ Returns:
+ a hex color code.
+ """
+ try:
+ return {
+ #number types
+ 'complex': Constants.COMPLEX_COLOR_SPEC,
+ 'real': Constants.FLOAT_COLOR_SPEC,
+ 'float': Constants.FLOAT_COLOR_SPEC,
+ 'int': Constants.INT_COLOR_SPEC,
+ #vector types
+ 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
+ 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
- 'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
- #special
- 'bool': Constants.INT_COLOR_SPEC,
- 'hex': Constants.INT_COLOR_SPEC,
- 'string': Constants.BYTE_VECTOR_COLOR_SPEC,
- 'id': Constants.ID_COLOR_SPEC,
- 'stream_id': Constants.ID_COLOR_SPEC,
- 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
- 'notebook': Constants.INT_VECTOR_COLOR_SPEC,
- 'raw': Constants.WILDCARD_COLOR_SPEC,
- }[self.get_type()]
- except: return _Param.get_color(self)
+ 'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
+ #special
+ 'bool': Constants.INT_COLOR_SPEC,
+ 'hex': Constants.INT_COLOR_SPEC,
+ 'string': Constants.BYTE_VECTOR_COLOR_SPEC,
+ 'id': Constants.ID_COLOR_SPEC,
+ 'stream_id': Constants.ID_COLOR_SPEC,
+ 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
+ 'notebook': Constants.INT_VECTOR_COLOR_SPEC,
+ 'raw': Constants.WILDCARD_COLOR_SPEC,
+ }[self.get_type()]
+ except: return _Param.get_color(self)
- def get_hide(self):
- """
- Get the hide value from the base class.
- Hide the ID parameter for most blocks. Exceptions below.
- If the parameter controls a port type, vlen, or nports, return part.
- If the parameter is an empty grid position, return part.
- These parameters are redundant to display in the flow graph view.
-
- Returns:
- hide the hide property string
- """
- hide = _Param.get_hide(self)
- if hide: return hide
- #hide ID in non variable blocks
- if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part'
- #hide port controllers for type and nports
- if self.get_key() in ' '.join(map(
- lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports())
- ): return 'part'
- #hide port controllers for vlen, when == 1
- if self.get_key() in ' '.join(map(
- lambda p: p._vlen, self.get_parent().get_ports())
- ):
- try:
- if int(self.get_evaluated()) == 1: return 'part'
- except: pass
- #hide empty grid positions
- if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part'
- return hide
+ def get_hide(self):
+ """
+ Get the hide value from the base class.
+ Hide the ID parameter for most blocks. Exceptions below.
+ If the parameter controls a port type, vlen, or nports, return part.
+ If the parameter is an empty grid position, return part.
+ These parameters are redundant to display in the flow graph view.
+
+ Returns:
+ hide the hide property string
+ """
+ hide = _Param.get_hide(self)
+ if hide: return hide
+ #hide ID in non variable blocks
+ if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part'
+ #hide port controllers for type and nports
+ if self.get_key() in ' '.join(map(
+ lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports())
+ ): return 'part'
+ #hide port controllers for vlen, when == 1
+ if self.get_key() in ' '.join(map(
+ lambda p: p._vlen, self.get_parent().get_ports())
+ ):
+ try:
+ if int(self.get_evaluated()) == 1: return 'part'
+ except: pass
+ #hide empty grid positions
+ if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part'
+ return hide
- def validate(self):
- """
- Validate the param.
- A test evaluation is performed
- """
- _Param.validate(self) #checks type
- self._evaluated = None
- try: self._evaluated = self.evaluate()
- except Exception, e: self.add_error_message(str(e))
+ def validate(self):
+ """
+ Validate the param.
+ A test evaluation is performed
+ """
+ _Param.validate(self) #checks type
+ self._evaluated = None
+ try: self._evaluated = self.evaluate()
+ except Exception, e: self.add_error_message(str(e))
- def get_evaluated(self): return self._evaluated
+ def get_evaluated(self): return self._evaluated
- def evaluate(self):
- """
- Evaluate the value.
-
- Returns:
- evaluated type
- """
- self._init = True
- self._lisitify_flag = False
- self._stringify_flag = False
- self._hostage_cells = list()
- def eval_string(v):
- try:
- e = self.get_parent().get_parent().evaluate(v)
- if isinstance(e, str): return e
- raise Exception #want to stringify
- except:
- self._stringify_flag = True
- return v
- t = self.get_type()
- v = self.get_value()
- #########################
- # Enum Type
- #########################
- if self.is_enum(): return v
- #########################
- # Numeric Types
- #########################
- elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'):
- #raise exception if python cannot evaluate this value
- try: e = self.get_parent().get_parent().evaluate(v)
- except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
- #raise an exception if the data is invalid
- if t == 'raw': return e
- elif t == 'complex':
- if not isinstance(e, COMPLEX_TYPES):
- raise Exception, 'Expression "%s" is invalid for type complex.'%str(e)
- return e
- elif t == 'real' or t == 'float':
- if not isinstance(e, REAL_TYPES):
- raise Exception, 'Expression "%s" is invalid for type float.'%str(e)
- return e
- elif t == 'int':
- if not isinstance(e, INT_TYPES):
- raise Exception, 'Expression "%s" is invalid for type integer.'%str(e)
- return e
- elif t == 'hex': return hex(e)
- elif t == 'bool':
- if not isinstance(e, bool):
- raise Exception, 'Expression "%s" is invalid for type bool.'%str(e)
- return e
- else: raise TypeError, 'Type "%s" not handled'%t
- #########################
- # Numeric Vector Types
- #########################
- elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'):
- if not v: v = '()' #turn a blank string into an empty list, so it will eval
- #raise exception if python cannot evaluate this value
- try: e = self.get_parent().get_parent().evaluate(v)
- except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
- #raise an exception if the data is invalid
- if t == 'complex_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e)
- return e
- elif t == 'real_vector' or t == 'float_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, REAL_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type float vector.'%str(e)
- return e
- elif t == 'int_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, INT_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e)
- return e
- #########################
- # String Types
- #########################
- elif t in ('string', 'file_open', 'file_save'):
- #do not check if file/directory exists, that is a runtime issue
- e = eval_string(v)
- return str(e)
- #########################
- # Unique ID Type
- #########################
- elif t == 'id':
- #can python use this as a variable?
- if not _check_id_matcher.match(v):
- raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
- ids = [param.get_value() for param in self.get_all_params(t)]
- if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
- raise Exception, 'ID "%s" is not unique.'%v
- if v in ID_BLACKLIST:
- raise Exception, 'ID "%s" is blacklisted.'%v
- return v
- #########################
- # Stream ID Type
- #########################
- elif t == 'stream_id':
- #get a list of all stream ids used in the virtual sinks
- ids = [param.get_value() for param in filter(
- lambda p: p.get_parent().is_virtual_sink(),
- self.get_all_params(t),
- )]
- #check that the virtual sink's stream id is unique
- if self.get_parent().is_virtual_sink():
- if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
- raise Exception, 'Stream ID "%s" is not unique.'%v
- #check that the virtual source's steam id is found
- if self.get_parent().is_virtual_source():
- if v not in ids:
- raise Exception, 'Stream ID "%s" is not found.'%v
- return v
- #########################
- # GUI Position/Hint
- #########################
- elif t == 'gui_hint':
- if ':' in v: tab, pos = v.split(':')
- elif '@' in v: tab, pos = v, ''
- else: tab, pos = '', v
+ def evaluate(self):
+ """
+ Evaluate the value.
+
+ Returns:
+ evaluated type
+ """
+ self._init = True
+ self._lisitify_flag = False
+ self._stringify_flag = False
+ self._hostage_cells = list()
+ def eval_string(v):
+ try:
+ e = self.get_parent().get_parent().evaluate(v)
+ if isinstance(e, str): return e
+ raise Exception #want to stringify
+ except:
+ self._stringify_flag = True
+ return v
+ t = self.get_type()
+ v = self.get_value()
+ #########################
+ # Enum Type
+ #########################
+ if self.is_enum(): return v
+ #########################
+ # Numeric Types
+ #########################
+ elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'):
+ #raise exception if python cannot evaluate this value
+ try: e = self.get_parent().get_parent().evaluate(v)
+ except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
+ #raise an exception if the data is invalid
+ if t == 'raw': return e
+ elif t == 'complex':
+ if not isinstance(e, COMPLEX_TYPES):
+ raise Exception, 'Expression "%s" is invalid for type complex.'%str(e)
+ return e
+ elif t == 'real' or t == 'float':
+ if not isinstance(e, REAL_TYPES):
+ raise Exception, 'Expression "%s" is invalid for type float.'%str(e)
+ return e
+ elif t == 'int':
+ if not isinstance(e, INT_TYPES):
+ raise Exception, 'Expression "%s" is invalid for type integer.'%str(e)
+ return e
+ elif t == 'hex': return hex(e)
+ elif t == 'bool':
+ if not isinstance(e, bool):
+ raise Exception, 'Expression "%s" is invalid for type bool.'%str(e)
+ return e
+ else: raise TypeError, 'Type "%s" not handled'%t
+ #########################
+ # Numeric Vector Types
+ #########################
+ elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'):
+ if not v: v = '()' #turn a blank string into an empty list, so it will eval
+ #raise exception if python cannot evaluate this value
+ try: e = self.get_parent().get_parent().evaluate(v)
+ except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
+ #raise an exception if the data is invalid
+ if t == 'complex_vector':
+ if not isinstance(e, VECTOR_TYPES):
+ self._lisitify_flag = True
+ e = [e]
+ if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]):
+ raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e)
+ return e
+ elif t == 'real_vector' or t == 'float_vector':
+ if not isinstance(e, VECTOR_TYPES):
+ self._lisitify_flag = True
+ e = [e]
+ if not all([isinstance(ei, REAL_TYPES) for ei in e]):
+ raise Exception, 'Expression "%s" is invalid for type float vector.'%str(e)
+ return e
+ elif t == 'int_vector':
+ if not isinstance(e, VECTOR_TYPES):
+ self._lisitify_flag = True
+ e = [e]
+ if not all([isinstance(ei, INT_TYPES) for ei in e]):
+ raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e)
+ return e
+ #########################
+ # String Types
+ #########################
+ elif t in ('string', 'file_open', 'file_save'):
+ #do not check if file/directory exists, that is a runtime issue
+ e = eval_string(v)
+ return str(e)
+ #########################
+ # Unique ID Type
+ #########################
+ elif t == 'id':
+ #can python use this as a variable?
+ if not _check_id_matcher.match(v):
+ raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
+ ids = [param.get_value() for param in self.get_all_params(t)]
+ if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
+ raise Exception, 'ID "%s" is not unique.'%v
+ if v in ID_BLACKLIST:
+ raise Exception, 'ID "%s" is blacklisted.'%v
+ return v
+ #########################
+ # Stream ID Type
+ #########################
+ elif t == 'stream_id':
+ #get a list of all stream ids used in the virtual sinks
+ ids = [param.get_value() for param in filter(
+ lambda p: p.get_parent().is_virtual_sink(),
+ self.get_all_params(t),
+ )]
+ #check that the virtual sink's stream id is unique
+ if self.get_parent().is_virtual_sink():
+ if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
+ raise Exception, 'Stream ID "%s" is not unique.'%v
+ #check that the virtual source's steam id is found
+ if self.get_parent().is_virtual_source():
+ if v not in ids:
+ raise Exception, 'Stream ID "%s" is not found.'%v
+ return v
+ #########################
+ # GUI Position/Hint
+ #########################
+ elif t == 'gui_hint':
+ if ':' in v: tab, pos = v.split(':')
+ elif '@' in v: tab, pos = v, ''
+ else: tab, pos = '', v
- if '@' in tab: tab, index = tab.split('@')
- else: index = '?'
+ if '@' in tab: tab, index = tab.split('@')
+ else: index = '?'
- widget_str = ({
- (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)',
- (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)',
- (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)',
- (False, False): 'self.top_layout.addWidget(%(widget)s)',
- }[bool(tab), bool(pos)])%{'tab': tab, 'index': index, 'widget': '%s', 'pos': pos}
+ widget_str = ({
+ (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)',
+ (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)',
+ (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)',
+ (False, False): 'self.top_layout.addWidget(%(widget)s)',
+ }[bool(tab), bool(pos)])%{'tab': tab, 'index': index, 'widget': '%s', 'pos': pos}
- def gui_hint(ws, w):
- if 'layout' in w: ws = ws.replace('addWidget', 'addLayout')
- return ws%w
+ def gui_hint(ws, w):
+ if 'layout' in w: ws = ws.replace('addWidget', 'addLayout')
+ return ws%w
- return lambda w: gui_hint(widget_str, w)
- #########################
- # Grid Position Type
- #########################
- elif t == 'grid_pos':
- if not v: return '' #allow for empty grid pos
- e = self.get_parent().get_parent().evaluate(v)
- if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]):
- raise Exception, 'A grid position must be a list of 4 integers.'
- row, col, row_span, col_span = e
- #check row, col
- if row < 0 or col < 0:
- raise Exception, 'Row and column must be non-negative.'
- #check row span, col span
- if row_span <= 0 or col_span <= 0:
- raise Exception, 'Row and column span must be greater than zero.'
- #get hostage cell parent
- try: my_parent = self.get_parent().get_param('notebook').evaluate()
- except: my_parent = ''
- #calculate hostage cells
- for r in range(row_span):
- for c in range(col_span):
- self._hostage_cells.append((my_parent, (row+r, col+c)))
- #avoid collisions
- params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
- for param in params:
- for parent, cell in param._hostage_cells:
- if (parent, cell) in self._hostage_cells:
- raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell))
- return e
- #########################
- # Notebook Page Type
- #########################
- elif t == 'notebook':
- if not v: return '' #allow for empty notebook
- #get a list of all notebooks
- notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks())
- #check for notebook param syntax
- try: notebook_id, page_index = map(str.strip, v.split(','))
- except: raise Exception, 'Bad notebook page format.'
- #check that the notebook id is valid
- try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0]
- except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id
- #check that page index exists
- if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())):
- raise Exception, 'Page index "%s" is not a valid index number.'%page_index
- return notebook_id, page_index
- #########################
- # Import Type
- #########################
- elif t == 'import':
- n = dict() #new namespace
- try: exec v in n
- except ImportError: raise Exception, 'Import "%s" failed.'%v
- except Exception: raise Exception, 'Bad import syntax: "%s".'%v
- return filter(lambda k: str(k) != '__builtins__', n.keys())
- #########################
- else: raise TypeError, 'Type "%s" not handled'%t
+ return lambda w: gui_hint(widget_str, w)
+ #########################
+ # Grid Position Type
+ #########################
+ elif t == 'grid_pos':
+ if not v: return '' #allow for empty grid pos
+ e = self.get_parent().get_parent().evaluate(v)
+ if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]):
+ raise Exception, 'A grid position must be a list of 4 integers.'
+ row, col, row_span, col_span = e
+ #check row, col
+ if row < 0 or col < 0:
+ raise Exception, 'Row and column must be non-negative.'
+ #check row span, col span
+ if row_span <= 0 or col_span <= 0:
+ raise Exception, 'Row and column span must be greater than zero.'
+ #get hostage cell parent
+ try: my_parent = self.get_parent().get_param('notebook').evaluate()
+ except: my_parent = ''
+ #calculate hostage cells
+ for r in range(row_span):
+ for c in range(col_span):
+ self._hostage_cells.append((my_parent, (row+r, col+c)))
+ #avoid collisions
+ params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
+ for param in params:
+ for parent, cell in param._hostage_cells:
+ if (parent, cell) in self._hostage_cells:
+ raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell))
+ return e
+ #########################
+ # Notebook Page Type
+ #########################
+ elif t == 'notebook':
+ if not v: return '' #allow for empty notebook
+ #get a list of all notebooks
+ notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks())
+ #check for notebook param syntax
+ try: notebook_id, page_index = map(str.strip, v.split(','))
+ except: raise Exception, 'Bad notebook page format.'
+ #check that the notebook id is valid
+ try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0]
+ except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id
+ #check that page index exists
+ if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())):
+ raise Exception, 'Page index "%s" is not a valid index number.'%page_index
+ return notebook_id, page_index
+ #########################
+ # Import Type
+ #########################
+ elif t == 'import':
+ n = dict() #new namespace
+ try: exec v in n
+ except ImportError: raise Exception, 'Import "%s" failed.'%v
+ except Exception: raise Exception, 'Bad import syntax: "%s".'%v
+ return filter(lambda k: str(k) != '__builtins__', n.keys())
+ #########################
+ else: raise TypeError, 'Type "%s" not handled'%t
- def to_code(self):
- """
- Convert the value to code.
- For string and list types, check the init flag, call evaluate().
- This ensures that evaluate() was called to set the xxxify_flags.
-
- Returns:
- a string representing the code
- """
- v = self.get_value()
- t = self.get_type()
- if t in ('string', 'file_open', 'file_save'): #string types
- if not self._init: self.evaluate()
- if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
- else: return v
- elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): #vector types
- if not self._init: self.evaluate()
- if self._lisitify_flag: return '(%s, )'%v
- else: return '(%s)'%v
- else: return v
+ def to_code(self):
+ """
+ Convert the value to code.
+ For string and list types, check the init flag, call evaluate().
+ This ensures that evaluate() was called to set the xxxify_flags.
+
+ Returns:
+ a string representing the code
+ """
+ v = self.get_value()
+ t = self.get_type()
+ if t in ('string', 'file_open', 'file_save'): #string types
+ if not self._init: self.evaluate()
+ if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
+ else: return v
+ elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): #vector types
+ if not self._init: self.evaluate()
+ if self._lisitify_flag: return '(%s, )'%v
+ else: return '(%s)'%v
+ else: return v
- def get_all_params(self, type):
- """
- Get all the params from the flowgraph that have the given type.
-
- Args:
- type: the specified type
-
- Returns:
- a list of params
- """
- return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], [])
+ def get_all_params(self, type):
+ """
+ Get all the params from the flowgraph that have the given type.
+
+ Args:
+ type: the specified type
+
+ Returns:
+ a list of params
+ """
+ return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], [])
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
index e036361ff0..f6adaf47a5 100644
--- a/grc/python/Platform.py
+++ b/grc/python/Platform.py
@@ -28,43 +28,43 @@ from Port import Port as _Port
from Param import Param as _Param
from Generator import Generator
from Constants import \
- HIER_BLOCKS_LIB_DIR, BLOCK_DTD, \
- DEFAULT_FLOW_GRAPH, BLOCKS_DIRS
+ HIER_BLOCKS_LIB_DIR, BLOCK_DTD, \
+ DEFAULT_FLOW_GRAPH, BLOCKS_DIRS
import Constants
COLORS = [(name, color) for name, key, sizeof, color in Constants.CORE_TYPES]
class Platform(_Platform, _GUIPlatform):
- def __init__(self):
- """
- Make a platform for gnuradio.
- """
- #ensure hier dir
- if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR)
- #convert block paths to absolute paths
- block_paths = set(map(os.path.abspath, BLOCKS_DIRS))
- #init
- _Platform.__init__(
- self,
- name='GNU Radio Companion',
- version=gr.version(),
- key='grc',
- license=__doc__.strip(),
- website='http://gnuradio.org/redmine/wiki/gnuradio/GNURadioCompanion',
- block_paths=block_paths,
- block_dtd=BLOCK_DTD,
- default_flow_graph=DEFAULT_FLOW_GRAPH,
- generator=Generator,
- colors=COLORS,
- )
- _GUIPlatform.__init__(self)
+ def __init__(self):
+ """
+ Make a platform for gnuradio.
+ """
+ #ensure hier dir
+ if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR)
+ #convert block paths to absolute paths
+ block_paths = set(map(os.path.abspath, BLOCKS_DIRS))
+ #init
+ _Platform.__init__(
+ self,
+ name='GNU Radio Companion',
+ version=gr.version(),
+ key='grc',
+ license=__doc__.strip(),
+ website='http://gnuradio.org/redmine/wiki/gnuradio/GNURadioCompanion',
+ block_paths=block_paths,
+ block_dtd=BLOCK_DTD,
+ default_flow_graph=DEFAULT_FLOW_GRAPH,
+ generator=Generator,
+ colors=COLORS,
+ )
+ _GUIPlatform.__init__(self)
- ##############################################
- # Constructors
- ##############################################
- FlowGraph = _FlowGraph
- Connection = _Connection
- Block = _Block
- Port = _Port
- Param = _Param
+ ##############################################
+ # Constructors
+ ##############################################
+ FlowGraph = _FlowGraph
+ Connection = _Connection
+ Block = _Block
+ Port = _Port
+ Param = _Param
diff --git a/grc/python/Port.py b/grc/python/Port.py
index d4afa6cf77..247dbed3e6 100644
--- a/grc/python/Port.py
+++ b/grc/python/Port.py
@@ -22,203 +22,203 @@ from .. gui.Port import Port as _GUIPort
import Constants
def _get_source_from_virtual_sink_port(vsp):
- """
- Resolve the source port that is connected to the given virtual sink port.
- Use the get source from virtual source to recursively resolve subsequent ports.
- """
- try: return _get_source_from_virtual_source_port(
- vsp.get_enabled_connections()[0].get_source())
- except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
+ """
+ Resolve the source port that is connected to the given virtual sink port.
+ Use the get source from virtual source to recursively resolve subsequent ports.
+ """
+ try: return _get_source_from_virtual_source_port(
+ vsp.get_enabled_connections()[0].get_source())
+ except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
def _get_source_from_virtual_source_port(vsp, traversed=[]):
- """
- Recursively resolve source ports over the virtual connections.
- Keep track of traversed sources to avoid recursive loops.
- """
- if not vsp.get_parent().is_virtual_source(): return vsp
- if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp
- try: return _get_source_from_virtual_source_port(
- _get_source_from_virtual_sink_port(
- filter(#get all virtual sinks with a matching stream id
- lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
- filter(#get all enabled blocks that are also virtual sinks
- lambda b: b.is_virtual_sink(),
- vsp.get_parent().get_parent().get_enabled_blocks(),
- ),
- )[0].get_sinks()[0]
- ), traversed + [vsp],
- )
- except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
+ """
+ Recursively resolve source ports over the virtual connections.
+ Keep track of traversed sources to avoid recursive loops.
+ """
+ if not vsp.get_parent().is_virtual_source(): return vsp
+ if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp
+ try: return _get_source_from_virtual_source_port(
+ _get_source_from_virtual_sink_port(
+ filter(#get all virtual sinks with a matching stream id
+ lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
+ filter(#get all enabled blocks that are also virtual sinks
+ lambda b: b.is_virtual_sink(),
+ vsp.get_parent().get_parent().get_enabled_blocks(),
+ ),
+ )[0].get_sinks()[0]
+ ), traversed + [vsp],
+ )
+ except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
def _get_sink_from_virtual_source_port(vsp):
- """
- Resolve the sink port that is connected to the given virtual source port.
- Use the get sink from virtual sink to recursively resolve subsequent ports.
- """
- try: return _get_sink_from_virtual_sink_port(
- vsp.get_enabled_connections()[0].get_sink()) # Could have many connections, but use first
- except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
+ """
+ Resolve the sink port that is connected to the given virtual source port.
+ Use the get sink from virtual sink to recursively resolve subsequent ports.
+ """
+ try: return _get_sink_from_virtual_sink_port(
+ vsp.get_enabled_connections()[0].get_sink()) # Could have many connections, but use first
+ except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
def _get_sink_from_virtual_sink_port(vsp, traversed=[]):
- """
- Recursively resolve sink ports over the virtual connections.
- Keep track of traversed sinks to avoid recursive loops.
- """
- if not vsp.get_parent().is_virtual_sink(): return vsp
- if vsp in traversed: raise Exception, 'Loop found when resolving virtual sink %s'%vsp
- try: return _get_sink_from_virtual_sink_port(
- _get_sink_from_virtual_source_port(
- filter(#get all virtual source with a matching stream id
- lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
- filter(#get all enabled blocks that are also virtual sinks
- lambda b: b.is_virtual_source(),
- vsp.get_parent().get_parent().get_enabled_blocks(),
- ),
- )[0].get_sources()[0]
- ), traversed + [vsp],
- )
- except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
+ """
+ Recursively resolve sink ports over the virtual connections.
+ Keep track of traversed sinks to avoid recursive loops.
+ """
+ if not vsp.get_parent().is_virtual_sink(): return vsp
+ if vsp in traversed: raise Exception, 'Loop found when resolving virtual sink %s'%vsp
+ try: return _get_sink_from_virtual_sink_port(
+ _get_sink_from_virtual_source_port(
+ filter(#get all virtual source with a matching stream id
+ lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
+ filter(#get all enabled blocks that are also virtual sinks
+ lambda b: b.is_virtual_source(),
+ vsp.get_parent().get_parent().get_enabled_blocks(),
+ ),
+ )[0].get_sources()[0]
+ ), traversed + [vsp],
+ )
+ except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
class Port(_Port, _GUIPort):
- def __init__(self, block, n, dir):
- """
- Make a new port from nested data.
-
- Args:
- block: the parent element
- n: the nested odict
- dir: the direction
- """
- self._n = n
- if n['type'] == 'msg': n['key'] = 'msg'
- if n['type'] == 'message': n['key'] = n['name']
- if dir == 'source' and not n.find('key'):
- n['key'] = str(block._source_count)
- block._source_count += 1
- if dir == 'sink' and not n.find('key'):
- n['key'] = str(block._sink_count)
- block._sink_count += 1
- #build the port
- _Port.__init__(
- self,
- block=block,
- n=n,
- dir=dir,
- )
- _GUIPort.__init__(self)
- self._nports = n.find('nports') or ''
- self._vlen = n.find('vlen') or ''
- self._optional = bool(n.find('optional'))
-
- def get_types(self): return Constants.TYPE_TO_SIZEOF.keys()
-
- def is_type_empty(self): return not self._n['type']
-
- def validate(self):
- _Port.validate(self)
- if not self.get_enabled_connections() and not self.get_optional():
- self.add_error_message('Port is not connected.')
- if not self.is_source() and (not self.get_type() == "message") and len(self.get_enabled_connections()) > 1:
- self.add_error_message('Port has too many connections.')
- #message port logic
- if self.get_type() == 'msg':
- if self.get_nports():
- self.add_error_message('A port of type "msg" cannot have "nports" set.')
- if self.get_vlen() != 1:
- self.add_error_message('A port of type "msg" must have a "vlen" of 1.')
-
- def rewrite(self):
- """
- Handle the port cloning for virtual blocks.
- """
- _Port.rewrite(self)
- if self.is_type_empty():
- try: #clone type and vlen
- source = self.resolve_empty_type()
- self._type = str(source.get_type())
- self._vlen = str(source.get_vlen())
- except: #reset type and vlen
- self._type = ''
- self._vlen = ''
-
- def resolve_virtual_source(self):
- if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self)
- if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self)
-
- def resolve_empty_type(self):
- if self.is_sink():
- try:
- src = _get_source_from_virtual_sink_port(self)
- if not src.is_type_empty(): return src
- except: pass
- sink = _get_sink_from_virtual_sink_port(self)
- if not sink.is_type_empty(): return sink
- if self.is_source():
- try:
- src = _get_source_from_virtual_source_port(self)
- if not src.is_type_empty(): return src
- except: pass
- sink = _get_sink_from_virtual_source_port(self)
- if not sink.is_type_empty(): return sink
-
- def get_vlen(self):
- """
- Get the vector length.
- If the evaluation of vlen cannot be cast to an integer, return 1.
-
- Returns:
- the vector length or 1
- """
- vlen = self.get_parent().resolve_dependencies(self._vlen)
- try: return int(self.get_parent().get_parent().evaluate(vlen))
- except: return 1
-
- def get_nports(self):
- """
- Get the number of ports.
- If already blank, return a blank
- If the evaluation of nports cannot be cast to an integer, return 1.
-
- Returns:
- the number of ports or 1
- """
- nports = self.get_parent().resolve_dependencies(self._nports)
- #return blank if nports is blank
- if not nports: return ''
- try:
- nports = int(self.get_parent().get_parent().evaluate(nports))
- if 0 < nports: return nports
- except: return 1
-
- def get_optional(self): return bool(self._optional)
-
- def get_color(self):
- """
- Get the color that represents this port's type.
- Codes differ for ports where the vec length is 1 or greater than 1.
-
- Returns:
- a hex color code.
- """
- try:
- color = Constants.TYPE_TO_COLOR[self.get_type()]
- vlen = self.get_vlen()
- if vlen == 1: return color
- color_val = int(color[1:], 16)
- r = (color_val >> 16) & 0xff
- g = (color_val >> 8) & 0xff
- b = (color_val >> 0) & 0xff
- dark = (0, 0, 30, 50, 70)[min(4, vlen)]
- r = max(r-dark, 0)
- g = max(g-dark, 0)
- b = max(b-dark, 0)
- return '#%.2x%.2x%.2x'%(r, g, b)
- except: return _Port.get_color(self)
-
- def copy(self, new_key=None):
- n = self._n.copy()
- #remove nports from the key so the copy cannot be a duplicator
- if n.has_key('nports'): n.pop('nports')
- if new_key: n['key'] = new_key
- return self.__class__(self.get_parent(), n, self._dir)
+ def __init__(self, block, n, dir):
+ """
+ Make a new port from nested data.
+
+ Args:
+ block: the parent element
+ n: the nested odict
+ dir: the direction
+ """
+ self._n = n
+ if n['type'] == 'msg': n['key'] = 'msg'
+ if n['type'] == 'message': n['key'] = n['name']
+ if dir == 'source' and not n.find('key'):
+ n['key'] = str(block._source_count)
+ block._source_count += 1
+ if dir == 'sink' and not n.find('key'):
+ n['key'] = str(block._sink_count)
+ block._sink_count += 1
+ #build the port
+ _Port.__init__(
+ self,
+ block=block,
+ n=n,
+ dir=dir,
+ )
+ _GUIPort.__init__(self)
+ self._nports = n.find('nports') or ''
+ self._vlen = n.find('vlen') or ''
+ self._optional = bool(n.find('optional'))
+
+ def get_types(self): return Constants.TYPE_TO_SIZEOF.keys()
+
+ def is_type_empty(self): return not self._n['type']
+
+ def validate(self):
+ _Port.validate(self)
+ if not self.get_enabled_connections() and not self.get_optional():
+ self.add_error_message('Port is not connected.')
+ if not self.is_source() and (not self.get_type() == "message") and len(self.get_enabled_connections()) > 1:
+ self.add_error_message('Port has too many connections.')
+ #message port logic
+ if self.get_type() == 'msg':
+ if self.get_nports():
+ self.add_error_message('A port of type "msg" cannot have "nports" set.')
+ if self.get_vlen() != 1:
+ self.add_error_message('A port of type "msg" must have a "vlen" of 1.')
+
+ def rewrite(self):
+ """
+ Handle the port cloning for virtual blocks.
+ """
+ _Port.rewrite(self)
+ if self.is_type_empty():
+ try: #clone type and vlen
+ source = self.resolve_empty_type()
+ self._type = str(source.get_type())
+ self._vlen = str(source.get_vlen())
+ except: #reset type and vlen
+ self._type = ''
+ self._vlen = ''
+
+ def resolve_virtual_source(self):
+ if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self)
+ if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self)
+
+ def resolve_empty_type(self):
+ if self.is_sink():
+ try:
+ src = _get_source_from_virtual_sink_port(self)
+ if not src.is_type_empty(): return src
+ except: pass
+ sink = _get_sink_from_virtual_sink_port(self)
+ if not sink.is_type_empty(): return sink
+ if self.is_source():
+ try:
+ src = _get_source_from_virtual_source_port(self)
+ if not src.is_type_empty(): return src
+ except: pass
+ sink = _get_sink_from_virtual_source_port(self)
+ if not sink.is_type_empty(): return sink
+
+ def get_vlen(self):
+ """
+ Get the vector length.
+ If the evaluation of vlen cannot be cast to an integer, return 1.
+
+ Returns:
+ the vector length or 1
+ """
+ vlen = self.get_parent().resolve_dependencies(self._vlen)
+ try: return int(self.get_parent().get_parent().evaluate(vlen))
+ except: return 1
+
+ def get_nports(self):
+ """
+ Get the number of ports.
+ If already blank, return a blank
+ If the evaluation of nports cannot be cast to an integer, return 1.
+
+ Returns:
+ the number of ports or 1
+ """
+ nports = self.get_parent().resolve_dependencies(self._nports)
+ #return blank if nports is blank
+ if not nports: return ''
+ try:
+ nports = int(self.get_parent().get_parent().evaluate(nports))
+ if 0 < nports: return nports
+ except: return 1
+
+ def get_optional(self): return bool(self._optional)
+
+ def get_color(self):
+ """
+ Get the color that represents this port's type.
+ Codes differ for ports where the vec length is 1 or greater than 1.
+
+ Returns:
+ a hex color code.
+ """
+ try:
+ color = Constants.TYPE_TO_COLOR[self.get_type()]
+ vlen = self.get_vlen()
+ if vlen == 1: return color
+ color_val = int(color[1:], 16)
+ r = (color_val >> 16) & 0xff
+ g = (color_val >> 8) & 0xff
+ b = (color_val >> 0) & 0xff
+ dark = (0, 0, 30, 50, 70)[min(4, vlen)]
+ r = max(r-dark, 0)
+ g = max(g-dark, 0)
+ b = max(b-dark, 0)
+ return '#%.2x%.2x%.2x'%(r, g, b)
+ except: return _Port.get_color(self)
+
+ def copy(self, new_key=None):
+ n = self._n.copy()
+ #remove nports from the key so the copy cannot be a duplicator
+ if n.has_key('nports'): n.pop('nports')
+ if new_key: n['key'] = new_key
+ return self.__class__(self.get_parent(), n, self._dir)
diff --git a/grc/python/block.dtd b/grc/python/block.dtd
index 292ea06cb6..21ffbe09af 100644
--- a/grc/python/block.dtd
+++ b/grc/python/block.dtd
@@ -17,25 +17,25 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-->
<!--
- gnuradio_python.blocks.dtd
- Josh Blum
- The document type definition for blocks.
+ gnuradio_python.blocks.dtd
+ Josh Blum
+ The document type definition for blocks.
-->
<!--
- Top level element.
- A block contains a name, ...parameters list, and list of IO ports.
+ Top level element.
+ A block contains a name, ...parameters list, and list of IO ports.
-->
-<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, check*, sink*, source*, doc?, grc_source?)>
+<!ELEMENT block (name, key, category?, throttle?, import*, var_make?, make, callback*, param*, bus_sink?, bus_source?, check*, sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)>
<!--
- Sub level elements.
+ Sub level elements.
-->
<!ELEMENT param (name, key, value?, type, hide?, option*)>
<!ELEMENT option (name, key, opt*)>
<!ELEMENT sink (name, type, vlen?, nports?, optional?)>
<!ELEMENT source (name, type, vlen?, nports?, optional?)>
<!--
- Bottom level elements.
- Character data only.
+ Bottom level elements.
+ Character data only.
-->
<!ELEMENT category (#PCDATA)>
<!ELEMENT import (#PCDATA)>
@@ -44,11 +44,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
<!ELEMENT name (#PCDATA)>
<!ELEMENT key (#PCDATA)>
<!ELEMENT check (#PCDATA)>
+<!ELEMENT bus_sink (#PCDATA)>
+<!ELEMENT bus_source (#PCDATA)>
<!ELEMENT opt (#PCDATA)>
<!ELEMENT type (#PCDATA)>
<!ELEMENT hide (#PCDATA)>
<!ELEMENT vlen (#PCDATA)>
<!ELEMENT nports (#PCDATA)>
+<!ELEMENT bus_structure_sink (#PCDATA)>
+<!ELEMENT bus_structure_source (#PCDATA)>
<!ELEMENT var_make (#PCDATA)>
<!ELEMENT make (#PCDATA)>
<!ELEMENT value (#PCDATA)>
diff --git a/grc/python/convert_hier.py b/grc/python/convert_hier.py
index 508ec63b2b..dc86daa0ef 100644
--- a/grc/python/convert_hier.py
+++ b/grc/python/convert_hier.py
@@ -22,77 +22,89 @@ from .. base import ParseXML
from .. base import odict
def convert_hier(flow_graph, python_file):
- #extract info from the flow graph
- input_sigs = flow_graph.get_io_signaturev('in')
- output_sigs = flow_graph.get_io_signaturev('out')
- input_msgp = flow_graph.get_msg_pad_sources();
- output_msgp = flow_graph.get_msg_pad_sinks();
- parameters = flow_graph.get_parameters()
- block_key = flow_graph.get_option('id')
- block_name = flow_graph.get_option('title') or flow_graph.get_option('id').replace('_', ' ').title()
- block_category = flow_graph.get_option('category')
- block_desc = flow_graph.get_option('description')
- block_author = flow_graph.get_option('author')
- #build the nested data
- block_n = odict()
- block_n['name'] = block_name
- block_n['key'] = block_key
- block_n['category'] = block_category
- block_n['import'] = 'execfile("%s")'%python_file
- #make data
- if parameters: block_n['make'] = '%s(\n\t%s,\n)'%(
- block_key,
- ',\n\t'.join(['%s=$%s'%(param.get_id(), param.get_id()) for param in parameters]),
- )
- else: block_n['make'] = '%s()'%block_key
- #callback data
- block_n['callback'] = ['set_%s($%s)'%(param.get_id(), param.get_id()) for param in parameters]
- #param data
- params_n = list()
- for param in parameters:
- param_n = odict()
- param_n['name'] = param.get_param('label').get_value() or param.get_id()
- param_n['key'] = param.get_id()
- param_n['value'] = param.get_param('value').get_value()
- param_n['type'] = 'raw'
- params_n.append(param_n)
- block_n['param'] = params_n
- #sink data stream ports
- block_n['sink'] = list()
- for input_sig in input_sigs:
- sink_n = odict()
- sink_n['name'] = input_sig['label']
- sink_n['type'] = input_sig['type']
- sink_n['vlen'] = input_sig['vlen']
- if input_sig['optional']: sink_n['optional'] = '1'
- block_n['sink'].append(sink_n)
- #sink data msg ports
- for input_sig in input_msgp:
- sink_n = odict()
- sink_n['name'] = input_sig.get_param("label").get_value();
- sink_n['type'] = "message"
- sink_n['optional'] = input_sig.get_param("optional").get_value();
- block_n['sink'].append(sink_n)
- #source data stream ports
- block_n['source'] = list()
- for output_sig in output_sigs:
- source_n = odict()
- source_n['name'] = output_sig['label']
- source_n['type'] = output_sig['type']
- source_n['vlen'] = output_sig['vlen']
- if output_sig['optional']: source_n['optional'] = '1'
- block_n['source'].append(source_n)
- #source data msg ports
- for output_sig in output_msgp:
- source_n = odict()
- source_n['name'] = output_sig.get_param("label").get_value();
- source_n['type'] = "message"
- source_n['optional'] = output_sig.get_param("optional").get_value();
- block_n['source'].append(source_n)
- #doc data
- block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file)
- block_n['grc_source'] = "%s"%(flow_graph.grc_file_path)
- #write the block_n to file
- xml_file = python_file + '.xml'
- ParseXML.to_file({'block': block_n}, xml_file)
- ParseXML.validate_dtd(xml_file, BLOCK_DTD)
+ #extract info from the flow graph
+ input_sigs = flow_graph.get_io_signaturev('in')
+ output_sigs = flow_graph.get_io_signaturev('out')
+ input_msgp = flow_graph.get_msg_pad_sources();
+ output_msgp = flow_graph.get_msg_pad_sinks();
+ parameters = flow_graph.get_parameters()
+ bussink = flow_graph.get_bussink()
+ bussrc = flow_graph.get_bussrc()
+ bus_struct_sink = flow_graph.get_bus_structure_sink()
+ bus_struct_src = flow_graph.get_bus_structure_src()
+ block_key = flow_graph.get_option('id')
+ block_name = flow_graph.get_option('title') or flow_graph.get_option('id').replace('_', ' ').title()
+ block_category = flow_graph.get_option('category')
+ block_desc = flow_graph.get_option('description')
+ block_author = flow_graph.get_option('author')
+ #build the nested data
+ block_n = odict()
+ block_n['name'] = block_name
+ block_n['key'] = block_key
+ block_n['category'] = block_category
+ block_n['import'] = 'execfile("%s")'%python_file
+ #make data
+ if parameters: block_n['make'] = '%s(\n %s,\n)'%(
+ block_key,
+ ',\n '.join(['%s=$%s'%(param.get_id(), param.get_id()) for param in parameters]),
+ )
+ else: block_n['make'] = '%s()'%block_key
+ #callback data
+ block_n['callback'] = ['set_%s($%s)'%(param.get_id(), param.get_id()) for param in parameters]
+ #param data
+ params_n = list()
+ for param in parameters:
+ param_n = odict()
+ param_n['name'] = param.get_param('label').get_value() or param.get_id()
+ param_n['key'] = param.get_id()
+ param_n['value'] = param.get_param('value').get_value()
+ param_n['type'] = 'raw'
+ params_n.append(param_n)
+ block_n['param'] = params_n
+ #sink data stream ports
+ if bussink:
+ block_n['bus_sink'] = '1';
+ if bussrc:
+ block_n['bus_source'] = '1';
+ block_n['sink'] = list()
+ for input_sig in input_sigs:
+ sink_n = odict()
+ sink_n['name'] = input_sig['label']
+ sink_n['type'] = input_sig['type']
+ sink_n['vlen'] = input_sig['vlen']
+ if input_sig['optional']: sink_n['optional'] = '1'
+ block_n['sink'].append(sink_n)
+ #sink data msg ports
+ for input_sig in input_msgp:
+ sink_n = odict()
+ sink_n['name'] = input_sig.get_param("label").get_value();
+ sink_n['type'] = "message"
+ sink_n['optional'] = input_sig.get_param("optional").get_value();
+ block_n['sink'].append(sink_n)
+ #source data stream ports
+ block_n['source'] = list()
+ if bus_struct_sink:
+ block_n['bus_structure_sink'] = bus_struct_sink[0].get_param('struct').get_value();
+ if bus_struct_src:
+ block_n['bus_structure_source'] = bus_struct_src[0].get_param('struct').get_value();
+ for output_sig in output_sigs:
+ source_n = odict()
+ source_n['name'] = output_sig['label']
+ source_n['type'] = output_sig['type']
+ source_n['vlen'] = output_sig['vlen']
+ if output_sig['optional']: source_n['optional'] = '1'
+ block_n['source'].append(source_n)
+ #source data msg ports
+ for output_sig in output_msgp:
+ source_n = odict()
+ source_n['name'] = output_sig.get_param("label").get_value();
+ source_n['type'] = "message"
+ source_n['optional'] = output_sig.get_param("optional").get_value();
+ block_n['source'].append(source_n)
+ #doc data
+ block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file)
+ block_n['grc_source'] = "%s"%(flow_graph.grc_file_path)
+ #write the block_n to file
+ xml_file = python_file + '.xml'
+ ParseXML.to_file({'block': block_n}, xml_file)
+ ParseXML.validate_dtd(xml_file, BLOCK_DTD)
diff --git a/grc/python/default_flow_graph.grc b/grc/python/default_flow_graph.grc
index dea26f3a5e..53d39e885a 100644
--- a/grc/python/default_flow_graph.grc
+++ b/grc/python/default_flow_graph.grc
@@ -2,42 +2,42 @@
<!--
###################################################
##Default Flow Graph:
-## include an options block and a variable for sample rate
+## include an options block and a variable for sample rate
###################################################
-->
<flow_graph>
- <block>
- <key>options</key>
- <param>
- <key>id</key>
- <value>top_block</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(10, 10)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable</key>
- <param>
- <key>id</key>
- <value>samp_rate</value>
- </param>
- <param>
- <key>value</key>
- <value>32000</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(10, 170)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>top_block</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 10)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>32000</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(10, 170)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
</flow_graph>
diff --git a/grc/python/expr_utils.py b/grc/python/expr_utils.py
index 67580f6ffc..85f420f04c 100644
--- a/grc/python/expr_utils.py
+++ b/grc/python/expr_utils.py
@@ -21,157 +21,157 @@ import string
VAR_CHARS = string.letters + string.digits + '_'
class graph(object):
- """
- Simple graph structure held in a dictionary.
- """
+ """
+ Simple graph structure held in a dictionary.
+ """
- def __init__(self): self._graph = dict()
+ def __init__(self): self._graph = dict()
- def __str__(self): return str(self._graph)
+ def __str__(self): return str(self._graph)
- def add_node(self, node_key):
- if self._graph.has_key(node_key): return
- self._graph[node_key] = set()
+ def add_node(self, node_key):
+ if self._graph.has_key(node_key): return
+ self._graph[node_key] = set()
- def remove_node(self, node_key):
- if not self._graph.has_key(node_key): return
- for edges in self._graph.values():
- if node_key in edges: edges.remove(node_key)
- self._graph.pop(node_key)
+ def remove_node(self, node_key):
+ if not self._graph.has_key(node_key): return
+ for edges in self._graph.values():
+ if node_key in edges: edges.remove(node_key)
+ self._graph.pop(node_key)
- def add_edge(self, src_node_key, dest_node_key):
- self._graph[src_node_key].add(dest_node_key)
+ def add_edge(self, src_node_key, dest_node_key):
+ self._graph[src_node_key].add(dest_node_key)
- def remove_edge(self, src_node_key, dest_node_key):
- self._graph[src_node_key].remove(dest_node_key)
+ def remove_edge(self, src_node_key, dest_node_key):
+ self._graph[src_node_key].remove(dest_node_key)
- def get_nodes(self): return self._graph.keys()
+ def get_nodes(self): return self._graph.keys()
- def get_edges(self, node_key): return self._graph[node_key]
+ def get_edges(self, node_key): return self._graph[node_key]
def expr_split(expr):
- """
- Split up an expression by non alphanumeric characters, including underscore.
- Leave strings in-tact.
- #TODO ignore escaped quotes, use raw strings.
-
- Args:
- expr: an expression string
-
- Returns:
- a list of string tokens that form expr
- """
- toks = list()
- tok = ''
- quote = ''
- for char in expr:
- if quote or char in VAR_CHARS:
- if char == quote: quote = ''
- tok += char
- elif char in ("'", '"'):
- toks.append(tok)
- tok = char
- quote = char
- else:
- toks.append(tok)
- toks.append(char)
- tok = ''
- toks.append(tok)
- return filter(lambda t: t, toks)
+ """
+ Split up an expression by non alphanumeric characters, including underscore.
+ Leave strings in-tact.
+ #TODO ignore escaped quotes, use raw strings.
+
+ Args:
+ expr: an expression string
+
+ Returns:
+ a list of string tokens that form expr
+ """
+ toks = list()
+ tok = ''
+ quote = ''
+ for char in expr:
+ if quote or char in VAR_CHARS:
+ if char == quote: quote = ''
+ tok += char
+ elif char in ("'", '"'):
+ toks.append(tok)
+ tok = char
+ quote = char
+ else:
+ toks.append(tok)
+ toks.append(char)
+ tok = ''
+ toks.append(tok)
+ return filter(lambda t: t, toks)
def expr_replace(expr, replace_dict):
- """
- Search for vars in the expression and add the prepend.
-
- Args:
- expr: an expression string
- replace_dict: a dict of find:replace
-
- Returns:
- a new expression with the prepend
- """
- expr_splits = expr_split(expr)
- for i, es in enumerate(expr_splits):
- if es in replace_dict.keys():
- expr_splits[i] = replace_dict[es]
- return ''.join(expr_splits)
+ """
+ Search for vars in the expression and add the prepend.
+
+ Args:
+ expr: an expression string
+ replace_dict: a dict of find:replace
+
+ Returns:
+ a new expression with the prepend
+ """
+ expr_splits = expr_split(expr)
+ for i, es in enumerate(expr_splits):
+ if es in replace_dict.keys():
+ expr_splits[i] = replace_dict[es]
+ return ''.join(expr_splits)
def get_variable_dependencies(expr, vars):
- """
- Return a set of variables used in this expression.
-
- Args:
- expr: an expression string
- vars: a list of variable names
-
- Returns:
- a subset of vars used in the expression
- """
- expr_toks = expr_split(expr)
- return set(filter(lambda v: v in expr_toks, vars))
+ """
+ Return a set of variables used in this expression.
+
+ Args:
+ expr: an expression string
+ vars: a list of variable names
+
+ Returns:
+ a subset of vars used in the expression
+ """
+ expr_toks = expr_split(expr)
+ return set(filter(lambda v: v in expr_toks, vars))
def get_graph(exprs):
- """
- Get a graph representing the variable dependencies
-
- Args:
- exprs: a mapping of variable name to expression
-
- Returns:
- a graph of variable deps
- """
- vars = exprs.keys()
- #get dependencies for each expression, load into graph
- var_graph = graph()
- for var in vars: var_graph.add_node(var)
- for var, expr in exprs.iteritems():
- for dep in get_variable_dependencies(expr, vars):
- if dep != var: var_graph.add_edge(dep, var)
- return var_graph
+ """
+ Get a graph representing the variable dependencies
+
+ Args:
+ exprs: a mapping of variable name to expression
+
+ Returns:
+ a graph of variable deps
+ """
+ vars = exprs.keys()
+ #get dependencies for each expression, load into graph
+ var_graph = graph()
+ for var in vars: var_graph.add_node(var)
+ for var, expr in exprs.iteritems():
+ for dep in get_variable_dependencies(expr, vars):
+ if dep != var: var_graph.add_edge(dep, var)
+ return var_graph
def sort_variables(exprs):
- """
- Get a list of variables in order of dependencies.
-
- Args:
- exprs: a mapping of variable name to expression
-
- Returns:
- a list of variable names
- @throws Exception circular dependencies
- """
- var_graph = get_graph(exprs)
- sorted_vars = list()
- #determine dependency order
- while var_graph.get_nodes():
- #get a list of nodes with no edges
- indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes())
- if not indep_vars: raise Exception('circular dependency caught in sort_variables')
- #add the indep vars to the end of the list
- sorted_vars.extend(sorted(indep_vars))
- #remove each edge-less node from the graph
- for var in indep_vars: var_graph.remove_node(var)
- return reversed(sorted_vars)
+ """
+ Get a list of variables in order of dependencies.
+
+ Args:
+ exprs: a mapping of variable name to expression
+
+ Returns:
+ a list of variable names
+ @throws Exception circular dependencies
+ """
+ var_graph = get_graph(exprs)
+ sorted_vars = list()
+ #determine dependency order
+ while var_graph.get_nodes():
+ #get a list of nodes with no edges
+ indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes())
+ if not indep_vars: raise Exception('circular dependency caught in sort_variables')
+ #add the indep vars to the end of the list
+ sorted_vars.extend(sorted(indep_vars))
+ #remove each edge-less node from the graph
+ for var in indep_vars: var_graph.remove_node(var)
+ return reversed(sorted_vars)
def sort_objects(objects, get_id, get_expr):
- """
- Sort a list of objects according to their expressions.
-
- Args:
- objects: the list of objects to sort
- get_id: the function to extract an id from the object
- get_expr: the function to extract an expression from the object
-
- Returns:
- a list of sorted objects
- """
- id2obj = dict([(get_id(obj), obj) for obj in objects])
- #map obj id to expression code
- id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects])
- #sort according to dependency
- sorted_ids = sort_variables(id2expr)
- #return list of sorted objects
- return [id2obj[id] for id in sorted_ids]
+ """
+ Sort a list of objects according to their expressions.
+
+ Args:
+ objects: the list of objects to sort
+ get_id: the function to extract an id from the object
+ get_expr: the function to extract an expression from the object
+
+ Returns:
+ a list of sorted objects
+ """
+ id2obj = dict([(get_id(obj), obj) for obj in objects])
+ #map obj id to expression code
+ id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects])
+ #sort according to dependency
+ sorted_ids = sort_variables(id2expr)
+ #return list of sorted objects
+ return [id2obj[id] for id in sorted_ids]
if __name__ == '__main__':
- for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i
+ for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i
diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py
index 1d1c738dcc..b3b87e64ca 100644
--- a/grc/python/extract_docs.py
+++ b/grc/python/extract_docs.py
@@ -20,55 +20,55 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import re
def _extract(key):
- """
- Extract the documentation from the python __doc__ strings.
- If multiple modules match, combine the docs.
-
- Args:
- key: the block key
-
- Returns:
- a string with documentation
- """
- #extract matches
- try:
- module_name, constructor_name = key.split('_', 1)
- module = __import__('gnuradio.'+module_name)
- module = getattr(module, module_name)
- except ImportError:
- try:
- module_name, constructor_name = key.split('_', 1)
- module = __import__(module_name)
- except: return ''
- except:
- return ''
- pattern = constructor_name.replace('_', '_*').replace('x', '\w')
- pattern_matcher = re.compile('^%s\w*$'%pattern)
- matches = filter(lambda x: pattern_matcher.match(x), dir(module))
- #combine all matches
- doc_strs = list()
- for match in matches:
- try:
- title = ' --- ' + match + ' --- '
- doc_strs.append('\n\n'.join([title, getattr(module, match).__doc__]).strip())
- except: pass
- return '\n\n'.join(doc_strs)
+ """
+ Extract the documentation from the python __doc__ strings.
+ If multiple modules match, combine the docs.
+
+ Args:
+ key: the block key
+
+ Returns:
+ a string with documentation
+ """
+ #extract matches
+ try:
+ module_name, constructor_name = key.split('_', 1)
+ module = __import__('gnuradio.'+module_name)
+ module = getattr(module, module_name)
+ except ImportError:
+ try:
+ module_name, constructor_name = key.split('_', 1)
+ module = __import__(module_name)
+ except: return ''
+ except:
+ return ''
+ pattern = constructor_name.replace('_', '_*').replace('x', '\w')
+ pattern_matcher = re.compile('^%s\w*$'%pattern)
+ matches = filter(lambda x: pattern_matcher.match(x), dir(module))
+ #combine all matches
+ doc_strs = list()
+ for match in matches:
+ try:
+ title = ' --- ' + match + ' --- '
+ doc_strs.append('\n\n'.join([title, getattr(module, match).__doc__]).strip())
+ except: pass
+ return '\n\n'.join(doc_strs)
_docs_cache = dict()
def extract(key):
- """
- Call the private extract and cache the result.
-
- Args:
- key: the block key
-
- Returns:
- a string with documentation
- """
- if not _docs_cache.has_key(key):
- _docs_cache[key] = _extract(key)
- return _docs_cache[key]
+ """
+ Call the private extract and cache the result.
+
+ Args:
+ key: the block key
+
+ Returns:
+ a string with documentation
+ """
+ if not _docs_cache.has_key(key):
+ _docs_cache[key] = _extract(key)
+ return _docs_cache[key]
if __name__ == '__main__':
- import sys
- print extract(sys.argv[1])
+ import sys
+ print extract(sys.argv[1])
diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl
index d104d4913d..cf789233ec 100644
--- a/grc/python/flow_graph.tmpl
+++ b/grc/python/flow_graph.tmpl
@@ -13,7 +13,7 @@
##@param var_id2cbs variable id map to callback strings
########################################################
#def indent($code)
-#set $code = '\n\t\t'.join(str($code).splitlines())
+#set $code = '\n '.join(str($code).splitlines())
$code#slurp
#end def
#import time
@@ -39,304 +39,310 @@ $imp
########################################################
##Create Class
-## Write the class declaration for a top or hier block.
-## The parameter names are the arguments to __init__.
-## Determine the absolute icon path (wx gui only).
-## Setup the IO signature (hier block only).
+## Write the class declaration for a top or hier block.
+## The parameter names are the arguments to __init__.
+## Determine the absolute icon path (wx gui only).
+## Setup the IO signature (hier block only).
########################################################
#set $class_name = $flow_graph.get_option('id')
#set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters])
#if $generate_options == 'wx_gui'
- #import gtk
- #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0)
+ #import gtk
+ #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0)
class $(class_name)(grc_wxgui.top_block_gui):
- def __init__($param_str):
- grc_wxgui.top_block_gui.__init__(self, title="$title")
- #if $icon
- _icon_path = "$icon.get_filename()"
- self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))
- #end if
+ def __init__($param_str):
+ grc_wxgui.top_block_gui.__init__(self, title="$title")
+ #if $icon
+ _icon_path = "$icon.get_filename()"
+ self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))
+ #end if
#elif $generate_options == 'qt_gui'
class $(class_name)(gr.top_block, Qt.QWidget):
- def __init__($param_str):
- gr.top_block.__init__(self, "$title")
- Qt.QWidget.__init__(self)
- self.setWindowTitle("$title")
- try:
- self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
- except:
- pass
- self.top_scroll_layout = Qt.QVBoxLayout()
- self.setLayout(self.top_scroll_layout)
- self.top_scroll = Qt.QScrollArea()
- self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
- self.top_scroll_layout.addWidget(self.top_scroll)
- self.top_scroll.setWidgetResizable(True)
- self.top_widget = Qt.QWidget()
- self.top_scroll.setWidget(self.top_widget)
- self.top_layout = Qt.QVBoxLayout(self.top_widget)
- self.top_grid_layout = Qt.QGridLayout()
- self.top_layout.addLayout(self.top_grid_layout)
+ def __init__($param_str):
+ gr.top_block.__init__(self, "$title")
+ Qt.QWidget.__init__(self)
+ self.setWindowTitle("$title")
+ try:
+ self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
+ except:
+ pass
+ self.top_scroll_layout = Qt.QVBoxLayout()
+ self.setLayout(self.top_scroll_layout)
+ self.top_scroll = Qt.QScrollArea()
+ self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
+ self.top_scroll_layout.addWidget(self.top_scroll)
+ self.top_scroll.setWidgetResizable(True)
+ self.top_widget = Qt.QWidget()
+ self.top_scroll.setWidget(self.top_widget)
+ self.top_layout = Qt.QVBoxLayout(self.top_widget)
+ self.top_grid_layout = Qt.QGridLayout()
+ self.top_layout.addLayout(self.top_grid_layout)
- self.settings = Qt.QSettings("GNU Radio", "$class_name")
- self.restoreGeometry(self.settings.value("geometry").toByteArray())
+ self.settings = Qt.QSettings("GNU Radio", "$class_name")
+ self.restoreGeometry(self.settings.value("geometry").toByteArray())
#elif $generate_options == 'no_gui'
class $(class_name)(gr.top_block):
- def __init__($param_str):
- gr.top_block.__init__(self, "$title")
+ def __init__($param_str):
+ gr.top_block.__init__(self, "$title")
#elif $generate_options == 'hb'
- #set $in_sigs = $flow_graph.get_io_signaturev('in')
- #set $out_sigs = $flow_graph.get_io_signaturev('out')
+ #set $in_sigs = $flow_graph.get_io_signaturev('in')
+ #set $out_sigs = $flow_graph.get_io_signaturev('out')
class $(class_name)(gr.hier_block2):
#def make_io_sig($io_sigs)
- #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs]
- #if len($io_sigs) == 0
+ #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs]
+ #if len($io_sigs) == 0
gr.io_signature(0, 0, 0)#slurp
- #elif len($io_sigs) == 1
+ #elif len($io_sigs) == 1
gr.io_signature(1, 1, $size_strs[0])#slurp
- #else
+ #else
gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])#slurp
- #end if
+ #end if
#end def
- def __init__($param_str):
- gr.hier_block2.__init__(
- self, "$title",
- $make_io_sig($in_sigs),
- $make_io_sig($out_sigs),
- )
+ def __init__($param_str):
+ gr.hier_block2.__init__(
+ self, "$title",
+ $make_io_sig($in_sigs),
+ $make_io_sig($out_sigs),
+ )
#end if
########################################################
##Create Parameters
-## Set the parameter to a property of self.
+## Set the parameter to a property of self.
########################################################
#if $parameters
- $DIVIDER
- # Parameters
- $DIVIDER
+ $DIVIDER
+ # Parameters
+ $DIVIDER
#end if
#for $param in $parameters
- $indent($param.get_var_make())
+ $indent($param.get_var_make())
#end for
########################################################
##Create Variables
########################################################
#if $variables
- $DIVIDER
- # Variables
- $DIVIDER
+ $DIVIDER
+ # Variables
+ $DIVIDER
#end if
#for $var in $variables
- $indent($var.get_var_make())
+ $indent($var.get_var_make())
#end for
########################################################
##Create Message Queues
########################################################
#if $messages
- $DIVIDER
- # Message Queues
- $DIVIDER
+ $DIVIDER
+ # Message Queues
+ $DIVIDER
#end if
#for $msg in $messages
- $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2)
+ $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2)
#end for
########################################################
##Create Blocks
########################################################
#if $blocks
- $DIVIDER
- # Blocks
- $DIVIDER
+ $DIVIDER
+ # Blocks
+ $DIVIDER
#end if
#for $blk in filter(lambda b: b.get_make(), $blocks)
- #if $blk in $variables
- $indent($blk.get_make())
- #else
- self.$blk.get_id() = $indent($blk.get_make())
- #end if
+ #if $blk in $variables
+ $indent($blk.get_make())
+ #else
+ self.$blk.get_id() = $indent($blk.get_make())
+ #if $blk.has_param('affinity') and $blk.get_param('affinity').get_value()
+ (self.$blk.get_id()).set_processor_affinity($blk.get_param('affinity').get_value())
+ #end if
+ #if (len($blk.get_sources())>0) and $blk.has_param('affinity') and (int($blk.get_param('minoutbuf').get_value()) > 0)
+ (self.$blk.get_id()).set_min_output_buffer($blk.get_param('minoutbuf').get_value())
+ #end if
+ #end if
#end for
########################################################
##Create Connections
-## The port name should be the id of the parent block.
-## However, port names for IO pads should be self.
+## The port name should be the id of the parent block.
+## However, port names for IO pads should be self.
########################################################
#def make_port_sig($port)
- #if $port.get_parent().get_key() == 'pad_source'
+ #if $port.get_parent().get_key() == 'pad_source'
(self, $flow_graph.get_pad_sources().index($port.get_parent()))#slurp
- #elif $port.get_parent().get_key() == 'pad_sink'
+ #elif $port.get_parent().get_key() == 'pad_sink'
(self, $flow_graph.get_pad_sinks().index($port.get_parent()))#slurp
- #else
+ #else
(self.$port.get_parent().get_id(), $port.get_key())#slurp
- #end if
+ #end if
#end def
#if $connections
- $DIVIDER
- # Connections
- $DIVIDER
+ $DIVIDER
+ # Connections
+ $DIVIDER
#end if
#for $con in $connections
- #set $source = $con.get_source()
- #set $sink = $con.get_sink()
- ##resolve virtual sources to the actual sources
- #if $source.get_parent().is_virtual_source()
- #set $source = $source.resolve_virtual_source()
- #end if
- ##do not generate connections with virtual sinks
- #if not $sink.get_parent().is_virtual_sink()
- self.connect($make_port_sig($source), $make_port_sig($sink))
- #end if
+ #set $source = $con.get_source()
+ #set $sink = $con.get_sink()
+ ##resolve virtual sources to the actual sources
+ #if $source.get_parent().is_virtual_source()
+ #set $source = $source.resolve_virtual_source()
+ #end if
+ ##do not generate connections with virtual sinks
+ #if not $sink.get_parent().is_virtual_sink()
+ self.connect($make_port_sig($source), $make_port_sig($sink))
+ #end if
#end for
########################################################
##Create Asynch Message Connections
########################################################
#if $messages2
- $DIVIDER
- # Asynch Message Connections
- $DIVIDER
+ $DIVIDER
+ # Asynch Message Connections
+ $DIVIDER
#end if
#for $msg in $messages2
- #set $sr = $msg.get_source()
- #set $source = "self.%s"%($sr.get_parent().get_id())
- #set $source_port = $sr.get_name();
- #if $sr.get_parent().get_key() == "pad_source"
- #set $source = "self"
- #set $source_port = $sr.get_parent().get_param("label").get_value();
- #end if
- #set $sk = $msg.get_sink()
- #set $sink = "self.%s"%($sk.get_parent().get_id())
- #set $sink_port = $sk.get_name();
- #if $sk.get_parent().get_key() == "pad_sink"
- #set $sink = "self"
- #set $sink_port = $sk.get_parent().get_param("label").get_value();
- #end if
- self.msg_connect($source, "$source_port", $sink, "$sink_port")
+ #set $sr = $msg.get_source()
+ #set $source = "self.%s"%($sr.get_parent().get_id())
+ #set $source_port = $sr.get_name();
+ #if $sr.get_parent().get_key() == "pad_source"
+ #set $source = "self"
+ #set $source_port = $sr.get_parent().get_param("label").get_value();
+ #end if
+ #set $sk = $msg.get_sink()
+ #set $sink = "self.%s"%($sk.get_parent().get_id())
+ #set $sink_port = $sk.get_name();
+ #if $sk.get_parent().get_key() == "pad_sink"
+ #set $sink = "self"
+ #set $sink_port = $sk.get_parent().get_param("label").get_value();
+ #end if
+ self.msg_connect($source, "$source_port", $sink, "$sink_port")
#end for
########################################################
# QT sink close method reimplementation
########################################################
#if $generate_options == 'qt_gui'
- def closeEvent(self, event):
- self.settings = Qt.QSettings("GNU Radio", "$class_name")
- self.settings.setValue("geometry", self.saveGeometry())
- event.accept()
+ def closeEvent(self, event):
+ self.settings = Qt.QSettings("GNU Radio", "$class_name")
+ self.settings.setValue("geometry", self.saveGeometry())
+ event.accept()
#end if
########################################################
##Create Callbacks
-## Write a set method for this variable that calls the callbacks
+## Write a set method for this variable that calls the callbacks
########################################################
#for $var in $parameters + $variables
- #set $id = $var.get_id()
- def get_$(id)(self):
- return self.$id
+ #set $id = $var.get_id()
+ def get_$(id)(self):
+ return self.$id
- def set_$(id)(self, $id):
- self.$id = $id
- #for $callback in $var_id2cbs[$id]
- $indent($callback)
- #end for
+ def set_$(id)(self, $id):
+ self.$id = $id
+ #for $callback in $var_id2cbs[$id]
+ $indent($callback)
+ #end for
#end for
########################################################
##Create Main
-## For top block code, generate a main routine.
-## Instantiate the top block and run as gui or cli.
+## For top block code, generate a main routine.
+## Instantiate the top block and run as gui or cli.
########################################################
#def make_default($type, $param)
- #if $type == 'eng_float'
+ #if $type == 'eng_float'
eng_notation.num_to_str($param.get_make())#slurp
- #else
+ #else
$param.get_make()#slurp
- #end if
+ #end if
#end def
#def make_short_id($param)
- #set $short_id = $param.get_param('short_id').get_evaluated()
- #if $short_id
- #set $short_id = '-' + $short_id
- #end if
+ #set $short_id = $param.get_param('short_id').get_evaluated()
+ #if $short_id
+ #set $short_id = '-' + $short_id
+ #end if
$short_id#slurp
#end def
#if $generate_options != 'hb'
if __name__ == '__main__':
- parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
- #set $params_eq_list = list()
- #for $param in $parameters
- #set $type = $param.get_param('type').get_value()
- #if $type
- #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
- parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
- help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
- #end if
- #end for
- (options, args) = parser.parse_args()
- #if $flow_graph.get_option('realtime_scheduling')
- if gr.enable_realtime_scheduling() != gr.RT_OK:
- print "Error: failed to enable realtime scheduling."
- #end if
- #if $generate_options == 'wx_gui'
- tb = $(class_name)($(', '.join($params_eq_list)))
- #if $flow_graph.get_option('max_nouts')
- tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts'))
- #else
- tb.Start($flow_graph.get_option('run'))
+ parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+ #set $params_eq_list = list()
+ #for $param in $parameters
+ #set $type = $param.get_param('type').get_value()
+ #if $type
+ #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
+ parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
+ help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
+ #end if
+ #end for
+ (options, args) = parser.parse_args()
+ #if $flow_graph.get_option('realtime_scheduling')
+ if gr.enable_realtime_scheduling() != gr.RT_OK:
+ print "Error: failed to enable realtime scheduling."
+ #end if
+ #if $generate_options == 'wx_gui'
+ tb = $(class_name)($(', '.join($params_eq_list)))
+ #if $flow_graph.get_option('max_nouts')
+ tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts'))
+ #else
+ tb.Start($flow_graph.get_option('run'))
#for $m in $monitors
- (tb.$m.get_id()).start()
+ (tb.$m.get_id()).start()
#end for
- tb.Wait()
- #end if
- #elif $generate_options == 'qt_gui'
- qapp = Qt.QApplication(sys.argv)
- tb = $(class_name)($(', '.join($params_eq_list)))
- #if $flow_graph.get_option('run')
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
- #end if
- tb.show()
+ tb.Wait()
+ #end if
+ #elif $generate_options == 'qt_gui'
+ qapp = Qt.QApplication(sys.argv)
+ tb = $(class_name)($(', '.join($params_eq_list)))
+ #if $flow_graph.get_option('run')
+ #if $flow_graph.get_option('max_nouts')
+ tb.start($flow_graph.get_option('max_nouts'))
+ #else
+ tb.start()
+ #end if
+ #end if
+ tb.show()
#for $m in $monitors
- (tb.$m.get_id()).start()
+ (tb.$m.get_id()).start()
#end for
- qapp.exec_()
- tb.stop()
- tb = None #to clean up Qt widgets
- #elif $generate_options == 'no_gui'
- tb = $(class_name)($(', '.join($params_eq_list)))
- #set $run_options = $flow_graph.get_option('run_options')
- #if $run_options == 'prompt'
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
+ qapp.exec_()
+ tb.stop()
+ tb = None #to clean up Qt widgets
+ #elif $generate_options == 'no_gui'
+ tb = $(class_name)($(', '.join($params_eq_list)))
+ #set $run_options = $flow_graph.get_option('run_options')
+ #if $run_options == 'prompt'
+ #if $flow_graph.get_option('max_nouts')
+ tb.start($flow_graph.get_option('max_nouts'))
+ #else
+ tb.start()
+ #end if
#for $m in $monitors
- (tb.$m.get_id()).start()
+ (tb.$m.get_id()).start()
#end for
- raw_input('Press Enter to quit: ')
- tb.stop()
- #elif $run_options == 'run'
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
- #end if
+ raw_input('Press Enter to quit: ')
+ tb.stop()
+ #elif $run_options == 'run'
+ #if $flow_graph.get_option('max_nouts')
+ tb.start($flow_graph.get_option('max_nouts'))
+ #else
+ tb.start()
+ #end if
+ #end if
#for $m in $monitors
- (tb.$m.get_id()).start()
+ (tb.$m.get_id()).start()
#end for
- tb.wait()
- #end if
+ tb.wait()
+ #end if
#end if
diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion
index dabca3028f..6d45ecc246 100755
--- a/grc/scripts/gnuradio-companion
+++ b/grc/scripts/gnuradio-companion
@@ -24,36 +24,36 @@ import gtk
try: from gnuradio import gr
except ImportError, e:
- d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format="""
+ d = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, message_format="""
Cannot import gnuradio.
Is the python path environment variable set correctly?
- All OS: PYTHONPATH
+ All OS: PYTHONPATH
Is the library path environment variable set correctly?
- Linux: LD_LIBRARY_PATH
- Windows: PATH
- MacOSX: DYLD_LIBRARY_PATH
+ Linux: LD_LIBRARY_PATH
+ Windows: PATH
+ MacOSX: DYLD_LIBRARY_PATH
""")
- d.set_title(str(e))
- d.run()
- exit(-1)
+ d.set_title(str(e))
+ d.run()
+ exit(-1)
from optparse import OptionParser
import os
if __name__ == "__main__":
- if ('GR_DONT_LOAD_PREFS' in os.environ.keys() and
- (not 'GRC_BLOCKS_PATH' in os.environ.keys() or len(os.environ['GRC_BLOCKS_PATH']) == 0)):
- d = gtk.MessageDialog(
- type=gtk.MESSAGE_ERROR,
- buttons=gtk.BUTTONS_CLOSE,
- message_format="""Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH. """)
- d.set_title("No block definitions available.")
- d.run()
- exit(-1)
- usage = 'usage: %prog [options] [saved flow graphs]'
- version = """
+ if ('GR_DONT_LOAD_PREFS' in os.environ.keys() and
+ (not 'GRC_BLOCKS_PATH' in os.environ.keys() or len(os.environ['GRC_BLOCKS_PATH']) == 0)):
+ d = gtk.MessageDialog(
+ type=gtk.MESSAGE_ERROR,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format="""Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH. """)
+ d.set_title("No block definitions available.")
+ d.run()
+ exit(-1)
+ usage = 'usage: %prog [options] [saved flow graphs]'
+ version = """
GNU Radio Companion %s
This program is part of GNU Radio
@@ -61,12 +61,12 @@ GRC comes with ABSOLUTELY NO WARRANTY.
This is free software,
and you are welcome to redistribute it.
"""%gr.version()
- parser = OptionParser(usage=usage, version=version)
- (options, args) = parser.parse_args()
- from gnuradio.grc.python.Platform import Platform
- from gnuradio.grc.gui.ActionHandler import ActionHandler
- #setup icon using icon theme
- try: gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0))
- except: pass
- ActionHandler(args, Platform())
+ parser = OptionParser(usage=usage, version=version)
+ (options, args) = parser.parse_args()
+ from gnuradio.grc.python.Platform import Platform
+ from gnuradio.grc.gui.ActionHandler import ActionHandler
+ #setup icon using icon theme
+ try: gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0))
+ except: pass
+ ActionHandler(args, Platform())