summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt43
-rw-r--r--cmake/Modules/GnuradioConfig.cmake.in (renamed from cmake/Modules/GnuradioConfig.cmake)4
-rw-r--r--cmake/Modules/GrVersion.cmake8
-rw-r--r--docs/exploring-gnuradio/fm_tx.grc4
-rw-r--r--gnuradio-runtime/apps/gnuradio-config-info.cc10
-rw-r--r--gnuradio-runtime/include/gnuradio/block.h4
-rw-r--r--gnuradio-runtime/include/gnuradio/block_detail.h7
-rw-r--r--gnuradio-runtime/include/gnuradio/buffer.h4
-rw-r--r--gnuradio-runtime/include/gnuradio/prefs.h3
-rw-r--r--gnuradio-runtime/include/gnuradio/sys_paths.h3
-rw-r--r--gnuradio-runtime/lib/block_detail.cc20
-rw-r--r--gnuradio-runtime/lib/flat_flowgraph.cc13
-rw-r--r--gnuradio-runtime/lib/prefs.cc150
-rw-r--r--gnuradio-runtime/lib/sys_paths.cc9
-rwxr-xr-xgr-analog/examples/fmtest.py3
-rw-r--r--gr-analog/grc/analog_block_tree.xml2
-rw-r--r--gr-analog/grc/analog_fm_preemph.xml8
-rw-r--r--gr-analog/grc/analog_nbfm_tx.xml8
-rw-r--r--gr-analog/grc/analog_wfm_tx.xml7
-rw-r--r--gr-analog/lib/CMakeLists.txt11
-rw-r--r--gr-analog/lib/frequency_modulator_fc_impl.cc22
-rw-r--r--gr-analog/lib/frequency_modulator_fc_impl.h2
-rw-r--r--gr-analog/lib/sig_source_X_impl.cc.t32
-rw-r--r--gr-analog/lib/sig_source_X_impl.h.t2
-rw-r--r--gr-analog/python/analog/fm_emph.py254
-rw-r--r--gr-analog/python/analog/nbfm_tx.py5
-rw-r--r--gr-analog/python/analog/wfm_tx.py5
-rw-r--r--gr-audio/grc/audio_sink.xml2
-rw-r--r--gr-audio/grc/audio_source.xml2
-rw-r--r--gr-audio/lib/windows/windows_sink.cc424
-rw-r--r--gr-audio/lib/windows/windows_sink.h13
-rw-r--r--gr-blocks/CMakeLists.txt1
-rw-r--r--gr-blocks/grc/blks2_error_rate.xml (renamed from grc/blocks/blks2_error_rate.xml)1
-rw-r--r--gr-blocks/grc/blks2_selector.xml (renamed from grc/blocks/blks2_selector.xml)1
-rw-r--r--gr-blocks/grc/blks2_tcp_sink.xml (renamed from grc/blocks/blks2_tcp_sink.xml)1
-rw-r--r--gr-blocks/grc/blks2_tcp_source.xml (renamed from grc/blocks/blks2_tcp_source.xml)1
-rw-r--r--gr-blocks/grc/blks2_valve.xml (renamed from grc/blocks/blks2_valve.xml)1
-rw-r--r--gr-blocks/grc/blocks_block_tree.xml6
-rw-r--r--gr-blocks/grc/blocks_repeat.xml1
-rw-r--r--gr-blocks/grc/xmlrpc_client.xml (renamed from grc/blocks/xmlrpc_client.xml)0
-rw-r--r--gr-blocks/grc/xmlrpc_server.xml (renamed from grc/blocks/xmlrpc_server.xml)0
-rw-r--r--gr-blocks/include/gnuradio/blocks/repeat.h18
-rw-r--r--gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t1
-rw-r--r--gr-blocks/include/gnuradio/blocks/vector_source_X.h.t1
-rw-r--r--gr-blocks/lib/repeat_impl.cc20
-rw-r--r--gr-blocks/lib/repeat_impl.h6
-rw-r--r--gr-blocks/lib/tuntap_pdu_impl.cc33
-rw-r--r--gr-blocks/lib/tuntap_pdu_impl.h1
-rw-r--r--gr-blocks/lib/udp_source_impl.cc4
-rw-r--r--gr-blocks/lib/vector_sink_X_impl.h.t2
-rw-r--r--gr-blocks/lib/vector_source_X_impl.h.t1
-rw-r--r--gr-blocks/python/blocks/qa_block_behavior.py79
-rwxr-xr-xgr-blocks/python/blocks/qa_vector_sink_source.py36
-rw-r--r--gr-blocks/python/grc_gnuradio/CMakeLists.txt (renamed from grc/grc_gnuradio/CMakeLists.txt)8
-rw-r--r--gr-blocks/python/grc_gnuradio/README (renamed from grc/grc_gnuradio/README)0
-rw-r--r--gr-blocks/python/grc_gnuradio/__init__.py (renamed from grc/grc_gnuradio/__init__.py)0
-rw-r--r--gr-blocks/python/grc_gnuradio/blks2/__init__.py (renamed from grc/grc_gnuradio/blks2/__init__.py)10
-rw-r--r--gr-blocks/python/grc_gnuradio/blks2/error_rate.py (renamed from grc/grc_gnuradio/blks2/error_rate.py)0
-rw-r--r--gr-blocks/python/grc_gnuradio/blks2/selector.py (renamed from grc/grc_gnuradio/blks2/selector.py)0
-rw-r--r--gr-blocks/python/grc_gnuradio/blks2/tcp.py (renamed from grc/grc_gnuradio/blks2/tcp.py)0
-rw-r--r--gr-channels/grc/channels_block_tree.xml2
-rw-r--r--gr-digital/CMakeLists.txt1
-rw-r--r--gr-digital/grc/blks2_packet_decoder.xml (renamed from grc/blocks/blks2_packet_decoder.xml)2
-rw-r--r--gr-digital/grc/blks2_packet_encoder.xml (renamed from grc/blocks/blks2_packet_encoder.xml)2
-rw-r--r--gr-digital/grc/digital_block_tree.xml2
-rw-r--r--gr-digital/grc/digital_burst_shaper.xml2
-rw-r--r--gr-digital/grc/digital_constellation.xml51
-rw-r--r--gr-digital/grc/digital_header_payload_demux.xml7
-rw-r--r--gr-digital/include/gnuradio/digital/header_payload_demux.h91
-rw-r--r--gr-digital/lib/header_payload_demux_impl.cc670
-rw-r--r--gr-digital/lib/header_payload_demux_impl.h75
-rwxr-xr-xgr-digital/python/digital/qa_correlate_access_code_XX_ts.py90
-rwxr-xr-xgr-digital/python/digital/qa_header_payload_demux.py451
-rw-r--r--gr-digital/python/grc_gnuradio/CMakeLists.txt (renamed from grc/base/CMakeLists.txt)29
-rw-r--r--gr-digital/python/grc_gnuradio/blks2/packet.py (renamed from grc/grc_gnuradio/blks2/packet.py)0
-rw-r--r--gr-dtv/CMakeLists.txt2
-rw-r--r--gr-dtv/examples/CMakeLists.txt27
-rw-r--r--gr-dtv/examples/README.catv31
-rw-r--r--gr-dtv/examples/README.dvbs26
-rwxr-xr-xgr-dtv/examples/atsc_ctrlport_monitor.py149
-rw-r--r--gr-dtv/examples/catv_tx_64qam.grc2079
-rw-r--r--gr-dtv/examples/dvbs2_tx.grc2256
-rw-r--r--gr-dtv/examples/dvbs_tx.grc2853
-rw-r--r--gr-dtv/grc/CMakeLists.txt7
-rw-r--r--gr-dtv/grc/dtv_block_tree.xml12
-rw-r--r--gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml26
-rw-r--r--gr-dtv/grc/dtv_catv_randomizer_bb.xml20
-rw-r--r--gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml20
-rw-r--r--gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml20
-rw-r--r--gr-dtv/grc/dtv_catv_trellis_enc_bb.xml20
-rw-r--r--gr-dtv/grc/dtv_dvbs2_modulator_bc.xml22
-rw-r--r--gr-dtv/include/gnuradio/dtv/CMakeLists.txt7
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_equalizer.h3
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h15
-rw-r--r--gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h6
-rw-r--r--gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h54
-rw-r--r--gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h53
-rw-r--r--gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h53
-rw-r--r--gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h53
-rw-r--r--gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h53
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbs2_config.h6
-rw-r--r--gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h6
-rw-r--r--gr-dtv/lib/CMakeLists.txt7
-rw-r--r--gr-dtv/lib/atsc/atsc_equalizer_impl.cc89
-rw-r--r--gr-dtv/lib/atsc/atsc_equalizer_impl.h7
-rw-r--r--gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc89
-rw-r--r--gr-dtv/lib/atsc/atsc_rs_decoder_impl.h13
-rw-r--r--gr-dtv/lib/atsc/atsc_single_viterbi.cc65
-rw-r--r--gr-dtv/lib/atsc/atsc_single_viterbi.h17
-rw-r--r--gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc25
-rw-r--r--gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h4
-rw-r--r--gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc96
-rw-r--r--gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h50
-rw-r--r--gr-dtv/lib/catv/catv_randomizer_bb_impl.cc104
-rw-r--r--gr-dtv/lib/catv/catv_randomizer_bb_impl.h49
-rw-r--r--gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc153
-rw-r--r--gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h56
-rw-r--r--gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc131
-rw-r--r--gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h84
-rw-r--r--gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc193
-rw-r--r--gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h60
-rw-r--r--gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc272
-rw-r--r--gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h3
-rw-r--r--gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc178
-rw-r--r--gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h21
-rw-r--r--gr-dtv/swig/dtv_swig.i17
-rw-r--r--gr-fcd/grc/fcd_source_c.xml2
-rw-r--r--gr-fec/grc/fec_block_tree.xml2
-rw-r--r--gr-fft/grc/fft_block_tree.xml2
-rwxr-xr-xgr-filter/examples/synth_to_chan.py2
-rw-r--r--gr-filter/grc/filter_block_tree.xml2
-rw-r--r--gr-filter/lib/pfb_decimator_ccf_impl.cc32
-rw-r--r--gr-filter/lib/pfb_decimator_ccf_impl.h6
-rw-r--r--gr-noaa/grc/noaa_hrpt_decoder.xml2
-rw-r--r--gr-noaa/grc/noaa_hrpt_deframer.xml2
-rw-r--r--gr-noaa/grc/noaa_hrpt_pll_cf.xml2
-rw-r--r--gr-pager/grc/pager_flex_deinterleave.xml2
-rw-r--r--gr-pager/grc/pager_flex_sync.xml2
-rw-r--r--gr-pager/grc/pager_slicer_fb.xml2
-rw-r--r--gr-qtgui/CMakeLists.txt1
-rw-r--r--gr-qtgui/doc/qtgui.dox48
-rw-r--r--gr-qtgui/examples/CMakeLists.txt1
-rw-r--r--gr-qtgui/examples/c++/CMakeLists.txt49
-rw-r--r--gr-qtgui/examples/c++/display_qt.cc126
-rw-r--r--gr-qtgui/examples/c++/display_qt.h77
-rw-r--r--gr-qtgui/examples/test_qtgui_msg.grc (renamed from grc/examples/xmlrpc/xmlrpc_server.grc)868
-rw-r--r--gr-qtgui/grc/qtgui_block_tree.xml3
-rw-r--r--gr-qtgui/grc/qtgui_const_sink_x.xml18
-rw-r--r--gr-qtgui/grc/qtgui_edit_box_msg.xml152
-rw-r--r--gr-qtgui/grc/qtgui_freq_sink_x.xml35
-rw-r--r--gr-qtgui/grc/qtgui_histogram_sink_x.xml18
-rw-r--r--gr-qtgui/grc/qtgui_time_raster_x.xml17
-rw-r--r--gr-qtgui/grc/qtgui_time_sink_x.xml18
-rw-r--r--gr-qtgui/grc/qtgui_waterfall_sink_x.xml18
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/const_sink_c.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/displayform.h3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h151
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h2
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h3
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/qtgui_types.h20
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/time_sink_c.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/time_sink_f.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h2
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h1
-rw-r--r--gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h1
-rw-r--r--gr-qtgui/lib/CMakeLists.txt2
-rw-r--r--gr-qtgui/lib/DisplayPlot.cc9
-rw-r--r--gr-qtgui/lib/FrequencyDisplayPlot.cc13
-rw-r--r--gr-qtgui/lib/WaterfallDisplayPlot.cc2
-rw-r--r--gr-qtgui/lib/const_sink_c_impl.cc6
-rw-r--r--gr-qtgui/lib/const_sink_c_impl.h1
-rw-r--r--gr-qtgui/lib/displayform.cc16
-rw-r--r--gr-qtgui/lib/edit_box_msg_impl.cc571
-rw-r--r--gr-qtgui/lib/edit_box_msg_impl.h93
-rw-r--r--gr-qtgui/lib/freq_sink_c_impl.cc13
-rw-r--r--gr-qtgui/lib/freq_sink_c_impl.h2
-rw-r--r--gr-qtgui/lib/freq_sink_f_impl.cc13
-rw-r--r--gr-qtgui/lib/freq_sink_f_impl.h2
-rw-r--r--gr-qtgui/lib/freqcontrolpanel.cc5
-rw-r--r--gr-qtgui/lib/freqdisplayform.cc6
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.cc6
-rw-r--r--gr-qtgui/lib/histogram_sink_f_impl.h1
-rw-r--r--gr-qtgui/lib/time_raster_sink_b_impl.cc6
-rw-r--r--gr-qtgui/lib/time_raster_sink_b_impl.h1
-rw-r--r--gr-qtgui/lib/time_raster_sink_f_impl.cc6
-rw-r--r--gr-qtgui/lib/time_raster_sink_f_impl.h1
-rw-r--r--gr-qtgui/lib/time_sink_c_impl.cc8
-rw-r--r--gr-qtgui/lib/time_sink_c_impl.h1
-rw-r--r--gr-qtgui/lib/time_sink_f_impl.cc6
-rw-r--r--gr-qtgui/lib/time_sink_f_impl.h1
-rw-r--r--gr-qtgui/lib/timecontrolpanel.cc5
-rw-r--r--gr-qtgui/lib/waterfall_sink_c_impl.cc6
-rw-r--r--gr-qtgui/lib/waterfall_sink_c_impl.h1
-rw-r--r--gr-qtgui/lib/waterfall_sink_f_impl.cc6
-rw-r--r--gr-qtgui/lib/waterfall_sink_f_impl.h1
-rw-r--r--gr-qtgui/swig/qtgui_swig.i15
-rw-r--r--gr-trellis/grc/trellis_encoder_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_metrics_x.xml2
-rw-r--r--gr-trellis/grc/trellis_pccc_decoder_combined_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_pccc_decoder_x.xml2
-rw-r--r--gr-trellis/grc/trellis_pccc_encoder_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_permutation.xml2
-rw-r--r--gr-trellis/grc/trellis_sccc_decoder_combined_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_sccc_decoder_x.xml2
-rw-r--r--gr-trellis/grc/trellis_sccc_encoder_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_siso_combined_f.xml2
-rw-r--r--gr-trellis/grc/trellis_siso_f.xml2
-rw-r--r--gr-trellis/grc/trellis_viterbi_combined_xx.xml2
-rw-r--r--gr-trellis/grc/trellis_viterbi_x.xml2
-rw-r--r--gr-uhd/apps/uhd_app.py7
-rwxr-xr-xgr-uhd/examples/python/fm_tx4.py3
-rw-r--r--gr-uhd/grc/gen_uhd_usrp_blocks.py92
-rw-r--r--gr-uhd/grc/uhd_block_tree.xml2
-rw-r--r--gr-uhd/include/gnuradio/uhd/usrp_source.h82
-rw-r--r--gr-uhd/lib/usrp_block_impl.h8
-rw-r--r--gr-uhd/lib/usrp_sink_impl.cc2
-rw-r--r--gr-uhd/lib/usrp_source_impl.cc142
-rw-r--r--gr-uhd/lib/usrp_source_impl.h14
-rw-r--r--gr-uhd/swig/uhd_swig.i12
-rw-r--r--gr-utils/python/modtool/gr-newmod/CMakeLists.txt15
-rw-r--r--gr-utils/python/modtool/gr-newmod/lib/CMakeLists.txt16
-rw-r--r--gr-utils/python/modtool/modtool_add.py14
-rw-r--r--gr-utils/python/modtool/templates.py2
-rw-r--r--gr-video-sdl/grc/video_block_tree.xml2
-rw-r--r--gr-vocoder/grc/vocoder_block_tree.xml2
-rw-r--r--gr-wxgui/grc/notebook.xml2
-rw-r--r--gr-wxgui/grc/variable_check_box.xml2
-rw-r--r--gr-wxgui/grc/variable_chooser.xml2
-rw-r--r--gr-wxgui/grc/variable_slider.xml2
-rw-r--r--gr-wxgui/grc/variable_static_text.xml2
-rw-r--r--gr-wxgui/grc/variable_text_box.xml2
-rw-r--r--gr-wxgui/grc/wxgui_constellationsink2.xml2
-rw-r--r--gr-wxgui/grc/wxgui_fftsink2.xml2
-rw-r--r--gr-wxgui/grc/wxgui_histosink2.xml2
-rw-r--r--gr-wxgui/grc/wxgui_numbersink2.xml2
-rw-r--r--gr-wxgui/grc/wxgui_scopesink2.xml2
-rw-r--r--gr-wxgui/grc/wxgui_termsink.xml2
-rw-r--r--gr-wxgui/grc/wxgui_waterfallsink2.xml2
-rw-r--r--gr-zeromq/grc/zeromq_pub_msg_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_pub_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_pull_msg_source.xml2
-rw-r--r--gr-zeromq/grc/zeromq_pull_source.xml2
-rw-r--r--gr-zeromq/grc/zeromq_push_msg_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_push_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_rep_msg_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_rep_sink.xml2
-rw-r--r--gr-zeromq/grc/zeromq_req_msg_source.xml2
-rw-r--r--gr-zeromq/grc/zeromq_req_source.xml2
-rw-r--r--gr-zeromq/grc/zeromq_sub_msg_source.xml2
-rw-r--r--gr-zeromq/grc/zeromq_sub_source.xml2
-rw-r--r--grc/CMakeLists.txt10
-rw-r--r--grc/__main__.py20
-rw-r--r--grc/base/Block.py542
-rw-r--r--grc/base/Constants.py50
-rw-r--r--grc/base/FlowGraph.py484
-rw-r--r--grc/base/Param.py205
-rw-r--r--grc/base/Platform.py271
-rw-r--r--grc/base/Port.py136
-rw-r--r--grc/base/__init__.py20
-rw-r--r--grc/blocks/block_tree.xml28
-rw-r--r--grc/blocks/epy_block.xml10
-rw-r--r--grc/blocks/epy_module.xml1
-rw-r--r--grc/blocks/options.xml2
-rw-r--r--grc/blocks/pad_sink.xml5
-rw-r--r--grc/blocks/pad_source.xml5
-rw-r--r--grc/blocks/variable_function_probe.xml18
-rw-r--r--grc/blocks/variable_struct.xml.py1
-rwxr-xr-xgrc/checks.py80
-rw-r--r--grc/core/Block.py850
-rw-r--r--grc/core/CMakeLists.txt (renamed from grc/examples/CMakeLists.txt)24
-rw-r--r--grc/core/Config.py55
-rw-r--r--grc/core/Connection.py (renamed from grc/base/Connection.py)83
-rw-r--r--grc/core/Constants.py (renamed from grc/python/Constants.py)94
-rw-r--r--grc/core/Element.py (renamed from grc/base/Element.py)58
-rw-r--r--grc/core/FlowGraph.py592
-rw-r--r--grc/core/Messages.py (renamed from grc/gui/Messages.py)57
-rw-r--r--grc/core/Param.py740
-rw-r--r--grc/core/ParseXML.py (renamed from grc/base/ParseXML.py)22
-rw-r--r--grc/core/Platform.py309
-rw-r--r--grc/core/Port.py404
-rw-r--r--grc/core/__init__.py (renamed from grc/python/__init__.py)0
-rw-r--r--grc/core/block.dtd (renamed from grc/python/block.dtd)0
-rw-r--r--grc/core/block_tree.dtd (renamed from grc/base/block_tree.dtd)0
-rw-r--r--grc/core/default_flow_graph.grc (renamed from grc/python/default_flow_graph.grc)0
-rw-r--r--grc/core/domain.dtd (renamed from grc/base/domain.dtd)0
-rw-r--r--grc/core/flow_graph.dtd (renamed from grc/base/flow_graph.dtd)0
-rw-r--r--grc/core/generator/CMakeLists.txt (renamed from grc/python/CMakeLists.txt)24
-rw-r--r--grc/core/generator/FlowGraphProxy.py126
-rw-r--r--grc/core/generator/Generator.py (renamed from grc/python/Generator.py)224
-rw-r--r--grc/core/generator/__init__.py18
-rw-r--r--grc/core/generator/flow_graph.tmpl (renamed from grc/python/flow_graph.tmpl)15
-rw-r--r--grc/core/utils/CMakeLists.txt26
-rw-r--r--grc/core/utils/__init__.py22
-rw-r--r--grc/core/utils/complexity.py49
-rw-r--r--grc/core/utils/epy_block_io.py (renamed from grc/python/epy_block_io.py)52
-rw-r--r--grc/core/utils/expr_utils.py (renamed from grc/python/expr_utils.py)64
-rw-r--r--grc/core/utils/extract_docs.py (renamed from grc/python/extract_docs.py)47
-rw-r--r--grc/core/utils/odict.py (renamed from grc/base/odict.py)22
-rw-r--r--grc/cpp/README5
-rw-r--r--grc/examples/simple/variable_config.grc561
-rw-r--r--grc/examples/xmlrpc/readme.txt18
-rw-r--r--grc/examples/xmlrpc/xmlrpc_client.grc428
-rw-r--r--grc/examples/xmlrpc/xmlrpc_client_script.py23
-rw-r--r--grc/gui/ActionHandler.py536
-rw-r--r--grc/gui/Actions.py96
-rw-r--r--grc/gui/Bars.py13
-rw-r--r--grc/gui/Block.py103
-rw-r--r--grc/gui/BlockTreeWindow.py123
-rw-r--r--grc/gui/CMakeLists.txt32
-rw-r--r--grc/gui/Colors.py5
-rw-r--r--grc/gui/Config.py74
-rw-r--r--grc/gui/Connection.py18
-rw-r--r--grc/gui/Constants.py57
-rw-r--r--grc/gui/Dialogs.py43
-rw-r--r--grc/gui/DrawingArea.py27
-rw-r--r--grc/gui/Element.py16
-rw-r--r--grc/gui/Executor.py121
-rw-r--r--grc/gui/FileDialogs.py65
-rw-r--r--grc/gui/FlowGraph.py149
-rw-r--r--grc/gui/MainWindow.py175
-rw-r--r--grc/gui/NotebookPage.py15
-rw-r--r--grc/gui/Param.py34
-rw-r--r--grc/gui/Platform.py53
-rw-r--r--grc/gui/Port.py43
-rw-r--r--grc/gui/Preferences.py27
-rw-r--r--grc/gui/PropsDialog.py38
-rw-r--r--grc/gui/Utils.py9
-rw-r--r--grc/gui/VariableEditor.py354
-rwxr-xr-xgrc/main.py55
-rw-r--r--grc/python/Block.py323
-rw-r--r--grc/python/Connection.py45
-rw-r--r--grc/python/FlowGraph.py338
-rw-r--r--grc/python/Param.py433
-rw-r--r--grc/python/Platform.py176
-rw-r--r--grc/python/Port.py268
-rw-r--r--grc/scripts/CMakeLists.txt2
-rw-r--r--grc/scripts/freedesktop/CMakeLists.txt (renamed from grc/freedesktop/CMakeLists.txt)0
-rw-r--r--grc/scripts/freedesktop/README (renamed from grc/freedesktop/README)0
-rwxr-xr-xgrc/scripts/freedesktop/convert.sh (renamed from grc/freedesktop/convert.sh)0
-rw-r--r--grc/scripts/freedesktop/gnuradio-grc.desktop (renamed from grc/freedesktop/gnuradio-grc.desktop)0
-rw-r--r--grc/scripts/freedesktop/gnuradio-grc.xml (renamed from grc/freedesktop/gnuradio-grc.xml)0
-rw-r--r--grc/scripts/freedesktop/gnuradio_logo_icon-square.svg (renamed from grc/freedesktop/gnuradio_logo_icon-square.svg)0
-rw-r--r--grc/scripts/freedesktop/grc-icon-128.png (renamed from grc/freedesktop/grc-icon-128.png)bin4758 -> 4758 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-16.png (renamed from grc/freedesktop/grc-icon-16.png)bin537 -> 537 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-24.png (renamed from grc/freedesktop/grc-icon-24.png)bin840 -> 840 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-256.png (renamed from grc/freedesktop/grc-icon-256.png)bin9762 -> 9762 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-32.png (renamed from grc/freedesktop/grc-icon-32.png)bin1148 -> 1148 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-48.png (renamed from grc/freedesktop/grc-icon-48.png)bin1796 -> 1796 bytes
-rw-r--r--grc/scripts/freedesktop/grc-icon-64.png (renamed from grc/freedesktop/grc-icon-64.png)bin2355 -> 2355 bytes
-rw-r--r--grc/scripts/freedesktop/grc_setup_freedesktop.in (renamed from grc/freedesktop/grc_setup_freedesktop.in)0
-rwxr-xr-xgrc/scripts/gnuradio-companion124
-rw-r--r--grc/todo.txt69
m---------volk0
361 files changed, 18623 insertions, 7813 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 622b724b38..4b4714eb42 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,8 +46,8 @@ message(STATUS "Build type set to ${CMAKE_BUILD_TYPE}.")
# Set the version information here
set(VERSION_INFO_MAJOR_VERSION 3)
set(VERSION_INFO_API_COMPAT 7)
-set(VERSION_INFO_MINOR_VERSION 9)
-set(VERSION_INFO_MAINT_VERSION 2)
+set(VERSION_INFO_MINOR_VERSION 10)
+set(VERSION_INFO_MAINT_VERSION git)
include(GrVersion) #setup version info
# Append -O2 optimization flag for Debug builds (Not on MSVC since conflicts with RTC1 flag)
@@ -55,6 +55,32 @@ IF (NOT MSVC)
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O2")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O2")
ENDIF()
+
+# Set C/C++ standard for all targets
+# NOTE: Starting with cmake v3.1 this should be used:
+# set(CMAKE_C_STANDARD 90)
+# set(CMAKE_CXX_STANDARD 98)
+
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
+ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
+ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98")
+ELSE()
+ message(warning "C++ standard could not be set because compiler is not GNU, Clang or MSVC.")
+ENDIF()
+
+IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
+ELSE()
+ message(warning "C standard could not be set because compiler is not GNU, Clang or MSVC.")
+ENDIF()
+
########################################################################
# Environment setup
########################################################################
@@ -327,6 +353,9 @@ if(NOT VOLK_FOUND)
set(VOLK_LIBRARIES volk)
+ set(VOLK_INSTALL_LIBRARY_DIR ${CMAKE_INSTALL_PREFIX}/lib)
+ set(VOLK_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_PREFIX}/include)
+
if(ENABLE_VOLK)
include(GrPackage)
@@ -348,6 +377,9 @@ if(NOT VOLK_FOUND)
else()
message(STATUS " An external VOLK has been found and will be used for build.")
set(ENABLE_VOLK TRUE)
+
+ get_filename_component(VOLK_INSTALL_LIBRARY_DIR "${VOLK_LIBRARIES}" DIRECTORY)
+ set(VOLK_INSTALL_INCLUDE_DIR ${VOLK_INCLUDE_DIRS})
endif(NOT VOLK_FOUND)
message(STATUS " Override with -DENABLE_INTERNAL_VOLK=ON/OFF")
@@ -429,12 +461,17 @@ endif(ENABLE_GR_CTRLPORT)
# http://www.cmake.org/Wiki/CMake/Tutorials/Packaging
configure_file(
+ ${CMAKE_SOURCE_DIR}/cmake/Modules/GnuradioConfig.cmake.in
+ ${CMAKE_BINARY_DIR}/cmake/Modules/GnuradioConfig.cmake
+@ONLY)
+
+configure_file(
${CMAKE_SOURCE_DIR}/cmake/Modules/GnuradioConfigVersion.cmake.in
${CMAKE_BINARY_DIR}/cmake/Modules/GnuradioConfigVersion.cmake
@ONLY)
SET(cmake_configs
- ${CMAKE_SOURCE_DIR}/cmake/Modules/GnuradioConfig.cmake
+ ${CMAKE_BINARY_DIR}/cmake/Modules/GnuradioConfig.cmake
${CMAKE_BINARY_DIR}/cmake/Modules/GnuradioConfigVersion.cmake
)
diff --git a/cmake/Modules/GnuradioConfig.cmake b/cmake/Modules/GnuradioConfig.cmake.in
index 31532c605c..fc7499dfdf 100644
--- a/cmake/Modules/GnuradioConfig.cmake
+++ b/cmake/Modules/GnuradioConfig.cmake.in
@@ -72,6 +72,8 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE)
${CMAKE_INSTALL_PREFIX}/include
PATHS /usr/local/include
/usr/include
+ "@CMAKE_INSTALL_PREFIX@/include"
+ "@VOLK_INSTALL_INCLUDE_DIR@"
)
# look for libs
@@ -87,6 +89,8 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE)
/usr/local/lib64
/usr/lib
/usr/lib64
+ "@CMAKE_INSTALL_PREFIX@/lib"
+ "@VOLK_INSTALL_LIBRARY_DIR@"
)
list(APPEND ${LIBVAR_NAME} ${${LIBVAR_NAME}_${libname}})
endforeach(libname)
diff --git a/cmake/Modules/GrVersion.cmake b/cmake/Modules/GrVersion.cmake
index bafd0a7326..dceac67bab 100644
--- a/cmake/Modules/GrVersion.cmake
+++ b/cmake/Modules/GrVersion.cmake
@@ -41,7 +41,13 @@ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git)
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
else()
- set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}.x-xxx-xunknown")
+ if(NOT GR_GIT_COUNT)
+ set(GR_GIT_COUNT "compat-xxx")
+ endif()
+ if(NOT GR_GIT_HASH)
+ set(GR_GIT_HASH "xunknown")
+ endif()
+ set(GIT_DESCRIBE "v${MAJOR_VERSION}.${API_COMPAT}-${GR_GIT_COUNT}-${GR_GIT_HASH}")
endif()
########################################################################
diff --git a/docs/exploring-gnuradio/fm_tx.grc b/docs/exploring-gnuradio/fm_tx.grc
index 2f047bf09b..bb13417a6b 100644
--- a/docs/exploring-gnuradio/fm_tx.grc
+++ b/docs/exploring-gnuradio/fm_tx.grc
@@ -792,6 +792,10 @@
<value>75e3</value>
</param>
<param>
+ <key>fh</key>
+ <value>0.925 * tx_rate/2.0</value>
+ </param>
+ <param>
<key>affinity</key>
<value></value>
</param>
diff --git a/gnuradio-runtime/apps/gnuradio-config-info.cc b/gnuradio-runtime/apps/gnuradio-config-info.cc
index c91b080039..813dda138c 100644
--- a/gnuradio-runtime/apps/gnuradio-config-info.cc
+++ b/gnuradio-runtime/apps/gnuradio-config-info.cc
@@ -25,6 +25,8 @@
#endif
#include <gnuradio/constants.h>
+#include <gnuradio/sys_paths.h>
+#include <gnuradio/prefs.h>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -43,6 +45,8 @@ main(int argc, char **argv)
("prefix", "print GNU Radio installation prefix")
("sysconfdir", "print GNU Radio system configuration directory")
("prefsdir", "print GNU Radio preferences directory")
+ ("userprefsdir", "print GNU Radio user preferences directory")
+ ("prefs", "print GNU Radio preferences")
("builddate", "print GNU Radio build date (RFC2822 format)")
("enabled-components", "print GNU Radio build time enabled components")
("cc", "print GNU Radio C compiler version")
@@ -75,6 +79,12 @@ main(int argc, char **argv)
if(vm.count("prefsdir"))
std::cout << gr::prefsdir() << std::endl;
+ if(vm.count("userprefsdir"))
+ std::cout << gr::userconf_path() << std::endl;
+
+ if(vm.count("prefs"))
+ std::cout << gr::prefs::singleton()->to_string() << std::endl;
+
if(vm.count("builddate"))
std::cout << gr::build_date() << std::endl;
diff --git a/gnuradio-runtime/include/gnuradio/block.h b/gnuradio-runtime/include/gnuradio/block.h
index c6185d9f2d..a484ccf429 100644
--- a/gnuradio-runtime/include/gnuradio/block.h
+++ b/gnuradio-runtime/include/gnuradio/block.h
@@ -80,7 +80,9 @@ namespace gr {
* History is the number of x_i's that are examined to produce one y_i.
* This comes in handy for FIR filters, where we use history to
* ensure that our input contains the appropriate "history" for the
- * filter. History should be equal to the number of filter taps.
+ * filter. History should be equal to the number of filter taps. First
+ * history samples (when there are no previous samples) are
+ * initialized with zeroes.
*/
unsigned history() const;
void set_history(unsigned history);
diff --git a/gnuradio-runtime/include/gnuradio/block_detail.h b/gnuradio-runtime/include/gnuradio/block_detail.h
index 916c0a46c1..a71030b439 100644
--- a/gnuradio-runtime/include/gnuradio/block_detail.h
+++ b/gnuradio-runtime/include/gnuradio/block_detail.h
@@ -100,6 +100,13 @@ namespace gr {
// Return the number of items written on output stream which_output
uint64_t nitems_written(unsigned int which_output);
+ // sets nitems_read and nitems_written to 0 for all input/output
+ // buffers.
+ void reset_nitem_counters();
+
+ // Clears all tags from the input buffers.
+ void clear_tags();
+
/*!
* \brief Adds a new tag to the given output stream.
*
diff --git a/gnuradio-runtime/include/gnuradio/buffer.h b/gnuradio-runtime/include/gnuradio/buffer.h
index 5da383dc8f..914661b318 100644
--- a/gnuradio-runtime/include/gnuradio/buffer.h
+++ b/gnuradio-runtime/include/gnuradio/buffer.h
@@ -100,6 +100,8 @@ namespace gr {
uint64_t nitems_written() { return d_abs_write_offset; }
+ void reset_nitem_counter() { d_abs_write_offset = 0; }
+
size_t get_sizeof_item() { return d_sizeof_item; }
/*!
@@ -288,6 +290,8 @@ namespace gr {
uint64_t nitems_read() { return d_abs_read_offset; }
+ void reset_nitem_counter() { d_abs_read_offset = 0; }
+
size_t get_sizeof_item() { return d_buffer->get_sizeof_item(); }
/*!
diff --git a/gnuradio-runtime/include/gnuradio/prefs.h b/gnuradio-runtime/include/gnuradio/prefs.h
index 4dc92b3631..287f86cc7c 100644
--- a/gnuradio-runtime/include/gnuradio/prefs.h
+++ b/gnuradio-runtime/include/gnuradio/prefs.h
@@ -165,8 +165,7 @@ namespace gr {
protected:
virtual std::vector<std::string> _sys_prefs_filenames();
- virtual std::string _read_files(const std::vector<std::string> &filenames);
- virtual void _convert_to_map(const std::string &conf);
+ virtual void _read_files(const std::vector<std::string> &filenames);
virtual char * option_to_env(std::string section, std::string option);
private:
diff --git a/gnuradio-runtime/include/gnuradio/sys_paths.h b/gnuradio-runtime/include/gnuradio/sys_paths.h
index 1bd2e0deb7..efea07b599 100644
--- a/gnuradio-runtime/include/gnuradio/sys_paths.h
+++ b/gnuradio-runtime/include/gnuradio/sys_paths.h
@@ -32,6 +32,9 @@ namespace gr {
//! directory to store application data
GR_RUNTIME_API const char *appdata_path();
+ //! directory to store user configuration
+ GR_RUNTIME_API const char *userconf_path();
+
} /* namespace gr */
#endif /* GR_SYS_PATHS_H */
diff --git a/gnuradio-runtime/lib/block_detail.cc b/gnuradio-runtime/lib/block_detail.cc
index 9463e8d13b..484d849652 100644
--- a/gnuradio-runtime/lib/block_detail.cc
+++ b/gnuradio-runtime/lib/block_detail.cc
@@ -162,6 +162,26 @@ namespace gr {
}
void
+ block_detail::reset_nitem_counters()
+ {
+ for(unsigned int i = 0; i < d_ninputs; i++) {
+ d_input[i]->reset_nitem_counter();
+ }
+ for(unsigned int o = 0; o < d_noutputs; o++) {
+ d_output[o]->reset_nitem_counter();
+ }
+ }
+
+ void
+ block_detail::clear_tags()
+ {
+ for(unsigned int i = 0; i < d_ninputs; i++) {
+ uint64_t max_time = 0xFFFFFFFFFFFFFFFF; // from now to the end of time
+ d_input[i]->buffer()->prune_tags(max_time);
+ }
+ }
+
+ void
block_detail::add_item_tag(unsigned int which_output, const tag_t &tag)
{
if(!pmt::is_symbol(tag.key)) {
diff --git a/gnuradio-runtime/lib/flat_flowgraph.cc b/gnuradio-runtime/lib/flat_flowgraph.cc
index 82680bfc2d..434a92fb3d 100644
--- a/gnuradio-runtime/lib/flat_flowgraph.cc
+++ b/gnuradio-runtime/lib/flat_flowgraph.cc
@@ -177,6 +177,13 @@ namespace gr {
catch(std::bad_alloc&) {
b = make_buffer(nitems, item_size, grblock);
}
+
+ // Set the max noutput items size here to make sure it's always
+ // set in the block and available in the start() method.
+ // But don't overwrite if the user has set this externally.
+ if(!grblock->is_set_max_noutput_items())
+ grblock->set_max_noutput_items(nitems);
+
return b;
}
@@ -225,9 +232,10 @@ namespace gr {
std::cout << "merge: allocating new detail for block " << (*p) << std::endl;
block->set_detail(allocate_block_detail(block));
}
- else
+ else {
if(FLAT_FLOWGRAPH_DEBUG)
std::cout << "merge: reusing original detail for block " << (*p) << std::endl;
+ }
}
// Calculate the old edges that will be going away, and clear the
@@ -311,6 +319,9 @@ namespace gr {
// Now deal with the fact that the block details might have
// changed numbers of inputs and outputs vs. in the old
// flowgraph.
+
+ block->detail()->reset_nitem_counters();
+ block->detail()->clear_tags();
}
}
diff --git a/gnuradio-runtime/lib/prefs.cc b/gnuradio-runtime/lib/prefs.cc
index b303ffdaf9..341028eba8 100644
--- a/gnuradio-runtime/lib/prefs.cc
+++ b/gnuradio-runtime/lib/prefs.cc
@@ -27,12 +27,18 @@
#include <gnuradio/prefs.h>
#include <gnuradio/sys_paths.h>
#include <gnuradio/constants.h>
+
#include <algorithm>
+#include <fstream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/program_options.hpp>
+#include <boost/foreach.hpp>
namespace fs = boost::filesystem;
+namespace po = boost::program_options;
+typedef std::ifstream::char_type char_t;
namespace gr {
@@ -46,10 +52,7 @@ namespace gr {
prefs::prefs()
{
- std::string config = _read_files(_sys_prefs_filenames());
-
- // Convert the string into a map
- _convert_to_map(config);
+ _read_files(_sys_prefs_filenames());
}
prefs::~prefs()
@@ -77,115 +80,47 @@ namespace gr {
// Find if there is a ~/.gnuradio/config.conf file and add this to
// the end of the file list to override any preferences in the
// installed path config files.
- fs::path homedir = fs::path(gr::appdata_path());
- homedir = homedir/".gnuradio/config.conf";
- if(fs::exists(homedir)) {
- fnames.push_back(homedir.string());
+ fs::path userconf = fs::path(gr::userconf_path()) / "config.conf";
+ if(fs::exists(userconf)) {
+ fnames.push_back(userconf.string());
}
return fnames;
}
- std::string
+ void
prefs::_read_files(const std::vector<std::string> &filenames)
{
- std::string config;
-
- std::vector<std::string>::const_iterator sitr;
- char tmp[1024];
- for(sitr = filenames.begin(); sitr != filenames.end(); sitr++) {
- fs::ifstream fin(*sitr);
- while(!fin.eof()) {
- fin.getline(tmp, 1024);
- std::string t(tmp);
- // ignore empty lines or lines of just comments
- if((t.size() > 0) && (t[0] != '#')) {
- // remove any comments in the line
- size_t hash = t.find("#");
-
- // Remove any white space unless it's between quotes
- // Search if the string has any quotes in it
- size_t quote1 = t.find("\"");
- if(quote1 != std::string::npos) {
- // If yes, find where the start and end quotes are.
- // Note that this isn't robust if there are multiple
- // quoted strings in the line; this will just take the
- // first and last, and if there is only a single quote,
- // this will treat the entire line after the quote as the
- // quoted text.
- // the inq variable is strips the quotes as well.
- size_t quote2 = t.find_last_of("\"");
- std::string sol = t.substr(0, quote1);
- std::string inq = t.substr(quote1+1, quote2-quote1-1);
- std::string eol = t.substr(quote2+1, t.size()-quote2-1);
-
- // Remove all white space of the text before the first quote
- sol.erase(std::remove_if(sol.begin(), sol.end(),
- ::isspace), sol.end());
-
- // Remove all white space of the text after the end quote
- eol.erase(std::remove_if(eol.begin(), eol.end(),
- ::isspace), eol.end());
-
- // Pack the stripped start and end of lines with the part
- // of the string in quotes (but without the quotes).
- t = sol + inq + eol;
+ BOOST_FOREACH( std::string fname, filenames) {
+ std::ifstream infile(fname.c_str());
+ if(infile.good()) {
+ try {
+ po::basic_parsed_options<char_t> parsed = po::parse_config_file(infile, po::options_description(), true);
+ BOOST_FOREACH(po::basic_option<char_t> o, (parsed.options) ){
+ std::string okey = o.string_key;
+ size_t pos = okey.find(".");
+ std::string section, key;
+ if(pos != std::string::npos) {
+ section = okey.substr(0,pos);
+ key = okey.substr(pos+1);
+ } else {
+ section = "default";
+ key = okey;
+ }
+ std::transform(section.begin(), section.end(), section.begin(), ::tolower);
+ std::transform(key.begin(), key.end(), key.begin(), ::tolower);
+ // value of a basic_option is always a std::vector<string>; we only allow single values, so:
+ std::string value = o.value[0];
+ d_config_map[section][key] = value;
}
- else {
- // No quotes, just strip all white space
- t.erase(std::remove_if(t.begin(), t.end(),
- ::isspace), t.end());
- }
-
- // Use hash marks at the end of each segment as a delimiter
- config += t.substr(0, hash) + '#';
+ } catch(const boost::program_options::invalid_config_file_syntax & e) {
+ std::cerr << "WARNING: Config file '" << fname << "' failed to parse:" << std::endl;
+ std::cerr << e.what() << std::endl;
+ std::cerr << "Skipping it" << std::endl;
}
+ } else { // infile.good();
+ std::cerr << "WARNING: Config file '" << fname << "' could not be opened for reading." << std::endl;
}
- fin.close();
- }
-
- return config;
- }
-
- void
- prefs::_convert_to_map(const std::string &conf)
- {
- // Convert the string into an map of maps
- // Map is structured as {section name: map of options}
- // And options map is simply: {option name: option value}
- std::string sub = conf;
- size_t sec_start = sub.find("[");
- while(sec_start != std::string::npos) {
- sub = sub.substr(sec_start);
-
- size_t sec_end = sub.find("]");
- if(sec_end == std::string::npos)
- throw std::runtime_error("Config file error: Mismatched section label.\n");
-
- std::string sec = sub.substr(1, sec_end-1);
- size_t next_sec_start = sub.find("[", sec_end);
- std::string subsec = sub.substr(sec_end+1, next_sec_start-sec_end-2);
-
- std::transform(sec.begin(), sec.end(), sec.begin(), ::tolower);
-
- std::map<std::string, std::string> options_map = d_config_map[sec];
- size_t next_opt = 0;
- size_t next_val = 0;
- next_opt = subsec.find("#");
- while(next_opt < subsec.size()-1) {
- next_val = subsec.find("=", next_opt);
- std::string option = subsec.substr(next_opt+1, next_val-next_opt-1);
-
- next_opt = subsec.find("#", next_val);
- std::string value = subsec.substr(next_val+1, next_opt-next_val-1);
-
- std::transform(option.begin(), option.end(), option.begin(), ::tolower);
- options_map[option] = value;
- }
-
- d_config_map[sec] = options_map;
-
- sec_start = sub.find("[", sec_end);
}
}
@@ -195,8 +130,7 @@ namespace gr {
std::vector<std::string> filenames;
filenames.push_back(configfile);
- std::string config = _read_files(filenames);
- _convert_to_map(config);
+ _read_files(filenames);
}
@@ -222,10 +156,8 @@ namespace gr {
prefs::save()
{
std::string conf = to_string();
-
- fs::path homedir = fs::path(gr::appdata_path());
- homedir = homedir/".gnuradio/config.conf";
- fs::ofstream fout(homedir);
+ fs::path userconf = fs::path(gr::userconf_path()) / "config.conf";
+ fs::ofstream fout(userconf);
fout << conf;
fout.close();
}
diff --git a/gnuradio-runtime/lib/sys_paths.cc b/gnuradio-runtime/lib/sys_paths.cc
index 64853c68b2..3bf6697bac 100644
--- a/gnuradio-runtime/lib/sys_paths.cc
+++ b/gnuradio-runtime/lib/sys_paths.cc
@@ -23,6 +23,8 @@
#include <cstdlib> //getenv
#include <cstdio> //P_tmpdir (maybe)
+#include <boost/filesystem/path.hpp>
+
namespace gr {
const char *tmp_path()
@@ -62,4 +64,11 @@ namespace gr {
return tmp_path();
}
+ const char *userconf_path()
+ {
+ boost::filesystem::path p(appdata_path());
+ p = p / ".gnuradio";
+ return p.c_str();
+ }
+
} /* namespace gr */
diff --git a/gr-analog/examples/fmtest.py b/gr-analog/examples/fmtest.py
index 327da8eacb..7ed08cafbe 100755
--- a/gr-analog/examples/fmtest.py
+++ b/gr-analog/examples/fmtest.py
@@ -48,7 +48,8 @@ class fmtx(gr.hier_block2):
gr.io_signature(1, 1, gr.sizeof_float),
gr.io_signature(1, 1, gr.sizeof_gr_complex))
- fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, tau=75e-6)
+ fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3,
+ tau=75e-6, fh=0.925*if_rate/2.0)
# Local oscillator
lo = analog.sig_source_c(if_rate, # sample rate
diff --git a/gr-analog/grc/analog_block_tree.xml b/gr-analog/grc/analog_block_tree.xml
index d08e646663..64ccbdd855 100644
--- a/gr-analog/grc/analog_block_tree.xml
+++ b/gr-analog/grc/analog_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Level Controllers</name>
<block>analog_agc_xx</block>
diff --git a/gr-analog/grc/analog_fm_preemph.xml b/gr-analog/grc/analog_fm_preemph.xml
index fb898b87f3..a754ce9c6f 100644
--- a/gr-analog/grc/analog_fm_preemph.xml
+++ b/gr-analog/grc/analog_fm_preemph.xml
@@ -8,7 +8,7 @@
<name>FM Preemphasis</name>
<key>analog_fm_preemph</key>
<import>from gnuradio import analog</import>
- <make>analog.fm_preemph(fs=$samp_rate, tau=$tau)</make>
+ <make>analog.fm_preemph(fs=$samp_rate, tau=$tau, fh=$fh)</make>
<param>
<name>Sample Rate</name>
<key>samp_rate</key>
@@ -20,6 +20,12 @@
<value>75e-6</value>
<type>real</type>
</param>
+ <param>
+ <name>High Corner Freq</name>
+ <key>fh</key>
+ <value>-1.0</value>
+ <type>real</type>
+ </param>
<sink>
<name>in</name>
<type>float</type>
diff --git a/gr-analog/grc/analog_nbfm_tx.xml b/gr-analog/grc/analog_nbfm_tx.xml
index ea13b8f1c9..bc80fffbcb 100644
--- a/gr-analog/grc/analog_nbfm_tx.xml
+++ b/gr-analog/grc/analog_nbfm_tx.xml
@@ -13,6 +13,7 @@
quad_rate=$quad_rate,
tau=$tau,
max_dev=$max_dev,
+ fh=$fh,
)</make>
<callback>set_max_deviation($max_dev)</callback>
@@ -42,6 +43,13 @@
<type>real</type>
</param>
+ <param>
+ <name>Preemphasis High Corner Freq</name>
+ <key>fh</key>
+ <value>-1.0</value>
+ <type>real</type>
+ </param>
+
<check>($quad_rate)%($audio_rate) == 0</check>
<sink>
diff --git a/gr-analog/grc/analog_wfm_tx.xml b/gr-analog/grc/analog_wfm_tx.xml
index 89844f9ef3..507c2ea894 100644
--- a/gr-analog/grc/analog_wfm_tx.xml
+++ b/gr-analog/grc/analog_wfm_tx.xml
@@ -13,6 +13,7 @@
quad_rate=$quad_rate,
tau=$tau,
max_dev=$max_dev,
+ fh=$fh,
)</make>
<param>
<name>Audio Rate</name>
@@ -36,6 +37,12 @@
<value>75e3</value>
<type>real</type>
</param>
+ <param>
+ <name>Preemphasis High Corner Freq</name>
+ <key>fh</key>
+ <value>-1.0</value>
+ <type>real</type>
+ </param>
<check>($quad_rate)%($audio_rate) == 0</check>
<sink>
<name>in</name>
diff --git a/gr-analog/lib/CMakeLists.txt b/gr-analog/lib/CMakeLists.txt
index 918f894abe..a75d70337b 100644
--- a/gr-analog/lib/CMakeLists.txt
+++ b/gr-analog/lib/CMakeLists.txt
@@ -110,17 +110,6 @@ GR_LIBRARY_FOO(gnuradio-analog RUNTIME_COMPONENT "analog_runtime" DEVEL_COMPONEN
add_dependencies(gnuradio-analog analog_generated_includes analog_generated_swigs gnuradio-filter)
if(ENABLE_STATIC_LIBS)
- if(ENABLE_GR_CTRLPORT)
- # Remove GR_CTRLPORT set this target's definitions.
- # Makes sure we don't try to use ControlPort stuff in source files
- GET_DIRECTORY_PROPERTY(STATIC_DEFS COMPILE_DEFINITIONS)
- list(REMOVE_ITEM STATIC_DEFS "GR_CTRLPORT")
- SET_PROPERTY(DIRECTORY PROPERTY COMPILE_DEFINITIONS "${STATIC_DEFS}")
-
- # readd it to the target since we removed it from the directory-wide list.
- SET_PROPERTY(TARGET gnuradio-analog APPEND PROPERTY COMPILE_DEFINITIONS "GR_CTRLPORT")
- endif(ENABLE_GR_CTRLPORT)
-
add_library(gnuradio-analog_static STATIC ${analog_sources})
add_dependencies(gnuradio-analog_static
diff --git a/gr-analog/lib/frequency_modulator_fc_impl.cc b/gr-analog/lib/frequency_modulator_fc_impl.cc
index 812eb8bf0b..56fa0f7c17 100644
--- a/gr-analog/lib/frequency_modulator_fc_impl.cc
+++ b/gr-analog/lib/frequency_modulator_fc_impl.cc
@@ -76,5 +76,27 @@ namespace gr {
return noutput_items;
}
+ void
+ frequency_modulator_fc_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<frequency_modulator_fc, float>(
+ alias(), "sensitivity",
+ &frequency_modulator_fc::sensitivity,
+ pmt::mp(-1024.0f), pmt::mp(1024.0f), pmt::mp(0.0f),
+ "", "Sensitivity", RPC_PRIVLVL_MIN,
+ DISPTIME | DISPOPTSTRIP)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_set<frequency_modulator_fc, float>(
+ alias(), "sensitivity",
+ &frequency_modulator_fc::set_sensitivity,
+ pmt::mp(-1024.0f), pmt::mp(1024.0f), pmt::mp(0.0f),
+ "", "sensitivity",
+ RPC_PRIVLVL_MIN, DISPNULL)));
+#endif /* GR_CTRLPORT */
+
+ }
} /* namespace analog */
} /* namespace gr */
diff --git a/gr-analog/lib/frequency_modulator_fc_impl.h b/gr-analog/lib/frequency_modulator_fc_impl.h
index 9f5310ce97..9f595d1ddb 100644
--- a/gr-analog/lib/frequency_modulator_fc_impl.h
+++ b/gr-analog/lib/frequency_modulator_fc_impl.h
@@ -41,6 +41,8 @@ namespace gr {
void set_sensitivity(float sens) { d_sensitivity = sens; }
float sensitivity() const { return d_sensitivity; }
+ void setup_rpc();
+
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
diff --git a/gr-analog/lib/sig_source_X_impl.cc.t b/gr-analog/lib/sig_source_X_impl.cc.t
index 227d4ba46e..017177eae0 100644
--- a/gr-analog/lib/sig_source_X_impl.cc.t
+++ b/gr-analog/lib/sig_source_X_impl.cc.t
@@ -53,7 +53,7 @@ namespace gr {
d_frequency(frequency), d_ampl(ampl), d_offset(offset)
{
set_frequency(frequency);
-
+
message_port_register_in(pmt::mp("freq"));
set_msg_handler(pmt::mp("freq"), boost::bind(&@IMPL_NAME@::set_frequency_msg, this, _1));
}
@@ -62,6 +62,36 @@ namespace gr {
{
}
+ void
+ @IMPL_NAME@::set_frequency_msg(pmt::pmt_t msg)
+ {
+ // Accepts either a number that is assumed to be the new
+ // frequency or a key:value pair message where the key must be
+ // "freq" and the value is the new frequency.
+
+ if(pmt::is_number(msg)) {
+ set_frequency(pmt::to_double(msg));
+ }
+ else if(pmt::is_pair(msg)) {
+ pmt::pmt_t key = pmt::car(msg);
+ pmt::pmt_t val = pmt::cdr(msg);
+ if(pmt::eq(key, pmt::intern("freq"))) {
+ if(pmt::is_number(val)) {
+ set_frequency(pmt::to_double(val));
+ }
+ }
+ else {
+ GR_LOG_WARN(d_logger, boost::format("Set Frequency Message must have "
+ "the key = 'freq'; got '%1%'.") \
+ % pmt::write_string(key));
+ }
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Set Frequency Message must be either a number or a "
+ "key:value pair where the key is 'freq'.");
+ }
+ }
+
int
@IMPL_NAME@::work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-analog/lib/sig_source_X_impl.h.t b/gr-analog/lib/sig_source_X_impl.h.t
index bd3609df16..f5dfd5c4f6 100644
--- a/gr-analog/lib/sig_source_X_impl.h.t
+++ b/gr-analog/lib/sig_source_X_impl.h.t
@@ -59,7 +59,7 @@ namespace gr {
void set_sampling_freq(double sampling_freq);
void set_waveform(gr_waveform_t waveform);
- void set_frequency_msg(pmt::pmt_t msg){ set_frequency(pmt::to_double(msg)); };
+ void set_frequency_msg(pmt::pmt_t msg);
void set_frequency(double frequency);
void set_amplitude(double ampl);
void set_offset(@TYPE@ offset);
diff --git a/gr-analog/python/analog/fm_emph.py b/gr-analog/python/analog/fm_emph.py
index d2a38d4aff..bfa4742ace 100644
--- a/gr-analog/python/analog/fm_emph.py
+++ b/gr-analog/python/analog/fm_emph.py
@@ -21,17 +21,78 @@
from gnuradio import gr, filter
import math
+import cmath
#
-# 1
-# H(s) = -------
-# 1 + s
+# An analog deemphasis filter:
#
-# tau is the RC time constant.
-# critical frequency: w_p = 1/tau
+# R
+# o------/\/\/\/---+----o
+# |
+# = C
+# |
+# ---
#
-# We prewarp and use the bilinear z-transform to get our IIR coefficients.
-# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+# Has this transfer function:
+#
+# 1 1
+# ---- ---
+# RC tau
+# H(s) = ---------- = ----------
+# 1 1
+# s + ---- s + ---
+# RC tau
+#
+# And has its -3 dB response, due to the pole, at
+#
+# |H(j w_c)|^2 = 1/2 => s = j w_c = j (1/(RC))
+#
+# Historically, this corner frequency of analog audio deemphasis filters
+# been specified by the RC time constant used, called tau.
+# So w_c = 1/tau.
+#
+# FWIW, for standard tau values, some standard analog components would be:
+# tau = 75 us = (50K)(1.5 nF) = (50 ohms)(1.5 uF)
+# tau = 50 us = (50K)(1.0 nF) = (50 ohms)(1.0 uF)
+#
+# In specifying tau for this digital deemphasis filter, tau specifies
+# the *digital* corner frequency, w_c, desired.
+#
+# The digital deemphasis filter design below, uses the
+# "bilinear transformation" method of designing digital filters:
+#
+# 1. Convert digitial specifications into the analog domain, by prewarping
+# digital frequency specifications into analog frequencies.
+#
+# w_a = (2/T)tan(wT/2)
+#
+# 2. Use an analog filter design technique to design the filter.
+#
+# 3. Use the bilinear transformation to convert the analog filter design to a
+# digital filter design.
+#
+# H(z) = H(s)|
+# s = (2/T)(1-z^-1)/(1+z^-1)
+#
+#
+# w_ca 1 1 - (-1) z^-1
+# H(z) = ---- * ----------- * -----------------------
+# 2 fs -w_ca -w_ca
+# 1 - ----- 1 + -----
+# 2 fs 2 fs
+# 1 - ----------- z^-1
+# -w_ca
+# 1 - -----
+# 2 fs
+#
+# We use this design technique, because it is an easy way to obtain a filter
+# design with the -6 dB/octave roll-off required of the deemphasis filter.
+#
+# Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_,
+# Kluwer Academic Publishers, 1989, pp 201-212
+#
+# Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall,
+# 1996, pp 573-583
#
@@ -51,15 +112,24 @@ class fm_deemph(gr.hier_block2):
gr.io_signature(1, 1, gr.sizeof_float), # Input signature
gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
- w_p = 1/tau
- w_pp = math.tan(w_p / (fs * 2)) # prewarped analog freq
+ # Digital corner frequency
+ w_c = 1.0 / tau
+
+ # Prewarped analog corner frequency
+ w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs))
- a1 = (w_pp - 1)/(w_pp + 1)
- b0 = w_pp/(1 + w_pp)
- b1 = b0
+ # Resulting digital pole, zero, and gain term from the bilinear
+ # transformation of H(s) = w_ca / (s + w_ca) to
+ # H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
+ k = -w_ca / (2.0 * fs)
+ z1 = -1.0
+ p1 = (1.0 + k) / (1.0 - k)
+ b0 = -k / (1.0 - k)
- btaps = [b0, b1]
- ataps = [1, a1]
+ btaps = [ b0 * 1.0, b0 * -z1 ]
+ ataps = [ 1.0, -p1 ]
+
+ # Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC
if 0:
print "btaps =", btaps
@@ -67,26 +137,17 @@ class fm_deemph(gr.hier_block2):
global plot1
plot1 = gru.gnuplot_freqz(gru.freqz(btaps, ataps), fs, True)
- deemph = filter.iir_filter_ffd(btaps, ataps)
+ deemph = filter.iir_filter_ffd(btaps, ataps, False)
self.connect(self, deemph, self)
#
-# 1 + s*t1
-# H(s) = ----------
-# 1 + s*t2
-#
-# I think this is the right transfer function.
-#
+# An analog preemphasis filter, that flattens out again at the high end:
#
-# This fine ASCII rendition is based on Figure 5-15
-# in "Digital and Analog Communication Systems", Leon W. Couch II
-#
-#
-# R1
+# C
# +-----||------+
# | |
# o------+ +-----+--------o
-# | C1 | |
+# | R1 | |
# +----/\/\/\/--+ \
# /
# \ R2
@@ -95,28 +156,94 @@ class fm_deemph(gr.hier_block2):
# |
# o--------------------------+--------o
#
-# f1 = 1/(2*pi*t1) = 1/(2*pi*R1*C)
+# (This fine ASCII rendition is based on Figure 5-15
+# in "Digital and Analog Communication Systems", Leon W. Couch II)
+#
+# Has this transfer function:
#
-# 1 R1 + R2
-# f2 = ------- = ------------
-# 2*pi*t2 2*pi*R1*R2*C
+# 1
+# s + ---
+# R1C
+# H(s) = ------------------
+# 1 R1
+# s + --- (1 + --)
+# R1C R2
#
-# t1 is 75us in US, 50us in EUR
-# f2 should be higher than our audio bandwidth.
#
+# It has a corner due to the numerator, where the rise starts, at
#
-# The Bode plot looks like this:
+# |Hn(j w_cl)|^2 = 2*|Hn(0)|^2 => s = j w_cl = j (1/(R1C))
#
+# It has a corner due to the denominator, where it levels off again, at
#
-# /----------------
-# /
-# / <-- slope = 20dB/decade
-# /
-# -------------/
-# f1 f2
+# |Hn(j w_ch)|^2 = 1/2*|Hd(0)|^2 => s = j w_ch = j (1/(R1C) * (1 + R1/R2))
#
-# We prewarp and use the bilinear z-transform to get our IIR coefficients.
-# See "Digital Signal Processing: A Practical Approach" by Ifeachor and Jervis
+# Historically, the corner frequency of analog audio preemphasis filters
+# been specified by the R1C time constant used, called tau.
+#
+# So
+# w_cl = 1/tau = 1/R1C; f_cl = 1/(2*pi*tau) = 1/(2*pi*R1*C)
+# w_ch = 1/tau2 = (1+R1/R2)/R1C; f_ch = 1/(2*pi*tau2) = (1+R1/R2)/(2*pi*R1*C)
+#
+# and note f_ch = f_cl * (1 + R1/R2).
+#
+# For broadcast FM audio, tau is 75us in the United States and 50us in Europe.
+# f_ch should be higher than our digital audio bandwidth.
+#
+# The Bode plot looks like this:
+#
+#
+# /----------------
+# /
+# / <-- slope = 20dB/decade
+# /
+# -------------/
+# f_cl f_ch
+#
+# In specifying tau for this digital preemphasis filter, tau specifies
+# the *digital* corner frequency, w_cl, desired.
+#
+# The digital preemphasis filter design below, uses the
+# "bilinear transformation" method of designing digital filters:
+#
+# 1. Convert digitial specifications into the analog domain, by prewarping
+# digital frequency specifications into analog frequencies.
+#
+# w_a = (2/T)tan(wT/2)
+#
+# 2. Use an analog filter design technique to design the filter.
+#
+# 3. Use the bilinear transformation to convert the analog filter design to a
+# digital filter design.
+#
+# H(z) = H(s)|
+# s = (2/T)(1-z^-1)/(1+z^-1)
+#
+#
+# -w_cla
+# 1 + ------
+# 2 fs
+# 1 - ------------ z^-1
+# -w_cla -w_cla
+# 1 - ------ 1 - ------
+# 2 fs 2 fs
+# H(z) = ------------ * -----------------------
+# -w_cha -w_cha
+# 1 - ------ 1 + ------
+# 2 fs 2 fs
+# 1 - ------------ z^-1
+# -w_cha
+# 1 - ------
+# 2 fs
+#
+# We use this design technique, because it is an easy way to obtain a filter
+# design with the 6 dB/octave rise required of the premphasis filter.
+#
+# Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_,
+# Kluwer Academic Publishers, 1989, pp 201-212
+#
+# Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall,
+# 1996, pp 573-583
#
@@ -124,21 +251,52 @@ class fm_preemph(gr.hier_block2):
"""
FM Preemphasis IIR filter.
"""
- def __init__(self, fs, tau=75e-6):
+ def __init__(self, fs, tau=75e-6, fh=-1.0):
"""
Args:
fs: sampling frequency in Hz (float)
tau: Time constant in seconds (75us in US, 50us in EUR) (float)
+ fh: High frequency at which to flatten out (< 0 means default of 0.925*fs/2.0) (float)
"""
- gr.hier_block2.__init__(self, "fm_deemph",
+ gr.hier_block2.__init__(self, "fm_preemph",
gr.io_signature(1, 1, gr.sizeof_float), # Input signature
gr.io_signature(1, 1, gr.sizeof_float)) # Output signature
- # FIXME make this compute the right answer
+ # Set fh to something sensible, if needed.
+ # N.B. fh == fs/2.0 or fh == 0.0 results in a pole on the unit circle
+ # at z = -1.0 or z = 1.0 respectively. That makes the filter unstable
+ # and useless.
+ if fh <= 0.0 or fh >= fs/2.0:
+ fh = 0.925 * fs/2.0
+
+ # Digital corner frequencies
+ w_cl = 1.0 / tau
+ w_ch = 2.0 * math.pi * fh
+
+ # Prewarped analog corner frequencies
+ w_cla = 2.0 * fs * math.tan(w_cl / (2.0 * fs))
+ w_cha = 2.0 * fs * math.tan(w_ch / (2.0 * fs))
+
+ # Resulting digital pole, zero, and gain term from the bilinear
+ # transformation of H(s) = (s + w_cla) / (s + w_cha) to
+ # H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
+ kl = -w_cla / (2.0 * fs)
+ kh = -w_cha / (2.0 * fs)
+ z1 = (1.0 + kl) / (1.0 - kl)
+ p1 = (1.0 + kh) / (1.0 - kh)
+ b0 = (1.0 - kl) / (1.0 - kh)
+
+ # Since H(s = infinity) = 1.0, then H(z = -1) = 1.0 and
+ # this filter has 0 dB gain at fs/2.0.
+ # That isn't what users are going to expect, so adjust with a
+ # gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC.
+ w_0dB = 2.0 * math.pi * 0.0
+ g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \
+ / (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB)))
- btaps = [1]
- ataps = [1]
+ btaps = [ g * b0 * 1.0, g * b0 * -z1 ]
+ ataps = [ 1.0, -p1 ]
if 0:
print "btaps =", btaps
@@ -146,5 +304,5 @@ class fm_preemph(gr.hier_block2):
global plot2
plot2 = gru.gnuplot_freqz(gru.freqz(btaps, ataps), fs, True)
- preemph = filter.iir_filter_ffd(btaps, ataps)
+ preemph = filter.iir_filter_ffd(btaps, ataps, False)
self.connect(self, preemph, self)
diff --git a/gr-analog/python/analog/nbfm_tx.py b/gr-analog/python/analog/nbfm_tx.py
index ffd539ec55..aa6c1eccc7 100644
--- a/gr-analog/python/analog/nbfm_tx.py
+++ b/gr-analog/python/analog/nbfm_tx.py
@@ -29,7 +29,7 @@ except ImportError:
import analog_swig as analog
class nbfm_tx(gr.hier_block2):
- def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3):
+ def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3, fh=-1.0):
"""
Narrow Band FM Transmitter.
@@ -41,6 +41,7 @@ class nbfm_tx(gr.hier_block2):
quad_rate: sample rate of output stream (integer)
tau: preemphasis time constant (default 75e-6) (float)
max_dev: maximum deviation in Hz (default 5e3) (float)
+ fh: high frequency at which to flatten preemphasis; < 0 means default of 0.925*quad_rate/2.0 (float)
quad_rate must be an integer multiple of audio_rate.
"""
@@ -71,7 +72,7 @@ class nbfm_tx(gr.hier_block2):
#print "len(interp_taps) =", len(interp_taps)
self.interpolator = filter.interp_fir_filter_fff (interp_factor, interp_taps)
- self.preemph = fm_preemph(quad_rate, tau=tau)
+ self.preemph = fm_preemph(quad_rate, tau=tau, fh=fh)
k = 2 * math.pi * max_dev / quad_rate
self.modulator = analog.frequency_modulator_fc(k)
diff --git a/gr-analog/python/analog/wfm_tx.py b/gr-analog/python/analog/wfm_tx.py
index be662310db..a1b589350d 100644
--- a/gr-analog/python/analog/wfm_tx.py
+++ b/gr-analog/python/analog/wfm_tx.py
@@ -30,7 +30,7 @@ except ImportError:
import analog_swig as analog
class wfm_tx(gr.hier_block2):
- def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3):
+ def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3, fh=-1.0):
"""
Wide Band FM Transmitter.
@@ -42,6 +42,7 @@ class wfm_tx(gr.hier_block2):
quad_rate: sample rate of output stream (integer)
tau: preemphasis time constant (default 75e-6) (float)
max_dev: maximum deviation in Hz (default 75e3) (float)
+ fh: high frequency at which to flatten preemphasis; < 0 means default of 0.925*quad_rate/2.0 (float)
quad_rate must be an integer multiple of audio_rate.
"""
@@ -71,7 +72,7 @@ class wfm_tx(gr.hier_block2):
print "len(interp_taps) =", len(interp_taps)
self.interpolator = filter.interp_fir_filter_fff (interp_factor, interp_taps)
- self.preemph = fm_preemph(quad_rate, tau=tau)
+ self.preemph = fm_preemph(quad_rate, tau=tau, fh=fh)
k = 2 * math.pi * max_dev / quad_rate
self.modulator = analog.frequency_modulator_fc (k)
diff --git a/gr-audio/grc/audio_sink.xml b/gr-audio/grc/audio_sink.xml
index 727767b72e..9181055cd9 100644
--- a/gr-audio/grc/audio_sink.xml
+++ b/gr-audio/grc/audio_sink.xml
@@ -7,7 +7,7 @@
<block>
<name>Audio Sink</name>
<key>audio_sink</key>
- <category>Audio</category>
+ <category>[Core]/Audio</category>
<flags>throttle</flags>
<import>from gnuradio import audio</import>
<make>audio.sink($samp_rate, $device_name, $ok_to_block)</make>
diff --git a/gr-audio/grc/audio_source.xml b/gr-audio/grc/audio_source.xml
index aaa3225e8b..044b14466f 100644
--- a/gr-audio/grc/audio_source.xml
+++ b/gr-audio/grc/audio_source.xml
@@ -7,7 +7,7 @@
<block>
<name>Audio Source</name>
<key>audio_source</key>
- <category>Audio</category>
+ <category>[Core]/Audio</category>
<flags>throttle</flags>
<import>from gnuradio import audio</import>
<make>audio.source($samp_rate, $device_name, $ok_to_block)</make>
diff --git a/gr-audio/lib/windows/windows_sink.cc b/gr-audio/lib/windows/windows_sink.cc
index 6598c973d4..4ec798b0ba 100644
--- a/gr-audio/lib/windows/windows_sink.cc
+++ b/gr-audio/lib/windows/windows_sink.cc
@@ -27,6 +27,8 @@
#include "audio_registry.h"
#include <windows_sink.h>
#include <gnuradio/io_signature.h>
+#include <gnuradio/prefs.h>
+#include <gnuradio/logger.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -36,27 +38,29 @@
#include <stdexcept>
#include <string>
#include <sstream>
+#include "boost/lexical_cast.hpp"
namespace gr {
namespace audio {
sink::sptr
windows_sink_fcn(int sampling_rate,
- const std::string &device_name,
- bool)
+ const std::string &device_name,
+ bool)
{
return sink::sptr
(new windows_sink(sampling_rate, device_name));
}
- static const double CHUNK_TIME = 0.1; //0.001; // 100 ms
-
- // FIXME these should query some kind of user preference
+ static const double CHUNK_TIME = prefs::singleton()->get_double("audio_windows", "period_time", 0.1); // 100 ms (below 3ms distortion will likely occur regardless of number of buffers, will likely be a higher limit on slower machines)
+ static const int nPeriods = prefs::singleton()->get_long("audio_windows", "nperiods", 4); // 4 should be more than enough with a normal chunk time (2 will likely work as well)... at 3ms chunks 10 was enough on a fast machine
+ static const bool verbose = prefs::singleton()->get_bool("audio_windows", "verbose", false);
+ static const std::string default_device = prefs::singleton()->get_string("audio_windows", "standard_output_device", "default");
static std::string
default_device_name()
{
- return "WAVE_MAPPER";
+ return (default_device == "default" ? "WAVE_MAPPER" : default_device);
}
windows_sink::windows_sink(int sampling_freq, const std::string device_name)
@@ -65,28 +69,63 @@ namespace gr {
io_signature::make(0, 0, 0)),
d_sampling_freq(sampling_freq),
d_device_name(device_name.empty() ? default_device_name() : device_name),
- d_fd(-1), d_buffer(0), d_chunk_size(0)
+ d_fd(-1), d_buffers(0), d_chunk_size(0)
{
+ /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */
+ wave_format.wFormatTag = WAVE_FORMAT_PCM;
+ wave_format.nChannels = 2; // changing this will require adjustments to the work routine.
+ wave_format.wBitsPerSample = 16; // changing this will necessitate changing buffer type from short.
+ wave_format.nSamplesPerSec = d_sampling_freq; // 44100 is default but up to flowgraph settings;
+ wave_format.nBlockAlign =
+ wave_format.nChannels * (wave_format.wBitsPerSample / 8);
+ wave_format.nAvgBytesPerSec =
+ wave_format.nSamplesPerSec * wave_format.nBlockAlign;
+ wave_format.cbSize = 0;
+
+ d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME); // Samples per chunk
+ set_output_multiple(d_chunk_size);
+ d_buffer_size = d_chunk_size * wave_format.nChannels * (wave_format.wBitsPerSample / 8); // room for 16-bit audio on two channels.
+
d_wave_write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(open_waveout_device() < 0) {
- //fprintf(stderr, "audio_windows_sink:open_waveout_device() failed\n");
+ if (open_waveout_device() < 0) {
perror("audio_windows_sink:open_waveout_device() failed\n");
throw
- std::runtime_error ("audio_windows_sink:open_waveout_device() failed");
+ std::runtime_error("audio_windows_sink:open_waveout_device() failed");
}
-
- d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME);
- set_output_multiple(d_chunk_size);
-
- d_buffer = new short[d_chunk_size * 2];
+ else if (verbose) {
+ GR_LOG_INFO(logger, "Opened windows waveout device");
+ }
+ d_buffers = new LPWAVEHDR[nPeriods];
+ for (int i = 0; i < nPeriods; i++)
+ {
+ d_buffers[i] = new WAVEHDR;
+ d_buffers[i]->dwLoops = 0L;
+ d_buffers[i]->dwFlags = WHDR_DONE;
+ d_buffers[i]->dwBufferLength = d_buffer_size;
+ d_buffers[i]->lpData = new CHAR[d_buffer_size];
+ }
+ if (verbose) GR_LOG_INFO(logger, boost::format("Initialized %1% %2%ms audio buffers, total memory used: %3$0.2fkB") % (nPeriods) % (CHUNK_TIME * 1000) % ((d_buffer_size * nPeriods) / 1024.0));
}
windows_sink::~windows_sink()
{
+ // stop playback and set all buffers to DONE.
+ waveOutReset(d_h_waveout);
+ // Now we can deallocate the buffers
+ for (int i = 0; i < nPeriods; i++)
+ {
+ if (d_buffers[i]->dwFlags & (WHDR_DONE | WHDR_PREPARED)) {
+ waveOutUnprepareHeader(d_h_waveout, d_buffers[i], sizeof(d_buffers[i]));
+ }
+ else {
+
+ }
+ delete d_buffers[i]->lpData;
+ }
/* Free the callback Event */
CloseHandle(d_wave_write_event);
waveOutClose(d_h_waveout);
- delete [] d_buffer;
+ delete [] d_buffers;
}
int
@@ -95,66 +134,71 @@ namespace gr {
gr_vector_void_star & output_items)
{
const float *f0, *f1;
- bool playtestsound = false;
- if(playtestsound) {
- // dummy
- f0 = (const float*)input_items[0];
- for(int i = 0; i < noutput_items; i += d_chunk_size) {
- for(int j = 0; j < d_chunk_size; j++) {
- d_buffer[2*j + 0] = (short)(sin(2.0 * 3.1415926535897932384626 *
- (float)j * 1000.0 / (float)d_sampling_freq) *
- 8192 + 0); //+32767
- d_buffer[2*j + 1] = d_buffer[2*j + 0];
+ // Pick the first available wave header (buffer)
+ // If none available, then wait until the processing event if fired and check again
+ // Not all events free up a buffer, so it could take more than one loop to get one
+ // however, to avoid a lock, only wait 1 second for a freed up buffer then abort.
+ LPWAVEHDR chosen_header = NULL;
+ int c = 0;
+ while (!chosen_header)
+ {
+ ResetEvent(d_wave_write_event);
+ for (int i = 0; i < nPeriods; i++)
+ {
+ if (d_buffers[i]->dwFlags & WHDR_DONE) {
+ // uncomment the below to see which buffers are being consumed
+ // printf("%d ", i);
+ chosen_header = d_buffers[i];
+ break;
}
- f0 += d_chunk_size;
- if(write_waveout
- ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
- fprintf(stderr, "audio_windows_sink: write failed\n");
- perror("audio_windows_sink: write failed");
+ }
+ if (!chosen_header) {
+ WaitForSingleObject(d_wave_write_event, 100);
+ printf("aO");
+ }
+ if (c++ > 10) {
+ for (int i = 0; i < nPeriods; i++) {
+ printf("%d: %d\n", i, d_buffers[i]->dwFlags);
}
- }
- // break;
+ perror("audio_windows_sink: no audio buffers available");
+ return -1;
+ }
}
- else {
- switch(input_items.size ()) {
- case 1: // mono input
- f0 = (const float*)input_items[0];
-
- for(int i = 0; i < noutput_items; i += d_chunk_size) {
- for(int j = 0; j < d_chunk_size; j++) {
- d_buffer[2*j + 0] = (short)(f0[j] * 32767);
- d_buffer[2*j + 1] = (short)(f0[j] * 32767);
- }
- f0 += d_chunk_size;
- if(write_waveout
- ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
- //fprintf(stderr, "audio_windows_sink: write failed\n");
- perror("audio_windows_sink: write failed");
- }
- }
- break;
- case 2: // stereo input
- f0 = (const float*)input_items[0];
- f1 = (const float*)input_items[1];
+ short *d_buffer = (short *)chosen_header->lpData;
- for(int i = 0; i < noutput_items; i += d_chunk_size) {
- for(int j = 0; j < d_chunk_size; j++) {
- d_buffer[2*j + 0] = (short)(f0[j] * 32767);
- d_buffer[2*j + 1] = (short)(f1[j] * 32767);
- }
- f0 += d_chunk_size;
- f1 += d_chunk_size;
- if(write_waveout
- ((HPSTR)d_buffer, 2*d_chunk_size * sizeof(short)) < 0) {
- //fprintf(stderr, "audio_windows_sink: write failed\n");
- perror("audio_windows_sink: write failed");
- }
+ switch (input_items.size()) {
+ case 1: // mono input
+ f0 = (const float*)input_items[0];
+
+ for (int i = 0; i < noutput_items; i += d_chunk_size) {
+ for (int j = 0; j < d_chunk_size; j++) {
+ d_buffer[2 * j + 0] = (short)(f0[j] * 32767);
+ d_buffer[2 * j + 1] = (short)(f0[j] * 32767);
}
- break;
- }
+ f0 += d_chunk_size;
+ }
+ break;
+ case 2: // stereo input
+ f0 = (const float*)input_items[0];
+ f1 = (const float*)input_items[1];
+
+ for (int i = 0; i < noutput_items; i += d_chunk_size) {
+ for (int j = 0; j < d_chunk_size; j++) {
+ d_buffer[2 * j + 0] = (short)(f0[j] * 32767);
+ d_buffer[2 * j + 1] = (short)(f1[j] * 32767);
+ }
+ f0 += d_chunk_size;
+ f1 += d_chunk_size;
+ }
+ break;
+ }
+ if (write_waveout
+ (chosen_header) < 0) {
+ perror("audio_windows_sink: write failed");
}
+
return noutput_items;
}
@@ -162,154 +206,162 @@ namespace gr {
windows_sink::string_to_int(const std::string & s)
{
int i;
- std::istringstream (s) >> i;
+ std::istringstream(s) >> i;
return i;
- } //ToInt()
+ }
- int
- windows_sink::open_waveout_device(void)
+ MMRESULT windows_sink::is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID)
{
- UINT /*UINT_PTR */ u_device_id;
-
- /** Identifier of the waveform-audio output device to open. It
- can be either a device identifier or a handle of an open
- waveform-audio input device. You can use the following flag
- instead of a device identifier.
- *
- * Value Meaning
- * WAVE_MAPPER The function selects a waveform-audio output
- * device capable of playing the given format.
- */
- if(d_device_name.empty () || default_device_name () == d_device_name)
- u_device_id = WAVE_MAPPER;
- else
- u_device_id = (UINT) string_to_int (d_device_name);
- // Open a waveform device for output using event callback.
-
- unsigned long result;
- //HWAVEOUT outHandle;
- WAVEFORMATEX wave_format;
+ return (waveOutOpen(
+ NULL, // ptr can be NULL for query
+ uDeviceID, // the device identifier
+ pwfx, // defines requested format
+ NULL, // no callback
+ NULL, // no instance data
+ WAVE_FORMAT_QUERY)); // query only, do not open device
+ }
- /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */
- wave_format.wFormatTag = WAVE_FORMAT_PCM;
- wave_format.nChannels = 2;
- wave_format.nSamplesPerSec = d_sampling_freq; //44100;
- wave_format.wBitsPerSample = 16;
- wave_format.nBlockAlign =
- wave_format.nChannels * (wave_format.wBitsPerSample / 8);
- wave_format.nAvgBytesPerSec =
- wave_format.nSamplesPerSec * wave_format.nBlockAlign;
- wave_format.cbSize = 0;
+ bool windows_sink::is_number(const std::string& s)
+ {
+ std::string::const_iterator it = s.begin();
+ while (it != s.end() && std::isdigit(*it)) ++it;
+ return !s.empty() && it == s.end();
+ }
- /* Open the (preferred) Digital Audio Out device. */
- result = waveOutOpen(&d_h_waveout, WAVE_MAPPER,
- &wave_format,
- (DWORD_PTR)d_wave_write_event,
- 0, CALLBACK_EVENT | WAVE_ALLOWSYNC);
- //|WAVE_FORMAT_DIRECT | CALLBACK_EVENT| WAVE_ALLOWSYNC
+ UINT windows_sink::find_device(std::string szDeviceName)
+ {
+ UINT result = -1;
+ UINT num_devices = waveOutGetNumDevs();
+ if (num_devices > 0) {
+ // what the device name passed as a number?
+ if (is_number(szDeviceName))
+ {
+ // a number, so must be referencing a device ID (which incremement from zero)
+ UINT num = std::stoul(szDeviceName);
+ if (num < num_devices) {
+ result = num;
+ }
+ else {
+ GR_LOG_INFO(logger, boost::format("Warning: waveOut deviceID %d was not found, defaulting to WAVE_MAPPER") % num);
+ result = WAVE_MAPPER;
+ }
- if(result) {
- //fprintf(stderr, "audio_windows_sink: Failed to open waveform output device.\n");
- perror("audio_windows_sink: Failed to open waveform output device.");
- //LocalUnlock(hFormat);
- //LocalFree(hFormat);
- //mmioClose(hmmio, 0);
- return -1;
+ }
+ else {
+ // device name passed as string
+ for (UINT i = 0; i < num_devices; i++)
+ {
+ WAVEOUTCAPS woc;
+ if (waveOutGetDevCaps(i, &woc, sizeof(woc)) != MMSYSERR_NOERROR)
+ {
+ perror("Error: Could not retrieve wave out device capabilities for device");
+ return -1;
+ }
+ if (woc.szPname == szDeviceName)
+ {
+ result = i;
+ }
+ if (verbose) GR_LOG_INFO(logger, boost::format("WaveOut Device %d: %s") % i % woc.szPname);
+ }
+ if (result == -1) {
+ GR_LOG_INFO(logger, boost::format("Warning: waveOut device '%s' was not found, defaulting to WAVE_MAPPER") % szDeviceName);
+ result = WAVE_MAPPER;
+ }
+ }
+ }
+ else {
+ perror("Error: No WaveOut devices present or accessible");
}
+ return result;
+ }
- //
- // Do not Swallow the "open" event.
- //
- //WaitForSingleObject(d_wave_write_event, INFINITE);
+ int
+ windows_sink::open_waveout_device(void)
+ {
+ UINT u_device_id;
+ unsigned long result;
- // Allocate and lock memory for the header.
+ /** Identifier of the waveform-audio output device to open. It
+ can be either a device identifier or a handle of an open
+ waveform-audio input device. You can use the following flag
+ instead of a device identifier.
+ WAVE_MAPPER The function selects a waveform-audio output
+ device capable of playing the given format.
+ */
+ if (d_device_name.empty() || default_device_name() == d_device_name)
+ u_device_id = WAVE_MAPPER;
+ else
+ // The below could be uncommented to allow selection of different device handles
+ // however it is unclear what other devices are out there and how a user
+ // would know the device ID so at the moment we will ignore that setting
+ // and stick with WAVE_MAPPER
+ u_device_id = find_device(d_device_name);
+ if (verbose) GR_LOG_INFO(logger, boost::format("waveOut Device ID: %1%") % (u_device_id));
- d_h_wave_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
- (DWORD)sizeof(WAVEHDR));
- if(d_h_wave_hdr == NULL) {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf(stderr, "audio_windows_sink: Not enough memory for header.\n");
- perror("audio_windows_sink: Not enough memory for header.");
+ // Check if the sampling rate/bits/channels are good to go with the device.
+ MMRESULT supported = is_format_supported(&wave_format, u_device_id);
+ if (supported != MMSYSERR_NOERROR) {
+ char err_msg[50];
+ waveOutGetErrorText(supported, err_msg, 50);
+ GR_LOG_INFO(logger, boost::format("format error: %s") % err_msg);
+ perror("audio_windows_sink: Requested audio format is not supported by device driver");
return -1;
}
- d_lp_wave_hdr = (LPWAVEHDR)GlobalLock(d_h_wave_hdr);
- if(d_lp_wave_hdr == NULL) {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf(stderr, "audio_windows_sink: Failed to lock memory for header.\n");
- perror("audio_windows_sink: Failed to lock memory for header.");
+ // Open a waveform device for output using event callback.
+ result = waveOutOpen(&d_h_waveout, u_device_id,
+ &wave_format,
+ (DWORD_PTR)d_wave_write_event,
+ 0, CALLBACK_EVENT | WAVE_ALLOWSYNC);
+
+ if (result) {
+ perror("audio_windows_sink: Failed to open waveform output device.");
return -1;
}
- //d_lp_wave_hdr->dwFlags = WHDR_DONE;
return 0;
}
int
- windows_sink::write_waveout(HPSTR lp_data, DWORD dw_data_size)
+ windows_sink::write_waveout(LPWAVEHDR lp_wave_hdr)
{
UINT w_result;
- int teller = 100;
- // After allocation, set up and prepare header.
- /*while ((d_lp_wave_hdr->dwFlags & WHDR_DONE)==0 && teller>0) {
- teller--;
- Sleep(1);
- } */
- // Wait until previous wave write completes (first event is the open event).
- WaitForSingleObject(d_wave_write_event, 100); // INFINITE
- d_lp_wave_hdr->lpData = lp_data;
- d_lp_wave_hdr->dwBufferLength = dw_data_size;
- d_lp_wave_hdr->dwFlags = 0L;
+
/* Clear the WHDR_DONE bit (which the driver set last time that
- this WAVEHDR was sent via waveOutWrite and was played). Some
- drivers need this to be cleared */
- //d_lp_wave_hdr->dwFlags &= ~WHDR_DONE;
+ this WAVEHDR was sent via waveOutWrite and was played). Some
+ drivers need this to be cleared */
+ lp_wave_hdr->dwFlags = 0L;
- d_lp_wave_hdr->dwLoops = 0L;
w_result =
- waveOutPrepareHeader(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
- if(w_result != 0) {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf(stderr, "audio_windows_sink: Failed to waveOutPrepareHeader. error %i\n",w_result);
+ waveOutPrepareHeader(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR));
+ if (w_result != 0) {
perror("audio_windows_sink: Failed to waveOutPrepareHeader");
+ return -1;
}
- // Now the data block can be sent to the output device. The
- // waveOutWrite function returns immediately and waveform
- // data is sent to the output device in the background.
- //while(!readyforplayback) Sleep(1);
- //readyforplayback=false;
-
- w_result = waveOutWrite(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
- if(w_result != 0) {
- //GlobalUnlock(hData);
- //GlobalFree(hData);
- //fprintf(stderr, "audio_windows_sink: Failed to write block to device.error %i\n",w_result);
+
+ w_result = waveOutWrite(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR));
+ if (w_result != 0) {
perror("audio_windows_sink: Failed to write block to device");
- switch(w_result) {
- case MMSYSERR_INVALHANDLE:
- fprintf(stderr, "Specified device handle is invalid.\n");
- break;
- case MMSYSERR_NODRIVER:
- fprintf(stderr, " No device driver is present.\n");
- break;
- case MMSYSERR_NOMEM:
- fprintf(stderr, " Unable to allocate or lock memory.\n");
- break;
- case WAVERR_UNPREPARED:
- fprintf(stderr,
- " The data block pointed to by the pwh parameter hasn't been prepared.\n");
- break;
- default:
- fprintf(stderr, "Unknown error %i\n", w_result);
- }
- waveOutUnprepareHeader(d_h_waveout, d_lp_wave_hdr, sizeof(WAVEHDR));
+ switch (w_result) {
+ case MMSYSERR_INVALHANDLE:
+ fprintf(stderr, "Specified device handle is invalid.\n");
+ break;
+ case MMSYSERR_NODRIVER:
+ fprintf(stderr, " No device driver is present.\n");
+ break;
+ case MMSYSERR_NOMEM:
+ fprintf(stderr, " Unable to allocate or lock memory.\n");
+ break;
+ case WAVERR_UNPREPARED:
+ fprintf(stderr,
+ " The data block pointed to by the pwh parameter hasn't been prepared.\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown error %i\n", w_result);
+ }
+ waveOutUnprepareHeader(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR));
return -1;
}
- //WaitForSingleObject(d_wave_write_event, INFINITE);
return 0;
}
-
} /* namespace audio */
} /* namespace gr */
diff --git a/gr-audio/lib/windows/windows_sink.h b/gr-audio/lib/windows/windows_sink.h
index 3d21cc47a3..2bfdbd318d 100644
--- a/gr-audio/lib/windows/windows_sink.h
+++ b/gr-audio/lib/windows/windows_sink.h
@@ -47,17 +47,20 @@ namespace gr {
int d_sampling_freq;
std::string d_device_name;
int d_fd;
- short *d_buffer;
- int d_chunk_size;
+ LPWAVEHDR *d_buffers;
+ DWORD d_chunk_size;
+ DWORD d_buffer_size;
HWAVEOUT d_h_waveout;
- HGLOBAL d_h_wave_hdr;
- LPWAVEHDR d_lp_wave_hdr;
HANDLE d_wave_write_event;
+ WAVEFORMATEX wave_format;
protected:
int string_to_int(const std::string & s);
int open_waveout_device(void);
- int write_waveout(HPSTR lp_data, DWORD dw_data_size);
+ int write_waveout(LPWAVEHDR lp_wave_hdr);
+ MMRESULT is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID);
+ bool is_number(const std::string& s);
+ UINT find_device(std::string szDeviceName);
public:
windows_sink(int sampling_freq,
diff --git a/gr-blocks/CMakeLists.txt b/gr-blocks/CMakeLists.txt
index 13b41a2e3c..685f5736fb 100644
--- a/gr-blocks/CMakeLists.txt
+++ b/gr-blocks/CMakeLists.txt
@@ -87,6 +87,7 @@ add_subdirectory(lib)
#endif(ENABLE_TESTING)
if(ENABLE_PYTHON)
add_subdirectory(python/blocks)
+ add_subdirectory(python/grc_gnuradio)
add_subdirectory(swig)
add_subdirectory(grc)
add_subdirectory(doc)
diff --git a/grc/blocks/blks2_error_rate.xml b/gr-blocks/grc/blks2_error_rate.xml
index 91a303206d..c71739f914 100644
--- a/grc/blocks/blks2_error_rate.xml
+++ b/gr-blocks/grc/blks2_error_rate.xml
@@ -8,6 +8,7 @@
<block>
<name>Error Rate</name>
<key>blks2_error_rate</key>
+ <category>[Core]/Deprecated</category>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.error_rate(
type=$type,
diff --git a/grc/blocks/blks2_selector.xml b/gr-blocks/grc/blks2_selector.xml
index 2d89df1860..3442b2cdb8 100644
--- a/grc/blocks/blks2_selector.xml
+++ b/gr-blocks/grc/blks2_selector.xml
@@ -8,6 +8,7 @@
<block>
<name>Selector</name>
<key>blks2_selector</key>
+ <category>[Core]/Deprecated</category>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.selector(
item_size=$type.size*$vlen,
diff --git a/grc/blocks/blks2_tcp_sink.xml b/gr-blocks/grc/blks2_tcp_sink.xml
index cfe7b42d84..2bff7e6d45 100644
--- a/grc/blocks/blks2_tcp_sink.xml
+++ b/gr-blocks/grc/blks2_tcp_sink.xml
@@ -7,6 +7,7 @@
<block>
<name>TCP Sink</name>
<key>blks2_tcp_sink</key>
+ <category>[Core]/Deprecated</category>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.tcp_sink(
itemsize=$type.size*$vlen,
diff --git a/grc/blocks/blks2_tcp_source.xml b/gr-blocks/grc/blks2_tcp_source.xml
index 6bf742aa00..f6cc41015f 100644
--- a/grc/blocks/blks2_tcp_source.xml
+++ b/gr-blocks/grc/blks2_tcp_source.xml
@@ -7,6 +7,7 @@
<block>
<name>TCP Source</name>
<key>blks2_tcp_source</key>
+ <category>[Core]/Deprecated</category>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.tcp_source(
itemsize=$type.size*$vlen,
diff --git a/grc/blocks/blks2_valve.xml b/gr-blocks/grc/blks2_valve.xml
index 47c553523f..c3f25163b2 100644
--- a/grc/blocks/blks2_valve.xml
+++ b/gr-blocks/grc/blks2_valve.xml
@@ -8,6 +8,7 @@
<block>
<name>Valve</name>
<key>blks2_valve</key>
+ <category>[Core]/Deprecated</category>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.valve(item_size=$type.size*$vlen, open=bool($open))</make>
<callback>set_open(bool($open))</callback>
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml
index f35815b4dd..a9441a9ffb 100644
--- a/gr-blocks/grc/blocks_block_tree.xml
+++ b/gr-blocks/grc/blocks_block_tree.xml
@@ -27,9 +27,9 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
- <name>Audio</name>
+ <name>Audio</name>
<block>blocks_wavfile_source</block>
<block>blocks_wavfile_sink</block>
</cat>
@@ -144,6 +144,8 @@
<block>blocks_null_sink</block>
<block>blocks_copy</block>
<block>blocks_nop</block>
+ <block>xmlrpc_server</block>
+ <block>xmlrpc_client</block>
</cat>
<cat>
<name>Modulators</name>
diff --git a/gr-blocks/grc/blocks_repeat.xml b/gr-blocks/grc/blocks_repeat.xml
index c6c17c9900..793d0148b2 100644
--- a/gr-blocks/grc/blocks_repeat.xml
+++ b/gr-blocks/grc/blocks_repeat.xml
@@ -9,6 +9,7 @@
<key>blocks_repeat</key>
<import>from gnuradio import blocks</import>
<make>blocks.repeat($type.size*$vlen, $interp)</make>
+ <callback>set_interpolation($interp)</callback>
<param>
<name>Type</name>
<key>type</key>
diff --git a/grc/blocks/xmlrpc_client.xml b/gr-blocks/grc/xmlrpc_client.xml
index dc4d154d14..dc4d154d14 100644
--- a/grc/blocks/xmlrpc_client.xml
+++ b/gr-blocks/grc/xmlrpc_client.xml
diff --git a/grc/blocks/xmlrpc_server.xml b/gr-blocks/grc/xmlrpc_server.xml
index 602d444161..602d444161 100644
--- a/grc/blocks/xmlrpc_server.xml
+++ b/gr-blocks/grc/xmlrpc_server.xml
diff --git a/gr-blocks/include/gnuradio/blocks/repeat.h b/gr-blocks/include/gnuradio/blocks/repeat.h
index 622b066017..b34bda1ec5 100644
--- a/gr-blocks/include/gnuradio/blocks/repeat.h
+++ b/gr-blocks/include/gnuradio/blocks/repeat.h
@@ -32,6 +32,10 @@ namespace gr {
/*!
* \brief repeat each input \p repeat times
* \ingroup stream_operators_blk
+ *
+ * Message Ports:
+ * * interpolation (in):
+ * Takes a pmt_pair(pmt::mp("interpolation"), pmt_long interp), setting the interpolation to interp.
*/
class BLOCKS_API repeat : virtual public sync_interpolator
{
@@ -46,6 +50,20 @@ namespace gr {
* \param repeat number of times to repeat the input
*/
static sptr make(size_t itemsize, int repeat);
+
+ /*!
+ * \brief Return current interpolation
+ */
+ virtual int interpolation() const = 0;
+
+ /*!
+ * \brief sets the interpolation
+ *
+ * Call this method in a callback to adjust the interpolation at run time.
+ *
+ * \param interp interpolation to be set
+ */
+ virtual void set_interpolation(int interp) = 0;
};
} /* namespace blocks */
diff --git a/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t b/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t
index 527ebf7dff..a4ef38fd04 100644
--- a/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t
+++ b/gr-blocks/include/gnuradio/blocks/vector_sink_X.h.t
@@ -43,6 +43,7 @@ namespace gr {
static sptr make(int vlen = 1);
+ //! Clear the data and tags containers.
virtual void reset() = 0;
virtual std::vector<@TYPE@> data() const = 0;
virtual std::vector<tag_t> tags() const = 0;
diff --git a/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t b/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t
index d5298e8b47..b0ca6b869f 100644
--- a/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t
+++ b/gr-blocks/include/gnuradio/blocks/vector_source_X.h.t
@@ -76,6 +76,7 @@ namespace gr {
virtual void rewind() = 0;
virtual void set_data(const std::vector<@TYPE@> &data,
const std::vector<tag_t> &tags=std::vector<tag_t>()) = 0;
+ virtual void set_repeat(bool repeat) = 0;
};
} /* namespace blocks */
diff --git a/gr-blocks/lib/repeat_impl.cc b/gr-blocks/lib/repeat_impl.cc
index 9c2ccc63c8..fb62265134 100644
--- a/gr-blocks/lib/repeat_impl.cc
+++ b/gr-blocks/lib/repeat_impl.cc
@@ -43,6 +43,26 @@ namespace gr {
d_itemsize(itemsize),
d_interp(interp)
{
+ message_port_register_in(pmt::mp("interpolation"));
+ set_msg_handler(pmt::mp("interpolation"),
+ boost::bind(&repeat_impl::msg_set_interpolation, this, _1));
+ }
+
+ void
+ repeat_impl::msg_set_interpolation(pmt::pmt_t msg)
+ {
+ // Dynamization by Kevin McQuiggin:
+ d_interp = pmt::to_long(pmt::cdr(msg));
+ sync_interpolator::set_interpolation(d_interp);
+ }
+ void
+ repeat_impl::set_interpolation(int interp)
+ {
+ // This ensures that interpolation is only changed between calls to work
+ // (and not in the middle of an ongoing work)
+ _post( pmt::mp("interpolation"), /* port */
+ pmt::cons(pmt::mp("interpolation"), pmt::from_long(interp)) /* pair */
+ );
}
int
diff --git a/gr-blocks/lib/repeat_impl.h b/gr-blocks/lib/repeat_impl.h
index 1942729194..486a47a1ad 100644
--- a/gr-blocks/lib/repeat_impl.h
+++ b/gr-blocks/lib/repeat_impl.h
@@ -36,9 +36,15 @@ namespace gr {
public:
repeat_impl(size_t itemsize, int d_interp);
+ int interpolation() const { return d_interp; }
+ void set_interpolation(int interp);
+
+
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
+ private:
+ void msg_set_interpolation(pmt::pmt_t msg);
};
} /* namespace blocks */
diff --git a/gr-blocks/lib/tuntap_pdu_impl.cc b/gr-blocks/lib/tuntap_pdu_impl.cc
index 45995e4803..391b33937a 100644
--- a/gr-blocks/lib/tuntap_pdu_impl.cc
+++ b/gr-blocks/lib/tuntap_pdu_impl.cc
@@ -76,6 +76,14 @@ namespace gr {
if (d_fd <= 0)
throw std::runtime_error("gr::tuntap_pdu::make: tun_alloc failed (are you running as root?)");
+ int err = set_mtu(dev_cstr, MTU);
+ if(err < 0)
+ std::cerr << boost::format(
+ "gr::tuntap_pdu: failed to set MTU to %d.\n"
+ "You should use ifconfig to set the MTU. E.g.,\n"
+ " $ sudo ifconfig %s mtu %d\n"
+ ) % MTU % dev % MTU << std::endl;
+
std::cout << boost::format(
"Allocated virtual ethernet interface: %s\n"
"You must now use ifconfig to set its IP address. E.g.,\n"
@@ -140,6 +148,31 @@ namespace gr {
*/
return fd;
}
+
+ int
+ tuntap_pdu_impl::set_mtu(const char *dev, int MTU)
+ {
+ struct ifreq ifr;
+ int sfd, err;
+
+ /* MTU must be set by passing a socket fd to ioctl;
+ * create an arbitrary socket for this purpose
+ */
+ if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return sfd;
+
+ /* preparation of the struct ifr, of type "struct ifreq" */
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ ifr.ifr_addr.sa_family = AF_INET; /* address family */
+ ifr.ifr_mtu = MTU;
+
+ /* try to set MTU */
+ if ((err = ioctl(sfd, SIOCSIFMTU, (void *) &ifr)) < 0)
+ return err;
+
+ return MTU;
+ }
#endif
} /* namespace blocks */
diff --git a/gr-blocks/lib/tuntap_pdu_impl.h b/gr-blocks/lib/tuntap_pdu_impl.h
index 360f954630..3a53e3acb5 100644
--- a/gr-blocks/lib/tuntap_pdu_impl.h
+++ b/gr-blocks/lib/tuntap_pdu_impl.h
@@ -40,6 +40,7 @@ namespace gr {
std::string d_dev;
bool d_istunflag;
int tun_alloc(char *dev, int flags);
+ int set_mtu(const char *dev, int MTU);
public:
tuntap_pdu_impl(std::string dev, int MTU, bool istunflag);
diff --git a/gr-blocks/lib/udp_source_impl.cc b/gr-blocks/lib/udp_source_impl.cc
index c3705d8f66..ea2f2b60a0 100644
--- a/gr-blocks/lib/udp_source_impl.cc
+++ b/gr-blocks/lib/udp_source_impl.cc
@@ -27,6 +27,7 @@
#include "udp_source_impl.h"
#include <gnuradio/io_signature.h>
#include <gnuradio/math.h>
+#include <gnuradio/prefs.h>
#include <stdexcept>
#include <errno.h>
#include <stdio.h>
@@ -35,7 +36,8 @@
namespace gr {
namespace blocks {
- const int udp_source_impl::BUF_SIZE_PAYLOADS = 50;
+ const int udp_source_impl::BUF_SIZE_PAYLOADS =
+ gr::prefs::singleton()->get_long("udp_blocks", "buf_size_payloads", 50);
udp_source::sptr
udp_source::make(size_t itemsize,
diff --git a/gr-blocks/lib/vector_sink_X_impl.h.t b/gr-blocks/lib/vector_sink_X_impl.h.t
index b5d3bd6432..86f0e8773c 100644
--- a/gr-blocks/lib/vector_sink_X_impl.h.t
+++ b/gr-blocks/lib/vector_sink_X_impl.h.t
@@ -41,7 +41,7 @@ namespace gr {
@NAME_IMPL@(int vlen);
~@NAME_IMPL@();
- void reset() { d_data.clear(); }
+ void reset() { d_data.clear(); d_tags.clear(); }
std::vector<@TYPE@> data() const;
std::vector<tag_t> tags() const;
diff --git a/gr-blocks/lib/vector_source_X_impl.h.t b/gr-blocks/lib/vector_source_X_impl.h.t
index 2641c6661b..bc9b329d8f 100644
--- a/gr-blocks/lib/vector_source_X_impl.h.t
+++ b/gr-blocks/lib/vector_source_X_impl.h.t
@@ -50,6 +50,7 @@ namespace gr {
void rewind() { d_offset=0; }
void set_data(const std::vector<@TYPE@> &data,
const std::vector<tag_t> &tags);
+ void set_repeat(bool repeat) { d_repeat=repeat; };
int work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-blocks/python/blocks/qa_block_behavior.py b/gr-blocks/python/blocks/qa_block_behavior.py
new file mode 100644
index 0000000000..a21e423b21
--- /dev/null
+++ b/gr-blocks/python/blocks/qa_block_behavior.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 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
+
+class test_block_behavior(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_000(self):
+ '''
+ Tests the max noutput sizes set by the scheduler. When creating
+ the block, there is no block_detail and so the max buffer size
+ is 0. When the top_block is run, it builds the detail and
+ buffers and sets the max value. test_0001 tests when the
+ max_noutput_items is set by hand.
+
+ '''
+
+ src = blocks.null_source(gr.sizeof_float)
+ op = blocks.head(gr.sizeof_float, 100)
+ snk = blocks.null_sink(gr.sizeof_float)
+
+ maxn_pre = op.max_noutput_items()
+
+ self.tb.connect(src, op, snk)
+ self.tb.run()
+
+ maxn_post = op.max_noutput_items()
+
+ self.assertEqual(maxn_pre, 0)
+ self.assertEqual(maxn_post, 16384)
+
+ def test_001(self):
+ '''
+ Tests the max noutput size when being explicitly set.
+ '''
+
+ src = blocks.null_source(gr.sizeof_float)
+ op = blocks.head(gr.sizeof_float, 100)
+ snk = blocks.null_sink(gr.sizeof_float)
+
+ op.set_max_noutput_items(1024)
+
+ maxn_pre = op.max_noutput_items()
+
+ self.tb.connect(src, op, snk)
+ self.tb.run()
+
+ maxn_post = op.max_noutput_items()
+
+ self.assertEqual(maxn_pre, 1024)
+ self.assertEqual(maxn_post, 1024)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_block_behavior, "test_block_behavior.xml")
diff --git a/gr-blocks/python/blocks/qa_vector_sink_source.py b/gr-blocks/python/blocks/qa_vector_sink_source.py
index 5dab7014cd..026713f5f4 100755
--- a/gr-blocks/python/blocks/qa_vector_sink_source.py
+++ b/gr-blocks/python/blocks/qa_vector_sink_source.py
@@ -46,6 +46,7 @@ class test_vector_sink_source(gr_unittest.TestCase):
self.tb = None
def test_001(self):
+ # Test that sink has data set in source for the simplest case
src_data = [float(x) for x in range(16)]
expected_result = tuple(src_data)
@@ -58,6 +59,7 @@ class test_vector_sink_source(gr_unittest.TestCase):
self.assertEqual(expected_result, result_data)
def test_002(self):
+ # Test vectors (the gnuradio vector I/O type)
src_data = [float(x) for x in range(16)]
expected_result = tuple(src_data)
@@ -70,11 +72,14 @@ class test_vector_sink_source(gr_unittest.TestCase):
self.assertEqual(expected_result, result_data)
def test_003(self):
+ # Test that we can only make vectors (the I/O type) if the input
+ # vector has sufficient size
src_data = [float(x) for x in range(16)]
expected_result = tuple(src_data)
self.assertRaises(RuntimeError, lambda : blocks.vector_source_f(src_data, False, 3))
def test_004(self):
+ # Test sending and receiving tagged streams
src_data = [float(x) for x in range(16)]
expected_result = tuple(src_data)
src_tags = tuple([make_tag('key', 'val', 0, 'src')])
@@ -92,6 +97,7 @@ class test_vector_sink_source(gr_unittest.TestCase):
self.assertTrue(compare_tags(expected_tags[0], result_tags[0]))
def test_005(self):
+ # Test that repeat works (with tagged streams)
length = 16
src_data = [float(x) for x in range(length)]
expected_result = tuple(src_data + src_data)
@@ -112,6 +118,36 @@ class test_vector_sink_source(gr_unittest.TestCase):
self.assertTrue(compare_tags(expected_tags[0], result_tags[0]))
self.assertTrue(compare_tags(expected_tags[1], result_tags[1]))
+ def test_006(self):
+ # Test set_data
+ src_data = [float(x) for x in range(16)]
+ expected_result = tuple(src_data)
+
+ src = blocks.vector_source_f((3,1,4))
+ dst = blocks.vector_sink_f()
+ src.set_data(src_data)
+
+ self.tb.connect(src, dst)
+ self.tb.run()
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+
+ def test_007(self):
+ # Test set_repeat
+ src_data = [float(x) for x in range(16)]
+ expected_result = tuple(src_data)
+
+ src = blocks.vector_source_f(src_data, True)
+ dst = blocks.vector_sink_f()
+ src.set_repeat(False)
+
+ self.tb.connect(src, dst)
+ # will timeout if set_repeat does not work
+ self.tb.run()
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+
+
if __name__ == '__main__':
gr_unittest.run(test_vector_sink_source, "test_vector_sink_source.xml")
diff --git a/grc/grc_gnuradio/CMakeLists.txt b/gr-blocks/python/grc_gnuradio/CMakeLists.txt
index e992a60a39..9ff1240997 100644
--- a/grc/grc_gnuradio/CMakeLists.txt
+++ b/gr-blocks/python/grc_gnuradio/CMakeLists.txt
@@ -18,18 +18,20 @@
# Boston, MA 02110-1301, USA.
########################################################################
+
+include(GrPython)
+
GR_PYTHON_INSTALL(
FILES __init__.py
DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio
- COMPONENT "grc"
+ COMPONENT "blocks_python"
)
GR_PYTHON_INSTALL(FILES
blks2/__init__.py
blks2/error_rate.py
- blks2/packet.py
blks2/selector.py
blks2/tcp.py
DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio/blks2
- COMPONENT "grc"
+ COMPONENT "blocks_python"
)
diff --git a/grc/grc_gnuradio/README b/gr-blocks/python/grc_gnuradio/README
index 897eed65ca..897eed65ca 100644
--- a/grc/grc_gnuradio/README
+++ b/gr-blocks/python/grc_gnuradio/README
diff --git a/grc/grc_gnuradio/__init__.py b/gr-blocks/python/grc_gnuradio/__init__.py
index 8b13789179..8b13789179 100644
--- a/grc/grc_gnuradio/__init__.py
+++ b/gr-blocks/python/grc_gnuradio/__init__.py
diff --git a/grc/grc_gnuradio/blks2/__init__.py b/gr-blocks/python/grc_gnuradio/blks2/__init__.py
index e6941ab91b..d3c8210834 100644
--- a/grc/grc_gnuradio/blks2/__init__.py
+++ b/gr-blocks/python/grc_gnuradio/blks2/__init__.py
@@ -19,8 +19,12 @@
#
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
from error_rate import error_rate
from tcp import tcp_source, tcp_sink
+
+try:
+ 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
+except ImportError:
+ pass # only available if gr-digital is install
diff --git a/grc/grc_gnuradio/blks2/error_rate.py b/gr-blocks/python/grc_gnuradio/blks2/error_rate.py
index 9bf387030a..9bf387030a 100644
--- a/grc/grc_gnuradio/blks2/error_rate.py
+++ b/gr-blocks/python/grc_gnuradio/blks2/error_rate.py
diff --git a/grc/grc_gnuradio/blks2/selector.py b/gr-blocks/python/grc_gnuradio/blks2/selector.py
index 24e3844658..24e3844658 100644
--- a/grc/grc_gnuradio/blks2/selector.py
+++ b/gr-blocks/python/grc_gnuradio/blks2/selector.py
diff --git a/grc/grc_gnuradio/blks2/tcp.py b/gr-blocks/python/grc_gnuradio/blks2/tcp.py
index aee90fad2c..aee90fad2c 100644
--- a/grc/grc_gnuradio/blks2/tcp.py
+++ b/gr-blocks/python/grc_gnuradio/blks2/tcp.py
diff --git a/gr-channels/grc/channels_block_tree.xml b/gr-channels/grc/channels_block_tree.xml
index 383f4b199c..00886e8eed 100644
--- a/gr-channels/grc/channels_block_tree.xml
+++ b/gr-channels/grc/channels_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Channel Models</name>
<block>channels_channel_model</block>
diff --git a/gr-digital/CMakeLists.txt b/gr-digital/CMakeLists.txt
index 7a9f8f6c48..c6fa0798d1 100644
--- a/gr-digital/CMakeLists.txt
+++ b/gr-digital/CMakeLists.txt
@@ -97,6 +97,7 @@ add_subdirectory(doc)
if(ENABLE_PYTHON)
add_subdirectory(swig)
add_subdirectory(python/digital)
+ add_subdirectory(python/grc_gnuradio)
add_subdirectory(grc)
add_subdirectory(examples)
endif(ENABLE_PYTHON)
diff --git a/grc/blocks/blks2_packet_decoder.xml b/gr-digital/grc/blks2_packet_decoder.xml
index 07b0d1f2eb..fedb2e74f3 100644
--- a/grc/blocks/blks2_packet_decoder.xml
+++ b/gr-digital/grc/blks2_packet_decoder.xml
@@ -7,6 +7,8 @@
<block>
<name>Packet Decoder</name>
<key>blks2_packet_decoder</key>
+ <category>[Core]/Deprecated</category>
+ <flags>deprecated</flags>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.packet_demod_$(type.fcn)(grc_blks2.packet_decoder(
access_code=$access_code,
diff --git a/grc/blocks/blks2_packet_encoder.xml b/gr-digital/grc/blks2_packet_encoder.xml
index 88e1ba350c..d030f6ae22 100644
--- a/grc/blocks/blks2_packet_encoder.xml
+++ b/gr-digital/grc/blks2_packet_encoder.xml
@@ -7,6 +7,8 @@
<block>
<name>Packet Encoder</name>
<key>blks2_packet_encoder</key>
+ <category>[Core]/Deprecated</category>
+ <flags>deprecated</flags>
<import>from grc_gnuradio import blks2 as grc_blks2</import>
<make>grc_blks2.packet_mod_$(type.fcn)(grc_blks2.packet_encoder(
samples_per_symbol=$samples_per_symbol,
diff --git a/gr-digital/grc/digital_block_tree.xml b/gr-digital/grc/digital_block_tree.xml
index 6707a8e4db..9bdf6e993f 100644
--- a/gr-digital/grc/digital_block_tree.xml
+++ b/gr-digital/grc/digital_block_tree.xml
@@ -26,7 +26,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Coding</name>
<block>digital_additive_scrambler_bb</block>
diff --git a/gr-digital/grc/digital_burst_shaper.xml b/gr-digital/grc/digital_burst_shaper.xml
index 5c0bc78d0a..95e1bcbc77 100644
--- a/gr-digital/grc/digital_burst_shaper.xml
+++ b/gr-digital/grc/digital_burst_shaper.xml
@@ -2,7 +2,7 @@
<block>
<name>Burst Shaper</name>
<key>digital_burst_shaper_xx</key>
- <category>Packet Operators</category>
+ <category>[Core]/Packet Operators</category>
<import>from gnuradio import digital</import>
<make>digital.burst_shaper_$(type.fcn)($window, $pre_padding, $post_padding, $insert_phasing, $length_tag_name)</make>
<param>
diff --git a/gr-digital/grc/digital_constellation.xml b/gr-digital/grc/digital_constellation.xml
index 5254e4d799..ef5364d248 100644
--- a/gr-digital/grc/digital_constellation.xml
+++ b/gr-digital/grc/digital_constellation.xml
@@ -9,7 +9,13 @@
<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>
+#if str($type) == "calcdist"
+self.$(id) = $(id) = digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims).base()
+#else
+self.$(id) = $(id) = digital.constellation_$(type)().base()
+#end if
+
#if str($soft_dec_lut).lower() == '"auto"' or str($soft_dec_lut).lower() == "'auto'"
self.$(id).gen_soft_dec_lut($precision)
#else if str($soft_dec_lut) != 'None'
@@ -17,16 +23,53 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision)
#end if
</var_make>
- <var_value>digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims)</var_value>
+<var_value>
+#if str($type) == "calcdist"
+digital.constellation_calcdist($const_points, $sym_map, $rot_sym, $dims)
+#else
+digital.constellation_$(type)()
+#end if
+</var_value>
<make></make>
<!--<callback></callback>-->
<param>
+ <name>Constellation Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Variable Constellation</name>
+ <key>calcdist</key>
+ </option>
+ <option>
+ <name>BPSK</name>
+ <key>bpsk</key>
+ </option>
+ <option>
+ <name>QPSK</name>
+ <key>qpsk</key>
+ </option>
+ <option>
+ <name>DQPSK</name>
+ <key>dqpsk</key>
+ </option>
+ <option>
+ <name>8PSK</name>
+ <key>8psk</key>
+ </option>
+ <option>
+ <name>16QAM</name>
+ <key>16qam</key>
+ </option>
+
+ </param>
+ <param>
<name>Symbol Map</name>
<key>sym_map</key>
<value>[0, 1, 3, 2]</value>
<type>int_vector</type>
+ <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide>
</param>
<param>
@@ -34,6 +77,7 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision)
<key>const_points</key>
<value>[-1-1j, -1+1j, 1+1j, 1-1j]</value>
<type>complex_vector</type>
+ <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide>
</param>
<param>
@@ -41,6 +85,7 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision)
<key>rot_sym</key>
<value>4</value>
<type>int</type>
+ <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide>
</param>
<param>
@@ -48,8 +93,8 @@ self.$(id).set_soft_dec_lut($soft_dec_lut, $precision)
<key>dims</key>
<value>1</value>
<type>int</type>
+ <hide> #if str($type) == "calcdist" then 'none' else 'all' #</hide>
</param>
-
<param>
<name>Soft Decisions Precision</name>
<key>precision</key>
diff --git a/gr-digital/grc/digital_header_payload_demux.xml b/gr-digital/grc/digital_header_payload_demux.xml
index 24c6c5b216..a2fe80e621 100644
--- a/gr-digital/grc/digital_header_payload_demux.xml
+++ b/gr-digital/grc/digital_header_payload_demux.xml
@@ -13,6 +13,7 @@
$timing_tag_key,
$samp_rate,
$special_tags,
+ $header_padding,
)</make>
<param>
<name>Header Length (Symbols)</name>
@@ -20,6 +21,12 @@
<type>int</type>
</param>
<param>
+ <name>Header Padding (Uncertainty / Symbols)</name>
+ <key>header_padding</key>
+ <value>0</value>
+ <type>int</type>
+ </param>
+ <param>
<name>Items per symbol</name>
<key>items_per_symbol</key>
<type>int</type>
diff --git a/gr-digital/include/gnuradio/digital/header_payload_demux.h b/gr-digital/include/gnuradio/digital/header_payload_demux.h
index 303bebbf32..bcd6bd108a 100644
--- a/gr-digital/include/gnuradio/digital/header_payload_demux.h
+++ b/gr-digital/include/gnuradio/digital/header_payload_demux.h
@@ -1,5 +1,5 @@
/* -*- c++ -*- */
-/* Copyright 2012 Free Software Foundation, Inc.
+/* Copyright 2012-2016 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -29,7 +29,7 @@ namespace gr {
namespace digital {
/*!
- * \brief Header/Payload demuxer.
+ * \brief Header/Payload demuxer (HPD).
* \ingroup packet_operators_blk
*
* \details
@@ -58,6 +58,9 @@ namespace gr {
* and taken as the payload length. The payload, together with the header data
* as tags, is then copied to output 1.
*
+ * If the header demodulation fails, the header must send a PMT with value
+ * pmt::PMT_F. The state gets reset and the header is ignored.
+ *
* \section hpd_item_sizes Symbols, Items and Item Sizes
*
* To generically and transparently handle different kinds of modulations,
@@ -68,20 +71,66 @@ namespace gr {
* grouping items. In OFDM, we usually don't care about individual samples, but
* we do care about full OFDM symbols, so we set \p items_per_symbol to the
* IFFT / FFT length of the OFDM modulator / demodulator.
- * For most single-carrier modulations, this value can be set to 1 (the default
- * value).
+ * For single-carrier modulations, this value can be set to the number of
+ * samples per symbol, to handle data in number of symbols, or to 1 to
+ * handle data in number of samples.
* If specified, \p guard_interval items are discarded before every symbol.
* This is useful for demuxing bursts of OFDM signals.
*
* On the output, we can deal with symbols directly by setting \p output_symbols
* to true. In that case, the output item size is the <em>symbol size</em>.
*
- * \b Example: OFDM with 48 sub-carriers, using a length-64 IFFT on the modulator,
- * and a cyclic-prefix length of 16 samples. In this case, the itemsize is
- * `sizeof(gr_complex)`, because we're receiving complex samples. One OFDM symbol
- * has 64 samples, hence \p items_per_symbol is set to 64, and \p guard_interval to
- * 16. The header length is specified in number of OFDM symbols. Because we want to
- * deal with full OFDM symbols, we set \p output_symbols to true.
+ * \b Example: OFDM with 48 sub-carriers, using a length-64 IFFT on the
+ * modulator, and a cyclic-prefix length of 16 samples. In this case,
+ * \p itemsize is `sizeof(gr_complex)`, because we're receiving complex
+ * samples. One OFDM symbol has 64 samples, hence \p items_per_symbol is
+ * set to 64, and \p guard_interval to 16. The header length is specified
+ * in number of OFDM symbols. Because we want to deal with full OFDM
+ * symbols, we set \p output_symbols to true.
+ *
+ * \b Example: PSK-modulated signals, with 4 samples per symbol. Again,
+ * \p itemsize is `sizeof(gr_complex)` because we're still dealing with
+ * complex samples. \p items_per_symbol is 4, because one item is one
+ * sample. \p guard_interval must be set to 0. The header length is
+ * given in number of PSK symbols.
+ *
+ * \section hpd_uncertainty Handling timing uncertainty on the trigger
+ *
+ * By default, the assumption is made that the trigger arrives on *exactly*
+ * the sample that the header starts. These triggers typically come from
+ * timing synchronization algorithms which may be suboptimal, and have a
+ * known timing uncertainty (e.g., we know the trigger might be a sample
+ * too early or too late).
+ *
+ * The demuxer has an option for this case, the \p header_padding. If this
+ * value is non-zero, it specifies the number of items that are prepended
+ * and appended to the header before copying it to the header output.
+ *
+ * Example: Say our synchronization algorithm can be off by up to two
+ * samples, and the header length is 20 samples. So we set \p header_len
+ * to 20, and \p header_padding to 2.
+ * Now assume a trigger arrives on sample index 100. We copy a total of
+ * 24 samples to the header port, starting at sample index 98.
+ *
+ * The payload is *not* padded. Let's say the header demod reports a
+ * payload length of 100. In the previous examples, we would copy 100
+ * samples to the payload port, starting at sample index 120 (this means
+ * the padded samples appended to the header are copied to both ports!).
+ * However, the header demodulator has the option to specify a payload
+ * offset, which cannot exceed the padding value. To do this, include
+ * a key `payload_offset` in the message sent back to the HPD. A negative
+ * value means the payload starts earlier than otherwise.
+ * (If you wanted to always pad the payload, you could set `payload_offset`
+ * to `-header_padding` and increase the reported length of the payload).
+ *
+ * Because the padding is specified in number of items, and not symbols,
+ * this value can only be multiples of the number of items per symbol *if*
+ * either \p output_symbols is true, or a guard interval is specified (or
+ * both). Note that in practice, it is rare that both a guard interval is
+ * specified *and* a padding value is required. The difference between the
+ * padding value and a guard interval is that a guard interval is part of
+ * the signal, and comes with *every* symbol, whereas the header padding
+ * is added to only the header, and is not by design.
*
* \section hpd_tag_handling Tag Handling
*
@@ -95,12 +144,14 @@ namespace gr {
* it belongs to this packet or the following. In this case, it is possible that the
* tag might be propagated twice.
*
- * Tags outside of packets are generally discarded. If this information is important,
- * there are two additional mechanisms to preserve the tags:
+ * Tags outside of packets are generally discarded. If there are tags that
+ * carry important information that must not be list, there are two
+ * additional mechanisms to preserve the tags:
* - Timing tags might be relevant to know \b when a packet was received. By
* specifying the name of a timestamp tag and the sample rate at this block, it
* keeps track of the time and will add the time to the first item of every packet.
- * The name of the timestamp tag is usually 'rx_time' (see gr::uhd::usrp_source::make()).
+ * The name of the timestamp tag is usually 'rx_time' (see, e.g.,
+ * gr::uhd::usrp_source::make()).
* The time value must be specified in the UHD time format.
* - Other tags are simply stored and updated. As an example, the user might want to know the
* rx frequency, which UHD stores in the rx_freq tag. In this case, add the tag name 'rx_freq'
@@ -124,18 +175,20 @@ namespace gr {
* \param timing_tag_key The name of the tag with timing information, usually 'rx_time' or empty (this means timing info is discarded)
* \param samp_rate Sampling rate at the input. Necessary to calculate the rx time of packets.
* \param special_tags A vector of strings denoting tags which shall be preserved (see \ref hpd_tag_handling)
+ * \param header_padding A number of items that is appended and prepended to the header.
*/
static sptr make(
- int header_len,
- int items_per_symbol=1,
- int guard_interval=0,
+ const int header_len,
+ const int items_per_symbol=1,
+ const int guard_interval=0,
const std::string &length_tag_key="frame_len",
const std::string &trigger_tag_key="",
- bool output_symbols=false,
- size_t itemsize=sizeof(gr_complex),
+ const bool output_symbols=false,
+ const size_t itemsize=sizeof(gr_complex),
const std::string &timing_tag_key="",
const double samp_rate=1.0,
- const std::vector<std::string> &special_tags=std::vector<std::string>()
+ const std::vector<std::string> &special_tags=std::vector<std::string>(),
+ const size_t header_padding=0
);
};
diff --git a/gr-digital/lib/header_payload_demux_impl.cc b/gr-digital/lib/header_payload_demux_impl.cc
index 89428fa86e..f887ea1eb3 100644
--- a/gr-digital/lib/header_payload_demux_impl.cc
+++ b/gr-digital/lib/header_payload_demux_impl.cc
@@ -1,5 +1,5 @@
/* -*- c++ -*- */
-/* Copyright 2012-2014 Free Software Foundation, Inc.
+/* Copyright 2012-2016 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -23,10 +23,10 @@
#include "config.h"
#endif
-#include <climits>
-#include <boost/format.hpp>
-#include <gnuradio/io_signature.h>
#include "header_payload_demux_impl.h"
+#include <gnuradio/io_signature.h>
+#include <boost/format.hpp>
+#include <climits>
namespace gr {
namespace digital {
@@ -55,55 +55,63 @@ namespace gr {
enum out_port_indexes_t {
PORT_HEADER = 0,
- PORT_PAYLOAD = 1
+ PORT_PAYLOAD = 1,
+ PORT_INPUTDATA = 0,
+ PORT_TRIGGER = 1
};
#define msg_port_id pmt::mp("header_data")
header_payload_demux::sptr
header_payload_demux::make(
- int header_len,
- int items_per_symbol,
- int guard_interval,
- const std::string &length_tag_key,
- const std::string &trigger_tag_key,
- bool output_symbols,
- size_t itemsize,
- const std::string &timing_tag_key,
- const double samp_rate,
- const std::vector<std::string> &special_tags
+ int header_len,
+ int items_per_symbol,
+ int guard_interval,
+ const std::string &length_tag_key,
+ const std::string &trigger_tag_key,
+ bool output_symbols,
+ size_t itemsize,
+ const std::string &timing_tag_key,
+ const double samp_rate,
+ const std::vector<std::string> &special_tags,
+ const size_t header_padding
){
return gnuradio::get_initial_sptr (
- new header_payload_demux_impl(
- header_len,
- items_per_symbol,
- guard_interval,
- length_tag_key,
- trigger_tag_key,
- output_symbols,
- itemsize,
- timing_tag_key,
- samp_rate,
- special_tags
- )
+ new header_payload_demux_impl(
+ header_len,
+ items_per_symbol,
+ guard_interval,
+ length_tag_key,
+ trigger_tag_key,
+ output_symbols,
+ itemsize,
+ timing_tag_key,
+ samp_rate,
+ special_tags,
+ header_padding
+ )
);
}
header_payload_demux_impl::header_payload_demux_impl(
- int header_len,
- int items_per_symbol,
- int guard_interval,
- const std::string &length_tag_key,
- const std::string &trigger_tag_key,
- bool output_symbols,
- size_t itemsize,
- const std::string &timing_tag_key,
- const double samp_rate,
- const std::vector<std::string> &special_tags
+ int header_len,
+ int items_per_symbol,
+ int guard_interval,
+ const std::string &length_tag_key,
+ const std::string &trigger_tag_key,
+ bool output_symbols,
+ size_t itemsize,
+ const std::string &timing_tag_key,
+ const double samp_rate,
+ const std::vector<std::string> &special_tags,
+ const size_t header_padding
) : block("header_payload_demux",
- io_signature::make2(1, 2, itemsize, sizeof(char)),
- io_signature::make(2, 2, (output_symbols ? itemsize * items_per_symbol : itemsize))),
+ io_signature::make2(1, 2, itemsize, sizeof(char)),
+ io_signature::make(2, 2, (output_symbols ? itemsize * items_per_symbol : itemsize))),
d_header_len(header_len),
+ d_header_padding_symbols(header_padding / items_per_symbol),
+ d_header_padding_items(header_padding % items_per_symbol),
+ d_header_padding_total_items(header_padding),
d_items_per_symbol(items_per_symbol),
d_gi(guard_interval),
d_len_tag_key(pmt::string_to_symbol(length_tag_key)),
@@ -113,32 +121,42 @@ namespace gr {
d_uses_trigger_tag(!trigger_tag_key.empty()),
d_state(STATE_FIND_TRIGGER),
d_curr_payload_len(0),
+ d_curr_payload_offset(0),
d_payload_tag_keys(0),
d_payload_tag_values(0),
d_track_time(!timing_tag_key.empty()),
d_timing_key(pmt::intern(timing_tag_key)),
+ d_payload_offset_key(pmt::intern("payload_offset")),
d_last_time_offset(0),
d_last_time(pmt::make_tuple(pmt::from_uint64(0L), pmt::from_double(0.0))),
d_sampling_time(1.0/samp_rate)
{
if (d_header_len < 1) {
- throw std::invalid_argument("Header length must be at least 1 symbol.");
+ throw std::invalid_argument("Header length must be at least 1 symbol.");
+ }
+ if (header_padding < 0) {
+ throw std::invalid_argument("Header padding must be non-negative.");
}
if (d_items_per_symbol < 1 || d_gi < 0 || d_itemsize < 1) {
- throw std::invalid_argument("Items and symbol sizes must be at least 1.");
+ throw std::invalid_argument("Items and symbol sizes must be at least 1.");
}
if (d_output_symbols) {
- set_relative_rate(1.0 / (d_items_per_symbol + d_gi));
+ set_relative_rate(1.0 / (d_items_per_symbol + d_gi));
} else {
- set_relative_rate((double)d_items_per_symbol / (d_items_per_symbol + d_gi));
- set_output_multiple(d_items_per_symbol);
+ set_relative_rate((double)d_items_per_symbol / (d_items_per_symbol + d_gi));
+ set_output_multiple(d_items_per_symbol);
+ }
+ if ((d_output_symbols || d_gi) && d_header_padding_items) {
+ throw std::invalid_argument(
+ "If output_symbols is true or a guard interval is given, padding must be a multiple of items_per_symbol!"
+ );
}
set_tag_propagation_policy(TPP_DONT);
message_port_register_in(msg_port_id);
set_msg_handler(msg_port_id, boost::bind(&header_payload_demux_impl::parse_header_data_msg, this, _1));
- for (unsigned i = 0; i < special_tags.size(); i++) {
- d_special_tags.push_back(pmt::string_to_symbol(special_tags[i]));
- d_special_tags_last_value.push_back(pmt::PMT_NIL);
+ for (size_t i = 0; i < special_tags.size(); i++) {
+ d_special_tags.push_back(pmt::string_to_symbol(special_tags[i]));
+ d_special_tags_last_value.push_back(pmt::PMT_NIL);
}
}
@@ -146,144 +164,219 @@ namespace gr {
{
}
+ // forecast() depends on state:
+ // - When waiting for a header, we require at least the header length
+ // - when waiting for a payload, we require at least the payload length
+ // - Otherwise, pretend this is a sync block with a decimation/interpolation
+ // depending on symbol size and if we output symbols or items
void
- header_payload_demux_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
- {
+ header_payload_demux_impl::forecast(
+ int noutput_items,
+ gr_vector_int &ninput_items_required
+ ) {
int n_items_reqd = 0;
if (d_state == STATE_HEADER) {
- n_items_reqd = d_header_len * (d_items_per_symbol + d_gi);
+ n_items_reqd = d_header_len * (d_items_per_symbol + d_gi)
+ + 2*d_header_padding_total_items;
} else if (d_state == STATE_PAYLOAD) {
- n_items_reqd = d_curr_payload_len * (d_items_per_symbol + d_gi);
+ n_items_reqd = d_curr_payload_len * (d_items_per_symbol + d_gi);
} else {
- n_items_reqd = noutput_items * (d_items_per_symbol + d_gi);
- if (!d_output_symbols) {
- // here, noutput_items is an integer multiple of d_items_per_symbol!
- n_items_reqd /= d_items_per_symbol;
- }
+ n_items_reqd = noutput_items * (d_items_per_symbol + d_gi);
+ if (!d_output_symbols) {
+ // Here, noutput_items is an integer multiple of d_items_per_symbol!
+ n_items_reqd /= d_items_per_symbol;
+ }
}
for (unsigned i = 0; i < ninput_items_required.size(); i++) {
- ninput_items_required[i] = n_items_reqd;
+ ninput_items_required[i] = n_items_reqd;
}
}
- inline bool
- header_payload_demux_impl::check_items_available(
- int n_symbols,
- gr_vector_int &ninput_items,
- int noutput_items,
- int nread
- )
- {
- // Check there's enough items on the input
- if ((n_symbols * (d_items_per_symbol + d_gi)) > (ninput_items[0]-nread)
- || (ninput_items.size() == 2 && ((n_symbols * (d_items_per_symbol + d_gi)) > (ninput_items[1]-nread)))) {
- return false;
- }
-
+ bool header_payload_demux_impl::check_buffers_ready(
+ int output_symbols_reqd,
+ int extra_output_items_reqd,
+ int noutput_items,
+ int input_items_reqd,
+ gr_vector_int &ninput_items,
+ int n_items_read
+ ) {
// Check there's enough space on the output buffer
if (d_output_symbols) {
- if (noutput_items < n_symbols) {
- return false;
- }
+ if (noutput_items < output_symbols_reqd + extra_output_items_reqd) {
+ return false;
+ }
} else {
- if (noutput_items < n_symbols * d_items_per_symbol) {
- return false;
- }
+ if (noutput_items < (output_symbols_reqd * d_items_per_symbol) + extra_output_items_reqd) {
+ return false;
+ }
+ }
+
+ // Check there's enough items on the input
+ if (input_items_reqd > (ninput_items[0]-n_items_read)
+ || (ninput_items.size() == 2 && (input_items_reqd > (ninput_items[1]-n_items_read)))) {
+ return false;
}
+ // All good
return true;
}
int
- header_payload_demux_impl::general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
- {
- const unsigned char *in = (const unsigned char *) input_items[0];
+ header_payload_demux_impl::general_work(
+ int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ) {
+ const unsigned char *in = (const unsigned char *) input_items[PORT_INPUTDATA];
unsigned char *out_header = (unsigned char *) output_items[PORT_HEADER];
unsigned char *out_payload = (unsigned char *) output_items[PORT_PAYLOAD];
- int nread = 0;
- int trigger_offset = 0;
-
+ const int n_input_items = (ninput_items.size() == 2) ?
+ std::min(ninput_items[0], ninput_items[1]) :
+ ninput_items[0];
+ // Items read going into general_work()
+ const uint64_t n_items_read_base = nitems_read(PORT_INPUTDATA);
+ // Items read during this call to general_work()
+ int n_items_read = 0;
+
+ #define CONSUME_ITEMS(items_to_consume) \
+ update_special_tags( \
+ n_items_read_base + n_items_read, \
+ n_items_read_base + n_items_read + (items_to_consume) \
+ ); \
+ consume_each(items_to_consume); \
+ n_items_read += (items_to_consume); \
+ in += (items_to_consume) * d_itemsize;
switch (d_state) {
- case STATE_WAIT_FOR_MSG:
- // In an ideal world, this would never be called
- return 0;
-
- case STATE_HEADER_RX_FAIL:
- update_special_tags(0, 1);
- consume_each (1);
- in += d_itemsize;
- nread++;
- d_state = STATE_FIND_TRIGGER;
- // The following break was added to this state as well as STATE_FIND_TRIGGER
- // and STATE_HEADER. There appears to be a bug somewhere in this code without
- // the breaks that can lead to failure of this block. With the breaks in the code
- // testing has shown more stable performance with various block paramters.
- // If an offset calculation bug is found and fixed, it should be possible to
- // remove these breaks for some performance increase.
- break;
-
- case STATE_FIND_TRIGGER:
- trigger_offset = find_trigger_signal(nread, noutput_items, input_items);
- if (trigger_offset == -1) {
- update_special_tags(0, noutput_items - nread);
- consume_each(noutput_items - nread);
- break;
- }
- update_special_tags(0, trigger_offset);
- consume_each (trigger_offset);
- in += trigger_offset * d_itemsize;
- d_state = STATE_HEADER;
- break;
-
- case STATE_HEADER:
- if (check_items_available(d_header_len, ninput_items, noutput_items, nread)) {
- copy_n_symbols(in, out_header, PORT_HEADER, d_header_len);
- d_state = STATE_WAIT_FOR_MSG;
- add_special_tags();
- produce(
- PORT_HEADER,
- d_header_len * (d_output_symbols ? 1 : d_items_per_symbol)
- );
- }
- break;
-
- case STATE_HEADER_RX_SUCCESS:
- for (unsigned i = 0; i < d_payload_tag_keys.size(); i++) {
- add_item_tag(
- PORT_PAYLOAD,
- nitems_written(PORT_PAYLOAD),
- d_payload_tag_keys[i],
- d_payload_tag_values[i]
- );
- }
- nread += d_header_len * (d_items_per_symbol + d_gi);
- update_special_tags(0, nread);
- consume_each (nread);
- in += nread * d_itemsize;
- d_state = STATE_PAYLOAD;
- break;
-
- case STATE_PAYLOAD:
- if (check_items_available(d_curr_payload_len, ninput_items, noutput_items, nread)) {
- // The -1 because we won't consume the last item, it might hold the next trigger.
- update_special_tags(0, (d_curr_payload_len - 1) * (d_items_per_symbol + d_gi));
- copy_n_symbols(in, out_payload, PORT_PAYLOAD, d_curr_payload_len);
- produce(PORT_PAYLOAD, d_curr_payload_len * (d_output_symbols ? 1 : d_items_per_symbol));
- consume_each ((d_curr_payload_len - 1) * (d_items_per_symbol + d_gi)); // Same here
- set_min_noutput_items(d_output_symbols ? 1 : (d_items_per_symbol + d_gi));
- d_state = STATE_FIND_TRIGGER;
- }
- break;
-
- default:
- throw std::runtime_error("invalid state");
+ case STATE_WAIT_FOR_MSG:
+ // In an ideal world, this would never be called
+ // parse_header_data_msg() is the only place that can kick us out
+ // of this state.
+ return 0;
+
+ case STATE_HEADER_RX_FAIL:
+ // Actions:
+ // - Consume a single item to make sure we're not deleting any other
+ // info
+ CONSUME_ITEMS(1);
+ d_state = STATE_FIND_TRIGGER;
+ break;
+
+ case STATE_FIND_TRIGGER: {
+ // Assumptions going into this state:
+ // - No other state was active for this call to general_work()
+ // - i.e. n_items_read == 0
+ // Start looking for a trigger after any header padding.
+ // The trigger offset is relative to 'in'.
+ // => The absolute trigger offset is on n_items_read_base + n_items_read_base + trigger_offset
+ const int max_rel_offset = n_input_items - n_items_read;
+ const int trigger_offset = find_trigger_signal(
+ d_header_padding_total_items,
+ max_rel_offset,
+ n_items_read_base + n_items_read,
+ (input_items.size() == 2) ?
+ ((const unsigned char *) input_items[PORT_TRIGGER]) + n_items_read : NULL
+ );
+ if (trigger_offset < max_rel_offset) {
+ d_state = STATE_HEADER;
+ }
+ // If we're using padding, don't consume everything, or we might
+ // end up with not enough items before the trigger
+ const int items_to_consume = trigger_offset - d_header_padding_total_items;
+ CONSUME_ITEMS(items_to_consume);
+ break;
+ } /* case STATE_FIND_TRIGGER */
+
+ case STATE_HEADER:
+ // Assumptions going into this state:
+ // - The first items on `in' are the header samples (including padding)
+ // - So we can just copy from the beginning of `in'
+ // - The trigger is on item index `d_header_padding * d_items_per_symbol'
+ // Actions:
+ // - Copy the entire header (including padding) to the header port
+ // - Special tags are added to the header port
+ if (check_buffers_ready(
+ d_header_len + 2*d_header_padding_symbols,
+ d_header_padding_items,
+ noutput_items,
+ d_header_len * (d_items_per_symbol + d_gi) + 2*d_header_padding_total_items,
+ ninput_items,
+ n_items_read)) {
+ add_special_tags();
+ copy_n_symbols(
+ in,
+ out_header,
+ PORT_HEADER,
+ n_items_read_base + n_items_read,
+ d_header_len+2*d_header_padding_symbols, // Number of symbols to copy
+ 2*d_header_padding_items
+ );
+ d_state = STATE_WAIT_FOR_MSG;
+ }
+ break;
+
+ case STATE_HEADER_RX_SUCCESS:
+ // Copy tags from header to payload
+ for (size_t i = 0; i < d_payload_tag_keys.size(); i++) {
+ add_item_tag(
+ PORT_PAYLOAD,
+ nitems_written(PORT_PAYLOAD),
+ d_payload_tag_keys[i],
+ d_payload_tag_values[i]
+ );
+ }
+ // Consume header from input
+ {
+ // Consume the padding only once, we leave the second
+ // part in there because it might be part of the payload
+ const int items_to_consume =
+ d_header_len * (d_items_per_symbol + d_gi)
+ + d_header_padding_total_items
+ + d_curr_payload_offset;
+ CONSUME_ITEMS(items_to_consume);
+ d_curr_payload_offset = 0;
+ d_state = STATE_PAYLOAD;
+ }
+ break;
+
+ case STATE_PAYLOAD:
+ // Assumptions:
+ // - Input buffer is in the right spot to just start copying
+ if (check_buffers_ready(
+ d_curr_payload_len,
+ 0,
+ noutput_items,
+ d_curr_payload_len * (d_items_per_symbol + d_gi),
+ ninput_items,
+ n_items_read)) {
+ // Write payload
+ copy_n_symbols(
+ in,
+ out_payload,
+ PORT_PAYLOAD,
+ n_items_read_base + n_items_read,
+ d_curr_payload_len
+ );
+ // Consume payload
+ // We can't consume the full payload, because we need to hold off
+ // at least the padding value. We'll use a minimum padding of 1
+ // item here.
+ const int items_padding = std::max(d_header_padding_total_items, 1);
+ const int items_to_consume =
+ d_curr_payload_len * (d_items_per_symbol + d_gi)
+ - items_padding;
+ CONSUME_ITEMS(items_to_consume);
+ set_min_noutput_items(d_output_symbols ? 1 : (d_items_per_symbol + d_gi));
+ d_state = STATE_FIND_TRIGGER;
+ }
+ break;
+
+ default:
+ throw std::runtime_error("invalid state");
} /* switch */
return WORK_CALLED_PRODUCE;
@@ -292,35 +385,41 @@ namespace gr {
int
header_payload_demux_impl::find_trigger_signal(
- int nread,
- int noutput_items,
- gr_vector_const_void_star &input_items)
- {
- if (input_items.size() == 2) {
- unsigned char *in_trigger = (unsigned char *) input_items[1];
- in_trigger += nread;
- for (int i = 0; i < noutput_items-nread; i++) {
- if (in_trigger[i]) {
- return i;
- }
- }
+ int skip_items,
+ int max_rel_offset,
+ uint64_t base_offset,
+ const unsigned char *in_trigger
+ ) {
+ int rel_offset = max_rel_offset;
+ if (max_rel_offset < skip_items) {
+ return rel_offset;
+ }
+ if (in_trigger) {
+ for (int i = skip_items; i < max_rel_offset; i++) {
+ if (in_trigger[i]) {
+ rel_offset = i;
+ break;
+ }
+ }
}
if (d_uses_trigger_tag) {
std::vector<tag_t> tags;
- get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+noutput_items, d_trigger_tag_key);
- uint64_t min_offset = ULLONG_MAX;
- int tag_index = -1;
- for (unsigned i = 0; i < tags.size(); i++) {
- if (tags[i].offset < min_offset) {
- tag_index = (int) i;
- min_offset = tags[i].offset;
+ get_tags_in_range(
+ tags,
+ PORT_INPUTDATA,
+ base_offset + skip_items,
+ base_offset + max_rel_offset,
+ d_trigger_tag_key
+ );
+ if (!tags.empty()) {
+ std::sort(tags.begin(), tags.end(), tag_t::offset_compare);
+ const int tag_rel_offset = tags[0].offset - base_offset;
+ if (tag_rel_offset < rel_offset) {
+ rel_offset = tag_rel_offset;
}
}
- if (tag_index != -1) {
- return min_offset - nitems_read(0);
- }
}
- return -1;
+ return rel_offset;
} /* find_trigger_signal() */
@@ -332,77 +431,100 @@ namespace gr {
d_state = STATE_HEADER_RX_FAIL;
if (pmt::is_integer(header_data)) {
- d_curr_payload_len = pmt::to_long(header_data);
- d_payload_tag_keys.push_back(d_len_tag_key);
- d_payload_tag_values.push_back(header_data);
- d_state = STATE_HEADER_RX_SUCCESS;
+ d_curr_payload_len = pmt::to_long(header_data);
+ d_payload_tag_keys.push_back(d_len_tag_key);
+ d_payload_tag_values.push_back(header_data);
+ d_state = STATE_HEADER_RX_SUCCESS;
} else if (pmt::is_dict(header_data)) {
- pmt::pmt_t dict_items(pmt::dict_items(header_data));
- while (!pmt::is_null(dict_items)) {
- pmt::pmt_t this_item(pmt::car(dict_items));
- d_payload_tag_keys.push_back(pmt::car(this_item));
- d_payload_tag_values.push_back(pmt::cdr(this_item));
- if (pmt::equal(pmt::car(this_item), d_len_tag_key)) {
- d_curr_payload_len = pmt::to_long(pmt::cdr(this_item));
- d_state = STATE_HEADER_RX_SUCCESS;
- }
- dict_items = pmt::cdr(dict_items);
- }
- if (d_state == STATE_HEADER_RX_FAIL) {
- GR_LOG_CRIT(d_logger, "no length tag passed from header data");
- }
+ pmt::pmt_t dict_items(pmt::dict_items(header_data));
+ while (!pmt::is_null(dict_items)) {
+ pmt::pmt_t this_item(pmt::car(dict_items));
+ d_payload_tag_keys.push_back(pmt::car(this_item));
+ d_payload_tag_values.push_back(pmt::cdr(this_item));
+ if (pmt::equal(pmt::car(this_item), d_len_tag_key)) {
+ d_curr_payload_len = pmt::to_long(pmt::cdr(this_item));
+ d_state = STATE_HEADER_RX_SUCCESS;
+ }
+ if (pmt::equal(pmt::car(this_item), d_payload_offset_key)) {
+ d_curr_payload_offset = pmt::to_long(pmt::cdr(this_item));
+ if (std::abs(d_curr_payload_offset) > d_header_padding_total_items) {
+ GR_LOG_CRIT(d_logger, "Payload offset exceeds padding");
+ d_state = STATE_HEADER_RX_FAIL;
+ return;
+ }
+ }
+ dict_items = pmt::cdr(dict_items);
+ }
+ if (d_state == STATE_HEADER_RX_FAIL) {
+ GR_LOG_CRIT(d_logger, "no payload length passed from header data");
+ }
} else if (header_data == pmt::PMT_F || pmt::is_null(header_data)) {
- GR_LOG_INFO(d_logger, boost::format("Parser returned %1%") % pmt::write_string(header_data));
+ GR_LOG_INFO(d_logger, boost::format("Parser returned %1%") % pmt::write_string(header_data));
} else {
- GR_LOG_ALERT(d_logger, boost::format("Received illegal header data (%1%)") % pmt::write_string(header_data));
+ GR_LOG_ALERT(d_logger, boost::format("Received illegal header data (%1%)") % pmt::write_string(header_data));
}
if (d_state == STATE_HEADER_RX_SUCCESS)
{
- if ((d_curr_payload_len * (d_output_symbols ? 1 : d_items_per_symbol)) > max_output_buffer(1)/2) {
- d_state = STATE_HEADER_RX_FAIL;
- GR_LOG_INFO(d_logger, boost::format("Detected a packet larger than max frame size (%1% symbols)") % d_curr_payload_len);
- } else {
- set_min_noutput_items(d_curr_payload_len * (d_output_symbols ? 1 : d_items_per_symbol));
- }
+ if (d_curr_payload_len < 0) {
+ GR_LOG_WARN(d_logger, boost::format("Detected a packet larger than max frame size (%1% symbols)") % d_curr_payload_len);
+ d_curr_payload_len = 0;
+ d_state = STATE_HEADER_RX_FAIL;
+ }
+ if ((d_curr_payload_len * (d_output_symbols ? 1 : d_items_per_symbol)) > max_output_buffer(1)/2) {
+ d_state = STATE_HEADER_RX_FAIL;
+ GR_LOG_INFO(d_logger, boost::format("Detected a packet larger than max frame size (%1% symbols)") % d_curr_payload_len);
+ } else {
+ set_min_noutput_items(d_curr_payload_len * (d_output_symbols ? 1 : d_items_per_symbol));
+ }
}
} /* parse_header_data_msg() */
void
header_payload_demux_impl::copy_n_symbols(
- const unsigned char *in,
- unsigned char *out,
- int port,
- int n_symbols
- )
- {
+ const unsigned char *in,
+ unsigned char *out,
+ int port,
+ const uint64_t n_items_read_base,
+ int n_symbols,
+ int n_padding_items
+ ) {
// Copy samples
if (d_gi) {
- for (int i = 0; i < n_symbols; i++) {
- memcpy((void *) out, (void *) (in + d_gi * d_itemsize), d_items_per_symbol * d_itemsize);
- in += d_itemsize * (d_items_per_symbol + d_gi);
- out += d_itemsize * d_items_per_symbol;
- }
+ // Here we know n_padding_items must be 0 (see contract),
+ // because all padding items will be part of n_symbols
+ for (int i = 0; i < n_symbols; i++) {
+ memcpy(
+ (void *) out,
+ (void *) (in + d_gi * d_itemsize),
+ d_items_per_symbol * d_itemsize
+ );
+ in += d_itemsize * (d_items_per_symbol + d_gi);
+ out += d_itemsize * d_items_per_symbol;
+ }
} else {
- memcpy(
- (void *) out,
- (void *) in,
- n_symbols * d_items_per_symbol * d_itemsize
- );
+ memcpy(
+ (void *) out,
+ (void *) in,
+ (n_symbols * d_items_per_symbol + n_padding_items) * d_itemsize
+ );
}
// Copy tags
std::vector<tag_t> tags;
get_tags_in_range(
- tags, 0,
- nitems_read(0),
- nitems_read(0) + n_symbols * (d_items_per_symbol + d_gi)
+ tags,
+ PORT_INPUTDATA,
+ n_items_read_base,
+ n_items_read_base
+ + n_symbols * (d_items_per_symbol + d_gi)
+ + n_padding_items
);
for (size_t t = 0; t < tags.size(); t++) {
// The trigger tag is *not* propagated
if (tags[t].key == d_trigger_tag_key) {
continue;
}
- int new_offset = tags[t].offset - nitems_read(0);
+ int new_offset = tags[t].offset - n_items_read_base;
if (d_output_symbols) {
new_offset /= (d_items_per_symbol + d_gi);
} else if (d_gi) {
@@ -418,43 +540,49 @@ namespace gr {
tags[t].value
);
}
+ // Advance write pointers
+ // Items to produce might actually be symbols
+ const int items_to_produce = d_output_symbols ?
+ n_symbols :
+ (n_symbols * d_items_per_symbol + n_padding_items);
+ produce(port, items_to_produce);
} /* copy_n_symbols() */
void
header_payload_demux_impl::update_special_tags(
- int range_start,
- int range_end
+ uint64_t range_start,
+ uint64_t range_end
){
if (d_track_time) {
- std::vector<tag_t> tags;
- get_tags_in_range(tags, 0,
- nitems_read(0) + range_start,
- nitems_read(0) + range_end,
- d_timing_key
- );
- for (unsigned t = 0; t < tags.size(); t++) {
- if(tags[t].offset >= d_last_time_offset) {
- d_last_time = tags[t].value;
- d_last_time_offset = tags[t].offset;
- }
- }
+ std::vector<tag_t> tags;
+ get_tags_in_range(
+ tags,
+ PORT_INPUTDATA,
+ range_start,
+ range_end,
+ d_timing_key
+ );
+ if (!tags.empty()) {
+ std::sort(tags.begin(), tags.end(), tag_t::offset_compare);
+ d_last_time = tags.back().value;
+ d_last_time_offset = tags.back().offset;
+ }
}
std::vector<tag_t> tags;
- for (unsigned i = 0; i < d_special_tags.size(); i++) {
- uint64_t offset = 0;
- // TODO figure out if it's better to get all tags at once instead of doing this for every tag individually
- get_tags_in_range(tags, 0,
- nitems_read(0) + range_start,
- nitems_read(0) + range_end,
- d_special_tags[i]
- );
- for (unsigned t = 0; t < tags.size(); t++) {
- if(tags[t].offset >= offset) {
- d_special_tags_last_value[i] = tags[t].value;
- offset = tags[t].offset;
- }
- }
+ for (size_t i = 0; i < d_special_tags.size(); i++) {
+ // TODO figure out if it's better to get all tags at once instead of doing this for every tag individually
+ get_tags_in_range(
+ tags,
+ PORT_INPUTDATA, // Read from port 0
+ range_start,
+ range_end,
+ d_special_tags[i]
+ );
+ std::sort(tags.begin(), tags.end(), tag_t::offset_compare);
+ for (size_t t = 0; t < tags.size(); t++) {
+ d_special_tags_last_value[i] = tags[t].value;
+ }
}
} /* update_special_tags() */
@@ -462,24 +590,24 @@ namespace gr {
header_payload_demux_impl::add_special_tags(
){
if (d_track_time) {
- add_item_tag(
- PORT_HEADER,
- nitems_written(PORT_HEADER),
- d_timing_key,
- _update_pmt_time(
- d_last_time,
- d_sampling_time * (nitems_read(0) - d_last_time_offset)
- )
- );
+ add_item_tag(
+ PORT_HEADER,
+ nitems_written(PORT_HEADER),
+ d_timing_key,
+ _update_pmt_time(
+ d_last_time,
+ d_sampling_time * (nitems_read(PORT_INPUTDATA) - d_last_time_offset)
+ )
+ );
}
for (unsigned i = 0; i < d_special_tags.size(); i++) {
- add_item_tag(
- PORT_HEADER,
- nitems_written(PORT_HEADER),
- d_special_tags[i],
- d_special_tags_last_value[i]
- );
+ add_item_tag(
+ PORT_HEADER,
+ nitems_written(PORT_HEADER),
+ d_special_tags[i],
+ d_special_tags_last_value[i]
+ );
}
} /* add_special_tags() */
diff --git a/gr-digital/lib/header_payload_demux_impl.h b/gr-digital/lib/header_payload_demux_impl.h
index 1d45dc7ce1..0a70e7da3e 100644
--- a/gr-digital/lib/header_payload_demux_impl.h
+++ b/gr-digital/lib/header_payload_demux_impl.h
@@ -1,18 +1,18 @@
/* -*- c++ -*- */
-/* Copyright 2012 Free Software Foundation, Inc.
- *
+/* Copyright 2012-2016 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,
@@ -31,6 +31,9 @@ namespace gr {
{
private:
int d_header_len; //!< Number of bytes per header
+ const int d_header_padding_symbols; //!< Symbols header padding
+ const int d_header_padding_items; //!< Items header padding
+ const int d_header_padding_total_items; //!< Items header padding
int d_items_per_symbol; //!< Bytes per symbol
int d_gi; //!< Bytes per guard interval
pmt::pmt_t d_len_tag_key; //!< Key of length tag
@@ -40,10 +43,12 @@ namespace gr {
bool d_uses_trigger_tag; //!< If a trigger tag is used
int d_state; //!< Current read state
int d_curr_payload_len; //!< Length of the next payload (symbols)
+ int d_curr_payload_offset; //!< Offset of the next payload (symbols)
std::vector<pmt::pmt_t> d_payload_tag_keys; //!< Temporary buffer for PMTs that go on the payload (keys)
std::vector<pmt::pmt_t> d_payload_tag_values; //!< Temporary buffer for PMTs that go on the payload (values)
bool d_track_time; //!< Whether or not to keep track of the rx time
pmt::pmt_t d_timing_key; //!< Key of the timing tag (usually 'rx_time')
+ pmt::pmt_t d_payload_offset_key; //!< Key of payload offset (usually 'payload_offset')
uint64_t d_last_time_offset; //!< Item number of the last time tag
pmt::pmt_t d_last_time; //!< The actual time that was indicated
double d_sampling_time; //!< Inverse sampling rate
@@ -53,7 +58,14 @@ namespace gr {
// Helper functions to make the state machine more readable
//! Checks if there are enough items on the inputs and enough space on the output buffers to copy \p n_symbols symbols
- inline bool check_items_available(int n_symbols, gr_vector_int &ninput_items, int noutput_items, int nread);
+ bool check_buffers_ready(
+ int output_symbols_reqd,
+ int extra_output_items_reqd,
+ int noutput_items,
+ int input_items_reqd,
+ gr_vector_int &ninput_items,
+ int n_items_read
+ );
//! Message handler: Reads the result from the header demod and sets length tag (and other tags)
void parse_header_data_msg(pmt::pmt_t header_data);
@@ -62,49 +74,54 @@ namespace gr {
// Searches input 1 (if active), then the tags. Returns the offset in the input buffer
// (or -1 if none is found)
int find_trigger_signal(
- int nread,
- int noutput_items,
- gr_vector_const_void_star &input_items);
+ int skip_items,
+ int noutput_items,
+ uint64_t base_offset,
+ const unsigned char *in_trigger
+ );
//! Copies n symbols from in to out, makes sure tags are propagated properly. Does neither consume nor produce.
void copy_n_symbols(
- const unsigned char *in,
- unsigned char *out,
- int port,
- int n_symbols
+ const unsigned char *in,
+ unsigned char *out,
+ int port,
+ const uint64_t n_items_read_base,
+ int n_symbols,
+ int n_padding_items=0
);
//! Scans a given range for tags in d_special_tags
void update_special_tags(
- int range_start,
- int range_end
+ uint64_t range_start,
+ uint64_t range_end
);
//! Adds all tags in d_special_tags and timing info to the first item of the header.
void add_special_tags();
-
public:
header_payload_demux_impl(
- int header_len,
- int items_per_symbol,
- int guard_interval,
- const std::string &length_tag_key,
- const std::string &trigger_tag_key,
- bool output_symbols,
- size_t itemsize,
- const std::string &timing_tag_key,
- const double samp_rate,
- const std::vector<std::string> &special_tags
+ const int header_len,
+ const int items_per_symbol,
+ const int guard_interval,
+ const std::string &length_tag_key,
+ const std::string &trigger_tag_key,
+ const bool output_symbols,
+ const size_t itemsize,
+ const std::string &timing_tag_key,
+ const double samp_rate,
+ const std::vector<std::string> &special_tags,
+ const size_t header_padding
);
~header_payload_demux_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
int general_work(int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ );
};
} // namespace digital
diff --git a/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py
new file mode 100755
index 0000000000..5429ce1e07
--- /dev/null
+++ b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# Copyright 2006,2007,2010,2011,2013,2016 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, digital, blocks
+import pmt
+
+default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC'
+
+def string_to_1_0_list(s):
+ r = []
+ for ch in s:
+ x = ord(ch)
+ for i in range(8):
+ t = (x >> i) & 0x1
+ r.append(t)
+ return r
+
+def to_1_0_string(L):
+ return ''.join(map(lambda x: chr(x + ord('0')), L))
+
+class test_correlate_access_code_XX_ts(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_001(self):
+ payload = "test packet" # payload length is 11 bytes
+ header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped)
+ packet = header + payload
+ pad = (0,) * 64
+ src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad
+ expected = tuple(map(long, src_data[9+32:-len(pad)]))
+ src = blocks.vector_source_b(src_data)
+ op = digital.correlate_access_code_bb_ts("1011", 0, "sync")
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, op, dst)
+ self.tb.run()
+ result_data = dst.data()
+ result_tags = dst.tags()
+ self.assertEqual(len(result_data), len(payload)*8)
+ self.assertEqual(result_tags[0].offset, 0)
+ self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8)
+ self.assertEqual(result_data, expected)
+
+ def test_002(self):
+ payload = "test packet" # payload length is 11 bytes
+ header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped)
+ packet = header + payload
+ pad = (0,) * 64
+ src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad
+ src_floats = tuple(2*b-1 for b in src_data) # convert to binary antipodal symbols (-1,1)
+ expected = src_floats[9+32:-len(pad)]
+ src = blocks.vector_source_f(src_floats)
+ op = digital.correlate_access_code_ff_ts("1011", 0, "sync")
+ dst = blocks.vector_sink_f()
+ self.tb.connect(src, op, dst)
+ self.tb.run()
+ result_data = dst.data()
+ result_tags = dst.tags()
+ self.assertEqual(len(result_data), len(payload)*8)
+ self.assertEqual(result_tags[0].offset, 0)
+ self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8)
+ self.assertFloatTuplesAlmostEqual(result_data, expected, 5)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_correlate_access_code_XX_ts, "test_correlate_access_code_XX_ts.xml")
+
diff --git a/gr-digital/python/digital/qa_header_payload_demux.py b/gr-digital/python/digital/qa_header_payload_demux.py
index 8006d4442e..f36d71067c 100755
--- a/gr-digital/python/digital/qa_header_payload_demux.py
+++ b/gr-digital/python/digital/qa_header_payload_demux.py
@@ -1,29 +1,69 @@
#!/usr/bin/env python
-# Copyright 2012 Free Software Foundation, Inc.
-#
+# Copyright 2012-2016 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 __future__ import print_function
import time
-
-from gnuradio import gr, gr_unittest, digital, blocks
+import random
+import numpy
+from gnuradio import gr
+from gnuradio import gr_unittest
+from gnuradio import digital
+from gnuradio import blocks
import pmt
+def make_tag(key, value, offset):
+ tag = gr.tag_t()
+ tag.offset = offset
+ tag.key = pmt.string_to_symbol(key)
+ tag.value = pmt.to_pmt(value)
+ return tag
+
+
+class HeaderToMessageBlock(gr.sync_block):
+ """
+ Helps with testing the HPD. Receives a header, stores it, posts
+ a predetermined message.
+ """
+ def __init__(self, itemsize, header_len, messages, header_is_symbol=False):
+ gr.sync_block.__init__(
+ self,
+ name="HeaderToMessageBlock",
+ in_sig=[itemsize],
+ out_sig=[itemsize],
+ )
+ self.header_len = header_len
+ self.message_port_register_out(pmt.intern('header_data'))
+ self.messages = messages
+ self.msg_count = 0
+
+ def work(self, input_items, output_items):
+ for i in xrange(len(input_items[0])/self.header_len):
+ msg = self.messages[self.msg_count] or False
+ #print("Sending message: {0}".format(msg))
+ self.message_port_pub(pmt.intern('header_data'), pmt.to_pmt(msg))
+ self.msg_count += 1
+ output_items[0][:] = input_items[0][:]
+ return len(input_items[0])
+
+
class qa_header_payload_demux (gr_unittest.TestCase):
def setUp (self):
@@ -32,6 +72,36 @@ class qa_header_payload_demux (gr_unittest.TestCase):
def tearDown (self):
self.tb = None
+ def connect_all_blocks(self,
+ data_src, trigger_src,
+ hpd,
+ mock_header_demod,
+ payload_sink, header_sink
+ ):
+ """
+ Connect the standard HPD test flowgraph
+ """
+ self.tb.connect(data_src, (hpd, 0))
+ if trigger_src is not None:
+ self.tb.connect(trigger_src, (hpd, 1))
+ self.tb.connect((hpd, 0), mock_header_demod)
+ self.tb.connect(mock_header_demod, header_sink)
+ self.tb.msg_connect(
+ mock_header_demod, 'header_data',
+ hpd, 'header_data'
+ )
+ self.tb.connect((hpd, 1), payload_sink)
+
+ def run_tb(self, payload_sink, payload_len, header_sink, header_len, timeout=30):
+ stop_time = time.time() + timeout
+ self.tb.start()
+ while len(payload_sink.data()) < payload_len and \
+ len(header_sink.data()) < header_len and \
+ time.time() < stop_time:
+ time.sleep(.2)
+ self.tb.stop()
+ self.tb.wait()
+
def test_001_t (self):
""" Simplest possible test: put in zeros, then header,
then payload, trigger signal, try to demux.
@@ -45,25 +115,13 @@ class qa_header_payload_demux (gr_unittest.TestCase):
trigger_signal = [0,] * len(data_signal)
trigger_signal[n_zeros] = 1
# This is dropped:
- testtag1 = gr.tag_t()
- testtag1.offset = 0
- testtag1.key = pmt.string_to_symbol('tag1')
- testtag1.value = pmt.from_long(0)
+ testtag1 = make_tag('tag1', 0, 0)
# This goes on output 0, item 0:
- testtag2 = gr.tag_t()
- testtag2.offset = n_zeros
- testtag2.key = pmt.string_to_symbol('tag2')
- testtag2.value = pmt.from_long(23)
+ testtag2 = make_tag('tag2', 23, n_zeros)
# This goes on output 0, item 2:
- testtag3 = gr.tag_t()
- testtag3.offset = n_zeros + len(header) - 1
- testtag3.key = pmt.string_to_symbol('tag3')
- testtag3.value = pmt.from_long(42)
+ testtag3 = make_tag('tag3', 42, n_zeros + len(header) - 1)
# This goes on output 1, item 3:
- testtag4 = gr.tag_t()
- testtag4.offset = n_zeros + len(header) + 3
- testtag4.key = pmt.string_to_symbol('tag4')
- testtag4.value = pmt.from_long(314)
+ testtag4 = make_tag('tag4', 314, n_zeros + len(header) + 3)
data_src = blocks.vector_source_f(
data_signal,
False,
@@ -73,26 +131,17 @@ class qa_header_payload_demux (gr_unittest.TestCase):
hpd = digital.header_payload_demux(
len(header), 1, 0, "frame_len", "detect", False, gr.sizeof_float
)
+ mock_header_demod = HeaderToMessageBlock(
+ numpy.float32,
+ len(header),
+ [len(payload)]
+ )
self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you
- header_sink = blocks.vector_sink_f()
payload_sink = blocks.vector_sink_f()
-
- self.tb.connect(data_src, (hpd, 0))
- self.tb.connect(trigger_src, (hpd, 1))
- self.tb.connect((hpd, 0), header_sink)
- self.tb.connect((hpd, 1), payload_sink)
- self.tb.start()
- time.sleep(.2) # Need this, otherwise, the next message is ignored
- hpd.to_basic_block()._post(
- pmt.intern('header_data'),
- pmt.from_long(len(payload))
- )
- while len(payload_sink.data()) < len(payload):
- time.sleep(.2)
- self.tb.stop()
- self.tb.wait()
-
- self.assertEqual(header_sink.data(), header)
+ header_sink = blocks.vector_sink_f()
+ self.connect_all_blocks(data_src, trigger_src, hpd, mock_header_demod, payload_sink, header_sink)
+ self.run_tb(payload_sink, len(payload), header_sink, len(header))
+ self.assertEqual(header_sink.data(), header)
self.assertEqual(payload_sink.data(), payload)
ptags_header = []
for tag in header_sink.tags():
@@ -122,30 +171,15 @@ class qa_header_payload_demux (gr_unittest.TestCase):
payload = tuple(range(5, 20))
data_signal = (0,) * n_zeros + header + payload
# Trigger tag
- trigger_tag = gr.tag_t()
- trigger_tag.offset = n_zeros
- trigger_tag.key = pmt.string_to_symbol('detect')
- trigger_tag.value = pmt.PMT_T
+ trigger_tag = make_tag('detect', True, n_zeros)
# This is dropped:
- testtag1 = gr.tag_t()
- testtag1.offset = 0
- testtag1.key = pmt.string_to_symbol('tag1')
- testtag1.value = pmt.from_long(0)
+ testtag1 = make_tag('tag1', 0, 0)
# This goes on output 0, item 0:
- testtag2 = gr.tag_t()
- testtag2.offset = n_zeros
- testtag2.key = pmt.string_to_symbol('tag2')
- testtag2.value = pmt.from_long(23)
+ testtag2 = make_tag('tag2', 23, n_zeros)
# This goes on output 0, item 2:
- testtag3 = gr.tag_t()
- testtag3.offset = n_zeros + len(header) - 1
- testtag3.key = pmt.string_to_symbol('tag3')
- testtag3.value = pmt.from_long(42)
+ testtag3 = make_tag('tag3', 42, n_zeros + len(header) - 1)
# This goes on output 1, item 3:
- testtag4 = gr.tag_t()
- testtag4.offset = n_zeros + len(header) + 3
- testtag4.key = pmt.string_to_symbol('tag4')
- testtag4.value = pmt.from_long(314)
+ testtag4 = make_tag('tag4', 314, n_zeros + len(header) + 3)
data_src = blocks.vector_source_f(
data_signal,
False,
@@ -157,21 +191,14 @@ class qa_header_payload_demux (gr_unittest.TestCase):
self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you
header_sink = blocks.vector_sink_f()
payload_sink = blocks.vector_sink_f()
-
- self.tb.connect(data_src, (hpd, 0))
- self.tb.connect((hpd, 0), header_sink)
- self.tb.connect((hpd, 1), payload_sink)
- self.tb.start()
- time.sleep(.2) # Need this, otherwise, the next message is ignored
- hpd.to_basic_block()._post(
- pmt.intern('header_data'),
- pmt.from_long(len(payload))
+ mock_header_demod = HeaderToMessageBlock(
+ numpy.float32,
+ len(header),
+ [len(payload)]
)
- while len(payload_sink.data()) < len(payload):
- time.sleep(.2)
- self.tb.stop()
- self.tb.wait()
-
+ self.connect_all_blocks(data_src, None, hpd, mock_header_demod, payload_sink, header_sink)
+ self.run_tb(payload_sink, len(payload), header_sink, len(header))
+ # Check results
self.assertEqual(header_sink.data(), header)
self.assertEqual(payload_sink.data(), payload)
ptags_header = []
@@ -193,8 +220,143 @@ class qa_header_payload_demux (gr_unittest.TestCase):
]
self.assertEqual(expected_tags_payload, ptags_payload)
+ def test_001_headerpadding (self):
+ """ Like test 1, but with header padding. """
+ n_zeros = 3
+ header = (1, 2, 3)
+ header_padding = 1
+ payload = tuple(range(5, 20))
+ data_signal = (0,) * n_zeros + header + payload
+ trigger_signal = [0,] * len(data_signal)
+ trigger_signal[n_zeros] = 1
+ # This is dropped:
+ testtag1 = make_tag('tag1', 0, 0)
+ # This goes on output 0, item 0:
+ testtag2 = make_tag('tag2', 23, n_zeros)
+ # This goes on output 0, item 2:
+ testtag3 = make_tag('tag3', 42, n_zeros + len(header) - 1)
+ # This goes on output 1, item 3:
+ testtag4 = make_tag('tag4', 314, n_zeros + len(header) + 3)
+ data_src = blocks.vector_source_f(
+ data_signal,
+ False,
+ tags=(testtag1, testtag2, testtag3, testtag4)
+ )
+ trigger_src = blocks.vector_source_b(trigger_signal, False)
+ hpd = digital.header_payload_demux(
+ len(header),
+ 1, # Items per symbol
+ 0, # Guard interval
+ "frame_len", # TSB tag key
+ "detect", # Trigger tag key
+ False, # No symbols please
+ gr.sizeof_float, # Item size
+ "", # Timing tag key
+ 1.0, # Samp rate
+ (), # No special tags
+ header_padding
+ )
+ mock_header_demod = HeaderToMessageBlock(
+ numpy.float32,
+ len(header),
+ [len(payload)]
+ )
+ header_sink = blocks.vector_sink_f()
+ payload_sink = blocks.vector_sink_f()
+ self.connect_all_blocks(data_src, trigger_src, hpd, mock_header_demod, payload_sink, header_sink)
+ self.run_tb(payload_sink, len(payload), header_sink, len(header)+2)
+ # Check values
+ # Header now is padded:
+ self.assertEqual(header_sink.data(), (0,) + header + (payload[0],))
+ self.assertEqual(payload_sink.data(), payload)
+ ptags_header = []
+ for tag in header_sink.tags():
+ ptag = gr.tag_to_python(tag)
+ ptags_header.append({'key': ptag.key, 'offset': ptag.offset})
+ expected_tags_header = [
+ {'key': 'tag2', 'offset': 1},
+ {'key': 'tag3', 'offset': 3},
+ ]
+ self.assertEqual(expected_tags_header, ptags_header)
+ ptags_payload = []
+ for tag in payload_sink.tags():
+ ptag = gr.tag_to_python(tag)
+ ptags_payload.append({'key': ptag.key, 'offset': ptag.offset})
+ expected_tags_payload = [
+ {'key': 'frame_len', 'offset': 0},
+ {'key': 'tag4', 'offset': 3},
+ ]
+ self.assertEqual(expected_tags_payload, ptags_payload)
+
+ def test_001_headerpadding_payload_offset (self):
+ """ Like test 1, but with header padding + payload offset. """
+ n_zeros = 3
+ header = (1, 2, 3)
+ header_padding = 1
+ payload_offset = -1
+ payload = tuple(range(5, 20))
+ data_signal = (0,) * n_zeros + header + payload + (0,) * 100
+ trigger_signal = [0,] * len(data_signal)
+ trigger_signal[n_zeros] = 1
+ # This goes on output 1, item 3 + 1 (for payload offset)
+ testtag4 = make_tag('tag4', 314, n_zeros + len(header) + 3)
+ data_src = blocks.vector_source_f(
+ data_signal,
+ False,
+ tags=(testtag4,)
+ )
+ trigger_src = blocks.vector_source_b(trigger_signal, False)
+ hpd = digital.header_payload_demux(
+ len(header),
+ 1, # Items per symbol
+ 0, # Guard interval
+ "frame_len", # TSB tag key
+ "detect", # Trigger tag key
+ False, # No symbols please
+ gr.sizeof_float, # Item size
+ "", # Timing tag key
+ 1.0, # Samp rate
+ (), # No special tags
+ header_padding
+ )
+ self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you
+ header_sink = blocks.vector_sink_f()
+ payload_sink = blocks.vector_sink_f()
+ self.tb.connect(data_src, (hpd, 0))
+ self.tb.connect(trigger_src, (hpd, 1))
+ self.tb.connect((hpd, 0), header_sink)
+ self.tb.connect((hpd, 1), payload_sink)
+ self.tb.start()
+ time.sleep(.2) # Need this, otherwise, the next message is ignored
+ hpd.to_basic_block()._post(
+ pmt.intern('header_data'),
+ pmt.to_pmt({'frame_len': len(payload), 'payload_offset': payload_offset})
+ )
+ while len(payload_sink.data()) < len(payload):
+ time.sleep(.2)
+ self.tb.stop()
+ self.tb.wait()
+ # Header is now padded:
+ self.assertEqual(header_sink.data(), (0,) + header + (payload[0],))
+ # Payload is now offset:
+ self.assertEqual(
+ payload_sink.data(),
+ data_signal[n_zeros + len(header) + payload_offset:n_zeros + len(header) + payload_offset + len(payload)]
+ )
+ ptags_payload = {}
+ for tag in payload_sink.tags():
+ ptag = gr.tag_to_python(tag)
+ ptags_payload[ptag.key] = ptag.offset
+ expected_tags_payload = {
+ 'frame_len': 0,
+ 'payload_offset': 0,
+ 'tag4': 3 - payload_offset,
+ }
+ self.assertEqual(expected_tags_payload, ptags_payload)
+
+
def test_002_symbols (self):
- """
+ """
Same as before, but operate on symbols
"""
n_zeros = 1
@@ -207,25 +369,13 @@ class qa_header_payload_demux (gr_unittest.TestCase):
trigger_signal = [0,] * len(data_signal)
trigger_signal[n_zeros] = 1
# This is dropped:
- testtag1 = gr.tag_t()
- testtag1.offset = 0
- testtag1.key = pmt.string_to_symbol('tag1')
- testtag1.value = pmt.from_long(0)
+ testtag1 = make_tag('tag1', 0, 0)
# This goes on output 0, item 0 (from the GI)
- testtag2 = gr.tag_t()
- testtag2.offset = n_zeros
- testtag2.key = pmt.string_to_symbol('tag2')
- testtag2.value = pmt.from_long(23)
+ testtag2 = make_tag('tag2', 23, n_zeros)
# This goes on output 0, item 0 (middle of the header symbol)
- testtag3 = gr.tag_t()
- testtag3.offset = n_zeros + gi + 1
- testtag3.key = pmt.string_to_symbol('tag3')
- testtag3.value = pmt.from_long(42)
+ testtag3 = make_tag('tag3', 42, n_zeros + gi + 1)
# This goes on output 1, item 1 (middle of the first payload symbol)
- testtag4 = gr.tag_t()
- testtag4.offset = n_zeros + (gi + items_per_symbol) * 2 + 1
- testtag4.key = pmt.string_to_symbol('tag4')
- testtag4.value = pmt.from_long(314)
+ testtag4 = make_tag('tag4', 314, n_zeros + (gi + items_per_symbol) * 2 + 1)
data_src = blocks.vector_source_f(data_signal, False, tags=(testtag1, testtag2, testtag3, testtag4))
trigger_src = blocks.vector_source_b(trigger_signal, False)
hpd = digital.header_payload_demux(
@@ -291,25 +441,20 @@ class qa_header_payload_demux (gr_unittest.TestCase):
trigger_signal[n_zeros] = 1
trigger_signal[len(data_signal)] = 1
trigger_signal[len(data_signal)+len(header_fail)+n_zeros] = 1
- tx_signal = data_signal + header_fail + (0,) * n_zeros + header + payload2 + (0,) * 1000
+ print("Triggers at: {0} {1} {2}".format(
+ n_zeros,
+ len(data_signal),
+ len(data_signal)+len(header_fail)+n_zeros)
+ )
+ tx_signal = data_signal + \
+ header_fail + (0,) * n_zeros + \
+ header + payload2 + (0,) * 1000
# Timing tag: This is preserved and updated:
- timing_tag = gr.tag_t()
- timing_tag.offset = 0
- timing_tag.key = pmt.string_to_symbol('rx_time')
- timing_tag.value = pmt.to_pmt((0, 0))
+ timing_tag = make_tag('rx_time', (0, 0), 0)
# Rx freq tags:
- rx_freq_tag1 = gr.tag_t()
- rx_freq_tag1.offset = 0
- rx_freq_tag1.key = pmt.string_to_symbol('rx_freq')
- rx_freq_tag1.value = pmt.from_double(1.0)
- rx_freq_tag2 = gr.tag_t()
- rx_freq_tag2.offset = 29
- rx_freq_tag2.key = pmt.string_to_symbol('rx_freq')
- rx_freq_tag2.value = pmt.from_double(1.5)
- rx_freq_tag3 = gr.tag_t()
- rx_freq_tag3.offset = 30
- rx_freq_tag3.key = pmt.string_to_symbol('rx_freq')
- rx_freq_tag3.value = pmt.from_double(2.0)
+ rx_freq_tag1 = make_tag('rx_freq', 1.0, 0)
+ rx_freq_tag2 = make_tag('rx_freq', 1.5, 29)
+ rx_freq_tag3 = make_tag('rx_freq', 2.0, 30)
### Flow graph
data_src = blocks.vector_source_f(
tx_signal, False,
@@ -388,6 +533,92 @@ class qa_header_payload_demux (gr_unittest.TestCase):
self.assertEqual(tags_header, tags_expected_header)
self.assertEqual(tags_payload, tags_expected_payload)
+ def test_004_fuzz(self):
+ """
+ Long random test
+ """
+ def create_signal(
+ n_bursts,
+ header_len,
+ max_gap,
+ max_burstsize,
+ fail_rate,
+ ):
+ signal = []
+ indexes = []
+ burst_sizes = []
+ total_payload_len = 0
+ for burst_count in xrange(n_bursts):
+ gap_size = random.randint(0, max_gap)
+ signal += [0] * gap_size
+ is_failure = random.random() < fail_rate
+ if not is_failure:
+ burst_size = random.randint(0, max_burstsize)
+ else:
+ burst_size = 0
+ total_payload_len += burst_size
+ indexes += [len(signal)]
+ signal += [1] * header_len
+ signal += [2] * burst_size
+ burst_sizes += [burst_size]
+ return (signal, indexes, total_payload_len, burst_sizes)
+ def indexes_to_triggers(indexes, signal_len):
+ """
+ Convert indexes to a mix of trigger signals and tags
+ """
+ trigger_signal = [0] * signal_len
+ trigger_tags = []
+ for index in indexes:
+ if random.random() > 0.5:
+ trigger_signal[index] = 1
+ else:
+ trigger_tags += [make_tag('detect', True, index)]
+ return (trigger_signal, trigger_tags)
+ ### Go, go, go
+ # The divide-by-20 means we'll usually get the same random seed
+ # between the first run and the XML run.
+ random_seed = int(time.time()/20)
+ random.seed(random_seed)
+ print("Random seed: {0}".format(random_seed))
+ n_bursts = 400
+ header_len = 5
+ max_gap = 50
+ max_burstsize = 100
+ fail_rate = 0.05
+ signal, indexes, total_payload_len, burst_sizes = create_signal(
+ n_bursts, header_len, max_gap, max_burstsize, fail_rate
+ )
+ trigger_signal, trigger_tags = indexes_to_triggers(indexes, len(signal))
+ # Flow graph
+ data_src = blocks.vector_source_f(
+ signal, False,
+ tags=trigger_tags
+ )
+ trigger_src = blocks.vector_source_b(trigger_signal, False)
+ hpd = digital.header_payload_demux(
+ header_len=header_len,
+ items_per_symbol=1,
+ guard_interval=0,
+ length_tag_key="frame_len",
+ trigger_tag_key="detect",
+ output_symbols=False,
+ itemsize=gr.sizeof_float,
+ timing_tag_key='rx_time',
+ samp_rate=1.0,
+ special_tags=('rx_freq',),
+ )
+ mock_header_demod = HeaderToMessageBlock(
+ numpy.float32,
+ header_len,
+ burst_sizes
+ )
+ header_sink = blocks.vector_sink_f()
+ payload_sink = blocks.vector_sink_f()
+ self.connect_all_blocks(data_src, trigger_src, hpd, mock_header_demod, payload_sink, header_sink)
+ self.run_tb(payload_sink, total_payload_len, header_sink, header_len*n_bursts)
+ self.assertEqual(header_sink.data(), tuple([1]*header_len*n_bursts))
+ self.assertEqual(payload_sink.data(), tuple([2]*total_payload_len))
+
if __name__ == '__main__':
gr_unittest.run(qa_header_payload_demux, "qa_header_payload_demux.xml")
diff --git a/grc/base/CMakeLists.txt b/gr-digital/python/grc_gnuradio/CMakeLists.txt
index bdc8a5006f..f021299f1a 100644
--- a/grc/base/CMakeLists.txt
+++ b/gr-digital/python/grc_gnuradio/CMakeLists.txt
@@ -18,26 +18,13 @@
# Boston, MA 02110-1301, USA.
########################################################################
-GR_PYTHON_INSTALL(FILES
- odict.py
- ParseXML.py
- Block.py
- Connection.py
- Constants.py
- Element.py
- FlowGraph.py
- Param.py
- Platform.py
- Port.py
- __init__.py
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
- COMPONENT "grc"
-)
-install(FILES
- block_tree.dtd
- domain.dtd
- flow_graph.dtd
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
- COMPONENT "grc"
+include(GrPython)
+
+# __init__ files come from gr-blocks
+
+GR_PYTHON_INSTALL(FILES
+ blks2/packet.py
+ DESTINATION ${GR_PYTHON_DIR}/grc_gnuradio/blks2
+ COMPONENT "digital_python"
)
diff --git a/grc/grc_gnuradio/blks2/packet.py b/gr-digital/python/grc_gnuradio/blks2/packet.py
index ef79afde64..ef79afde64 100644
--- a/grc/grc_gnuradio/blks2/packet.py
+++ b/gr-digital/python/grc_gnuradio/blks2/packet.py
diff --git a/gr-dtv/CMakeLists.txt b/gr-dtv/CMakeLists.txt
index fc7ab56bef..5a23482b26 100644
--- a/gr-dtv/CMakeLists.txt
+++ b/gr-dtv/CMakeLists.txt
@@ -41,6 +41,8 @@ GR_SET_GLOBAL(GR_DTV_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}/lib
)
+SET(GR_PKG_DTV_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/dtv)
+
########################################################################
# Begin conditional configuration
########################################################################
diff --git a/gr-dtv/examples/CMakeLists.txt b/gr-dtv/examples/CMakeLists.txt
index 82b663d924..8f209bce4f 100644
--- a/gr-dtv/examples/CMakeLists.txt
+++ b/gr-dtv/examples/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2014 Free Software Foundation, Inc.
+# Copyright 2014-2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -21,6 +21,31 @@ include(GrPython)
GR_PYTHON_INSTALL(
PROGRAMS
+ atsc_ctrlport_monitor.py
+ DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR}
+ COMPONENT "dtv_python"
+)
+
+install(
+ FILES
+ README.dvbs
+ README.dvbs2
+ README.dvbt
+ README.dvbt2
+ README.catv
+ dvbs2_tx.grc
+ dvbs_tx.grc
+ dvbt_rx_8k.grc
+ dvbt_tx_2k.grc
+ dvbt_tx_8k.grc
+ file_atsc_rx.grc
+ file_atsc_tx.grc
+ uhd_atsc_capture.grc
+ uhd_rx_atsc.grc
+ vv003-cr23.grc
+ vv009-4kfft.grc
+ vv018-miso.grc
+ catv_tx_64qam.grc
DESTINATION ${GR_PKG_DTV_EXAMPLES_DIR}
COMPONENT "dtv_python"
)
diff --git a/gr-dtv/examples/README.catv b/gr-dtv/examples/README.catv
new file mode 100644
index 0000000000..84c4cd0b26
--- /dev/null
+++ b/gr-dtv/examples/README.catv
@@ -0,0 +1,31 @@
+A test Transport Stream (26.970352 Mbps) for the example flow graph
+is available here:
+
+http://www.w6rz.net/advqam64.ts
+
+It is 357,356,980 bytes.
+
+The three parameters Control_Word, I_taps and J_increment can be
+used to control the interleaver from the following table.
+
+Control_Word I_taps J_increment Burst protection Latency
+ 0 128 1 95 us 4 ms
+ 1 128 1 95 us 4 ms
+ 2 128 2 190 us 8 ms
+ 3 64 2 47 us 2 ms
+ 4 128 3 285 us 12 ms
+ 5 32 4 24 us 0.98 ms
+ 6 128 4 379 us 16 ms
+ 7 16 8 12 us 0.48 ms
+ 8 128 5 474 us 20 ms
+ 9 8 16 5.9 us 0.22 ms
+ 10 128 6 569 us 24 ms
+ 11 Reserved
+ 12 128 7 664 us 28 ms
+ 13 Reserved
+ 14 128 8 759 us 32 ms
+ 15 Reserved
+
+The default is Control_Word = 6, I_taps = 128 and J_increment = 4
+which seems to be the most commonly used on CATV systems.
+
diff --git a/gr-dtv/examples/README.dvbs b/gr-dtv/examples/README.dvbs
new file mode 100644
index 0000000000..d9097c4876
--- /dev/null
+++ b/gr-dtv/examples/README.dvbs
@@ -0,0 +1,26 @@
+Puncturing values for DVB-S code rates:
+
+1/2 code rate = Puncture Size = 2, Puncture Pattern = 0b11
+2/3 code rate = Puncture Size = 4, Puncture Pattern = 0b1101
+3/4 code rate = Puncture Size = 6, Puncture Pattern = 0b110110
+5/6 code rate = Puncture Size = 10, Puncture Pattern = 0b1101100110
+7/8 code rate = Puncture Size = 14, Puncture Pattern = 0b11010101100110
+
+A test Transport Stream for the example flow graph
+(8 Msyms/s and 7/8 code rate) is available here:
+
+http://www.w6rz.net/advdvbs78.ts
+
+It is 170,950,844 bytes.
+
+This stream can also be used at:
+
+14 Msyms/s 1/2 code rate
+10.5 MSyms/s 2/3 code rate
+9.333333 MSyms/s 3/4 code rate
+8.4 Msyms/s 5/6 code rate
+
+The equation for calculating the correct Transport Stream bit-rate is:
+
+TS bit-rate = symbol rate * 2 * code rate * (188 / 204)
+
diff --git a/gr-dtv/examples/atsc_ctrlport_monitor.py b/gr-dtv/examples/atsc_ctrlport_monitor.py
new file mode 100755
index 0000000000..7c43aebb77
--- /dev/null
+++ b/gr-dtv/examples/atsc_ctrlport_monitor.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#
+# Copyright 2015 Free Software Foundation
+#
+# This program 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.
+#
+# This program 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 this program; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import sys
+import matplotlib
+matplotlib.use("QT4Agg")
+import matplotlib.pyplot as plt
+import matplotlib.animation as animation
+from gnuradio.ctrlport.GNURadioControlPortClient import GNURadioControlPortClient
+import scipy
+from scipy import fftpack
+
+"""
+If a host is running the ATSC receiver chain with ControlPort
+turned on, this script will connect to the host using the hostname and
+port pair of the ControlPort instance and display metrics of the
+receiver. The ATSC publishes information about the succes of the
+Reed-Solomon decoder and Viterbi metrics for use here in displaying
+the link quality. This also gets the equalizer taps of the receiver
+and displays the frequency response.
+"""
+
+class atsc_ctrlport_monitor:
+ def __init__(self, host, port):
+ argv = [None, host, port]
+ radiosys = GNURadioControlPortClient(argv=argv, rpcmethod='thrift')
+ self.radio = radiosys.client
+ print self.radio
+
+
+ vt_init_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics'
+ data = self.radio.getKnobs([vt_init_key])[vt_init_key]
+ init_metric = scipy.mean(data.value)
+ self._viterbi_metric = 100*[init_metric,]
+
+ table_col_labels = ('Num Packets', 'Error Rate', 'Packet Error Rate',
+ 'Viterbi Metric', 'SNR')
+
+ self._fig = plt.figure(1, figsize=(12,12), facecolor='w')
+ self._sp0 = self._fig.add_subplot(4,1,1)
+ self._sp1 = self._fig.add_subplot(4,1,2)
+ self._sp2 = self._fig.add_subplot(4,1,3)
+ self._plot_taps = self._sp0.plot([], [], 'k', linewidth=2)
+ self._plot_psd = self._sp1.plot([], [], 'k', linewidth=2)
+ self._plot_data = self._sp2.plot([], [], 'ok', linewidth=2, markersize=4, alpha=0.05)
+
+ self._ax2 = self._fig.add_subplot(4,1,4)
+ self._table = self._ax2.table(cellText=[len(table_col_labels)*['0']],
+ colLabels=table_col_labels,
+ loc='center')
+ self._ax2.axis('off')
+ cells = self._table.properties()['child_artists']
+ for c in cells:
+ c.set_lw(0.1) # set's line width
+ c.set_ls('solid')
+ c.set_height(0.2)
+
+ ani = animation.FuncAnimation(self._fig, self.update_data, frames=200,
+ fargs=(self._plot_taps[0], self._plot_psd[0],
+ self._plot_data[0], self._table),
+ init_func=self.init_function,
+ blit=True)
+ plt.show()
+
+ def update_data(self, x, taps, psd, syms, table):
+ try:
+ eqdata_key = 'dtv_atsc_equalizer0::taps'
+ symdata_key = 'dtv_atsc_equalizer0::data'
+ rs_nump_key = 'dtv_atsc_rs_decoder0::num_packets'
+ rs_numbp_key = 'dtv_atsc_rs_decoder0::num_bad_packets'
+ rs_numerrs_key = 'dtv_atsc_rs_decoder0::num_errors_corrected'
+ vt_metrics_key = 'dtv_atsc_viterbi_decoder0::decoder_metrics'
+ snr_key = 'probe2_f0::SNR'
+
+ data = self.radio.getKnobs([])
+ eqdata = data[eqdata_key]
+ symdata = data[symdata_key]
+ rs_num_packets = data[rs_nump_key]
+ rs_num_bad_packets = data[rs_numbp_key]
+ rs_num_errors_corrected = data[rs_numerrs_key]
+ vt_decoder_metrics = data[vt_metrics_key]
+ snr_est = data[snr_key]
+
+ vt_decoder_metrics = scipy.mean(vt_decoder_metrics.value)
+ self._viterbi_metric.pop()
+ self._viterbi_metric.insert(0, vt_decoder_metrics)
+
+ except:
+ sys.stderr.write("Lost connection, exiting")
+ sys.exit(1)
+
+ ntaps = len(eqdata.value)
+ taps.set_ydata(eqdata.value)
+ taps.set_xdata(xrange(ntaps))
+ self._sp0.set_xlim(0, ntaps)
+ self._sp0.set_ylim(min(eqdata.value), max(eqdata.value))
+
+ fs = 6.25e6
+ freq = scipy.linspace(-fs/2, fs/2, 10000)
+ H = fftpack.fftshift(fftpack.fft(eqdata.value, 10000))
+ HdB = 20.0*scipy.log10(abs(H))
+ psd.set_ydata(HdB)
+ psd.set_xdata(freq)
+ self._sp1.set_xlim(0, fs/2)
+ self._sp1.set_ylim([min(HdB), max(HdB)])
+ self._sp1.set_yticks([min(HdB), max(HdB)])
+ self._sp1.set_yticklabels(["min", "max"])
+
+ nsyms = len(symdata.value)
+ syms.set_ydata(symdata.value)
+ syms.set_xdata(nsyms*[0,])
+ self._sp2.set_xlim([-1, 1])
+ self._sp2.set_ylim([-10, 10])
+
+ per = float(rs_num_bad_packets.value) / float(rs_num_packets.value)
+ ber = float(rs_num_errors_corrected.value) / float(187*rs_num_packets.value)
+
+ table._cells[(1,0)]._text.set_text("{0}".format(rs_num_packets.value))
+ table._cells[(1,1)]._text.set_text("{0:.2g}".format(ber))
+ table._cells[(1,2)]._text.set_text("{0:.2g}".format(per))
+ table._cells[(1,3)]._text.set_text("{0:.1f}".format(scipy.mean(self._viterbi_metric)))
+ table._cells[(1,4)]._text.set_text("{0:.4f}".format(snr_est.value[0]))
+
+ return (taps, psd, syms, table)
+
+ def init_function(self):
+ return self._plot_taps + self._plot_psd + self._plot_data
+
+if __name__ == "__main__":
+ host = sys.argv[1]
+ port = sys.argv[2]
+ m = atsc_ctrlport_monitor(host, port)
diff --git a/gr-dtv/examples/catv_tx_64qam.grc b/gr-dtv/examples/catv_tx_64qam.grc
new file mode 100644
index 0000000000..964ef8470f
--- /dev/null
+++ b/gr-dtv/examples/catv_tx_64qam.grc
@@ -0,0 +1,2079 @@
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.10'?>
+<flow_graph>
+ <timestamp>Thu Feb 20 21:02:41 2014</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>author</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>wx_gui</value>
+ </param>
+ <param>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>catv_tx_64qam</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 299)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>Control_Word</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>6</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 371)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>I_taps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>128</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 443)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>J_increment</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>4</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 155)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>center_freq</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>429000000</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 227)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>rrc_taps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>100</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 83)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>5056941 * 2</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_slider</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>int_converter</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>-8</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(312, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>vga1_gain</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>VGA1 Gain</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>-4</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>-35</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>num_steps</key>
+ <value>31</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.SL_HORIZONTAL</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_slider</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>converver</key>
+ <value>int_converter</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(448, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>vga2_gain</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value>VGA2 Gain</value>
+ </param>
+ <param>
+ <key>max</key>
+ <value>25</value>
+ </param>
+ <param>
+ <key>min</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>num_steps</key>
+ <value>25</value>
+ </param>
+ <param>
+ <key>style</key>
+ <value>wx.SL_HORIZONTAL</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_source</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>/run/shm/advqam64.ts</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(128, 163)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_file_source_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_packed_to_unpacked_xx</key>
+ <param>
+ <key>bits_per_chunk</key>
+ <value>7</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>endianness</key>
+ <value>gr.GR_MSB_FIRST</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(624, 163)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_packed_to_unpacked_xx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_ports</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_stream_to_vector</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(536, 251)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>180</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_stream_to_vector_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_items</key>
+ <value>I_taps</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_catv_frame_sync_enc_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ctrlword</key>
+ <value>Control_Word</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(584, 347)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_catv_frame_sync_enc_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_catv_randomizer_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(424, 353)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_catv_randomizer_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_catv_reed_solomon_enc_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(848, 177)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_catv_reed_solomon_enc_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_catv_transport_framing_enc_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(360, 177)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_catv_transport_framing_enc_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_catv_trellis_enc_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(800, 353)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_catv_trellis_enc_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbs2_modulator_bc</key>
+ <param>
+ <key>interpolation</key>
+ <value>INTERPOLATION_ON</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>rate</key>
+ <value>C_OTHER</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>constellation</key>
+ <value>MOD_64QAM</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(400, 499)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbs2_modulator_bc_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbt_convolutional_interleaver</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>blocks</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>M</key>
+ <value>J_increment</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(168, 339)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbt_convolutional_interleaver_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>I</key>
+ <value>I_taps</value>
+ </param>
+ </block>
+ <block>
+ <key>fft_filter_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(712, 507)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fft_filter_xxx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>nthreads</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_delay</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value>firdes.root_raised_cosine(0.14, samp_rate, samp_rate/2, 0.18, rrc_taps)</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>ccf</value>
+ </param>
+ </block>
+ <block>
+ <key>osmosdr_sink</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ant0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain0</key>
+ <value>vga1_gain</value>
+ </param>
+ <param>
+ <key>bw0</key>
+ <value>6000000</value>
+ </param>
+ <param>
+ <key>corr0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq0</key>
+ <value>center_freq</value>
+ </param>
+ <param>
+ <key>if_gain0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>gain0</key>
+ <value>vga2_gain</value>
+ </param>
+ <param>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain10</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq10</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain10</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain10</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant11</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain11</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq11</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain11</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain11</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant12</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq12</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant13</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain13</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq13</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain13</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain13</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant14</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain14</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq14</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain14</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain14</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant15</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain15</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq15</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain15</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain15</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant16</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain16</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq16</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain16</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain16</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant17</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain17</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq17</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain17</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain17</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant18</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain18</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq18</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain18</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain18</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant19</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain19</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq19</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain19</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain19</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain1</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq1</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain1</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain1</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant20</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain20</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq20</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain20</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain20</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant21</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain21</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq21</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain21</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain21</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant22</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain22</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq22</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain22</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain22</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant23</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain23</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq23</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain23</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain23</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant24</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain24</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq24</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain24</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain24</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant25</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain25</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq25</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain25</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain25</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant26</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain26</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq26</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain26</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain26</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant27</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain27</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq27</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain27</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain27</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant28</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain28</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq28</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain28</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain28</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant29</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain29</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq29</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain29</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain29</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain2</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq2</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain2</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain2</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant30</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain30</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq30</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain30</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain30</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant31</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain31</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq31</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain31</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain31</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain3</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq3</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain3</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain3</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain4</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq4</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain4</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain4</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain5</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq5</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain5</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain5</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain6</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq6</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain6</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain6</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain7</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq7</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain7</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain7</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain8</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq8</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain8</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain8</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain9</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq9</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain9</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain9</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>args</key>
+ <value>bladerf=0,buffers=128,buflen=32768</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1056, 467)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>osmosdr_sink_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fc32</value>
+ </param>
+ <param>
+ <key>clock_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>sample_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_fftsink2</key>
+ <param>
+ <key>avg_alpha</key>
+ <value>0.1333</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>baseband_freq</key>
+ <value>center_freq</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1056, 203)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>wxgui_fftsink2_0_0</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>-10</value>
+ </param>
+ <param>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>FFT Plot</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value>640,480</value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>y_divs</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>y_per_div</key>
+ <value>10</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>blocks_file_source_0</source_block_id>
+ <sink_block_id>dtv_catv_transport_framing_enc_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_packed_to_unpacked_xx_0</source_block_id>
+ <sink_block_id>dtv_catv_reed_solomon_enc_bb_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>dtv_dvbt_convolutional_interleaver_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_catv_frame_sync_enc_bb_0</source_block_id>
+ <sink_block_id>dtv_catv_trellis_enc_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_catv_randomizer_bb_0</source_block_id>
+ <sink_block_id>dtv_catv_frame_sync_enc_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_catv_reed_solomon_enc_bb_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>dtv_catv_transport_framing_enc_bb_0</source_block_id>
+ <sink_block_id>blocks_packed_to_unpacked_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_catv_trellis_enc_bb_0</source_block_id>
+ <sink_block_id>dtv_dvbs2_modulator_bc_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id>
+ <sink_block_id>fft_filter_xxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id>
+ <sink_block_id>dtv_catv_randomizer_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>osmosdr_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>wxgui_fftsink2_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-dtv/examples/dvbs2_tx.grc b/gr-dtv/examples/dvbs2_tx.grc
index 47daa4cb9d..c6de308ae3 100644
--- a/gr-dtv/examples/dvbs2_tx.grc
+++ b/gr-dtv/examples/dvbs2_tx.grc
@@ -1,23 +1,23 @@
-<?xml version='1.0' encoding='ASCII'?>
-<?grc format='1' created='3.7.7'?>
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.10'?>
<flow_graph>
<timestamp>Wed Sep 3 03:03:39 2014</timestamp>
<block>
<key>options</key>
<param>
- <key>id</key>
- <value>dvbs2_tx</value>
+ <key>author</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>window_size</key>
+ <value>1280, 1024</value>
</param>
<param>
- <key>title</key>
- <value></value>
+ <key>category</key>
+ <value>Custom</value>
</param>
<param>
- <key>author</key>
+ <key>comment</key>
<value></value>
</param>
<param>
@@ -25,16 +25,44 @@
<value></value>
</param>
<param>
- <key>window_size</key>
- <value>1280, 1024</value>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
</param>
<param>
<key>generate_options</key>
<value>wx_gui</value>
</param>
<param>
- <key>category</key>
- <value>Custom</value>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dvbs2_tx</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
</param>
<param>
<key>run_options</key>
@@ -45,45 +73,79 @@
<value>True</value>
</param>
<param>
- <key>max_nouts</key>
- <value>0</value>
+ <key>thread_safe_setters</key>
+ <value></value>
</param>
<param>
- <key>realtime_scheduling</key>
+ <key>title</key>
<value></value>
</param>
+ </block>
+ <block>
+ <key>variable</key>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(8, 11)</value>
+ <value>(8, 203)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
+ <param>
+ <key>id</key>
+ <value>frequency</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1280e6</value>
+ </param>
</block>
<block>
<key>variable</key>
<param>
- <key>id</key>
- <value>samp_rate</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
+ <key>_coordinate</key>
+ <value>(8, 267)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>rolloff</value>
+ </param>
+ <param>
<key>value</key>
- <value>symbol_rate * 2</value>
+ <value>0.2</value>
</param>
+ </block>
+ <block>
+ <key>variable</key>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
<key>_coordinate</key>
<value>(8, 75)</value>
</param>
@@ -91,107 +153,186 @@
<key>_rotation</key>
<value>0</value>
</param>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>symbol_rate * 2</value>
+ </param>
</block>
<block>
<key>variable</key>
<param>
- <key>id</key>
- <value>symbol_rate</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
+ <key>_coordinate</key>
+ <value>(8, 139)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>symbol_rate</value>
+ </param>
+ <param>
<key>value</key>
<value>5000000</value>
</param>
+ </block>
+ <block>
+ <key>variable</key>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(8, 139)</value>
+ <value>(8, 331)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>variable</key>
<param>
<key>id</key>
- <value>rolloff</value>
+ <value>taps</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>value</key>
+ <value>100</value>
</param>
+ </block>
+ <block>
+ <key>blocks_file_sink</key>
<param>
- <key>value</key>
- <value>0.2</value>
+ <key>append</key>
+ <value>False</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>adv.cfile</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(8, 203)</value>
+ <value>(784, 547)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>variable</key>
<param>
<key>id</key>
- <value>taps</value>
+ <value>blocks_file_sink_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>type</key>
+ <value>complex</value>
</param>
<param>
- <key>value</key>
- <value>50</value>
+ <key>unbuffered</key>
+ <value>False</value>
</param>
<param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_source</key>
+ <param>
<key>alias</key>
<value></value>
</param>
<param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>/run/shm/adv16apsk910.ts</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(8, 267)</value>
+ <value>(176, 43)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvb_bch_bb</key>
<param>
<key>id</key>
- <value>dtv_dvb_bch_bb_0</value>
+ <value>blocks_file_source_0</value>
</param>
<param>
- <key>_enabled</key>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ <param>
+ <key>repeat</key>
<value>True</value>
</param>
<param>
- <key>standard</key>
- <value>STANDARD_DVBS2</value>
+ <key>vlen</key>
+ <value>1</value>
</param>
+ </block>
+ <block>
+ <key>dtv_dvb_bbheader_bb</key>
<param>
- <key>framesize</key>
+ <key>mode</key>
<value>FECFRAME_NORMAL</value>
</param>
<param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
<key>rate1</key>
<value>C1_2</value>
</param>
@@ -208,7 +349,7 @@
<value>C1_4</value>
</param>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
@@ -216,39 +357,59 @@
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>fecblocks</key>
+ <value>168</value>
+ </param>
+ <param>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
<key>_coordinate</key>
- <value>(824, 35)</value>
+ <value>(400, 27)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvb_bbscrambler_bb</key>
<param>
<key>id</key>
- <value>dtv_dvb_bbscrambler_bb_0</value>
+ <value>dtv_dvb_bbheader_bb_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>inband</key>
+ <value>INBAND_OFF</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>rolloff</key>
+ <value>RO_0_20</value>
</param>
<param>
<key>standard</key>
<value>STANDARD_DVBS2</value>
</param>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>tsrate</key>
+ <value>4000000</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvb_bbscrambler_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
</param>
<param>
<key>rate1</key>
@@ -267,7 +428,7 @@
<value>C1_4</value>
</param>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
@@ -275,12 +436,12 @@
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
<key>_coordinate</key>
@@ -290,24 +451,28 @@
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvb_ldpc_bb</key>
<param>
<key>id</key>
- <value>dtv_dvb_ldpc_bb_0</value>
+ <value>dtv_dvb_bbscrambler_bb_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
<key>standard</key>
<value>STANDARD_DVBS2</value>
</param>
+ </block>
+ <block>
+ <key>dtv_dvb_bch_bb</key>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
<key>rate1</key>
@@ -326,11 +491,7 @@
<value>C1_4</value>
</param>
<param>
- <key>constellation</key>
- <value>MOD_OTHER</value>
- </param>
- <param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
@@ -338,239 +499,310 @@
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
<key>_coordinate</key>
- <value>(1048, 27)</value>
+ <value>(824, 35)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvb_bch_bb_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>standard</key>
+ <value>STANDARD_DVBS2</value>
+ </param>
</block>
<block>
- <key>dtv_dvbs2_interleaver_bb</key>
+ <key>dtv_dvb_ldpc_bb</key>
<param>
- <key>id</key>
- <value>dtv_dvbs2_interleaver_bb_0</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>rate1</key>
+ <value>C1_2</value>
</param>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>rate2</key>
+ <value>C1_3</value>
</param>
<param>
- <key>constellation</key>
- <value>MOD_16APSK</value>
+ <key>rate3</key>
+ <value>C9_10</value>
</param>
<param>
- <key>rate</key>
- <value>C_OTHER</value>
+ <key>rate4</key>
+ <value>C1_4</value>
</param>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>constellation</key>
+ <value>MOD_OTHER</value>
+ </param>
+ <param>
<key>affinity</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
<key>_coordinate</key>
- <value>(192, 235)</value>
+ <value>(1048, 27)</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>
+ <value>dtv_dvb_ldpc_bb_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>type</key>
- <value>complex</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>title</key>
- <value>FFT Plot</value>
+ <key>standard</key>
+ <value>STANDARD_DVBS2</value>
</param>
+ </block>
+ <block>
+ <key>dtv_dvbs2_interleaver_bb</key>
<param>
- <key>samp_rate</key>
- <value>samp_rate</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>baseband_freq</key>
- <value>1280000000</value>
+ <key>rate</key>
+ <value>C_OTHER</value>
</param>
<param>
- <key>y_per_div</key>
- <value>10</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>y_divs</key>
- <value>10</value>
+ <key>constellation</key>
+ <value>MOD_16APSK</value>
</param>
<param>
- <key>ref_level</key>
- <value>0</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
- <key>ref_scale</key>
- <value>2.0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>fft_size</key>
- <value>1024</value>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
- <key>fft_rate</key>
- <value>15</value>
+ <key>_coordinate</key>
+ <value>(192, 235)</value>
</param>
<param>
- <key>peak_hold</key>
- <value>False</value>
+ <key>_rotation</key>
+ <value>0</value>
</param>
<param>
- <key>average</key>
- <value>True</value>
+ <key>id</key>
+ <value>dtv_dvbs2_interleaver_bb_0</value>
</param>
<param>
- <key>avg_alpha</key>
- <value>0.13333</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>win</key>
- <value>None</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
+ </block>
+ <block>
+ <key>dtv_dvbs2_modulator_bc</key>
<param>
- <key>win_size</key>
- <value></value>
+ <key>interpolation</key>
+ <value>INTERPOLATION_OFF</value>
</param>
<param>
- <key>grid_pos</key>
+ <key>alias</key>
<value></value>
</param>
<param>
- <key>notebook</key>
- <value></value>
+ <key>rate</key>
+ <value>C9_10</value>
</param>
<param>
- <key>freqvar</key>
- <value>None</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>constellation</key>
+ <value>MOD_16APSK</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(1000, 395)</value>
+ <value>(472, 227)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvbs2_modulator_bc</key>
<param>
<key>id</key>
<value>dtv_dvbs2_modulator_bc_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
+ </block>
+ <block>
+ <key>dtv_dvbs2_physical_cc</key>
<param>
- <key>constellation</key>
- <value>MOD_16APSK</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
<key>rate</key>
<value>C9_10</value>
</param>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>constellation</key>
+ <value>MOD_16APSK</value>
+ </param>
+ <param>
<key>affinity</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
</param>
<param>
<key>_coordinate</key>
- <value>(472, 235)</value>
+ <value>(192, 443)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
+ <param>
+ <key>goldcode</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbs2_physical_cc_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>pilots</key>
+ <value>PILOTS_ON</value>
+ </param>
</block>
<block>
<key>fft_filter_xxx</key>
<param>
- <key>id</key>
- <value>fft_filter_xxx_0</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>type</key>
- <value>ccc</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
<key>decim</key>
<value>1</value>
</param>
<param>
- <key>taps</key>
- <value>firdes.root_raised_cosine(1, samp_rate, samp_rate/2, rolloff, taps)</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>samp_delay</key>
+ <key>_coordinate</key>
+ <value>(472, 459)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fft_filter_xxx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
<value>0</value>
</param>
<param>
@@ -578,1014 +810,1458 @@
<value>1</value>
</param>
<param>
+ <key>samp_delay</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value>firdes.root_raised_cosine(1.0, samp_rate, samp_rate/2, rolloff, taps)</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>ccc</value>
+ </param>
+ </block>
+ <block>
+ <key>osmosdr_sink</key>
+ <param>
<key>alias</key>
<value></value>
</param>
<param>
- <key>affinity</key>
+ <key>ant0</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
+ <key>bb_gain0</key>
+ <value>-10</value>
+ </param>
+ <param>
+ <key>bw0</key>
+ <value>6000000</value>
+ </param>
+ <param>
+ <key>corr0</key>
<value>0</value>
</param>
<param>
- <key>maxoutbuf</key>
+ <key>freq0</key>
+ <value>frequency</value>
+ </param>
+ <param>
+ <key>if_gain0</key>
<value>0</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(472, 459)</value>
+ <key>gain0</key>
+ <value>15</value>
</param>
<param>
- <key>_rotation</key>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain10</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw10</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvbs2_physical_cc</key>
<param>
- <key>id</key>
- <value>dtv_dvbs2_physical_cc_0</value>
+ <key>corr10</key>
+ <value>0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>freq10</key>
+ <value>100e6</value>
</param>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>if_gain10</key>
+ <value>20</value>
</param>
<param>
- <key>constellation</key>
- <value>MOD_16APSK</value>
+ <key>gain10</key>
+ <value>10</value>
</param>
<param>
- <key>rate</key>
- <value>C9_10</value>
+ <key>ant11</key>
+ <value></value>
</param>
<param>
- <key>pilots</key>
- <value>PILOTS_ON</value>
+ <key>bb_gain11</key>
+ <value>20</value>
</param>
<param>
- <key>goldcode</key>
+ <key>bw11</key>
<value>0</value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>corr11</key>
+ <value>0</value>
</param>
<param>
- <key>affinity</key>
+ <key>freq11</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain11</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain11</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant12</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
+ <key>bb_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw12</key>
<value>0</value>
</param>
<param>
- <key>maxoutbuf</key>
+ <key>corr12</key>
<value>0</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(192, 443)</value>
+ <key>freq12</key>
+ <value>100e6</value>
</param>
<param>
- <key>_rotation</key>
+ <key>if_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant13</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain13</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw13</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>osmosdr_sink</key>
<param>
- <key>id</key>
- <value>osmosdr_sink_0</value>
+ <key>corr13</key>
+ <value>0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>freq13</key>
+ <value>100e6</value>
</param>
<param>
- <key>type</key>
- <value>fc32</value>
+ <key>if_gain13</key>
+ <value>20</value>
</param>
<param>
- <key>args</key>
- <value>bladerf=0,buffers=128,buflen=32768</value>
+ <key>gain13</key>
+ <value>10</value>
</param>
<param>
- <key>sync</key>
+ <key>ant14</key>
<value></value>
</param>
<param>
- <key>num_mboards</key>
- <value>1</value>
+ <key>bb_gain14</key>
+ <value>20</value>
</param>
<param>
- <key>clock_source0</key>
- <value></value>
+ <key>bw14</key>
+ <value>0</value>
</param>
<param>
- <key>time_source0</key>
- <value></value>
+ <key>corr14</key>
+ <value>0</value>
</param>
<param>
- <key>clock_source1</key>
- <value></value>
+ <key>freq14</key>
+ <value>100e6</value>
</param>
<param>
- <key>time_source1</key>
- <value></value>
+ <key>if_gain14</key>
+ <value>20</value>
</param>
<param>
- <key>clock_source2</key>
- <value></value>
+ <key>gain14</key>
+ <value>10</value>
</param>
<param>
- <key>time_source2</key>
+ <key>ant15</key>
<value></value>
</param>
<param>
- <key>clock_source3</key>
- <value></value>
+ <key>bb_gain15</key>
+ <value>20</value>
</param>
<param>
- <key>time_source3</key>
- <value></value>
+ <key>bw15</key>
+ <value>0</value>
</param>
<param>
- <key>clock_source4</key>
- <value></value>
+ <key>corr15</key>
+ <value>0</value>
</param>
<param>
- <key>time_source4</key>
- <value></value>
+ <key>freq15</key>
+ <value>100e6</value>
</param>
<param>
- <key>clock_source5</key>
- <value></value>
+ <key>if_gain15</key>
+ <value>20</value>
</param>
<param>
- <key>time_source5</key>
- <value></value>
+ <key>gain15</key>
+ <value>10</value>
</param>
<param>
- <key>clock_source6</key>
+ <key>ant16</key>
<value></value>
</param>
<param>
- <key>time_source6</key>
- <value></value>
+ <key>bb_gain16</key>
+ <value>20</value>
</param>
<param>
- <key>clock_source7</key>
- <value></value>
+ <key>bw16</key>
+ <value>0</value>
</param>
<param>
- <key>time_source7</key>
- <value></value>
+ <key>corr16</key>
+ <value>0</value>
</param>
<param>
- <key>nchan</key>
- <value>1</value>
+ <key>freq16</key>
+ <value>100e6</value>
</param>
<param>
- <key>sample_rate</key>
- <value>samp_rate</value>
+ <key>if_gain16</key>
+ <value>20</value>
</param>
<param>
- <key>freq0</key>
- <value>1280e6</value>
+ <key>gain16</key>
+ <value>10</value>
</param>
<param>
- <key>corr0</key>
- <value>0</value>
+ <key>ant17</key>
+ <value></value>
</param>
<param>
- <key>gain0</key>
- <value>15</value>
+ <key>bb_gain17</key>
+ <value>20</value>
</param>
<param>
- <key>if_gain0</key>
+ <key>bw17</key>
<value>0</value>
</param>
<param>
- <key>bb_gain0</key>
- <value>-10</value>
+ <key>corr17</key>
+ <value>0</value>
</param>
<param>
- <key>ant0</key>
+ <key>freq17</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain17</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain17</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant18</key>
<value></value>
</param>
<param>
- <key>bw0</key>
- <value>6000000</value>
+ <key>bb_gain18</key>
+ <value>20</value>
</param>
<param>
- <key>freq1</key>
- <value>100e6</value>
+ <key>bw18</key>
+ <value>0</value>
</param>
<param>
- <key>corr1</key>
+ <key>corr18</key>
<value>0</value>
</param>
<param>
- <key>gain1</key>
+ <key>freq18</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain18</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain18</key>
<value>10</value>
</param>
<param>
- <key>if_gain1</key>
+ <key>ant19</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain19</key>
<value>20</value>
</param>
<param>
- <key>bb_gain1</key>
+ <key>bw19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq19</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain19</key>
<value>20</value>
</param>
<param>
+ <key>gain19</key>
+ <value>10</value>
+ </param>
+ <param>
<key>ant1</key>
<value></value>
</param>
<param>
+ <key>bb_gain1</key>
+ <value>20</value>
+ </param>
+ <param>
<key>bw1</key>
<value>0</value>
</param>
<param>
- <key>freq2</key>
+ <key>corr1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq1</key>
<value>100e6</value>
</param>
<param>
- <key>corr2</key>
- <value>0</value>
+ <key>if_gain1</key>
+ <value>20</value>
</param>
<param>
- <key>gain2</key>
+ <key>gain1</key>
<value>10</value>
</param>
<param>
- <key>if_gain2</key>
- <value>20</value>
+ <key>ant20</key>
+ <value></value>
</param>
<param>
- <key>bb_gain2</key>
+ <key>bb_gain20</key>
<value>20</value>
</param>
<param>
- <key>ant2</key>
- <value></value>
+ <key>bw20</key>
+ <value>0</value>
</param>
<param>
- <key>bw2</key>
+ <key>corr20</key>
<value>0</value>
</param>
<param>
- <key>freq3</key>
+ <key>freq20</key>
<value>100e6</value>
</param>
<param>
- <key>corr3</key>
- <value>0</value>
+ <key>if_gain20</key>
+ <value>20</value>
</param>
<param>
- <key>gain3</key>
+ <key>gain20</key>
<value>10</value>
</param>
<param>
- <key>if_gain3</key>
- <value>20</value>
+ <key>ant21</key>
+ <value></value>
</param>
<param>
- <key>bb_gain3</key>
+ <key>bb_gain21</key>
<value>20</value>
</param>
<param>
- <key>ant3</key>
- <value></value>
+ <key>bw21</key>
+ <value>0</value>
</param>
<param>
- <key>bw3</key>
+ <key>corr21</key>
<value>0</value>
</param>
<param>
- <key>freq4</key>
+ <key>freq21</key>
<value>100e6</value>
</param>
<param>
- <key>corr4</key>
- <value>0</value>
+ <key>if_gain21</key>
+ <value>20</value>
</param>
<param>
- <key>gain4</key>
+ <key>gain21</key>
<value>10</value>
</param>
<param>
- <key>if_gain4</key>
- <value>20</value>
+ <key>ant22</key>
+ <value></value>
</param>
<param>
- <key>bb_gain4</key>
+ <key>bb_gain22</key>
<value>20</value>
</param>
<param>
- <key>ant4</key>
- <value></value>
+ <key>bw22</key>
+ <value>0</value>
</param>
<param>
- <key>bw4</key>
+ <key>corr22</key>
<value>0</value>
</param>
<param>
- <key>freq5</key>
+ <key>freq22</key>
<value>100e6</value>
</param>
<param>
- <key>corr5</key>
- <value>0</value>
+ <key>if_gain22</key>
+ <value>20</value>
</param>
<param>
- <key>gain5</key>
+ <key>gain22</key>
<value>10</value>
</param>
<param>
- <key>if_gain5</key>
- <value>20</value>
+ <key>ant23</key>
+ <value></value>
</param>
<param>
- <key>bb_gain5</key>
+ <key>bb_gain23</key>
<value>20</value>
</param>
<param>
- <key>ant5</key>
- <value></value>
+ <key>bw23</key>
+ <value>0</value>
</param>
<param>
- <key>bw5</key>
+ <key>corr23</key>
<value>0</value>
</param>
<param>
- <key>freq6</key>
+ <key>freq23</key>
<value>100e6</value>
</param>
<param>
- <key>corr6</key>
- <value>0</value>
+ <key>if_gain23</key>
+ <value>20</value>
</param>
<param>
- <key>gain6</key>
+ <key>gain23</key>
<value>10</value>
</param>
<param>
- <key>if_gain6</key>
- <value>20</value>
+ <key>ant24</key>
+ <value></value>
</param>
<param>
- <key>bb_gain6</key>
+ <key>bb_gain24</key>
<value>20</value>
</param>
<param>
- <key>ant6</key>
- <value></value>
+ <key>bw24</key>
+ <value>0</value>
</param>
<param>
- <key>bw6</key>
+ <key>corr24</key>
<value>0</value>
</param>
<param>
- <key>freq7</key>
+ <key>freq24</key>
<value>100e6</value>
</param>
<param>
- <key>corr7</key>
- <value>0</value>
+ <key>if_gain24</key>
+ <value>20</value>
</param>
<param>
- <key>gain7</key>
+ <key>gain24</key>
<value>10</value>
</param>
<param>
- <key>if_gain7</key>
- <value>20</value>
+ <key>ant25</key>
+ <value></value>
</param>
<param>
- <key>bb_gain7</key>
+ <key>bb_gain25</key>
<value>20</value>
</param>
<param>
- <key>ant7</key>
- <value></value>
+ <key>bw25</key>
+ <value>0</value>
</param>
<param>
- <key>bw7</key>
+ <key>corr25</key>
<value>0</value>
</param>
<param>
- <key>freq8</key>
+ <key>freq25</key>
<value>100e6</value>
</param>
<param>
- <key>corr8</key>
- <value>0</value>
+ <key>if_gain25</key>
+ <value>20</value>
</param>
<param>
- <key>gain8</key>
+ <key>gain25</key>
<value>10</value>
</param>
<param>
- <key>if_gain8</key>
- <value>20</value>
+ <key>ant26</key>
+ <value></value>
</param>
<param>
- <key>bb_gain8</key>
+ <key>bb_gain26</key>
<value>20</value>
</param>
<param>
- <key>ant8</key>
- <value></value>
+ <key>bw26</key>
+ <value>0</value>
</param>
<param>
- <key>bw8</key>
+ <key>corr26</key>
<value>0</value>
</param>
<param>
- <key>freq9</key>
+ <key>freq26</key>
<value>100e6</value>
</param>
<param>
- <key>corr9</key>
- <value>0</value>
+ <key>if_gain26</key>
+ <value>20</value>
</param>
<param>
- <key>gain9</key>
+ <key>gain26</key>
<value>10</value>
</param>
<param>
- <key>if_gain9</key>
- <value>20</value>
+ <key>ant27</key>
+ <value></value>
</param>
<param>
- <key>bb_gain9</key>
+ <key>bb_gain27</key>
<value>20</value>
</param>
<param>
- <key>ant9</key>
- <value></value>
+ <key>bw27</key>
+ <value>0</value>
</param>
<param>
- <key>bw9</key>
+ <key>corr27</key>
<value>0</value>
</param>
<param>
- <key>freq10</key>
+ <key>freq27</key>
<value>100e6</value>
</param>
<param>
- <key>corr10</key>
- <value>0</value>
+ <key>if_gain27</key>
+ <value>20</value>
</param>
<param>
- <key>gain10</key>
+ <key>gain27</key>
<value>10</value>
</param>
<param>
- <key>if_gain10</key>
- <value>20</value>
+ <key>ant28</key>
+ <value></value>
</param>
<param>
- <key>bb_gain10</key>
+ <key>bb_gain28</key>
<value>20</value>
</param>
<param>
- <key>ant10</key>
- <value></value>
+ <key>bw28</key>
+ <value>0</value>
</param>
<param>
- <key>bw10</key>
+ <key>corr28</key>
<value>0</value>
</param>
<param>
- <key>freq11</key>
+ <key>freq28</key>
<value>100e6</value>
</param>
<param>
- <key>corr11</key>
- <value>0</value>
+ <key>if_gain28</key>
+ <value>20</value>
</param>
<param>
- <key>gain11</key>
+ <key>gain28</key>
<value>10</value>
</param>
<param>
- <key>if_gain11</key>
- <value>20</value>
+ <key>ant29</key>
+ <value></value>
</param>
<param>
- <key>bb_gain11</key>
+ <key>bb_gain29</key>
<value>20</value>
</param>
<param>
- <key>ant11</key>
- <value></value>
+ <key>bw29</key>
+ <value>0</value>
</param>
<param>
- <key>bw11</key>
+ <key>corr29</key>
<value>0</value>
</param>
<param>
- <key>freq12</key>
+ <key>freq29</key>
<value>100e6</value>
</param>
<param>
- <key>corr12</key>
- <value>0</value>
+ <key>if_gain29</key>
+ <value>20</value>
</param>
<param>
- <key>gain12</key>
+ <key>gain29</key>
<value>10</value>
</param>
<param>
- <key>if_gain12</key>
- <value>20</value>
+ <key>ant2</key>
+ <value></value>
</param>
<param>
- <key>bb_gain12</key>
+ <key>bb_gain2</key>
<value>20</value>
</param>
<param>
- <key>ant12</key>
- <value></value>
+ <key>bw2</key>
+ <value>0</value>
</param>
<param>
- <key>bw12</key>
+ <key>corr2</key>
<value>0</value>
</param>
<param>
- <key>freq13</key>
+ <key>freq2</key>
<value>100e6</value>
</param>
<param>
- <key>corr13</key>
- <value>0</value>
+ <key>if_gain2</key>
+ <value>20</value>
</param>
<param>
- <key>gain13</key>
+ <key>gain2</key>
<value>10</value>
</param>
<param>
- <key>if_gain13</key>
- <value>20</value>
+ <key>ant30</key>
+ <value></value>
</param>
<param>
- <key>bb_gain13</key>
+ <key>bb_gain30</key>
<value>20</value>
</param>
<param>
- <key>ant13</key>
- <value></value>
+ <key>bw30</key>
+ <value>0</value>
</param>
<param>
- <key>bw13</key>
+ <key>corr30</key>
<value>0</value>
</param>
<param>
- <key>freq14</key>
+ <key>freq30</key>
<value>100e6</value>
</param>
<param>
- <key>corr14</key>
- <value>0</value>
+ <key>if_gain30</key>
+ <value>20</value>
</param>
<param>
- <key>gain14</key>
+ <key>gain30</key>
<value>10</value>
</param>
<param>
- <key>if_gain14</key>
- <value>20</value>
+ <key>ant31</key>
+ <value></value>
</param>
<param>
- <key>bb_gain14</key>
+ <key>bb_gain31</key>
<value>20</value>
</param>
<param>
- <key>ant14</key>
- <value></value>
+ <key>bw31</key>
+ <value>0</value>
</param>
<param>
- <key>bw14</key>
+ <key>corr31</key>
<value>0</value>
</param>
<param>
- <key>freq15</key>
+ <key>freq31</key>
<value>100e6</value>
</param>
<param>
- <key>corr15</key>
- <value>0</value>
+ <key>if_gain31</key>
+ <value>20</value>
</param>
<param>
- <key>gain15</key>
+ <key>gain31</key>
<value>10</value>
</param>
<param>
- <key>if_gain15</key>
+ <key>ant3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain3</key>
<value>20</value>
</param>
<param>
- <key>bb_gain15</key>
+ <key>bw3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq3</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain3</key>
<value>20</value>
</param>
<param>
- <key>ant15</key>
+ <key>gain3</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant4</key>
<value></value>
</param>
<param>
- <key>bw15</key>
+ <key>bb_gain4</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw4</key>
<value>0</value>
</param>
<param>
- <key>freq16</key>
+ <key>corr4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq4</key>
<value>100e6</value>
</param>
<param>
- <key>corr16</key>
- <value>0</value>
+ <key>if_gain4</key>
+ <value>20</value>
</param>
<param>
- <key>gain16</key>
+ <key>gain4</key>
<value>10</value>
</param>
<param>
- <key>if_gain16</key>
+ <key>ant5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain5</key>
<value>20</value>
</param>
<param>
- <key>bb_gain16</key>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq5</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain5</key>
<value>20</value>
</param>
<param>
- <key>ant16</key>
+ <key>gain5</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant6</key>
<value></value>
</param>
<param>
- <key>bw16</key>
+ <key>bb_gain6</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw6</key>
<value>0</value>
</param>
<param>
- <key>freq17</key>
+ <key>corr6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq6</key>
<value>100e6</value>
</param>
<param>
- <key>corr17</key>
- <value>0</value>
+ <key>if_gain6</key>
+ <value>20</value>
</param>
<param>
- <key>gain17</key>
+ <key>gain6</key>
<value>10</value>
</param>
<param>
- <key>if_gain17</key>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain7</key>
<value>20</value>
</param>
<param>
- <key>bb_gain17</key>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq7</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain7</key>
<value>20</value>
</param>
<param>
- <key>ant17</key>
+ <key>gain7</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant8</key>
<value></value>
</param>
<param>
- <key>bw17</key>
+ <key>bb_gain8</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw8</key>
<value>0</value>
</param>
<param>
- <key>freq18</key>
+ <key>corr8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq8</key>
<value>100e6</value>
</param>
<param>
- <key>corr18</key>
- <value>0</value>
+ <key>if_gain8</key>
+ <value>20</value>
</param>
<param>
- <key>gain18</key>
+ <key>gain8</key>
<value>10</value>
</param>
<param>
- <key>if_gain18</key>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain9</key>
<value>20</value>
</param>
<param>
- <key>bb_gain18</key>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq9</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain9</key>
<value>20</value>
</param>
<param>
- <key>ant18</key>
+ <key>gain9</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>comment</key>
<value></value>
</param>
<param>
- <key>bw18</key>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>args</key>
+ <value>bladerf=0,buffers=128,buflen=32768</value>
+ </param>
+ <param>
+ <key>_enabled</key>
<value>0</value>
</param>
<param>
- <key>freq19</key>
- <value>100e6</value>
+ <key>_coordinate</key>
+ <value>(1040, 243)</value>
</param>
<param>
- <key>corr19</key>
+ <key>_rotation</key>
<value>0</value>
</param>
<param>
- <key>gain19</key>
- <value>10</value>
+ <key>id</key>
+ <value>osmosdr_sink_0</value>
</param>
<param>
- <key>if_gain19</key>
- <value>20</value>
+ <key>type</key>
+ <value>fc32</value>
</param>
<param>
- <key>bb_gain19</key>
- <value>20</value>
+ <key>clock_source0</key>
+ <value></value>
</param>
<param>
- <key>ant19</key>
+ <key>time_source0</key>
<value></value>
</param>
<param>
- <key>bw19</key>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>sample_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>uhd_usrp_sink</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ant0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw0</key>
<value>0</value>
</param>
<param>
- <key>freq20</key>
- <value>100e6</value>
+ <key>center_freq0</key>
+ <value>uhd.tune_request(frequency, ((symbol_rate * (1 + rolloff)) / 2 ) + 1e5)</value>
</param>
<param>
- <key>corr20</key>
+ <key>norm_gain0</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain0</key>
+ <value>60</value>
+ </param>
+ <param>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw10</key>
<value>0</value>
</param>
<param>
- <key>gain20</key>
- <value>10</value>
+ <key>center_freq10</key>
+ <value>0</value>
</param>
<param>
- <key>if_gain20</key>
- <value>20</value>
+ <key>norm_gain10</key>
+ <value>False</value>
</param>
<param>
- <key>bb_gain20</key>
- <value>20</value>
+ <key>gain10</key>
+ <value>0</value>
</param>
<param>
- <key>ant20</key>
+ <key>ant11</key>
<value></value>
</param>
<param>
- <key>bw20</key>
+ <key>bw11</key>
<value>0</value>
</param>
<param>
- <key>freq21</key>
- <value>100e6</value>
+ <key>center_freq11</key>
+ <value>0</value>
</param>
<param>
- <key>corr21</key>
+ <key>norm_gain11</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain11</key>
<value>0</value>
</param>
<param>
- <key>gain21</key>
- <value>10</value>
+ <key>ant12</key>
+ <value></value>
</param>
<param>
- <key>if_gain21</key>
- <value>20</value>
+ <key>bw12</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain21</key>
- <value>20</value>
+ <key>center_freq12</key>
+ <value>0</value>
</param>
<param>
- <key>ant21</key>
+ <key>norm_gain12</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant13</key>
<value></value>
</param>
<param>
- <key>bw21</key>
+ <key>bw13</key>
<value>0</value>
</param>
<param>
- <key>freq22</key>
- <value>100e6</value>
+ <key>center_freq13</key>
+ <value>0</value>
</param>
<param>
- <key>corr22</key>
+ <key>norm_gain13</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain13</key>
<value>0</value>
</param>
<param>
- <key>gain22</key>
- <value>10</value>
+ <key>ant14</key>
+ <value></value>
</param>
<param>
- <key>if_gain22</key>
- <value>20</value>
+ <key>bw14</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain22</key>
- <value>20</value>
+ <key>center_freq14</key>
+ <value>0</value>
</param>
<param>
- <key>ant22</key>
+ <key>norm_gain14</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant15</key>
<value></value>
</param>
<param>
- <key>bw22</key>
+ <key>bw15</key>
<value>0</value>
</param>
<param>
- <key>freq23</key>
- <value>100e6</value>
+ <key>center_freq15</key>
+ <value>0</value>
</param>
<param>
- <key>corr23</key>
+ <key>norm_gain15</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain15</key>
<value>0</value>
</param>
<param>
- <key>gain23</key>
- <value>10</value>
+ <key>ant16</key>
+ <value></value>
</param>
<param>
- <key>if_gain23</key>
- <value>20</value>
+ <key>bw16</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain23</key>
- <value>20</value>
+ <key>center_freq16</key>
+ <value>0</value>
</param>
<param>
- <key>ant23</key>
+ <key>norm_gain16</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant17</key>
<value></value>
</param>
<param>
- <key>bw23</key>
+ <key>bw17</key>
<value>0</value>
</param>
<param>
- <key>freq24</key>
- <value>100e6</value>
+ <key>center_freq17</key>
+ <value>0</value>
</param>
<param>
- <key>corr24</key>
+ <key>norm_gain17</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain17</key>
<value>0</value>
</param>
<param>
- <key>gain24</key>
- <value>10</value>
+ <key>ant18</key>
+ <value></value>
</param>
<param>
- <key>if_gain24</key>
- <value>20</value>
+ <key>bw18</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain24</key>
- <value>20</value>
+ <key>center_freq18</key>
+ <value>0</value>
</param>
<param>
- <key>ant24</key>
+ <key>norm_gain18</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant19</key>
<value></value>
</param>
<param>
- <key>bw24</key>
+ <key>bw19</key>
<value>0</value>
</param>
<param>
- <key>freq25</key>
- <value>100e6</value>
+ <key>center_freq19</key>
+ <value>0</value>
</param>
<param>
- <key>corr25</key>
+ <key>norm_gain19</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain19</key>
<value>0</value>
</param>
<param>
- <key>gain25</key>
- <value>10</value>
+ <key>ant1</key>
+ <value></value>
</param>
<param>
- <key>if_gain25</key>
- <value>20</value>
+ <key>bw1</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain25</key>
- <value>20</value>
+ <key>center_freq1</key>
+ <value>0</value>
</param>
<param>
- <key>ant25</key>
+ <key>norm_gain1</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant20</key>
<value></value>
</param>
<param>
- <key>bw25</key>
+ <key>bw20</key>
<value>0</value>
</param>
<param>
- <key>freq26</key>
- <value>100e6</value>
+ <key>center_freq20</key>
+ <value>0</value>
</param>
<param>
- <key>corr26</key>
+ <key>norm_gain20</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain20</key>
<value>0</value>
</param>
<param>
- <key>gain26</key>
- <value>10</value>
+ <key>ant21</key>
+ <value></value>
</param>
<param>
- <key>if_gain26</key>
- <value>20</value>
+ <key>bw21</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain26</key>
- <value>20</value>
+ <key>center_freq21</key>
+ <value>0</value>
</param>
<param>
- <key>ant26</key>
+ <key>norm_gain21</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant22</key>
<value></value>
</param>
<param>
- <key>bw26</key>
+ <key>bw22</key>
<value>0</value>
</param>
<param>
- <key>freq27</key>
- <value>100e6</value>
+ <key>center_freq22</key>
+ <value>0</value>
</param>
<param>
- <key>corr27</key>
+ <key>norm_gain22</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain22</key>
<value>0</value>
</param>
<param>
- <key>gain27</key>
- <value>10</value>
+ <key>ant23</key>
+ <value></value>
</param>
<param>
- <key>if_gain27</key>
- <value>20</value>
+ <key>bw23</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain27</key>
- <value>20</value>
+ <key>center_freq23</key>
+ <value>0</value>
</param>
<param>
- <key>ant27</key>
+ <key>norm_gain23</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant24</key>
<value></value>
</param>
<param>
- <key>bw27</key>
+ <key>bw24</key>
<value>0</value>
</param>
<param>
- <key>freq28</key>
- <value>100e6</value>
+ <key>center_freq24</key>
+ <value>0</value>
</param>
<param>
- <key>corr28</key>
+ <key>norm_gain24</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain24</key>
<value>0</value>
</param>
<param>
- <key>gain28</key>
- <value>10</value>
+ <key>ant25</key>
+ <value></value>
</param>
<param>
- <key>if_gain28</key>
- <value>20</value>
+ <key>bw25</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain28</key>
- <value>20</value>
+ <key>center_freq25</key>
+ <value>0</value>
</param>
<param>
- <key>ant28</key>
+ <key>norm_gain25</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant26</key>
<value></value>
</param>
<param>
- <key>bw28</key>
+ <key>bw26</key>
<value>0</value>
</param>
<param>
- <key>freq29</key>
- <value>100e6</value>
+ <key>center_freq26</key>
+ <value>0</value>
</param>
<param>
- <key>corr29</key>
+ <key>norm_gain26</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain26</key>
<value>0</value>
</param>
<param>
- <key>gain29</key>
- <value>10</value>
+ <key>ant27</key>
+ <value></value>
</param>
<param>
- <key>if_gain29</key>
- <value>20</value>
+ <key>bw27</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain29</key>
- <value>20</value>
+ <key>center_freq27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain27</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant28</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain28</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain28</key>
+ <value>0</value>
</param>
<param>
<key>ant29</key>
@@ -1596,24 +2272,36 @@
<value>0</value>
</param>
<param>
- <key>freq30</key>
- <value>100e6</value>
+ <key>center_freq29</key>
+ <value>0</value>
</param>
<param>
- <key>corr30</key>
+ <key>norm_gain29</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain29</key>
<value>0</value>
</param>
<param>
- <key>gain30</key>
- <value>10</value>
+ <key>ant2</key>
+ <value></value>
</param>
<param>
- <key>if_gain30</key>
- <value>20</value>
+ <key>bw2</key>
+ <value>0</value>
</param>
<param>
- <key>bb_gain30</key>
- <value>20</value>
+ <key>center_freq2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain2</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain2</key>
+ <value>0</value>
</param>
<param>
<key>ant30</key>
@@ -1624,82 +2312,183 @@
<value>0</value>
</param>
<param>
- <key>freq31</key>
- <value>100e6</value>
+ <key>center_freq30</key>
+ <value>0</value>
</param>
<param>
- <key>corr31</key>
+ <key>norm_gain30</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain30</key>
<value>0</value>
</param>
<param>
+ <key>ant31</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain31</key>
+ <value>False</value>
+ </param>
+ <param>
<key>gain31</key>
- <value>10</value>
+ <value>0</value>
</param>
<param>
- <key>if_gain31</key>
- <value>20</value>
+ <key>ant3</key>
+ <value></value>
</param>
<param>
- <key>bb_gain31</key>
- <value>20</value>
+ <key>bw3</key>
+ <value>0</value>
</param>
<param>
- <key>ant31</key>
+ <key>center_freq3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain3</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant4</key>
<value></value>
</param>
<param>
- <key>bw31</key>
+ <key>bw4</key>
<value>0</value>
</param>
<param>
- <key>alias</key>
+ <key>center_freq4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain4</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant5</key>
<value></value>
</param>
<param>
- <key>affinity</key>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain5</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant6</key>
<value></value>
</param>
<param>
- <key>_coordinate</key>
- <value>(1000, 203)</value>
+ <key>bw6</key>
+ <value>0</value>
</param>
<param>
- <key>_rotation</key>
+ <key>center_freq6</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>blocks_file_sink</key>
<param>
- <key>id</key>
- <value>blocks_file_sink_0</value>
+ <key>norm_gain6</key>
+ <value>False</value>
</param>
<param>
- <key>_enabled</key>
+ <key>gain6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain7</key>
<value>False</value>
</param>
<param>
- <key>file</key>
- <value>adv.cfile</value>
+ <key>gain7</key>
+ <value>0</value>
</param>
<param>
- <key>type</key>
- <value>complex</value>
+ <key>ant8</key>
+ <value></value>
</param>
<param>
- <key>vlen</key>
- <value>1</value>
+ <key>bw8</key>
+ <value>0</value>
</param>
<param>
- <key>unbuffered</key>
+ <key>center_freq8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain8</key>
<value>False</value>
</param>
<param>
- <key>append</key>
+ <key>gain8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain9</key>
<value>False</value>
</param>
<param>
- <key>alias</key>
+ <key>gain9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>clock_rate</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>comment</key>
<value></value>
</param>
<param>
@@ -1707,163 +2496,270 @@
<value></value>
</param>
<param>
+ <key>dev_addr</key>
+ <value>"send_frame_size=65536,num_send_frames=256,master_clock_rate=" + str(samp_rate*2)</value>
+ </param>
+ <param>
+ <key>dev_args</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(792, 547)</value>
+ <value>(1040, 427)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>dtv_dvb_bbheader_bb</key>
<param>
<key>id</key>
- <value>dtv_dvb_bbheader_bb_0</value>
+ <value>uhd_usrp_sink_0_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>type</key>
+ <value>fc32</value>
</param>
<param>
- <key>standard</key>
- <value>STANDARD_DVBS2</value>
+ <key>clock_source0</key>
+ <value></value>
</param>
<param>
- <key>framesize</key>
- <value>FECFRAME_NORMAL</value>
+ <key>sd_spec0</key>
+ <value></value>
</param>
<param>
- <key>rate1</key>
- <value>C1_2</value>
+ <key>time_source0</key>
+ <value></value>
</param>
<param>
- <key>rate2</key>
- <value>C1_3</value>
+ <key>clock_source1</key>
+ <value></value>
</param>
<param>
- <key>rate3</key>
- <value>C9_10</value>
+ <key>sd_spec1</key>
+ <value></value>
</param>
<param>
- <key>rate4</key>
- <value>C1_4</value>
+ <key>time_source1</key>
+ <value></value>
</param>
<param>
- <key>rolloff</key>
- <value>RO_0_20</value>
+ <key>clock_source2</key>
+ <value></value>
</param>
<param>
- <key>mode</key>
- <value>FECFRAME_NORMAL</value>
+ <key>sd_spec2</key>
+ <value></value>
</param>
<param>
- <key>inband</key>
- <value>INBAND_OFF</value>
+ <key>time_source2</key>
+ <value></value>
</param>
<param>
- <key>fecblocks</key>
- <value>168</value>
+ <key>clock_source3</key>
+ <value></value>
</param>
<param>
- <key>tsrate</key>
- <value>4000000</value>
+ <key>sd_spec3</key>
+ <value></value>
</param>
<param>
- <key>alias</key>
+ <key>time_source3</key>
<value></value>
</param>
<param>
- <key>affinity</key>
+ <key>clock_source4</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>sd_spec4</key>
+ <value></value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>time_source4</key>
+ <value></value>
</param>
<param>
- <key>_coordinate</key>
- <value>(400, 27)</value>
+ <key>clock_source5</key>
+ <value></value>
</param>
<param>
- <key>_rotation</key>
- <value>0</value>
+ <key>sd_spec5</key>
+ <value></value>
</param>
- </block>
- <block>
- <key>blocks_file_source</key>
<param>
- <key>id</key>
- <value>blocks_file_source_0</value>
+ <key>time_source5</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>clock_source6</key>
+ <value></value>
</param>
<param>
- <key>file</key>
- <value>/run/shm/adv16apsk910.ts</value>
+ <key>sd_spec6</key>
+ <value></value>
</param>
<param>
- <key>type</key>
- <value>byte</value>
+ <key>time_source6</key>
+ <value></value>
</param>
<param>
- <key>repeat</key>
- <value>True</value>
+ <key>clock_source7</key>
+ <value></value>
</param>
<param>
- <key>vlen</key>
+ <key>sd_spec7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
<value>1</value>
</param>
<param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>hide_cmd_port</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>stream_args</key>
+ <value></value>
+ </param>
+ <param>
+ <key>stream_chans</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ <param>
+ <key>len_tag_name</key>
+ <value></value>
+ </param>
+ <param>
+ <key>otw</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_fftsink2</key>
+ <param>
+ <key>avg_alpha</key>
+ <value>0.13333</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>baseband_freq</key>
+ <value>frequency</value>
+ </param>
+ <param>
<key>alias</key>
<value></value>
</param>
<param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
<key>affinity</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>True</value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>fft_size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
</param>
<param>
<key>_coordinate</key>
- <value>(176, 43)</value>
+ <value>(784, 203)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>wxgui_fftsink2_0</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>FFT Plot</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>y_divs</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>y_per_div</key>
+ <value>10</value>
+ </param>
</block>
<connection>
- <source_block_id>fft_filter_xxx_0</source_block_id>
- <sink_block_id>osmosdr_sink_0</sink_block_id>
- <source_key>0</source_key>
- <sink_key>0</sink_key>
- </connection>
- <connection>
- <source_block_id>fft_filter_xxx_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>fft_filter_xxx_0</source_block_id>
- <sink_block_id>blocks_file_sink_0</sink_block_id>
- <source_key>0</source_key>
- <sink_key>0</sink_key>
- </connection>
- <connection>
<source_block_id>blocks_file_source_0</source_block_id>
<sink_block_id>dtv_dvb_bbheader_bb_0</sink_block_id>
<source_key>0</source_key>
@@ -1900,14 +2796,38 @@
<sink_key>0</sink_key>
</connection>
<connection>
+ <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id>
+ <sink_block_id>dtv_dvbs2_physical_cc_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
<source_block_id>dtv_dvbs2_physical_cc_0</source_block_id>
<sink_block_id>fft_filter_xxx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
- <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id>
- <sink_block_id>dtv_dvbs2_physical_cc_0</sink_block_id>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>blocks_file_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>osmosdr_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>uhd_usrp_sink_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>wxgui_fftsink2_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
diff --git a/gr-dtv/examples/dvbs_tx.grc b/gr-dtv/examples/dvbs_tx.grc
new file mode 100644
index 0000000000..c9dd98a0b9
--- /dev/null
+++ b/gr-dtv/examples/dvbs_tx.grc
@@ -0,0 +1,2853 @@
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.10'?>
+<flow_graph>
+ <timestamp>Wed Jun 18 01:23:58 2014</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>author</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>wx_gui</value>
+ </param>
+ <param>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dvbs_tx</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>prompt</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 203)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>frequency</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>1280e6</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 267)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>rrc_taps</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>100</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 75)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>symbol_rate * 2</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 139)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>symbol_rate</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>8000000</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_sink</key>
+ <param>
+ <key>append</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>adv.bin</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(848, 507)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_file_sink_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>unbuffered</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_source</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>/run/shm/advdvbs78.ts</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(184, 59)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_file_source_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ <param>
+ <key>repeat</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_pack_k_bits_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(176, 451)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_pack_k_bits_bb_0</value>
+ </param>
+ <param>
+ <key>k</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_packed_to_unpacked_xx</key>
+ <param>
+ <key>bits_per_chunk</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>endianness</key>
+ <value>gr.GR_MSB_FIRST</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1080, 59)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_packed_to_unpacked_xx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>num_ports</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_unpack_k_bits_bb</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(408, 235)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>blocks_unpack_k_bits_bb_0</value>
+ </param>
+ <param>
+ <key>k</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbs2_modulator_bc</key>
+ <param>
+ <key>interpolation</key>
+ <value>INTERPOLATION_ON</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>rate</key>
+ <value>C_OTHER</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>constellation</key>
+ <value>MOD_QPSK</value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>framesize</key>
+ <value>FECFRAME_NORMAL</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(352, 427)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbs2_modulator_bc_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbt_convolutional_interleaver</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>blocks</key>
+ <value>136</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>M</key>
+ <value>17</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(832, 51)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbt_convolutional_interleaver_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>I</key>
+ <value>12</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbt_energy_dispersal</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nsize</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(408, 73)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbt_energy_dispersal_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>dtv_dvbt_reed_solomon_enc</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>blocks</key>
+ <value>8</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>gfpoly</key>
+ <value>0x11d</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(600, 19)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>dtv_dvbt_reed_solomon_enc_0</value>
+ </param>
+ <param>
+ <key>k</key>
+ <value>239</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>n</key>
+ <value>255</value>
+ </param>
+ <param>
+ <key>s</key>
+ <value>51</value>
+ </param>
+ <param>
+ <key>m</key>
+ <value>8</value>
+ </param>
+ <param>
+ <key>p</key>
+ <value>2</value>
+ </param>
+ <param>
+ <key>t</key>
+ <value>8</value>
+ </param>
+ </block>
+ <block>
+ <key>fec_puncture_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>delay</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(600, 219)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fec_puncture_xx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>puncpat</key>
+ <value>0b11010101100110</value>
+ </param>
+ <param>
+ <key>puncsize</key>
+ <value>14</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>byte</value>
+ </param>
+ </block>
+ <block>
+ <key>fft_filter_xxx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>decim</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(584, 435)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>fft_filter_xxx_0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>nthreads</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_delay</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>taps</key>
+ <value>firdes.root_raised_cosine(1.0, samp_rate, samp_rate/2, 0.35, rrc_taps)</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>ccc</value>
+ </param>
+ </block>
+ <block>
+ <key>osmosdr_sink</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ant0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain0</key>
+ <value>-10</value>
+ </param>
+ <param>
+ <key>bw0</key>
+ <value>10000000</value>
+ </param>
+ <param>
+ <key>corr0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq0</key>
+ <value>frequency</value>
+ </param>
+ <param>
+ <key>if_gain0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>gain0</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain10</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq10</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain10</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain10</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant11</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain11</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq11</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain11</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain11</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant12</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq12</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain12</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant13</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain13</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq13</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain13</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain13</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant14</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain14</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq14</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain14</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain14</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant15</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain15</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq15</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain15</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain15</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant16</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain16</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq16</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain16</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain16</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant17</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain17</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq17</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain17</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain17</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant18</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain18</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq18</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain18</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain18</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant19</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain19</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq19</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain19</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain19</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain1</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq1</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain1</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain1</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant20</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain20</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq20</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain20</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain20</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant21</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain21</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq21</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain21</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain21</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant22</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain22</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq22</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain22</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain22</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant23</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain23</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq23</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain23</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain23</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant24</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain24</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq24</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain24</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain24</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant25</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain25</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq25</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain25</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain25</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant26</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain26</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq26</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain26</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain26</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant27</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain27</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq27</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain27</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain27</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant28</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain28</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq28</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain28</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain28</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant29</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain29</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq29</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain29</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain29</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain2</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq2</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain2</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain2</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant30</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain30</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq30</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain30</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain30</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant31</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain31</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq31</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain31</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain31</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain3</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq3</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain3</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain3</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain4</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq4</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain4</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain4</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain5</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq5</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain5</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain5</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain6</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq6</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain6</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain6</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain7</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq7</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain7</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain7</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain8</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq8</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain8</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain8</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bb_gain9</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>corr9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>freq9</key>
+ <value>100e6</value>
+ </param>
+ <param>
+ <key>if_gain9</key>
+ <value>20</value>
+ </param>
+ <param>
+ <key>gain9</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>args</key>
+ <value>bladerf=0,buffers=128,buflen=32768</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1064, 211)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>osmosdr_sink_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fc32</value>
+ </param>
+ <param>
+ <key>clock_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>sample_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>trellis_encoder_xx</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>blocklength</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>blockwise</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>fsm_args</key>
+ <value>1, 2, (0171, 0133)</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(176, 227)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>trellis_encoder_xx_0</value>
+ </param>
+ <param>
+ <key>init_state</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>bb</value>
+ </param>
+ </block>
+ <block>
+ <key>uhd_usrp_sink</key>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>ant0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw0</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq0</key>
+ <value>uhd.tune_request(frequency, ((symbol_rate * 1.35) / 2 ) + 1e5)</value>
+ </param>
+ <param>
+ <key>norm_gain0</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain0</key>
+ <value>60</value>
+ </param>
+ <param>
+ <key>ant10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain10</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain10</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant11</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain11</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain11</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant12</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain12</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain12</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant13</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain13</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain13</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant14</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain14</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain14</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant15</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain15</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain15</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant16</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain16</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain16</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant17</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain17</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain17</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant18</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain18</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain18</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant19</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain19</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain19</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain1</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain1</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant20</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain20</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain20</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant21</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain21</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain21</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant22</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain22</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain22</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant23</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain23</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain23</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant24</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain24</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain24</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant25</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain25</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain25</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant26</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain26</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain26</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant27</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain27</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain27</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant28</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain28</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain28</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant29</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain29</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain29</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain2</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain2</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant30</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain30</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain30</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant31</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain31</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain31</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain3</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain3</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain4</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain4</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain5</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain5</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain6</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain6</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain7</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain7</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain8</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain8</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ant9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>bw9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>center_freq9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>norm_gain9</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>gain9</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>clock_rate</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>dev_addr</key>
+ <value>"send_frame_size=65536,num_send_frames=256,master_clock_rate=" + str(samp_rate*2)</value>
+ </param>
+ <param>
+ <key>dev_args</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(1064, 403)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>uhd_usrp_sink_0_0</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>fc32</value>
+ </param>
+ <param>
+ <key>clock_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source0</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source1</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source2</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source3</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>clock_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>sd_spec7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>time_source7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>nchan</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>num_mboards</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>hide_cmd_port</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>stream_args</key>
+ <value></value>
+ </param>
+ <param>
+ <key>stream_chans</key>
+ <value>[]</value>
+ </param>
+ <param>
+ <key>sync</key>
+ <value></value>
+ </param>
+ <param>
+ <key>len_tag_name</key>
+ <value></value>
+ </param>
+ <param>
+ <key>otw</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>wxgui_fftsink2</key>
+ <param>
+ <key>avg_alpha</key>
+ <value>0.13333</value>
+ </param>
+ <param>
+ <key>average</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>baseband_freq</key>
+ <value>frequency</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>fft_size</key>
+ <value>1024</value>
+ </param>
+ <param>
+ <key>freqvar</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(848, 195)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>grid_pos</key>
+ <value></value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>wxgui_fftsink2_0</value>
+ </param>
+ <param>
+ <key>notebook</key>
+ <value></value>
+ </param>
+ <param>
+ <key>peak_hold</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>ref_level</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ </param>
+ <param>
+ <key>fft_rate</key>
+ <value>15</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value>FFT Plot</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>complex</value>
+ </param>
+ <param>
+ <key>win_size</key>
+ <value></value>
+ </param>
+ <param>
+ <key>win</key>
+ <value>None</value>
+ </param>
+ <param>
+ <key>y_divs</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>y_per_div</key>
+ <value>10</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>blocks_file_source_0</source_block_id>
+ <sink_block_id>dtv_dvbt_energy_dispersal_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_pack_k_bits_bb_0</source_block_id>
+ <sink_block_id>dtv_dvbs2_modulator_bc_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_packed_to_unpacked_xx_0</source_block_id>
+ <sink_block_id>trellis_encoder_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_unpack_k_bits_bb_0</source_block_id>
+ <sink_block_id>fec_puncture_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbs2_modulator_bc_0</source_block_id>
+ <sink_block_id>fft_filter_xxx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbt_convolutional_interleaver_0</source_block_id>
+ <sink_block_id>blocks_packed_to_unpacked_xx_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbt_energy_dispersal_0</source_block_id>
+ <sink_block_id>dtv_dvbt_reed_solomon_enc_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>dtv_dvbt_reed_solomon_enc_0</source_block_id>
+ <sink_block_id>dtv_dvbt_convolutional_interleaver_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fec_puncture_xx_0</source_block_id>
+ <sink_block_id>blocks_pack_k_bits_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>blocks_file_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>osmosdr_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_0</source_block_id>
+ <sink_block_id>uhd_usrp_sink_0_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>fft_filter_xxx_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>trellis_encoder_xx_0</source_block_id>
+ <sink_block_id>blocks_unpack_k_bits_bb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-dtv/grc/CMakeLists.txt b/gr-dtv/grc/CMakeLists.txt
index 2fed81ab12..a1386c5adf 100644
--- a/gr-dtv/grc/CMakeLists.txt
+++ b/gr-dtv/grc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2014,2015 Free Software Foundation, Inc.
+# Copyright 2014,2015,2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -68,6 +68,11 @@ install(FILES
dtv_dvbt_convolutional_deinterleaver.xml
dtv_dvbt_reed_solomon_dec.xml
dtv_dvbt_energy_descramble.xml
+ dtv_catv_transport_framing_enc_bb.xml
+ dtv_catv_reed_solomon_enc_bb.xml
+ dtv_catv_randomizer_bb.xml
+ dtv_catv_frame_sync_enc_bb.xml
+ dtv_catv_trellis_enc_bb.xml
DESTINATION ${GRC_BLOCKS_DIR}
COMPONENT "dtv_python"
)
diff --git a/gr-dtv/grc/dtv_block_tree.xml b/gr-dtv/grc/dtv_block_tree.xml
index 32c8974531..8dcbd18127 100644
--- a/gr-dtv/grc/dtv_block_tree.xml
+++ b/gr-dtv/grc/dtv_block_tree.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- Copyright 2014,2015 Free Software Foundation, Inc.
+ Copyright 2014,2015,2016 Free Software Foundation, Inc.
This file is part of GNU Radio
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Digital Television</name>
<cat>
@@ -94,5 +94,13 @@
<block>dtv_dvbt_reed_solomon_dec</block>
<block>dtv_dvbt_energy_descramble</block>
</cat>
+ <cat>
+ <name>ITU-T J.83B</name>
+ <block>dtv_catv_transport_framing_enc_bb</block>
+ <block>dtv_catv_reed_solomon_enc_bb</block>
+ <block>dtv_catv_randomizer_bb</block>
+ <block>dtv_catv_frame_sync_enc_bb</block>
+ <block>dtv_catv_trellis_enc_bb</block>
+ </cat>
</cat>
</cat>
diff --git a/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml b/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml
new file mode 100644
index 0000000000..e7c1392960
--- /dev/null
+++ b/gr-dtv/grc/dtv_catv_frame_sync_enc_bb.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Frame Sync Encoder
+###################################################
+ -->
+<block>
+ <name>Frame Sync Encoder</name>
+ <key>dtv_catv_frame_sync_enc_bb</key>
+ <import>from gnuradio import dtv</import>
+ <make>dtv.catv_frame_sync_enc_bb($ctrlword)</make>
+ <param>
+ <name>Control Word</name>
+ <key>ctrlword</key>
+ <value>6</value>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+</block>
diff --git a/gr-dtv/grc/dtv_catv_randomizer_bb.xml b/gr-dtv/grc/dtv_catv_randomizer_bb.xml
new file mode 100644
index 0000000000..ca4787d786
--- /dev/null
+++ b/gr-dtv/grc/dtv_catv_randomizer_bb.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Randomizer
+###################################################
+ -->
+<block>
+ <name>Randomizer</name>
+ <key>dtv_catv_randomizer_bb</key>
+ <import>from gnuradio import dtv</import>
+ <make>dtv.catv_randomizer_bb()</make>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+</block>
diff --git a/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml b/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml
new file mode 100644
index 0000000000..a5dfdc2a5a
--- /dev/null
+++ b/gr-dtv/grc/dtv_catv_reed_solomon_enc_bb.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Reed Solomon Encoder
+###################################################
+ -->
+<block>
+ <name>Reed-Solomon Encoder</name>
+ <key>dtv_catv_reed_solomon_enc_bb</key>
+ <import>from gnuradio import dtv</import>
+ <make>dtv.catv_reed_solomon_enc_bb()</make>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+</block>
diff --git a/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml b/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml
new file mode 100644
index 0000000000..d0b6bf382b
--- /dev/null
+++ b/gr-dtv/grc/dtv_catv_transport_framing_enc_bb.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Transport Framing Encoder
+###################################################
+ -->
+<block>
+ <name>Transport Framing Encoder</name>
+ <key>dtv_catv_transport_framing_enc_bb</key>
+ <import>from gnuradio import dtv</import>
+ <make>dtv.catv_transport_framing_enc_bb()</make>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+</block>
diff --git a/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml b/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml
new file mode 100644
index 0000000000..a96d60c895
--- /dev/null
+++ b/gr-dtv/grc/dtv_catv_trellis_enc_bb.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+## Trellis Encoder
+###################################################
+ -->
+<block>
+ <name>Trellis Encoder</name>
+ <key>dtv_catv_trellis_enc_bb</key>
+ <import>from gnuradio import dtv</import>
+ <make>dtv.catv_trellis_enc_bb()</make>
+ <sink>
+ <name>in</name>
+ <type>byte</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>byte</type>
+ </source>
+</block>
diff --git a/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml b/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml
index 1f7fef09a3..8de645d585 100644
--- a/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml
+++ b/gr-dtv/grc/dtv_dvbs2_modulator_bc.xml
@@ -8,7 +8,7 @@
<name>DVB-S2X Modulator</name>
<key>dtv_dvbs2_modulator_bc</key>
<import>from gnuradio import dtv</import>
- <make>dtv.dvbs2_modulator_bc($framesize.val, $rate.val, $constellation.val)</make>
+ <make>dtv.dvbs2_modulator_bc($framesize.val, $rate.val, $constellation.val, $interpolation.val)</make>
<param>
<name>FECFRAME size</name>
<key>framesize</key>
@@ -253,6 +253,26 @@
<key>MOD_256APSK</key>
<opt>val:dtv.MOD_256APSK</opt>
</option>
+ <option>
+ <name>64QAM</name>
+ <key>MOD_64QAM</key>
+ <opt>val:dtv.MOD_64QAM</opt>
+ </option>
+ </param>
+ <param>
+ <name>2X Interpolation</name>
+ <key>interpolation</key>
+ <type>enum</type>
+ <option>
+ <name>Off</name>
+ <key>INTERPOLATION_OFF</key>
+ <opt>val:dtv.INTERPOLATION_OFF</opt>
+ </option>
+ <option>
+ <name>On</name>
+ <key>INTERPOLATION_ON</key>
+ <opt>val:dtv.INTERPOLATION_ON</opt>
+ </option>
</param>
<sink>
<name>in</name>
diff --git a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt
index 4232ff7065..620dd55879 100644
--- a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt
+++ b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2014,2015 Free Software Foundation, Inc.
+# Copyright 2014,2015,2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -74,6 +74,11 @@ install(FILES
dvbt_convolutional_deinterleaver.h
dvbt_reed_solomon_dec.h
dvbt_energy_descramble.h
+ catv_transport_framing_enc_bb.h
+ catv_reed_solomon_enc_bb.h
+ catv_randomizer_bb.h
+ catv_frame_sync_enc_bb.h
+ catv_trellis_enc_bb.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/dtv
COMPONENT "dtv_devel"
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
index 3fe101ac25..17f2e8f768 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_equalizer.h
@@ -45,6 +45,9 @@ namespace gr {
* \brief Make a new instance of gr::dtv::atsc_equalizer.
*/
static sptr make();
+
+ virtual std::vector<float> taps() const = 0;
+ virtual std::vector<float> data() const = 0;
};
} /* namespace dtv */
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
index 92eb263e5d..c2b7d0defa 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_rs_decoder.h
@@ -42,6 +42,21 @@ namespace gr {
typedef boost::shared_ptr<atsc_rs_decoder> sptr;
/*!
+ * Returns the number of errors corrected by the decoder.
+ */
+ virtual int num_errors_corrected() const = 0;
+
+ /*!
+ * Returns the number of bad packets rejected by the decoder.
+ */
+ virtual int num_bad_packets() const = 0;
+
+ /*!
+ * Returns the total number of packets seen by the decoder.
+ */
+ virtual int num_packets() const = 0;
+
+ /*!
* \brief Make a new instance of gr::dtv::atsc_rs_decoder.
*/
static sptr make();
diff --git a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
index a4c18c39da..8efece4c43 100644
--- a/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
+++ b/gr-dtv/include/gnuradio/dtv/atsc_viterbi_decoder.h
@@ -45,6 +45,12 @@ namespace gr {
* \brief Make a new instance of gr::dtv::atsc_viterbi_decoder.
*/
static sptr make();
+
+ /*!
+ * For each decoder, returns the current best state of the
+ * decoding metrics.
+ */
+ virtual std::vector<float> decoder_metrics() const = 0;
};
} /* namespace dtv */
diff --git a/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h
new file mode 100644
index 0000000000..799a2d3c55
--- /dev/null
+++ b/gr-dtv/include/gnuradio/dtv/catv_frame_sync_enc_bb.h
@@ -0,0 +1,54 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H
+#define INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H
+
+#include <gnuradio/dtv/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+ namespace dtv {
+
+ /*!
+ * \brief Frame Sync Encoder. Adds a 42-bit frame sync pattern with control word.
+ * \ingroup dtv
+ *
+ * Input: Scrambled FEC Frame packets of 60 * 128 7-bit symbols.\n
+ * Output: Scrambled FEC Frame packets of 60 * 128 7-bit symbols with 42-bit FSYNC word.
+ */
+ class DTV_API catv_frame_sync_enc_bb : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr<catv_frame_sync_enc_bb> sptr;
+
+ /*!
+ * \brief Create an ITU-T J.83B Frame Sync Encoder.
+ *
+ * \param ctrlword convolutional interleaver control word.
+ */
+ static sptr make(int ctrlword);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_H */
+
diff --git a/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h b/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h
new file mode 100644
index 0000000000..83230b8167
--- /dev/null
+++ b/gr-dtv/include/gnuradio/dtv/catv_randomizer_bb.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_RANDOMIZER_BB_H
+#define INCLUDED_DTV_CATV_RANDOMIZER_BB_H
+
+#include <gnuradio/dtv/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace dtv {
+
+ /*!
+ * \brief Randomizer, x^3 + x + alpha^3, 7-bit symbols.
+ * \ingroup dtv
+ *
+ * Input: Interleaved MPEG-2 + RS parity bitstream packets of 128 7-bit symbols.\n
+ * Output: Scrambled FEC Frame packets of 60 * 128 7-bit symbols.
+ */
+ class DTV_API catv_randomizer_bb : virtual public gr::sync_block
+ {
+ public:
+ typedef boost::shared_ptr<catv_randomizer_bb> sptr;
+
+ /*!
+ * \brief Create an ITU-T J.83B randomizer.
+ *
+ */
+ static sptr make();
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_RANDOMIZER_BB_H */
+
diff --git a/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h
new file mode 100644
index 0000000000..b661f0da7f
--- /dev/null
+++ b/gr-dtv/include/gnuradio/dtv/catv_reed_solomon_enc_bb.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H
+#define INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H
+
+#include <gnuradio/dtv/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+ namespace dtv {
+
+ /*!
+ * \brief Reed Solomon Encoder, t=3, (128,122), 7-bit symbols.
+ * \ingroup dtv
+ *
+ * Input: MPEG-2 bitstream packets of 122 7-bit symbols.\n
+ * Output: MPEG-2 + RS parity bitstream packets of 128 7-bit symbols.
+ */
+ class DTV_API catv_reed_solomon_enc_bb : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr<catv_reed_solomon_enc_bb> sptr;
+
+ /*!
+ * \brief Create an ITU-T J.83B Reed Solomon encoder.
+ *
+ */
+ static sptr make();
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_H */
+
diff --git a/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h
new file mode 100644
index 0000000000..7df100d990
--- /dev/null
+++ b/gr-dtv/include/gnuradio/dtv/catv_transport_framing_enc_bb.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H
+#define INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H
+
+#include <gnuradio/dtv/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+ namespace dtv {
+
+ /*!
+ * \brief Transport Framing Encoder. Adds a parity checksum to MPEG-2 packets.
+ * \ingroup dtv
+ *
+ * Input: MPEG-2 Transport Stream.\n
+ * Output: MPEG-2 Transport Stream with parity checksum byte.
+ */
+ class DTV_API catv_transport_framing_enc_bb : virtual public gr::sync_block
+ {
+ public:
+ typedef boost::shared_ptr<catv_transport_framing_enc_bb> sptr;
+
+ /*!
+ * \brief Create an ITU-T J.83B Transport Framing Encoder.
+ *
+ */
+ static sptr make();
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_H */
+
diff --git a/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h b/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h
new file mode 100644
index 0000000000..aa6cec1703
--- /dev/null
+++ b/gr-dtv/include/gnuradio/dtv/catv_trellis_enc_bb.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H
+#define INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H
+
+#include <gnuradio/dtv/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+ namespace dtv {
+
+ /*!
+ * \brief Trellis Encoder. 14/15 code rate.
+ * \ingroup dtv
+ *
+ * Input: Scrambled FEC Frame packets of 60 * 128 7-bit symbols with 42-bit FSYNC word.\n
+ * Output: Four 7-bit symbols (28 bits) Trellis encoded to 30 bits (14/15 code rate).
+ */
+ class DTV_API catv_trellis_enc_bb : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr<catv_trellis_enc_bb> sptr;
+
+ /*!
+ * \brief Create an ITU-T J.83B Trellis Encoder.
+ *
+ */
+ static sptr make();
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_TRELLIS_ENC_BB_H */
+
diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_config.h b/gr-dtv/include/gnuradio/dtv/dvbs2_config.h
index 919c7de155..079857a8cf 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbs2_config.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbs2_config.h
@@ -38,11 +38,17 @@ namespace gr {
PILOTS_ON,
};
+ enum dvbs2_interpolation_t {
+ INTERPOLATION_OFF = 0,
+ INTERPOLATION_ON,
+ };
+
} // namespace dtv
} // namespace gr
typedef gr::dtv::dvbs2_rolloff_factor_t dvbs2_rolloff_factor_t;
typedef gr::dtv::dvbs2_pilots_t dvbs2_pilots_t;
+typedef gr::dtv::dvbs2_interpolation_t dvbs2_interpolation_t;
#endif /* INCLUDED_DTV_DVBS2_CONFIG_H */
diff --git a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
index 68e5403e05..a1f2c9e6fe 100644
--- a/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
+++ b/gr-dtv/include/gnuradio/dtv/dvbs2_modulator_bc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2016 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include <gnuradio/dtv/api.h>
#include <gnuradio/dtv/dvb_config.h>
+#include <gnuradio/dtv/dvbs2_config.h>
#include <gnuradio/block.h>
namespace gr {
@@ -46,8 +47,9 @@ namespace gr {
* \param framesize FEC frame size (normal or short).
* \param rate FEC code rate.
* \param constellation DVB-S2 constellation.
+ * \param interpolation 2X zero stuffing interpolation (on/off).
*/
- static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation);
+ static sptr make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation);
};
} // namespace dtv
diff --git a/gr-dtv/lib/CMakeLists.txt b/gr-dtv/lib/CMakeLists.txt
index fc78cccf9e..fec48990a2 100644
--- a/gr-dtv/lib/CMakeLists.txt
+++ b/gr-dtv/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2014,2015 Free Software Foundation, Inc.
+# Copyright 2014,2015,2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -112,6 +112,11 @@ list(APPEND dtv_sources
dvbt/dvbt_convolutional_deinterleaver_impl.cc
dvbt/dvbt_reed_solomon_dec_impl.cc
dvbt/dvbt_energy_descramble_impl.cc
+ catv/catv_transport_framing_enc_bb_impl.cc
+ catv/catv_reed_solomon_enc_bb_impl.cc
+ catv/catv_randomizer_bb_impl.cc
+ catv/catv_frame_sync_enc_bb_impl.cc
+ catv/catv_trellis_enc_bb_impl.cc
)
if(ENABLE_GR_CTRLPORT)
diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
index c804be6dc7..de01cea6f2 100644
--- a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc
@@ -28,6 +28,7 @@
#include "atsc_types.h"
#include "atsc_pnXXX_impl.h"
#include <gnuradio/io_signature.h>
+#include <volk/volk.h>
namespace gr {
namespace dtv {
@@ -76,23 +77,42 @@ namespace gr {
init_field_sync_common(training_sequence1, 0);
init_field_sync_common(training_sequence2, 1);
- for (int i = 0; i < NTAPS; i++)
- d_taps[i] = 0.0;
+ d_taps.resize(NTAPS, 0.0f);
d_buff_not_filled = true;
+
+ const int alignment_multiple =
+ volk_get_alignment() / sizeof(float);
+ set_alignment(std::max(1, alignment_multiple));
}
atsc_equalizer_impl::~atsc_equalizer_impl()
{
}
+ std::vector<float>
+ atsc_equalizer_impl::taps() const
+ {
+ return d_taps;
+ }
+
+ std::vector<float>
+ atsc_equalizer_impl::data() const
+ {
+ std::vector<float> ret(&data_mem2[0], &data_mem2[ATSC_DATA_SEGMENT_LENGTH-1]);
+ return ret;
+ }
+
void
- atsc_equalizer_impl::filterN(const float *input_samples, float *output_samples, int nsamples)
+ atsc_equalizer_impl::filterN(const float *input_samples,
+ float *output_samples,
+ int nsamples)
{
for (int j = 0; j < nsamples; j++) {
output_samples[j] = 0;
- for(int i = 0; i < NTAPS; i++)
- output_samples[j] += d_taps[i] * input_samples[j + i];
+ volk_32f_x2_dot_prod_32f(&output_samples[j],
+ &input_samples[j],
+ &d_taps[0], NTAPS);
}
}
@@ -107,14 +127,16 @@ namespace gr {
for(int j = 0; j < nsamples; j++) {
output_samples[j] = 0;
- for( int i = 0; i < NTAPS; i++ )
- output_samples[j] += d_taps[i] * input_samples[j + i];
+ volk_32f_x2_dot_prod_32f(&output_samples[j],
+ &input_samples[j],
+ &d_taps[0], NTAPS);
- double e = output_samples[j] - training_pattern[j];
+ float e = output_samples[j] - training_pattern[j];
// update taps...
- for( int i = 0; i < NTAPS; i++ )
- d_taps[i] -= BETA * e * (double)(input_samples[j + i]);
+ float tmp_taps[NTAPS];
+ volk_32f_s32f_multiply_32f(tmp_taps, &input_samples[j], BETA*e, NTAPS);
+ volk_32f_x2_subtract_32f(&d_taps[0], &d_taps[0], tmp_taps, NTAPS);
}
}
@@ -131,8 +153,8 @@ namespace gr {
int i = 0;
if(d_buff_not_filled) {
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- data_mem[NPRETAPS + j] = in[i].data[j];
+ memcpy(&data_mem[NPRETAPS], in[i].data,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
d_flags = in[i].pli._flags;
d_segno = in[i].pli._segno;
d_buff_not_filled = false;
@@ -141,8 +163,8 @@ namespace gr {
for (; i < noutput_items; i++) {
- for(int j = 0; j < NTAPS - NPRETAPS; j++)
- data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS + j] = in[i].data[j];
+ memcpy(&data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS], in[i].data,
+ (NTAPS - NPRETAPS)*sizeof(float));
if(d_segno == -1) {
if(d_flags & 0x0010) {
@@ -157,19 +179,18 @@ namespace gr {
else {
filterN(data_mem, data_mem2, ATSC_DATA_SEGMENT_LENGTH);
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- out[output_produced].data[j] = data_mem2[j];
+ memcpy(out[output_produced].data, data_mem2,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
out[output_produced].pli._flags = d_flags;
out[output_produced].pli._segno = d_segno;
output_produced++;
}
- for( int j = 0; j < NPRETAPS; j++ )
- data_mem[j] = data_mem[ATSC_DATA_SEGMENT_LENGTH + j];
-
- for(int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++)
- data_mem[NPRETAPS + j] = in[i].data[j];
+ memcpy(data_mem, &data_mem[ATSC_DATA_SEGMENT_LENGTH],
+ NPRETAPS*sizeof(float));
+ memcpy(&data_mem[NPRETAPS], in[i].data,
+ ATSC_DATA_SEGMENT_LENGTH*sizeof(float));
d_flags = in[i].pli._flags;
d_segno = in[i].pli._segno;
@@ -179,5 +200,31 @@ namespace gr {
return output_produced;
}
+ void
+ atsc_equalizer_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >(
+ alias(), "taps",
+ &atsc_equalizer::taps,
+ pmt::make_f32vector(1,-10),
+ pmt::make_f32vector(1,10),
+ pmt::make_f32vector(1,0),
+ "", "Equalizer Taps", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float> >(
+ alias(), "data",
+ &atsc_equalizer::data,
+ pmt::make_f32vector(1,-10),
+ pmt::make_f32vector(1,10),
+ pmt::make_f32vector(1,0),
+ "", "Post-equalizer Data", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.h b/gr-dtv/lib/atsc/atsc_equalizer_impl.h
index 6ff89ca646..75862f6408 100644
--- a/gr-dtv/lib/atsc/atsc_equalizer_impl.h
+++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.h
@@ -46,7 +46,7 @@ namespace gr {
void adaptN(const float *input_samples, const float *training_pattern,
float *output_samples, int nsamples);
- float d_taps[NTAPS];
+ std::vector<float> d_taps;
float data_mem[ATSC_DATA_SEGMENT_LENGTH + NTAPS]; // Buffer for previous data packet
float data_mem2[ATSC_DATA_SEGMENT_LENGTH];
@@ -59,6 +59,11 @@ namespace gr {
atsc_equalizer_impl();
~atsc_equalizer_impl();
+ void setup_rpc();
+
+ std::vector<float> taps() const;
+ std::vector<float> data() const;
+
virtual int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
index 7a950e716e..b8ee91a52d 100644
--- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc
@@ -56,9 +56,9 @@ namespace gr {
{
d_rs = init_rs_char(rs_init_symsize, rs_init_gfpoly, rs_init_fcr, rs_init_prim, rs_init_nroots);
assert (d_rs != 0);
- nerrors_corrrected_count = 0;
- bad_packet_count = 0;
- total_packets = 0;
+ d_nerrors_corrrected_count = 0;
+ d_bad_packet_count = 0;
+ d_total_packets = 0;
}
int atsc_rs_decoder_impl::decode (atsc_mpeg_packet_no_sync &out, const atsc_mpeg_packet_rs_encoded &in)
@@ -89,6 +89,24 @@ namespace gr {
}
int
+ atsc_rs_decoder_impl::num_errors_corrected() const
+ {
+ return d_nerrors_corrrected_count;
+ }
+
+ int
+ atsc_rs_decoder_impl::num_bad_packets() const
+ {
+ return d_bad_packet_count;
+ }
+
+ int
+ atsc_rs_decoder_impl::num_packets() const
+ {
+ return d_total_packets;
+ }
+
+ int
atsc_rs_decoder_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
@@ -102,24 +120,20 @@ namespace gr {
int nerrors_corrrected = decode(out[i], in[i]);
out[i].pli.set_transport_error(nerrors_corrrected == -1);
- if (nerrors_corrrected == -1)
- bad_packet_count++;
- else
- nerrors_corrrected_count += nerrors_corrrected;
+ if (nerrors_corrrected == -1) {
+ d_bad_packet_count++;
+ d_nerrors_corrrected_count += 10; // lower bound estimate; most this RS can fix
+ }
+ else {
+ d_nerrors_corrrected_count += nerrors_corrrected;
+ }
- total_packets++;
+ d_total_packets++;
#if 0
- if (total_packets > 1000) {
- // FIXME: convert to logger
- std::cout << "Error rate: "
- << (float)nerrors_corrrected_count/total_packets
- << "\tPacket error rate: "
- << (float)bad_packet_count/total_packets
- << std::endl;
-
- nerrors_corrrected_count = 0;
- bad_packet_count = 0;
- total_packets = 0;
+ if (d_total_packets > 1000) {
+ GR_LOG_INFO(d_logger, boost::format("Error rate: %1%\tPacket error rate: %2%") \
+ % ((float)d_nerrors_corrrected_count/(ATSC_MPEG_DATA_LENGTH*d_total_packets))
+ % ((float)d_bad_packet_count/d_total_packets));
}
#endif
}
@@ -127,5 +141,42 @@ namespace gr {
return noutput_items;
}
+
+ void
+ atsc_rs_decoder_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_errors_corrected",
+ &atsc_rs_decoder::num_errors_corrected,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of errors corrected", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_bad_packets",
+ &atsc_rs_decoder::num_bad_packets,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of bad packets", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_rs_decoder, int >(
+ alias(), "num_packets",
+ &atsc_rs_decoder::num_packets,
+ pmt::from_long(0),
+ pmt::from_long(10000000),
+ pmt::from_long(0),
+ "", "Number of packets", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
index 57460128dc..adbc4879a9 100644
--- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
+++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h
@@ -36,15 +36,22 @@ namespace gr {
class atsc_rs_decoder_impl : public atsc_rs_decoder
{
private:
- int nerrors_corrrected_count;
- int bad_packet_count;
- int total_packets;
+ int d_nerrors_corrrected_count;
+ int d_bad_packet_count;
+ int d_total_packets;
+ int d_total_bits;
void *d_rs;
public:
atsc_rs_decoder_impl();
~atsc_rs_decoder_impl();
+ void setup_rpc();
+
+ int num_errors_corrected() const;
+ int num_bad_packets() const;
+ int num_packets() const;
+
/*!
* Decode RS encoded packet.
* \returns a count of corrected symbols, or -1 if the block was uncorrectible.
diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.cc b/gr-dtv/lib/atsc/atsc_single_viterbi.cc
index 385940e453..011cc0fe96 100644
--- a/gr-dtv/lib/atsc/atsc_single_viterbi.cc
+++ b/gr-dtv/lib/atsc/atsc_single_viterbi.cc
@@ -28,7 +28,7 @@ namespace gr {
/* was_sent is a table of what symbol we get given what bit pair
was sent and what state we where in [state][pair] */
- const int atsc_single_viterbi::was_sent[4][4] = {
+ const int atsc_single_viterbi::d_was_sent[4][4] = {
{0,2,4,6},
{0,2,4,6},
{1,3,5,7},
@@ -37,7 +37,7 @@ namespace gr {
/* transition_table is a table of what state we were in
given current state and bit pair sent [state][pair] */
- const int atsc_single_viterbi::transition_table[4][4] = {
+ const int atsc_single_viterbi::d_transition_table[4][4] = {
{0,2,0,2},
{2,0,2,0},
{1,3,1,3},
@@ -49,11 +49,12 @@ namespace gr {
{
for (unsigned int i = 0; i<2; i++)
for (unsigned int j = 0; j<4; j++) {
- path_metrics[i][j] = 0;
- traceback[i][j] = 0;
+ d_path_metrics[i][j] = 0;
+ d_traceback[i][j] = 0;
}
- post_coder_state = 0;
- phase = 0;
+ d_post_coder_state = 0;
+ d_phase = 0;
+ d_best_state_metric = 100000;
}
atsc_single_viterbi::atsc_single_viterbi()
@@ -61,17 +62,24 @@ namespace gr {
reset();
}
+ float
+ atsc_single_viterbi::best_state_metric() const
+ {
+ return d_best_state_metric;
+ }
+
char
atsc_single_viterbi::decode(float input)
{
unsigned int best_state = 0;
- float best_state_metric = 100000;
+ //float best_state_metric = 100000;
+ d_best_state_metric = 100000;
/* Precompute distances from input to each possible symbol */
- float distances[8] = { (float)fabs( input + 7 ), (float)fabs( input + 5 ),
- (float)fabs( input + 3 ), (float)fabs( input + 1 ),
- (float)fabs( input - 1 ), (float)fabs( input - 3 ),
- (float)fabs( input - 5 ), (float)fabs( input - 7 ) };
+ float distances[8] = { fabsf( input + 7 ), fabsf( input + 5 ),
+ fabsf( input + 3 ), fabsf( input + 1 ),
+ fabsf( input - 1 ), fabsf( input - 3 ),
+ fabsf( input - 5 ), fabsf( input - 7 ) };
/* We start by iterating over all possible states */
for (unsigned int state = 0; state < 4; state++) {
@@ -79,15 +87,20 @@ namespace gr {
states to the state we are testing, we only need to look at
the 4 paths that can be taken given the 2-bit input */
int min_metric_symb = 0;
- float min_metric = distances[was_sent[state][0]] + path_metrics[phase][transition_table[state][0]];
+ float min_metric = distances[d_was_sent[state][0]] +
+ d_path_metrics[d_phase][d_transition_table[state][0]];
+
for (unsigned int symbol_sent = 1; symbol_sent < 4; symbol_sent++)
- if( (distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]]) < min_metric) {
- min_metric = distances[was_sent[state][symbol_sent]] + path_metrics[phase][transition_table[state][symbol_sent]];
+ if( (distances[d_was_sent[state][symbol_sent]] +
+ d_path_metrics[d_phase][d_transition_table[state][symbol_sent]]) < min_metric) {
+ min_metric = distances[d_was_sent[state][symbol_sent]] +
+ d_path_metrics[d_phase][d_transition_table[state][symbol_sent]];
min_metric_symb = symbol_sent;
}
- path_metrics[phase^1][state] = min_metric;
- traceback[phase^1][state] = (((unsigned long long)min_metric_symb) << 62) | (traceback[phase][transition_table[state][min_metric_symb]] >> 2);
+ d_path_metrics[d_phase^1][state] = min_metric;
+ d_traceback[d_phase^1][state] = (((unsigned long long)min_metric_symb) << 62) |
+ (d_traceback[d_phase][d_transition_table[state][min_metric_symb]] >> 2);
/* If this is the most probable state so far remember it, this
only needs to be checked when we are about to output a path
@@ -98,26 +111,24 @@ namespace gr {
head state path will tend towards the optimal path with a
probability approaching 1 in just 8 or so transitions
*/
- if(min_metric <= best_state_metric) {
- best_state_metric = min_metric;
+ if(min_metric <= d_best_state_metric) {
+ d_best_state_metric = min_metric;
best_state = state;
}
}
- if(best_state_metric > 10000) {
+ if(d_best_state_metric > 10000) {
for(unsigned int state = 0; state < 4; state++)
- path_metrics[phase^1][state] -= best_state_metric;
+ d_path_metrics[d_phase^1][state] -= d_best_state_metric;
}
- phase ^= 1;
+ d_phase ^= 1;
- int y2 = (0x2 & traceback[phase][best_state]) >> 1;
- int x2 = y2 ^ post_coder_state;
- post_coder_state = y2;
+ int y2 = (0x2 & d_traceback[d_phase][best_state]) >> 1;
+ int x2 = y2 ^ d_post_coder_state;
+ d_post_coder_state = y2;
- return ( x2 << 1 ) | (0x1 & traceback[phase][best_state]);
+ return ( x2 << 1 ) | (0x1 & d_traceback[d_phase][best_state]);
}
} /* namespace dtv */
} /* namespace gr */
-
-
diff --git a/gr-dtv/lib/atsc/atsc_single_viterbi.h b/gr-dtv/lib/atsc/atsc_single_viterbi.h
index 3c756c7690..9522e2eb1b 100644
--- a/gr-dtv/lib/atsc/atsc_single_viterbi.h
+++ b/gr-dtv/lib/atsc/atsc_single_viterbi.h
@@ -44,14 +44,17 @@ namespace gr {
//! internal delay of decoder
static int delay () { return TB_LEN - 1; }
- protected:
- static const int transition_table[4][4];
- static const int was_sent[4][4];
+ float best_state_metric() const;
- float path_metrics [2][4];
- unsigned long long traceback [2][4];
- unsigned char phase;
- int post_coder_state;
+ protected:
+ static const int d_transition_table[4][4];
+ static const int d_was_sent[4][4];
+
+ float d_path_metrics [2][4];
+ unsigned long long d_traceback [2][4];
+ unsigned char d_phase;
+ int d_post_coder_state;
+ float d_best_state_metric;
};
} /* namespace dtv */
diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
index 430eb55a17..2284372dfb 100644
--- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
+++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc
@@ -77,6 +77,15 @@ namespace gr {
fifo[i]->reset();
}
+ std::vector<float>
+ atsc_viterbi_decoder_impl::decoder_metrics() const
+ {
+ std::vector<float> metrics(NCODERS);
+ for (int i = 0; i < NCODERS; i++)
+ metrics[i] = viterbi[i].best_state_metric();
+ return metrics;
+ }
+
int
atsc_viterbi_decoder_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
@@ -135,5 +144,21 @@ namespace gr {
return noutput_items;
}
+ void
+ atsc_viterbi_decoder_impl::setup_rpc()
+ {
+#ifdef GR_CTRLPORT
+ add_rpc_variable(
+ rpcbasic_sptr(new rpcbasic_register_get<atsc_viterbi_decoder, std::vector<float> >(
+ alias(), "decoder_metrics",
+ &atsc_viterbi_decoder::decoder_metrics,
+ pmt::make_f32vector(1,0),
+ pmt::make_f32vector(1,100000),
+ pmt::make_f32vector(1,0),
+ "", "Viterbi decoder metrics", RPC_PRIVLVL_MIN,
+ DISPTIME)));
+#endif /* GR_CTRLPORT */
+ }
+
} /* namespace dtv */
} /* namespace gr */
diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
index b4fbbd1033..ef4faab313 100644
--- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
+++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.h
@@ -63,8 +63,12 @@ namespace gr {
atsc_viterbi_decoder_impl();
~atsc_viterbi_decoder_impl();
+ void setup_rpc();
+
void reset();
+ std::vector<float> decoder_metrics() const;
+
virtual int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
diff --git a/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc
new file mode 100644
index 0000000000..87c706b445
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.cc
@@ -0,0 +1,96 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; 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 <gnuradio/io_signature.h>
+#include "catv_frame_sync_enc_bb_impl.h"
+
+namespace gr {
+ namespace dtv {
+
+ catv_frame_sync_enc_bb::sptr
+ catv_frame_sync_enc_bb::make(int ctrlword)
+ {
+ return gnuradio::get_initial_sptr
+ (new catv_frame_sync_enc_bb_impl(ctrlword));
+ }
+
+ /*
+ * The private constructor
+ */
+ catv_frame_sync_enc_bb_impl::catv_frame_sync_enc_bb_impl(int ctrlword)
+ : gr::block("catv_frame_sync_enc_bb",
+ gr::io_signature::make(1, 1, sizeof(unsigned char)),
+ gr::io_signature::make(1, 1, sizeof(unsigned char)))
+ {
+ set_output_multiple(60 * 128 + 6);
+ control_word = ctrlword;
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ catv_frame_sync_enc_bb_impl::~catv_frame_sync_enc_bb_impl()
+ {
+ }
+
+ void
+ catv_frame_sync_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ ninput_items_required[0] = noutput_items / (60 * 128 + 6) * (60 * 128);
+ }
+
+ int
+ catv_frame_sync_enc_bb_impl::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ int i = 0, j = 0;
+ while (i < noutput_items) {
+ memcpy(out + i, in + j, 60 * 128);
+ i += 60 * 128;
+ j += 60 * 128;
+
+ out[i++] = 0x75;
+ out[i++] = 0x2C;
+ out[i++] = 0x0D;
+ out[i++] = 0x6C;
+ out[i++] = control_word << 3;
+ out[i++] = 0x00;
+ }
+
+ // Tell runtime system how many input items we consumed on
+ // each input stream.
+ consume_each (j);
+
+ // Tell runtime system how many output items we produced.
+ return noutput_items;
+ }
+
+ } /* namespace dtv */
+} /* namespace gr */
+
diff --git a/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h
new file mode 100644
index 0000000000..fb924f7a14
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_frame_sync_enc_bb_impl.h
@@ -0,0 +1,50 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H
+#define INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H
+
+#include <gnuradio/dtv/catv_frame_sync_enc_bb.h>
+
+namespace gr {
+ namespace dtv {
+
+ class catv_frame_sync_enc_bb_impl : public catv_frame_sync_enc_bb
+ {
+ private:
+ int control_word;
+
+ public:
+ catv_frame_sync_enc_bb_impl(int ctrlword);
+ ~catv_frame_sync_enc_bb_impl();
+
+ void forecast (int noutput_items, gr_vector_int &ninput_items_required);
+
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_FRAME_SYNC_ENC_BB_IMPL_H */
+
diff --git a/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc b/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc
new file mode 100644
index 0000000000..698288dcd3
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_randomizer_bb_impl.cc
@@ -0,0 +1,104 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; 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 <gnuradio/io_signature.h>
+#include "catv_randomizer_bb_impl.h"
+
+namespace gr {
+ namespace dtv {
+
+ catv_randomizer_bb::sptr
+ catv_randomizer_bb::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new catv_randomizer_bb_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ catv_randomizer_bb_impl::catv_randomizer_bb_impl()
+ : gr::sync_block("catv_randomizer_bb",
+ gr::io_signature::make(1, 1, sizeof(unsigned char)),
+ gr::io_signature::make(1, 1, sizeof(unsigned char)))
+ {
+ init_rand();
+
+ offset = 0;
+ max_offset = 60 * 128;
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ catv_randomizer_bb_impl::~catv_randomizer_bb_impl()
+ {
+ }
+
+ void
+ catv_randomizer_bb_impl::init_rand()
+ {
+ unsigned char c2 = 0x7F, c1 = 0x7F, c0 = 0x7F;
+ unsigned char c2_new, c1_new, c0_new;
+ int n, i;
+
+ for (n = 0; n < 60 * 128; n++) {
+ rseq[n] = c2;
+ c2_new = c1;
+ c1_new = c0 ^ c2;
+ c0_new = c2;
+ for (i = 0; i < 3; i++) {
+ c0_new <<= 1;
+ if (c0_new & 0x80) {
+ c0_new = (c0_new & 0x7F) ^ 0x09;
+ }
+ }
+ c2 = c2_new;
+ c1 = c1_new;
+ c0 = c0_new;
+ }
+ }
+
+ int
+ catv_randomizer_bb_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for (int i = 0; i < noutput_items; i++) {
+ out[i] = in[i] ^ rseq[offset++];
+ if (offset == max_offset) {
+ offset = 0;
+ }
+ }
+
+ // Tell runtime system how many output items we produced.
+ return noutput_items;
+ }
+
+ } /* namespace dtv */
+} /* namespace gr */
+
diff --git a/gr-dtv/lib/catv/catv_randomizer_bb_impl.h b/gr-dtv/lib/catv/catv_randomizer_bb_impl.h
new file mode 100644
index 0000000000..e4e40f8f6e
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_randomizer_bb_impl.h
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H
+#define INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H
+
+#include <gnuradio/dtv/catv_randomizer_bb.h>
+
+namespace gr {
+ namespace dtv {
+
+ class catv_randomizer_bb_impl : public catv_randomizer_bb
+ {
+ private:
+ unsigned char rseq[60 * 128];
+ int offset, max_offset;
+ void init_rand();
+
+ public:
+ catv_randomizer_bb_impl();
+ ~catv_randomizer_bb_impl();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_RANDOMIZER_BB_IMPL_H */
+
diff --git a/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc
new file mode 100644
index 0000000000..06a1f12c3e
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.cc
@@ -0,0 +1,153 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; 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 <gnuradio/io_signature.h>
+#include "catv_reed_solomon_enc_bb_impl.h"
+
+namespace gr {
+ namespace dtv {
+
+ catv_reed_solomon_enc_bb::sptr
+ catv_reed_solomon_enc_bb::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new catv_reed_solomon_enc_bb_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ catv_reed_solomon_enc_bb_impl::catv_reed_solomon_enc_bb_impl()
+ : gr::block("catv_reed_solomon_enc_bb",
+ gr::io_signature::make(1, 1, sizeof(unsigned char)),
+ gr::io_signature::make(1, 1, sizeof(unsigned char)))
+ {
+ set_output_multiple(128);
+ init_rs();
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ catv_reed_solomon_enc_bb_impl::~catv_reed_solomon_enc_bb_impl()
+ {
+ }
+
+ void
+ catv_reed_solomon_enc_bb_impl::init_rs()
+ {
+ unsigned char x;
+ int i, j;
+
+ gf_exp[0] = 1;
+ gf_log[1] = 0;
+
+ x = 1;
+ for (i = 1; i < 127; i++) {
+ x <<= 1;
+ if (x & 0x80) {
+ x = (x & 0x7F) ^ 0x09;
+ }
+ gf_exp[i] = x;
+ gf_log[x] = i;
+ }
+ for (; i < 256; i++) {
+ gf_exp[i] = gf_exp[i - 127];
+ }
+
+ for (i = 0; i < 128; i++) {
+ for (j = 0; j < 128; j++) {
+ if ((i == 0) || (j == 0)) {
+ gf_mul_table[i][j] = 0;
+ } else {
+ gf_mul_table[i][j] = gf_exp[gf_log[i] + gf_log[j]];
+ }
+ }
+ }
+ }
+
+ unsigned char
+ catv_reed_solomon_enc_bb_impl::gf_poly_eval(unsigned char *p, int len, unsigned char x)
+ {
+ unsigned char y = p[0];
+ int i;
+
+ for (i = 1; i < len; i++) {
+ y = gf_mul_table[y][x] ^ p[i];
+ }
+ return y;
+ }
+
+ void
+ catv_reed_solomon_enc_bb_impl::reed_solomon_enc(const unsigned char *message, unsigned char *output)
+ {
+ // Generator polynomial from p.7 of ANSI/SCTE 07 2013
+ unsigned char g[] = {1, gf_exp[52], gf_exp[116], gf_exp[119], gf_exp[61], gf_exp[15]};
+ int i, j;
+
+ memcpy(output, message, 122);
+ memset(output + 122, 0, 6);
+
+ for (i = 0; i < 122; i++) {
+ for (j = 1; j < 6; j++) {
+ output[i + j] ^= gf_mul_table[output[i]][g[j]];
+ }
+ output[i] = message[i];
+ }
+
+ output[127] = gf_poly_eval(output, 128, gf_exp[6]);
+ }
+
+ void
+ catv_reed_solomon_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ ninput_items_required[0] = (noutput_items / 128) * 122;
+ }
+
+ int
+ catv_reed_solomon_enc_bb_impl::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+ int j = 0;
+
+ for (int i = 0; i < noutput_items; i += 128) {
+ reed_solomon_enc(in + j, out + i);
+ j += 122;
+ }
+
+ // Tell runtime system how many input items we consumed on
+ // each input stream.
+ consume_each (j);
+
+ // Tell runtime system how many output items we produced.
+ return noutput_items;
+ }
+
+ } /* namespace dtv */
+} /* namespace gr */
+
diff --git a/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h
new file mode 100644
index 0000000000..84e4cb500e
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_reed_solomon_enc_bb_impl.h
@@ -0,0 +1,56 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H
+#define INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H
+
+#include <gnuradio/dtv/catv_reed_solomon_enc_bb.h>
+
+namespace gr {
+ namespace dtv {
+
+ class catv_reed_solomon_enc_bb_impl : public catv_reed_solomon_enc_bb
+ {
+ private:
+ unsigned char gf_mul_table[128][128];
+ unsigned char gf_exp[256];
+ unsigned char gf_log[128];
+
+ void init_rs();
+ unsigned char gf_poly_eval(unsigned char *p, int len, unsigned char x);
+ void reed_solomon_enc(const unsigned char *message, unsigned char *output);
+
+ public:
+ catv_reed_solomon_enc_bb_impl();
+ ~catv_reed_solomon_enc_bb_impl();
+
+ void forecast (int noutput_items, gr_vector_int &ninput_items_required);
+
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_REED_SOLOMON_ENC_BB_IMPL_H */
+
diff --git a/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc
new file mode 100644
index 0000000000..4082e8265c
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.cc
@@ -0,0 +1,131 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; 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 <gnuradio/io_signature.h>
+#include "catv_transport_framing_enc_bb_impl.h"
+
+namespace gr {
+ namespace dtv {
+
+ catv_transport_framing_enc_bb::sptr
+ catv_transport_framing_enc_bb::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new catv_transport_framing_enc_bb_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ catv_transport_framing_enc_bb_impl::catv_transport_framing_enc_bb_impl()
+ : gr::sync_block("catv_transport_framing_enc_bb",
+ gr::io_signature::make(1, 1, sizeof(unsigned char)),
+ gr::io_signature::make(1, 1, sizeof(unsigned char)))
+ {
+ set_output_multiple(188);
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ catv_transport_framing_enc_bb_impl::~catv_transport_framing_enc_bb_impl()
+ {
+ }
+
+ unsigned char catv_transport_framing_enc_bb_impl::compute_sum(const unsigned char *bytes)
+ {
+ unsigned char i, bit, out, out1, out2, out3;
+
+ unsigned char tapsG = 0xB1; // 10110001
+ unsigned char tapsB = 0x45; // 1000101
+
+ unsigned char register1 = 0;
+ unsigned char register2 = 0;
+ unsigned char register3 = 0;
+
+ unsigned char result = 0x67;
+
+ unsigned char first7[] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ for (i = 0; i < 8; i++) {
+ bit = (bytes[0] >> (7-i)) & 1;
+ out = (register1 & 1) ^ bit;
+ if (i < 7) {
+ first7[i+1] = out;
+ }
+ register1 >>= 1;
+ if (out == 1) {
+ register1 ^= tapsG;
+ }
+ }
+
+ for (i = 1; i < 187; i++) {
+ register1 = crctable[((register1) ^ BitReverseTable[bytes[i]]) & 0xff];
+ }
+
+ for (i = 0; i < 8; i++) {
+ out1 = register1 & 1;
+ register1 >>= 1;
+ if (out1 == 1) {
+ register1 ^= tapsG;
+ }
+
+ out2 = (register2 & 1) ^ first7[i];
+ register2 >>= 1;
+ if (first7[i] == 1) {
+ register2 ^= tapsB;
+ }
+
+ out3 = (register3 & 1) ^ out1 ^ out2;
+ register3 >>= 1;
+ if ((out1 ^ out2) == 1) {
+ register3 ^= tapsG;
+ }
+
+ result ^= (out3 << (7-i));
+ }
+
+ return result;
+ }
+
+ int
+ catv_transport_framing_enc_bb_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for (int i = 0; i < noutput_items; i += 188) {
+ memcpy(out + i, in + i + 1, 187);
+ out[i + 187] = compute_sum(in + i + 1);
+ }
+
+ // Tell runtime system how many output items we produced.
+ return noutput_items;
+ }
+
+ } /* namespace dtv */
+} /* namespace gr */
+
diff --git a/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h
new file mode 100644
index 0000000000..fe69bc01f6
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_transport_framing_enc_bb_impl.h
@@ -0,0 +1,84 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H
+#define INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H
+
+#include <gnuradio/dtv/catv_transport_framing_enc_bb.h>
+
+namespace gr {
+ namespace dtv {
+ static const unsigned char crctable[] = {
+ 0x00,0x1b,0x36,0x2d,0x6c,0x77,0x5a,0x41,0xd8,0xc3,0xee,0xf5,0xb4,0xaf,0x82,0x99,
+ 0xd3,0xc8,0xe5,0xfe,0xbf,0xa4,0x89,0x92,0x0b,0x10,0x3d,0x26,0x67,0x7c,0x51,0x4a,
+ 0xc5,0xde,0xf3,0xe8,0xa9,0xb2,0x9f,0x84,0x1d,0x06,0x2b,0x30,0x71,0x6a,0x47,0x5c,
+ 0x16,0x0d,0x20,0x3b,0x7a,0x61,0x4c,0x57,0xce,0xd5,0xf8,0xe3,0xa2,0xb9,0x94,0x8f,
+ 0xe9,0xf2,0xdf,0xc4,0x85,0x9e,0xb3,0xa8,0x31,0x2a,0x07,0x1c,0x5d,0x46,0x6b,0x70,
+ 0x3a,0x21,0x0c,0x17,0x56,0x4d,0x60,0x7b,0xe2,0xf9,0xd4,0xcf,0x8e,0x95,0xb8,0xa3,
+ 0x2c,0x37,0x1a,0x01,0x40,0x5b,0x76,0x6d,0xf4,0xef,0xc2,0xd9,0x98,0x83,0xae,0xb5,
+ 0xff,0xe4,0xc9,0xd2,0x93,0x88,0xa5,0xbe,0x27,0x3c,0x11,0x0a,0x4b,0x50,0x7d,0x66,
+ 0xb1,0xaa,0x87,0x9c,0xdd,0xc6,0xeb,0xf0,0x69,0x72,0x5f,0x44,0x05,0x1e,0x33,0x28,
+ 0x62,0x79,0x54,0x4f,0x0e,0x15,0x38,0x23,0xba,0xa1,0x8c,0x97,0xd6,0xcd,0xe0,0xfb,
+ 0x74,0x6f,0x42,0x59,0x18,0x03,0x2e,0x35,0xac,0xb7,0x9a,0x81,0xc0,0xdb,0xf6,0xed,
+ 0xa7,0xbc,0x91,0x8a,0xcb,0xd0,0xfd,0xe6,0x7f,0x64,0x49,0x52,0x13,0x08,0x25,0x3e,
+ 0x58,0x43,0x6e,0x75,0x34,0x2f,0x02,0x19,0x80,0x9b,0xb6,0xad,0xec,0xf7,0xda,0xc1,
+ 0x8b,0x90,0xbd,0xa6,0xe7,0xfc,0xd1,0xca,0x53,0x48,0x65,0x7e,0x3f,0x24,0x09,0x12,
+ 0x9d,0x86,0xab,0xb0,0xf1,0xea,0xc7,0xdc,0x45,0x5e,0x73,0x68,0x29,0x32,0x1f,0x04,
+ 0x4e,0x55,0x78,0x63,0x22,0x39,0x14,0x0f,0x96,0x8d,0xa0,0xbb,0xfa,0xe1,0xcc,0xd7
+ };
+
+ static const unsigned char BitReverseTable[] = {
+ 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+ 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+ 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+ 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+ 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+ 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+ 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+ 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+ 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+ 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+ 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+ 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+ 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+ 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+ 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+ 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+ };
+
+ class catv_transport_framing_enc_bb_impl : public catv_transport_framing_enc_bb
+ {
+ private:
+ unsigned char compute_sum(const unsigned char *bytes);
+
+ public:
+ catv_transport_framing_enc_bb_impl();
+ ~catv_transport_framing_enc_bb_impl();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_TRANSPORT_FRAMING_ENC_BB_IMPL_H */
+
diff --git a/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc
new file mode 100644
index 0000000000..8fdb8722b6
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.cc
@@ -0,0 +1,193 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; 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 <gnuradio/io_signature.h>
+#include "catv_trellis_enc_bb_impl.h"
+
+namespace gr {
+ namespace dtv {
+
+ catv_trellis_enc_bb::sptr
+ catv_trellis_enc_bb::make()
+ {
+ return gnuradio::get_initial_sptr
+ (new catv_trellis_enc_bb_impl());
+ }
+
+ /*
+ * The private constructor
+ */
+ catv_trellis_enc_bb_impl::catv_trellis_enc_bb_impl()
+ : gr::block("catv_trellis_enc_bb",
+ gr::io_signature::make(1, 1, sizeof(unsigned char)),
+ gr::io_signature::make(1, 1, sizeof(unsigned char)))
+ {
+ set_output_multiple(5);
+
+ init_trellis();
+
+ Xq = 0;
+ Yq = 0;
+ XYp = 0;
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ catv_trellis_enc_bb_impl::~catv_trellis_enc_bb_impl()
+ {
+ }
+
+ void
+ catv_trellis_enc_bb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ ninput_items_required[0] = noutput_items / 5 * 4;
+ }
+
+ void
+ catv_trellis_enc_bb_impl::diff_precoder(unsigned char W, unsigned char Z, unsigned char *Xp, unsigned char *Yp)
+ {
+ unsigned char common, newX, newY;
+
+ common = (Z & (*Xp ^ *Yp));
+ newX = W ^ *Xp ^ common;
+ newY = Z ^ W ^ *Yp ^ common;
+
+ *Xp = newX;
+ *Yp = newY;
+ }
+
+ void
+ catv_trellis_enc_bb_impl::init_trellis()
+ {
+ unsigned char XYp, W, Z, X, Y, Xp, Yp, state, xy, Xq;
+ int i, n;
+
+ for (XYp = 0; XYp < 4; XYp++) {
+ for (W = 0; W < 16; W++) {
+ for (Z = 0; Z < 16; Z++) {
+ X = 0;
+ Y = 0;
+ Xp = (XYp & 0b10) >> 1;
+ Yp = (XYp & 0b01);
+ for (i = 0; i < 4; i++) {
+ diff_precoder((W >> i) & 1, (Z >> i) & 1, &Xp, &Yp);
+ X |= (Xp << i);
+ Y |= (Yp << i);
+ }
+ diff_precoder_table[XYp][W][Z][0] = (Xp << 1) + Yp;
+ diff_precoder_table[XYp][W][Z][1] = X;
+ diff_precoder_table[XYp][W][Z][2] = Y;
+ }
+ }
+ }
+
+ for (i = 0; i < 32; i++) {
+ G1table[i] = (i >> 4) ^ ((i & 0x04) >> 2) ^ (i & 1);
+ G2table[i] = (i >> 4) ^ ((i & 0x08) >> 3) ^ ((i & 0x04) >> 2) ^ ((i & 0x02) >> 1) ^ (i & 1);
+ }
+
+ memset(trellis_table_x, 0, 16*16*6);
+ memset(trellis_table_y, 0, 16*16*6);
+ for (state = 0; state < 16; state++) {
+ for (xy = 0; xy < 16; xy++) {
+ i = 0;
+ Xq = state;
+ for (n = 0; n < 4; n++) {
+ Xq = (Xq << 1) + ((xy >> n) & 1);
+
+ if (n == 3) {
+ trellis_table_x[state][xy][i+1] |= G1table[Xq] << 3;
+ trellis_table_y[state][xy][i+1] |= G1table[Xq];
+ i += 1;
+ }
+ trellis_table_x[state][xy][i+1] |= G2table[Xq] << 3;
+ trellis_table_y[state][xy][i+1] |= G2table[Xq];
+ i += 1;
+
+ Xq &= 0x0F;
+ }
+
+ trellis_table_x[state][xy][0] = Xq;
+ trellis_table_y[state][xy][0] = Xq;
+ }
+ }
+ }
+
+ void
+ catv_trellis_enc_bb_impl::trellis_code(const unsigned char *rs, unsigned char *qs)
+ {
+ unsigned char X, Y;
+ int A, B, n;
+
+ A = (rs[1] << 7) | rs[0];
+ B = (rs[3] << 7) | rs[2];
+
+ memset(qs, 0, 5);
+
+ for (n = 0; n < 5; n++) {
+ qs[n] |= ((A >> (2*n)) & 3) << 4;
+ qs[n] |= ((B >> (2*n)) & 3) << 1;
+ }
+
+ X = diff_precoder_table[XYp][A >> 10][B >> 10][1];
+ Y = diff_precoder_table[XYp][A >> 10][B >> 10][2];
+ XYp = diff_precoder_table[XYp][A >> 10][B >> 10][0];
+
+ for (n = 0; n < 5; n++) {
+ qs[n] |= trellis_table_x[Xq][X][1+n];
+ qs[n] |= trellis_table_y[Yq][Y][1+n];
+ }
+ Xq = trellis_table_x[Xq][X][0];
+ Yq = trellis_table_y[Yq][Y][0];
+ }
+
+ int
+ catv_trellis_enc_bb_impl::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ int i = 0, j = 0;
+
+ while (i < noutput_items) {
+ trellis_code(in + j, out + i);
+ i += 5;
+ j += 4;
+ }
+
+ // Tell runtime system how many input items we consumed on
+ // each input stream.
+ consume_each (j);
+
+ // Tell runtime system how many output items we produced.
+ return noutput_items;
+ }
+
+ } /* namespace dtv */
+} /* namespace gr */
+
diff --git a/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h
new file mode 100644
index 0000000000..aa7874d929
--- /dev/null
+++ b/gr-dtv/lib/catv/catv_trellis_enc_bb_impl.h
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 Free Software Foundation, Inc.
+ *
+ * This 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.
+ *
+ * This software 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 this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H
+#define INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H
+
+#include <gnuradio/dtv/catv_trellis_enc_bb.h>
+
+namespace gr {
+ namespace dtv {
+
+ class catv_trellis_enc_bb_impl : public catv_trellis_enc_bb
+ {
+ private:
+ unsigned char diff_precoder_table[4][16][16][3];
+ unsigned char G1table[32];
+ unsigned char G2table[32];
+ unsigned char trellis_table_x[16][16][6];
+ unsigned char trellis_table_y[16][16][6];
+ unsigned char Xq, Yq, XYp;
+
+ void diff_precoder(unsigned char W, unsigned char Z, unsigned char *Xp, unsigned char *Yp);
+ void init_trellis();
+ void trellis_code(const unsigned char *rs, unsigned char *qs);
+
+ public:
+ catv_trellis_enc_bb_impl();
+ ~catv_trellis_enc_bb_impl();
+
+ // Where all the action really happens
+ void forecast (int noutput_items, gr_vector_int &ninput_items_required);
+
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } // namespace dtv
+} // namespace gr
+
+#endif /* INCLUDED_DTV_CATV_TRELLIS_ENC_BB_IMPL_H */
+
diff --git a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc
index c8579d1c1e..d1f3b4aa27 100644
--- a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc
+++ b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2015 Free Software Foundation, Inc.
+ * Copyright 2015,2016 Free Software Foundation, Inc.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,16 +29,16 @@ namespace gr {
namespace dtv {
dvbs2_modulator_bc::sptr
- dvbs2_modulator_bc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation)
+ dvbs2_modulator_bc::make(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation)
{
return gnuradio::get_initial_sptr
- (new dvbs2_modulator_bc_impl(framesize, rate, constellation));
+ (new dvbs2_modulator_bc_impl(framesize, rate, constellation, interpolation));
}
/*
* The private constructor
*/
- dvbs2_modulator_bc_impl::dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation)
+ dvbs2_modulator_bc_impl::dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation)
: gr::block("dvbs2_modulator_bc",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(1, 1, sizeof(gr_complex)))
@@ -1660,6 +1660,72 @@ namespace gr {
m_256apsk[255] = gr_complex((r6 * cos(43 * M_PI / 32.0)), (r6 * sin(43 * M_PI / 32.0)));
}
break;
+ case MOD_64QAM:
+ m_64apsk[0] = gr_complex( 1.0, 1.0);
+ m_64apsk[1] = gr_complex( 1.0, -1.0);
+ m_64apsk[2] = gr_complex( 1.0, -3.0);
+ m_64apsk[3] = gr_complex( -3.0, -1.0);
+ m_64apsk[4] = gr_complex( -3.0, 1.0);
+ m_64apsk[5] = gr_complex( 1.0, 3.0);
+ m_64apsk[6] = gr_complex( -3.0, -3.0);
+ m_64apsk[7] = gr_complex( -3.0, 3.0);
+ m_64apsk[8] = gr_complex( -1.0, 1.0);
+ m_64apsk[9] = gr_complex( -1.0, -1.0);
+ m_64apsk[10] = gr_complex( 3.0, 1.0);
+ m_64apsk[11] = gr_complex(-1.0, 3.0);
+ m_64apsk[12] = gr_complex(-1.0, -3.0);
+ m_64apsk[13] = gr_complex( 3.0, -1.0);
+ m_64apsk[14] = gr_complex( 3.0, -3.0);
+ m_64apsk[15] = gr_complex( 3.0, 3.0);
+ m_64apsk[16] = gr_complex( 5.0, 1.0);
+ m_64apsk[17] = gr_complex( 1.0, -5.0);
+ m_64apsk[18] = gr_complex( 1.0, -7.0);
+ m_64apsk[19] = gr_complex(-7.0, -1.0);
+ m_64apsk[20] = gr_complex(-3.0, 5.0);
+ m_64apsk[21] = gr_complex( 5.0, 3.0);
+ m_64apsk[22] = gr_complex(-7.0, -3.0);
+ m_64apsk[23] = gr_complex(-3.0, 7.0);
+ m_64apsk[24] = gr_complex(-1.0, 5.0);
+ m_64apsk[25] = gr_complex(-5.0, -1.0);
+ m_64apsk[26] = gr_complex( 7.0, 1.0);
+ m_64apsk[27] = gr_complex(-1.0, 7.0);
+ m_64apsk[28] = gr_complex(-5.0, -3.0);
+ m_64apsk[29] = gr_complex( 3.0, -5.0);
+ m_64apsk[30] = gr_complex( 3.0, -7.0);
+ m_64apsk[31] = gr_complex( 7.0, 3.0);
+ m_64apsk[32] = gr_complex( 1.0, 5.0);
+ m_64apsk[33] = gr_complex( 5.0, -1.0);
+ m_64apsk[34] = gr_complex( 5.0, -3.0);
+ m_64apsk[35] = gr_complex(-3.0, -5.0);
+ m_64apsk[36] = gr_complex(-7.0, 1.0);
+ m_64apsk[37] = gr_complex( 1.0, 7.0);
+ m_64apsk[38] = gr_complex(-3.0, -7.0);
+ m_64apsk[39] = gr_complex(-7.0, 3.0);
+ m_64apsk[40] = gr_complex(-5.0, 1.0);
+ m_64apsk[41] = gr_complex(-1.0, -5.0);
+ m_64apsk[42] = gr_complex( 3.0, 5.0);
+ m_64apsk[43] = gr_complex(-5.0, 3.0);
+ m_64apsk[44] = gr_complex(-1.0, -7.0);
+ m_64apsk[45] = gr_complex( 7.0, -1.0);
+ m_64apsk[46] = gr_complex( 7.0, -3.0);
+ m_64apsk[47] = gr_complex( 3.0, 7.0);
+ m_64apsk[48] = gr_complex( 5.0, 5.0);
+ m_64apsk[49] = gr_complex( 5.0, -5.0);
+ m_64apsk[50] = gr_complex( 5.0, -7.0);
+ m_64apsk[51] = gr_complex(-7.0, -5.0);
+ m_64apsk[52] = gr_complex(-7.0, 5.0);
+ m_64apsk[53] = gr_complex( 5.0, 7.0);
+ m_64apsk[54] = gr_complex(-7.0, -7.0);
+ m_64apsk[55] = gr_complex(-7.0, 7.0);
+ m_64apsk[56] = gr_complex(-5.0, 5.0);
+ m_64apsk[57] = gr_complex(-5.0, -5.0);
+ m_64apsk[58] = gr_complex( 7.0, 5.0);
+ m_64apsk[59] = gr_complex(-5.0, 7.0);
+ m_64apsk[60] = gr_complex(-5.0, -7.0);
+ m_64apsk[61] = gr_complex( 7.0, -5.0);
+ m_64apsk[62] = gr_complex( 7.0, -7.0);
+ m_64apsk[63] = gr_complex( 7.0, 7.0);
+ break;
default:
m_qpsk[0] = gr_complex((r1 * cos(M_PI / 4.0)), (r1 * sin(M_PI / 4.0)));
m_qpsk[1] = gr_complex((r1 * cos(7 * M_PI / 4.0)), (r1 * sin(7 * M_PI / 4.0)));
@@ -1668,6 +1734,7 @@ namespace gr {
break;
}
signal_constellation = constellation;
+ signal_interpolation = interpolation;
set_output_multiple(2);
}
@@ -1681,7 +1748,12 @@ namespace gr {
void
dvbs2_modulator_bc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
- ninput_items_required[0] = noutput_items;
+ if (signal_interpolation == INTERPOLATION_OFF) {
+ ninput_items_required[0] = noutput_items;
+ }
+ else {
+ ninput_items_required[0] = noutput_items / 2;
+ }
}
int
@@ -1693,67 +1765,145 @@ namespace gr {
const unsigned char *in = (const unsigned char *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
int index;
+ gr_complex zero;
- switch (signal_constellation) {
- case MOD_QPSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_qpsk[index & 0x3];
- }
- break;
- case MOD_8PSK:
- case MOD_8APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_8psk[index & 0x7];
- }
- break;
- case MOD_16APSK:
- case MOD_8_8APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_16apsk[index & 0xf];
- }
- break;
- case MOD_32APSK:
- case MOD_4_12_16APSK:
- case MOD_4_8_4_16APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_32apsk[index & 0x1f];
- }
- break;
- case MOD_64APSK:
- case MOD_8_16_20_20APSK:
- case MOD_4_12_20_28APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_64apsk[index & 0x3f];
- }
- break;
- case MOD_128APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_128apsk[index & 0x7f];
- }
- break;
- case MOD_256APSK:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_256apsk[index & 0xff];
- }
- break;
- default:
- for (int i = 0; i < noutput_items; i++) {
- index = *in++;
- *out++ = m_qpsk[index & 0x3];
- }
- break;
+ zero = gr_complex(0.0, 0.0);
+
+ if (signal_interpolation == INTERPOLATION_OFF) {
+ switch (signal_constellation) {
+ case MOD_QPSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_qpsk[index & 0x3];
+ }
+ break;
+ case MOD_8PSK:
+ case MOD_8APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_8psk[index & 0x7];
+ }
+ break;
+ case MOD_16APSK:
+ case MOD_8_8APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_16apsk[index & 0xf];
+ }
+ break;
+ case MOD_32APSK:
+ case MOD_4_12_16APSK:
+ case MOD_4_8_4_16APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_32apsk[index & 0x1f];
+ }
+ break;
+ case MOD_64APSK:
+ case MOD_64QAM:
+ case MOD_8_16_20_20APSK:
+ case MOD_4_12_20_28APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_64apsk[index & 0x3f];
+ }
+ break;
+ case MOD_128APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_128apsk[index & 0x7f];
+ }
+ break;
+ case MOD_256APSK:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_256apsk[index & 0xff];
+ }
+ break;
+ default:
+ for (int i = 0; i < noutput_items; i++) {
+ index = *in++;
+ *out++ = m_qpsk[index & 0x3];
+ }
+ break;
+ }
+ }
+ else {
+ switch (signal_constellation) {
+ case MOD_QPSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_qpsk[index & 0x3];
+ *out++ = zero;
+ }
+ break;
+ case MOD_8PSK:
+ case MOD_8APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_8psk[index & 0x7];
+ *out++ = zero;
+ }
+ break;
+ case MOD_16APSK:
+ case MOD_8_8APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_16apsk[index & 0xf];
+ *out++ = zero;
+ }
+ break;
+ case MOD_32APSK:
+ case MOD_4_12_16APSK:
+ case MOD_4_8_4_16APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_32apsk[index & 0x1f];
+ *out++ = zero;
+ }
+ break;
+ case MOD_64APSK:
+ case MOD_64QAM:
+ case MOD_8_16_20_20APSK:
+ case MOD_4_12_20_28APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_64apsk[index & 0x3f];
+ *out++ = zero;
+ }
+ break;
+ case MOD_128APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_128apsk[index & 0x7f];
+ *out++ = zero;
+ }
+ break;
+ case MOD_256APSK:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_256apsk[index & 0xff];
+ *out++ = zero;
+ }
+ break;
+ default:
+ for (int i = 0; i < noutput_items / 2; i++) {
+ index = *in++;
+ *out++ = m_qpsk[index & 0x3];
+ *out++ = zero;
+ }
+ break;
+ }
}
// Tell runtime system how many input items we consumed on
// each input stream.
- consume_each (noutput_items);
+ if (signal_interpolation == INTERPOLATION_OFF) {
+ consume_each (noutput_items);
+ }
+ else {
+ consume_each (noutput_items / 2);
+ }
// Tell runtime system how many output items we produced.
return noutput_items;
diff --git a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h
index 8507878b0e..4fdbb149df 100644
--- a/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h
+++ b/gr-dtv/lib/dvbs2/dvbs2_modulator_bc_impl.h
@@ -31,6 +31,7 @@ namespace gr {
{
private:
int signal_constellation;
+ int signal_interpolation;
gr_complex m_qpsk[4];
gr_complex m_8psk[8];
gr_complex m_16apsk[16];
@@ -40,7 +41,7 @@ namespace gr {
gr_complex m_256apsk[256];
public:
- dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation);
+ dvbs2_modulator_bc_impl(dvb_framesize_t framesize, dvb_code_rate_t rate, dvb_constellation_t constellation, dvbs2_interpolation_t interpolation);
~dvbs2_modulator_bc_impl();
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
diff --git a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc
index 6617c2c11f..ee8dce0f15 100644
--- a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc
+++ b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.cc
@@ -34,12 +34,12 @@ namespace gr {
namespace dtv {
int
- dvbt_ofdm_sym_acquisition_impl::peak_detect_init(float threshold_factor_rise, float threshold_factor_fall, int look_ahead, float alpha)
+ dvbt_ofdm_sym_acquisition_impl::peak_detect_init(float threshold_factor_rise, float alpha)
{
d_avg_alpha = alpha;
d_threshold_factor_rise = threshold_factor_rise;
- d_threshold_factor_fall = threshold_factor_fall;
- d_avg = 0;
+ d_avg_max = - (float)INFINITY;
+ d_avg_min = (float)INFINITY;
return (0);
}
@@ -47,56 +47,50 @@ namespace gr {
int
dvbt_ofdm_sym_acquisition_impl::peak_detect_process(const float * datain, const int datain_length, int * peak_pos, int * peak_max)
{
- int state = 0;
- float peak_val = -(float)INFINITY; int peak_index = 0; int peak_pos_length = 0;
+ uint16_t peak_index = 0;
+ int peak_pos_length = 0;
- int i = 0;
+ volk_32f_index_max_16u(&peak_index, &datain[0], datain_length);
- while(i < datain_length) {
- if (state == 0) {
- if (datain[i] > d_avg * d_threshold_factor_rise) {
- state = 1;
- }
- else {
- d_avg = d_avg_alpha * datain[i] + (1 - d_avg_alpha) * d_avg;
- i++;
- }
+ peak_pos_length = 1;
+ if (datain_length >= d_fft_length) {
+ float min = datain[(peak_index + d_fft_length / 2) % d_fft_length];
+ if (d_avg_min == (float)INFINITY) {
+ d_avg_min = min;
}
- else if (state == 1) {
- if (datain[i] > peak_val) {
- peak_val = datain[i];
- peak_index = i;
- d_avg = d_avg_alpha * datain[i] + (1 - d_avg_alpha) * d_avg;
- i++;
- }
- else if (datain[i] > d_avg * d_threshold_factor_fall) {
- d_avg = (d_avg_alpha) * datain[i] + (1 - d_avg_alpha) * d_avg;
- i++;
- }
- else {
- peak_pos[peak_pos_length] = peak_index;
- peak_pos_length++;
- state = 0;
- peak_val = - (float)INFINITY;
- }
+ else {
+ d_avg_min = d_avg_alpha * min + (1 - d_avg_alpha) * d_avg_min;
}
}
- // Find peak of peaks
- if (peak_pos_length) {
- float max = datain[peak_pos[0]];
- int maxi = 0;
+ if (d_avg_max == -(float)INFINITY) {
+ // Initialize d_avg_max with the first value.
+ d_avg_max = datain[peak_index];
+ }
+ else if (datain[peak_index] > d_avg_max - d_threshold_factor_rise * (d_avg_max-d_avg_min)) {
+ d_avg_max = d_avg_alpha * datain[peak_index] + (1 - d_avg_alpha) * d_avg_max;
+ }
+ else {
+ peak_pos_length = 0;
+ }
- for (int i = 1; i < peak_pos_length; i++) {
- if (datain[peak_pos[i]] > max) {
- max = datain[peak_pos[i]];
- maxi = i;
- }
+ // We now check whether the peak is in the border of the search interval. This would mean that
+ // the search interval is not correct, and it should be re-set. This happens for instance when the
+ // hardware dropped some samples.
+ // Our definition of "border of the search interval" depends if the search interval is "big" or not.
+ if (datain_length < d_fft_length) {
+ if ((peak_index == 0) || (peak_index == (unsigned int)datain_length - 1)) {
+ peak_pos_length = 0;
+ }
+ }
+ else {
+ if ((peak_index < 5) || (peak_index > (unsigned int)datain_length - 5)) {
+ peak_pos_length = 0;
}
-
- *peak_max = maxi;
}
+ peak_pos[0] = peak_index;
+ *peak_max = 0;
return (peak_pos_length);
}
@@ -119,7 +113,8 @@ namespace gr {
volk_32fc_magnitude_squared_32f(&d_norm[low], &in[low], size);
// Calculate gamma on each point
- low = lookup_stop - d_cp_length + 1;
+ // TODO check these boundaries!!!!!!!
+ low = lookup_stop - (d_cp_length - 1);
size = lookup_start - low + 1;
volk_32fc_x2_multiply_conjugate_32fc(&d_corr[low - d_fft_length], &in[low], &in[low - d_fft_length], size);
@@ -220,6 +215,12 @@ namespace gr {
this->add_item_tag(0, offset, key, value);
}
+ // Derotates the signal
+ void dvbt_ofdm_sym_acquisition_impl::derotate(const gr_complex * in, gr_complex * out)
+ {
+ volk_32fc_x2_multiply_32fc(&out[0], &d_derot[0], &in[0], d_fft_length);
+ }
+
dvbt_ofdm_sym_acquisition::sptr
dvbt_ofdm_sym_acquisition::make(int blocks, int fft_length, int occupied_tones, int cp_length, float snr)
{
@@ -234,11 +235,10 @@ namespace gr {
: block("dvbt_ofdm_sym_acquisition",
io_signature::make(1, 1, sizeof (gr_complex) * blocks),
io_signature::make(1, 1, sizeof (gr_complex) * blocks * fft_length)),
- d_blocks(blocks), d_fft_length(fft_length), d_cp_length(cp_length), d_snr(snr),
- d_index(0), d_phase(0.0), d_phaseinc(0.0), d_cp_found(0), d_count(0), d_nextphaseinc(0), d_nextpos(0), \
- d_sym_acq_count(0),d_sym_acq_timeout(100), d_initial_acquisition(0), \
- d_freq_correction_count(0), d_freq_correction_timeout(0), d_cp_start(0), \
- d_to_consume(0), d_to_out(0)
+ d_blocks(blocks), d_fft_length(fft_length), d_cp_length(cp_length), d_snr(snr), \
+ d_phase(0.0), d_phaseinc(0.0), d_cp_found(0), d_nextphaseinc(0), d_nextpos(0), \
+ d_initial_acquisition(0), d_cp_start(0), \
+ d_to_consume(0), d_to_out(0), d_consumed(0), d_out(0)
{
set_relative_rate(1.0 / (double) (d_cp_length + d_fft_length));
@@ -296,7 +296,7 @@ namespace gr {
exit(1);
}
- peak_detect_init(0.8, 0.9, 30, 0.9);
+ peak_detect_init(0.3, 0.9);
}
/*
@@ -319,7 +319,7 @@ namespace gr {
// make sure we receive at least (symbol_length + fft_length)
for (int i = 0; i < ninputs; i++) {
- ninput_items_required[i] = (2 * d_fft_length + d_cp_length) * noutput_items;
+ ninput_items_required[i] = (d_cp_length + d_fft_length) * (noutput_items + 1);
}
}
@@ -336,45 +336,52 @@ namespace gr {
{
const gr_complex *in = (const gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
-
- int low, size;
-
- // This is initial acquisition of symbol start
- // TODO - make a FSM
- if (!d_initial_acquisition) {
- d_initial_acquisition = ml_sync(in, 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \
- &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out);
-
- // Send sync_start downstream
- send_sync_start();
- }
-
- // This is fractional frequency correction (pre FFT)
- // It is also called coarse frequency correction
- if (d_initial_acquisition) {
- d_cp_found = ml_sync(in, d_cp_start + 16, d_cp_start, \
- &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out);
+ int low;
+
+ d_consumed = 0;
+ d_out = 0;
+
+ for (int i = 0; i < noutput_items; i++) {
+ // This is initial acquisition of symbol start
+ // TODO - make a FSM
+ if (!d_initial_acquisition) {
+ d_initial_acquisition = ml_sync(&in[d_consumed], 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \
+ &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out);
+ d_cp_found = d_initial_acquisition;
+ }
+ else {
+ // If we are here it means that in the previous iteration we found the CP. We
+ // now thus only search near it.
+ d_cp_found = ml_sync(&in[d_consumed], d_cp_start + 8, std::max(d_cp_start - 8, d_cp_length+d_fft_length - 1), \
+ &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out);
+ if (!d_cp_found) {
+ // We may have not found the CP because the smaller search range was too small (rare, but possible).
+ // We re-try with the whole search range.
+ d_cp_found = ml_sync(&in[d_consumed], 2 * d_fft_length + d_cp_length - 1, d_fft_length + d_cp_length - 1, \
+ &d_cp_start, &d_derot[0], &d_to_consume, &d_to_out );
+ }
+ }
if (d_cp_found) {
- d_freq_correction_count = 0;
-
- // Derotate the signal and out
- low = d_cp_start - d_fft_length + 1;
- size = d_cp_start - (d_cp_start - d_fft_length + 1) + 1;
-
- volk_32fc_x2_multiply_32fc(&out[0], &d_derot[0], &in[low], size);
+ low = d_consumed + d_cp_start - d_fft_length + 1;
+ derotate(&in[low], &out[i * d_fft_length]);
}
else {
- // If we have a number of consecutive misses then we restart acquisition
- if (++d_freq_correction_count > d_freq_correction_timeout) {
- d_initial_acquisition = 0;
- d_freq_correction_count = 0;
-
- // Restart with a half number so that we'll not endup with the same situation
- // This will prevent peak_detect to not detect anything
- d_to_consume = d_to_consume / 2;
- }
+ // Send sync_start downstream
+ send_sync_start();
+ d_initial_acquisition = 0;
+
+ // Restart wit a half number so that we'll not end up with the same situation
+ // This will prevent peak_detect to not detect anything
+ d_to_consume = d_to_consume / 2;
+ d_consumed += d_to_consume;
+ consume_each(d_consumed);
+
+ // Tell runtime system how many output items we produced.
+ return (d_out);
}
+ d_consumed += d_to_consume;
+ d_out += d_to_out;
}
// Tell runtime system how many input items we consumed on
@@ -386,3 +393,4 @@ namespace gr {
}
} /* namespace dtv */
} /* namespace gr */
+
diff --git a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h
index e7b92cbd41..0964361b1e 100644
--- a/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h
+++ b/gr-dtv/lib/dvbt/dvbt_ofdm_sym_acquisition_impl.h
@@ -35,8 +35,6 @@ namespace gr {
float d_snr;
float d_rho;
- int d_index;
-
gr_complex * d_conj;
float * d_norm;
gr_complex * d_corr;
@@ -45,37 +43,35 @@ namespace gr {
// For peak detector
float d_threshold_factor_rise;
- float d_threshold_factor_fall;
float d_avg_alpha;
- float d_avg;
+ float d_avg_min;
+ float d_avg_max;
float d_phase;
double d_phaseinc;
int d_cp_found;
- int d_count;
double d_nextphaseinc;
int d_nextpos;
- int d_sym_acq_count;
- int d_sym_acq_timeout;
-
int d_initial_acquisition;
- int d_freq_correction_count;
- int d_freq_correction_timeout;
-
int d_cp_start;
gr_complex * d_derot;
int d_to_consume;
int d_to_out;
+ int d_consumed;
+ int d_out;
int ml_sync(const gr_complex * in, int lookup_start, int lookup_stop, int * cp_pos, gr_complex * derot, int * to_consume, int * to_out);
- int peak_detect_init(float threshold_factor_rise, float threshold_factor_fall, int look_ahead, float alpha);
+ int peak_detect_init(float threshold_factor_rise, float alpha);
int peak_detect_process(const float * datain, const int datain_length, int * peak_pos, int * peak_max);
void send_sync_start();
+
+ void derotate(const gr_complex * in, gr_complex *out);
+
public:
dvbt_ofdm_sym_acquisition_impl(int blocks, int fft_length, int occupied_tones, int cp_length, float snr);
~dvbt_ofdm_sym_acquisition_impl();
@@ -92,3 +88,4 @@ namespace gr {
} // namespace gr
#endif /* INCLUDED_DTV_DVBT_OFDM_SYM_ACQUISITION_IMPL_H */
+
diff --git a/gr-dtv/swig/dtv_swig.i b/gr-dtv/swig/dtv_swig.i
index c2fa312e05..24960bd2be 100644
--- a/gr-dtv/swig/dtv_swig.i
+++ b/gr-dtv/swig/dtv_swig.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2014,2015 Free Software Foundation, Inc.
+ * Copyright 2014,2015,2016 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -79,6 +79,11 @@
#include "gnuradio/dtv/dvbt_convolutional_deinterleaver.h"
#include "gnuradio/dtv/dvbt_reed_solomon_dec.h"
#include "gnuradio/dtv/dvbt_energy_descramble.h"
+#include "gnuradio/dtv/catv_transport_framing_enc_bb.h"
+#include "gnuradio/dtv/catv_reed_solomon_enc_bb.h"
+#include "gnuradio/dtv/catv_randomizer_bb.h"
+#include "gnuradio/dtv/catv_frame_sync_enc_bb.h"
+#include "gnuradio/dtv/catv_trellis_enc_bb.h"
%}
%include "gnuradio/dtv/atsc_deinterleaver.h"
@@ -132,6 +137,11 @@
%include "gnuradio/dtv/dvbt_convolutional_deinterleaver.h"
%include "gnuradio/dtv/dvbt_reed_solomon_dec.h"
%include "gnuradio/dtv/dvbt_energy_descramble.h"
+%include "gnuradio/dtv/catv_transport_framing_enc_bb.h"
+%include "gnuradio/dtv/catv_reed_solomon_enc_bb.h"
+%include "gnuradio/dtv/catv_randomizer_bb.h"
+%include "gnuradio/dtv/catv_frame_sync_enc_bb.h"
+%include "gnuradio/dtv/catv_trellis_enc_bb.h"
GR_SWIG_BLOCK_MAGIC2(dtv, atsc_deinterleaver);
GR_SWIG_BLOCK_MAGIC2(dtv, atsc_depad);
@@ -180,3 +190,8 @@ GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_viterbi_decoder);
GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_convolutional_deinterleaver);
GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_reed_solomon_dec);
GR_SWIG_BLOCK_MAGIC2(dtv, dvbt_energy_descramble);
+GR_SWIG_BLOCK_MAGIC2(dtv, catv_transport_framing_enc_bb);
+GR_SWIG_BLOCK_MAGIC2(dtv, catv_reed_solomon_enc_bb);
+GR_SWIG_BLOCK_MAGIC2(dtv, catv_randomizer_bb);
+GR_SWIG_BLOCK_MAGIC2(dtv, catv_frame_sync_enc_bb);
+GR_SWIG_BLOCK_MAGIC2(dtv, catv_trellis_enc_bb);
diff --git a/gr-fcd/grc/fcd_source_c.xml b/gr-fcd/grc/fcd_source_c.xml
index 01ea26d81c..b8975e4070 100644
--- a/gr-fcd/grc/fcd_source_c.xml
+++ b/gr-fcd/grc/fcd_source_c.xml
@@ -2,7 +2,7 @@
<block>
<name>Funcube Dongle Source</name>
<key>fcd_source_c</key>
- <category>FCD</category>
+ <category>[Core]/FCD</category>
<flags>throttle</flags>
<import>from gnuradio import fcd</import>
<make>fcd.source_c($device_name)
diff --git a/gr-fec/grc/fec_block_tree.xml b/gr-fec/grc/fec_block_tree.xml
index 5efc144cbd..b1535e3c42 100644
--- a/gr-fec/grc/fec_block_tree.xml
+++ b/gr-fec/grc/fec_block_tree.xml
@@ -5,7 +5,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Error Coding</name>
<cat>
diff --git a/gr-fft/grc/fft_block_tree.xml b/gr-fft/grc/fft_block_tree.xml
index 7028ed1049..e844d837b4 100644
--- a/gr-fft/grc/fft_block_tree.xml
+++ b/gr-fft/grc/fft_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name> <!-- Blank for Root Name -->
<cat>
<name>Fourier Analysis</name>
<block>fft_vxx</block>
diff --git a/gr-filter/examples/synth_to_chan.py b/gr-filter/examples/synth_to_chan.py
index 9e682021b7..88fb080a65 100755
--- a/gr-filter/examples/synth_to_chan.py
+++ b/gr-filter/examples/synth_to_chan.py
@@ -54,7 +54,7 @@ def main():
fmtx = list()
for fi in freqs:
s = analog.sig_source_f(fs, analog.GR_SIN_WAVE, fi, 1)
- fm = analog.nbfm_tx(fs, 4*fs, max_dev=10000, tau=75e-6)
+ fm = analog.nbfm_tx(fs, 4*fs, max_dev=10000, tau=75e-6, fh=0.925*(4*fs)/2.0)
sigs.append(s)
fmtx.append(fm)
diff --git a/gr-filter/grc/filter_block_tree.xml b/gr-filter/grc/filter_block_tree.xml
index ea869a75bd..3613df8202 100644
--- a/gr-filter/grc/filter_block_tree.xml
+++ b/gr-filter/grc/filter_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Filters</name>
<!-- FIR filter tap generators -->
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc b/gr-filter/lib/pfb_decimator_ccf_impl.cc
index e282b484fd..9d1d6f6139 100644
--- a/gr-filter/lib/pfb_decimator_ccf_impl.cc
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc
@@ -73,6 +73,26 @@ namespace gr {
else {
set_history(d_taps_per_filter);
}
+
+ d_tmp = NULL;
+ }
+
+ bool pfb_decimator_ccf_impl::start()
+ {
+ if(d_use_fft_filters) {
+ d_tmp = fft::malloc_complex(max_noutput_items()*d_rate);
+ }
+
+ return block::start();
+ }
+
+ bool pfb_decimator_ccf_impl::stop()
+ {
+ if((d_use_fft_filters) && (d_tmp)) {
+ fft::free(d_tmp);
+ }
+
+ return block::stop();
}
pfb_decimator_ccf_impl::~pfb_decimator_ccf_impl()
@@ -198,14 +218,13 @@ namespace gr {
gr_complex *out = (gr_complex *)output_items[0];
int i;
- gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate);
// Filter each input stream by the FFT filters; do all
// noutput_items at once to avoid repeated calls to the FFT
// setup and operation.
for(unsigned int j = 0; j < d_rate; j++) {
in = (gr_complex*)input_items[d_rate-j-1];
- d_fft_filters[j]->filter(noutput_items, in, &(tmp[j*noutput_items]));
+ d_fft_filters[j]->filter(noutput_items, in, &(d_tmp[j*noutput_items]));
}
// Rotate and add filter outputs (k=channel number; M=number of
@@ -214,11 +233,10 @@ namespace gr {
for(i = 0; i < noutput_items; i++) {
out[i] = 0;
for(unsigned int j = 0; j < d_rate; j++) {
- out[i] += tmp[j*noutput_items+i]*d_rotator[j];
+ out[i] += d_tmp[j*noutput_items+i]*d_rotator[j];
}
}
- fft::free(tmp);
return noutput_items;
}
@@ -231,18 +249,17 @@ namespace gr {
gr_complex *out = (gr_complex *)output_items[0];
int i;
- gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate);
for(unsigned int j = 0; j < d_rate; j++) {
in = (gr_complex*)input_items[d_rate-j-1];
- d_fft_filters[j]->filter(noutput_items, in, &tmp[j*noutput_items]);
+ d_fft_filters[j]->filter(noutput_items, in, &d_tmp[j*noutput_items]);
}
// Performs the rotate and add operations by implementing it as
// an FFT.
for(i = 0; i < noutput_items; i++) {
for(unsigned int j = 0; j < d_rate; j++) {
- d_fft->get_inbuf()[j] = tmp[j*noutput_items + i];
+ d_fft->get_inbuf()[j] = d_tmp[j*noutput_items + i];
}
// Perform the FFT to do the complex multiply despinning for all channels
@@ -252,7 +269,6 @@ namespace gr {
out[i] = d_fft->get_outbuf()[d_chan];
}
- fft::free(tmp);
return noutput_items;
}
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.h b/gr-filter/lib/pfb_decimator_ccf_impl.h
index 3397701cf9..5e0b70177d 100644
--- a/gr-filter/lib/pfb_decimator_ccf_impl.h
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.h
@@ -40,6 +40,7 @@ namespace gr {
bool d_use_fft_rotator;
bool d_use_fft_filters;
gr_complex *d_rotator;
+ gr_complex *d_tmp; // used for fft filters
gr::thread::mutex d_mutex; // mutex to protect set/work access
inline int work_fir_exp(int noutput_items,
@@ -55,7 +56,6 @@ namespace gr {
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
-
public:
pfb_decimator_ccf_impl(unsigned int decim,
const std::vector<float> &taps,
@@ -70,6 +70,10 @@ namespace gr {
std::vector<std::vector<float> > taps() const;
void set_channel(const unsigned int channel);
+ // Overload to create/destroy d_tmp based on max_noutput_items.
+ bool start();
+ bool stop();
+
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
diff --git a/gr-noaa/grc/noaa_hrpt_decoder.xml b/gr-noaa/grc/noaa_hrpt_decoder.xml
index 2d6e98c531..c5874159f2 100644
--- a/gr-noaa/grc/noaa_hrpt_decoder.xml
+++ b/gr-noaa/grc/noaa_hrpt_decoder.xml
@@ -2,7 +2,7 @@
<block>
<name>HRPT Decoder</name>
<key>noaa_hrpt_decoder</key>
- <category>NOAA</category>
+ <category>[Core]/NOAA</category>
<import>from gnuradio import noaa</import>
<make>noaa.hrpt_decoder($verbose,$output)</make>
diff --git a/gr-noaa/grc/noaa_hrpt_deframer.xml b/gr-noaa/grc/noaa_hrpt_deframer.xml
index af36abf2a2..fbb52f4e44 100644
--- a/gr-noaa/grc/noaa_hrpt_deframer.xml
+++ b/gr-noaa/grc/noaa_hrpt_deframer.xml
@@ -2,7 +2,7 @@
<block>
<name>HRPT Deframer</name>
<key>noaa_hrpt_deframer</key>
- <category>NOAA</category>
+ <category>[Core]/NOAA</category>
<import>from gnuradio import noaa</import>
<make>noaa.hrpt_deframer()</make>
<sink>
diff --git a/gr-noaa/grc/noaa_hrpt_pll_cf.xml b/gr-noaa/grc/noaa_hrpt_pll_cf.xml
index bbe15e8c32..a57d12ed71 100644
--- a/gr-noaa/grc/noaa_hrpt_pll_cf.xml
+++ b/gr-noaa/grc/noaa_hrpt_pll_cf.xml
@@ -2,7 +2,7 @@
<block>
<name>HRPT PLL</name>
<key>noaa_hrpt_pll_cf</key>
- <category>NOAA</category>
+ <category>[Core]/NOAA</category>
<import>from gnuradio import noaa</import>
<make>noaa.hrpt_pll_cf($alpha, $beta, $max_offset)</make>
<callback>set_alpha($alpha)</callback>
diff --git a/gr-pager/grc/pager_flex_deinterleave.xml b/gr-pager/grc/pager_flex_deinterleave.xml
index 14e5782da1..a006023212 100644
--- a/gr-pager/grc/pager_flex_deinterleave.xml
+++ b/gr-pager/grc/pager_flex_deinterleave.xml
@@ -7,7 +7,7 @@
<block>
<name>FLEX Deinterleave</name>
<key>pager_flex_deinterleave</key>
- <category>Pager</category>
+ <category>[Core]/Pager</category>
<import>from gnuradio import pager</import>
<make>pager.flex_deinterleave()</make>
diff --git a/gr-pager/grc/pager_flex_sync.xml b/gr-pager/grc/pager_flex_sync.xml
index ec22321aa5..d37a4fb7a9 100644
--- a/gr-pager/grc/pager_flex_sync.xml
+++ b/gr-pager/grc/pager_flex_sync.xml
@@ -7,7 +7,7 @@
<block>
<name>FLEX Synchronizer</name>
<key>pager_flex_sync</key>
- <category>Pager</category>
+ <category>[Core]/Pager</category>
<import>from gnuradio import pager</import>
<make>pager.flex_sync()</make>
diff --git a/gr-pager/grc/pager_slicer_fb.xml b/gr-pager/grc/pager_slicer_fb.xml
index 25642cb48f..f3e95e0748 100644
--- a/gr-pager/grc/pager_slicer_fb.xml
+++ b/gr-pager/grc/pager_slicer_fb.xml
@@ -7,7 +7,7 @@
<block>
<name>4-Level Slicer/DCR</name>
<key>pager_slicer_fb</key>
- <category>Pager</category>
+ <category>[Core]/Pager</category>
<import>from gnuradio import pager</import>
<make>pager.slicer_fb($alpha)</make>
diff --git a/gr-qtgui/CMakeLists.txt b/gr-qtgui/CMakeLists.txt
index 8fc49a0f5e..ad10363c1e 100644
--- a/gr-qtgui/CMakeLists.txt
+++ b/gr-qtgui/CMakeLists.txt
@@ -109,6 +109,7 @@ CPACK_COMPONENT("qtgui_swig"
add_subdirectory(include/gnuradio/qtgui)
add_subdirectory(lib)
add_subdirectory(doc)
+add_subdirectory(examples/c++)
if(ENABLE_PYTHON)
add_subdirectory(grc)
add_subdirectory(swig)
diff --git a/gr-qtgui/doc/qtgui.dox b/gr-qtgui/doc/qtgui.dox
index d95ab19f72..d0d7345f73 100644
--- a/gr-qtgui/doc/qtgui.dox
+++ b/gr-qtgui/doc/qtgui.dox
@@ -232,6 +232,54 @@ tb.msg_connect((msg_block, 'msg'), (tsnk, 'in'))
\endcode
+\section qtgui_widgets QTGUI Widgets
+
+The QTGUI component also includes a number of widgets that can be used
+to perform live updates of variables through standard QT input
+widgets. Most of the widgets are implemented directly in Python
+through PyQT. However, GNU Radio is introducing more widgets, written
+and therefore available in C++ that also produce messsages. The
+Python-based widgets only act as variables and so as they are changed,
+any block using those widgets to set paramters has the callback (i.e.,
+set_value()) function's called.
+
+\subsection qtgui_widgets_python Python widgets:
+
+\li Range: creates a slider and/or combo box to change to set/change
+the value of a parameter. This widget can set either float of int
+values.
+\li Entry: An edit box that allows a user to directly set a
+new value for the parameter.
+\li Chooser: Creates a drop-down menu of pre-set values.
+\li Check Box: Creates a check box. The user sets what the value of
+the check means when enabled or disabled.
+\li Push Button: Adds a button that changes state when pushed versus
+released (no sticky). The user sets up what the value is when pressed
+versus when released.
+\li Label: Adds a Label widget to annotate the GUI. Generally not used
+as a variable.
+\li Tab Widget: Adds a tab widget that can house other GUI widgets to
+format the interface. Use the GUI hint of the other QT widgets and
+instruments to specify if and where they exist in the tab widget using
+the format "tag widget name@index: row, col, row span, col
+span". Simply using "tab widget name@index" will put that widget into
+the specific index (starting at 0) of the tab widget while adding the
+"row, col, row span, col span" will allow the user to place them in
+the tab grid.
+\li
+
+
+\subsection qtgui_widgets_cpp C++ and Message-Passing Widgets
+
+\li \ref gr::qtgui::edit_box_msg "Message Edit Box": A QT edit box
+that emits a message when editing is done (e.g., user presses enter,
+tabs out of the widget, or mouse-clicks out of the widget). The
+message type is settable as are the contents. Messages can be sent as
+key:value pairs when Pair Mode is enabled. When Static Mode is
+enabled, the data type and the pair key (if in Pair Mode) are set at
+the start and cannot be changed at runtime.
+
+
\section qtgui_configuration Configuration
There is currently a single configuration option in the preferences
diff --git a/gr-qtgui/examples/CMakeLists.txt b/gr-qtgui/examples/CMakeLists.txt
index 3581bdaec1..5662dfa9c8 100644
--- a/gr-qtgui/examples/CMakeLists.txt
+++ b/gr-qtgui/examples/CMakeLists.txt
@@ -41,6 +41,7 @@ install(
qtgui_tags_viewing.grc
qtgui_vector_sink_example.grc
qtgui_message_inputs.grc
+ test_qtgui_msg.grc
DESTINATION ${GR_PKG_QTGUI_EXAMPLES_DIR}
COMPONENT "qtgui_python"
)
diff --git a/gr-qtgui/examples/c++/CMakeLists.txt b/gr-qtgui/examples/c++/CMakeLists.txt
new file mode 100644
index 0000000000..ad84287367
--- /dev/null
+++ b/gr-qtgui/examples/c++/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Copyright 2016 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_directories(
+ ${GR_QTGUI_INCLUDE_DIRS}
+ ${GR_ANALOG_INCLUDE_DIRS}
+ ${GR_FILTER_INCLUDE_DIRS}
+ ${GR_BLOCKS_INCLUDE_DIRS}
+ ${GR_FFT_INCLUDE_DIRS}
+ ${GNURADIO_RUNTIME_INCLUDE_DIRS}
+ ${QT_INCLUDE_DIRS}
+ ${Boost_INCLUDE_DIRS}
+)
+
+list(APPEND QTGUI_LIBRARIES
+ gnuradio-qtgui
+ gnuradio-analog
+ gnuradio-filter
+ gnuradio-blocks
+ gnuradio-fft
+ gnuradio-runtime
+ ${QWT_LIBRARY_DIRS}
+)
+
+QT4_WRAP_CPP(qtgui_moc_sources display_qt.h)
+add_executable(display_qt display_qt.cc ${qtgui_moc_sources})
+target_link_libraries(display_qt ${QTGUI_LIBRARIES})
+
+INSTALL(TARGETS
+ display_qt
+ DESTINATION ${GR_PKG_QTGUI_EXAMPLES_DIR}
+ COMPONENT "qtgui_examples"
+)
diff --git a/gr-qtgui/examples/c++/display_qt.cc b/gr-qtgui/examples/c++/display_qt.cc
new file mode 100644
index 0000000000..9d990b25d6
--- /dev/null
+++ b/gr-qtgui/examples/c++/display_qt.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016 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 "display_qt.h"
+
+mywindow::mywindow()
+ : QWidget()
+{
+ // We'll use a horizontal layout of two QTabWidgets
+ layout = new QHBoxLayout();
+
+ // Create the tab widgets
+ tab0 = new QTabWidget();
+ tab1 = new QTabWidget();
+
+ // Add the tab widgets to the layou
+ layout->addWidget(tab0);
+ layout->addWidget(tab1);
+
+ // Set the layout as the main widget's layou
+ setLayout(layout);
+
+ // Simple resizing of the app
+ resize(2000,800);
+
+ // sample rate
+ int rate = 48000;
+
+ // Create the GNU Radio top block
+ tb = make_top_block("display_qt");
+
+ // Source will be sine wave in noise
+ src0 = analog::sig_source_f::make(rate, analog::GR_SIN_WAVE, 1500, 1);
+ src1 = analog::noise_source_f::make(analog::GR_GAUSSIAN, 0.1);
+
+ // Combine signal and noise; add throttle
+ src = blocks::add_ff::make();
+ thr = blocks::throttle::make(sizeof(float), rate);
+
+ // Create the QTGUI sinks
+ // Time, Freq, Waterfall, and Histogram sinks
+ tsnk = qtgui::time_sink_f::make(1024, rate, "", 1);
+ fsnk = qtgui::freq_sink_f::make(1024, fft::window::WIN_HANN,
+ 0, rate, "", 1);
+ wsnk = qtgui::waterfall_sink_f::make(1024, fft::window::WIN_HANN,
+ 0, rate, "", 1);
+ hsnk = qtgui::histogram_sink_f::make(1024, 100, -2, 2, "", 1);
+
+ // Turn off the legend on these plots
+ tsnk->disable_legend();
+ fsnk->disable_legend();
+ hsnk->disable_legend();
+
+ // Connect the graph
+ tb->connect(src0, 0, src, 0);
+ tb->connect(src1, 0, src, 1);
+ tb->connect(src, 0, thr, 0);
+ tb->connect(thr, 0, tsnk, 0);
+ tb->connect(thr, 0, fsnk, 0);
+ tb->connect(thr, 0, wsnk, 0);
+ tb->connect(thr, 0, hsnk, 0);
+
+ // Get the raw QWidget objects from the GNU Radio blocks
+ qtgui_time_sink_win = tsnk->qwidget();
+ qtgui_freq_sink_win = fsnk->qwidget();
+ qtgui_waterfall_sink_win = wsnk->qwidget();
+ qtgui_histogram_sink_win = hsnk->qwidget();
+
+ // Plug the widgets into the tabs
+ tab0->addTab(qtgui_time_sink_win, "Time");
+ tab0->addTab(qtgui_histogram_sink_win, "Hist");
+ tab1->addTab(qtgui_freq_sink_win, "Freq");
+ tab1->addTab(qtgui_waterfall_sink_win, "Waterfall");
+}
+
+mywindow::~mywindow()
+{
+}
+
+void
+mywindow::start()
+{
+ tb->start();
+}
+
+void
+mywindow::quitting()
+{
+ tb->stop();
+ tb->wait();
+}
+
+int main(int argc, char **argv)
+{
+ // The global QT application
+ QApplication app(argc, argv);
+
+ mywindow *w = new mywindow();
+
+ QObject::connect(&app, SIGNAL(aboutToQuit()),
+ w, SLOT(quitting()));
+
+ w->start(); // Start the flowgraph
+ w->show(); // show the window
+ app.exec(); // run the QT executor loop
+
+ return 0;
+}
diff --git a/gr-qtgui/examples/c++/display_qt.h b/gr-qtgui/examples/c++/display_qt.h
new file mode 100644
index 0000000000..97c46c1faa
--- /dev/null
+++ b/gr-qtgui/examples/c++/display_qt.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 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.
+ */
+
+// Q_MOC_RUN is a workaround for a QT4 + Boost version issue
+#ifndef Q_MOC_RUN
+#include <gnuradio/top_block.h>
+#include <gnuradio/analog/sig_source_f.h>
+#include <gnuradio/analog/noise_source_f.h>
+#include <gnuradio/blocks/add_ff.h>
+#include <gnuradio/blocks/throttle.h>
+#include <gnuradio/qtgui/time_sink_f.h>
+#include <gnuradio/qtgui/freq_sink_f.h>
+#include <gnuradio/qtgui/waterfall_sink_f.h>
+#include <gnuradio/qtgui/histogram_sink_f.h>
+#include <gnuradio/fft/window.h>
+#endif
+
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QTabWidget>
+
+using namespace gr;
+
+class mywindow : public QWidget
+{
+ Q_OBJECT
+
+private:
+ QHBoxLayout *layout;
+ QTabWidget *tab0;
+ QTabWidget *tab1;
+ QWidget* qtgui_time_sink_win;
+ QWidget* qtgui_freq_sink_win;
+ QWidget* qtgui_waterfall_sink_win;
+ QWidget* qtgui_histogram_sink_win;
+
+#ifndef Q_MOC_RUN
+ top_block_sptr tb;
+ analog::sig_source_f::sptr src0;
+ analog::noise_source_f::sptr src1;
+ blocks::add_ff::sptr src;
+ blocks::throttle::sptr thr;
+ qtgui::time_sink_f::sptr tsnk;
+ qtgui::freq_sink_f::sptr fsnk;
+ qtgui::waterfall_sink_f::sptr wsnk;
+ qtgui::histogram_sink_f::sptr hsnk;
+#endif
+
+public slots:
+ // Stop the topblock before shutting down the window
+ void quitting();
+
+public:
+ mywindow();
+ virtual ~mywindow();
+
+ // call start() on the topblock
+ void start();
+};
diff --git a/grc/examples/xmlrpc/xmlrpc_server.grc b/gr-qtgui/examples/test_qtgui_msg.grc
index d210b2694e..12ca0e34c9 100644
--- a/grc/examples/xmlrpc/xmlrpc_server.grc
+++ b/gr-qtgui/examples/test_qtgui_msg.grc
@@ -1,39 +1,68 @@
-<?xml version='1.0' encoding='ASCII'?>
+<?xml version='1.0' encoding='utf-8'?>
+<?grc format='1' created='3.7.10'?>
<flow_graph>
- <timestamp>Sat Jul 12 17:11:40 2014</timestamp>
+ <timestamp>Wed Feb 10 14:28:57 2016</timestamp>
<block>
<key>options</key>
<param>
- <key>id</key>
- <value>server_block</value>
+ <key>author</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>window_size</key>
+ <value></value>
</param>
<param>
- <key>title</key>
- <value>XMLRPC Server</value>
+ <key>category</key>
+ <value>Custom</value>
</param>
<param>
- <key>author</key>
- <value>Example</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
<key>description</key>
- <value>example flow graph</value>
+ <value></value>
</param>
<param>
- <key>window_size</key>
- <value>1280, 1024</value>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(8, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
</param>
<param>
<key>generate_options</key>
<value>qt_gui</value>
</param>
<param>
- <key>category</key>
- <value>Custom</value>
+ <key>hier_block_src_path</key>
+ <value>.:</value>
+ </param>
+ <param>
+ <key>id</key>
+ <value>test_qtgui_msg</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>qt_qss_theme</key>
+ <value></value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>run_command</key>
+ <value>{python} -u {filename}</value>
</param>
<param>
<key>run_options</key>
@@ -44,38 +73,45 @@
<value>True</value>
</param>
<param>
- <key>max_nouts</key>
- <value>0</value>
+ <key>thread_safe_setters</key>
+ <value></value>
</param>
<param>
- <key>realtime_scheduling</key>
+ <key>title</key>
<value></value>
</param>
+ </block>
+ <block>
+ <key>variable</key>
<param>
- <key>alias</key>
+ <key>comment</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(0, -1)</value>
+ <value>(168, 11)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>variable</key>
<param>
<key>id</key>
- <value>ampl</value>
+ <value>samp_rate</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>value</key>
+ <value>32000</value>
</param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
<param>
- <key>value</key>
+ <key>amp</key>
<value>1</value>
</param>
<param>
@@ -83,363 +119,413 @@
<value></value>
</param>
<param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>1000</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(4, 291)</value>
+ <value>(80, 83)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>variable</key>
<param>
<key>id</key>
- <value>freq</value>
+ <value>analog_sig_source_x_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>value</key>
- <value>1000</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>offset</key>
+ <value>0</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(2, 213)</value>
+ <key>type</key>
+ <value>complex</value>
</param>
<param>
- <key>_rotation</key>
- <value>0</value>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_COS_WAVE</value>
</param>
</block>
<block>
- <key>variable</key>
+ <key>blocks_message_debug</key>
<param>
- <key>id</key>
- <value>samp_rate</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>value</key>
- <value>32000</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>_enabled</key>
+ <value>1</value>
</param>
<param>
<key>_coordinate</key>
- <value>(2, 136)</value>
+ <value>(600, 481)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>variable</key>
<param>
<key>id</key>
- <value>offset</value>
+ <value>blocks_message_debug_0</value>
</param>
+ </block>
+ <block>
+ <key>qtgui_edit_box_msg</key>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>value</key>
- <value>0</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>alias</key>
+ <key>affinity</key>
<value></value>
</param>
<param>
+ <key>_enabled</key>
+ <value>1</value>
+ </param>
+ <param>
<key>_coordinate</key>
- <value>(3, 366)</value>
+ <value>(104, 219)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>0,0,1,1</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>
+ <value>qtgui_edit_box_msg_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>key</key>
+ <value>freq</value>
</param>
<param>
- <key>type</key>
- <value>float</value>
+ <key>label</key>
+ <value>Frequency</value>
</param>
<param>
- <key>samp_rate</key>
- <value>samp_rate</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>waveform</key>
- <value>analog.GR_COS_WAVE</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>freq</key>
- <value>freq</value>
+ <key>is_pair</key>
+ <value>True</value>
</param>
<param>
- <key>amp</key>
- <value>ampl</value>
+ <key>is_static</key>
+ <value>True</value>
</param>
<param>
- <key>offset</key>
- <value>offset</value>
+ <key>type</key>
+ <value>float</value>
</param>
<param>
+ <key>value</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_edit_box_msg</key>
+ <param>
<key>alias</key>
<value></value>
</param>
<param>
- <key>affinity</key>
+ <key>comment</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>1</value>
</param>
<param>
<key>_coordinate</key>
- <value>(175, 0)</value>
+ <value>(88, 371)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,1,1,1</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>blocks_throttle</key>
<param>
<key>id</key>
- <value>blocks_throttle</value>
+ <value>qtgui_edit_box_msg_0_0</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>key</key>
+ <value></value>
</param>
<param>
- <key>type</key>
- <value>float</value>
+ <key>label</key>
+ <value></value>
</param>
<param>
- <key>samples_per_second</key>
- <value>samp_rate</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>vlen</key>
- <value>1</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>ignoretag</key>
- <value>True</value>
+ <key>is_pair</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>is_static</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>int_vec</value>
</param>
<param>
+ <key>value</key>
+ <value></value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_edit_box_msg</key>
+ <param>
<key>alias</key>
<value></value>
</param>
<param>
- <key>affinity</key>
+ <key>comment</key>
<value></value>
</param>
<param>
- <key>minoutbuf</key>
- <value>0</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
- <key>maxoutbuf</key>
- <value>0</value>
+ <key>_enabled</key>
+ <value>1</value>
</param>
<param>
<key>_coordinate</key>
- <value>(399, 35)</value>
+ <value>(272, 499)</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value>3,0,1,1</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>xmlrpc_server</key>
<param>
<key>id</key>
- <value>xmlrpc_server</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
+ <value>qtgui_edit_box_msg_0_0_0</value>
</param>
<param>
- <key>addr</key>
- <value>localhost</value>
- </param>
- <param>
- <key>port</key>
- <value>1234</value>
+ <key>key</key>
+ <value></value>
</param>
<param>
- <key>alias</key>
+ <key>label</key>
<value></value>
</param>
<param>
- <key>_coordinate</key>
- <value>(129, 137)</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>_rotation</key>
+ <key>minoutbuf</key>
<value>0</value>
</param>
- </block>
- <block>
- <key>qtgui_time_sink_x</key>
<param>
- <key>id</key>
- <value>qtgui_time_sink_x_0</value>
+ <key>is_pair</key>
+ <value>False</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>is_static</key>
+ <value>False</value>
</param>
<param>
<key>type</key>
- <value>float</value>
+ <value>int_vec</value>
</param>
<param>
- <key>name</key>
- <value>Scope Plot</value>
+ <key>value</key>
+ <value></value>
</param>
+ </block>
+ <block>
+ <key>qtgui_freq_sink_x</key>
<param>
- <key>size</key>
- <value>1024</value>
+ <key>autoscale</key>
+ <value>False</value>
</param>
<param>
- <key>srate</key>
- <value>samp_rate</value>
+ <key>average</key>
+ <value>1.0</value>
</param>
<param>
- <key>autoscale</key>
- <value>False</value>
+ <key>bw</key>
+ <value>samp_rate</value>
</param>
<param>
- <key>ymin</key>
- <value>-1</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>ymax</key>
- <value>1</value>
+ <key>fc</key>
+ <value>0</value>
</param>
<param>
- <key>nconnections</key>
- <value>1</value>
+ <key>comment</key>
+ <value></value>
</param>
<param>
- <key>update_time</key>
- <value>0.10</value>
+ <key>ctrlpanel</key>
+ <value>False</value>
</param>
<param>
- <key>entags</key>
- <value>True</value>
+ <key>affinity</key>
+ <value></value>
</param>
<param>
- <key>gui_hint</key>
- <value>0, 0, 2, 4</value>
+ <key>_enabled</key>
+ <value>1</value>
</param>
<param>
- <key>tr_mode</key>
- <value>qtgui.TRIG_MODE_FREE</value>
+ <key>fftsize</key>
+ <value>1024</value>
</param>
<param>
- <key>tr_slope</key>
- <value>qtgui.TRIG_SLOPE_POS</value>
+ <key>_coordinate</key>
+ <value>(512, 195)</value>
</param>
<param>
- <key>tr_level</key>
- <value>0.0</value>
+ <key>gui_hint</key>
+ <value>1,0,1,2</value>
</param>
<param>
- <key>tr_delay</key>
+ <key>_rotation</key>
<value>0</value>
</param>
<param>
- <key>tr_chan</key>
- <value>0</value>
+ <key>grid</key>
+ <value>False</value>
</param>
<param>
- <key>tr_tag</key>
- <value>""</value>
+ <key>id</key>
+ <value>qtgui_freq_sink_x_0</value>
</param>
<param>
- <key>label1</key>
- <value></value>
+ <key>legend</key>
+ <value>False</value>
</param>
<param>
- <key>width1</key>
- <value>1</value>
+ <key>alpha1</key>
+ <value>1.0</value>
</param>
<param>
<key>color1</key>
<value>"blue"</value>
</param>
<param>
- <key>style1</key>
- <value>1</value>
+ <key>label1</key>
+ <value></value>
</param>
<param>
- <key>marker1</key>
- <value>-1</value>
+ <key>width1</key>
+ <value>1</value>
</param>
<param>
- <key>alpha1</key>
+ <key>alpha10</key>
<value>1.0</value>
</param>
<param>
- <key>label2</key>
+ <key>color10</key>
+ <value>"dark blue"</value>
+ </param>
+ <param>
+ <key>label10</key>
<value></value>
</param>
<param>
- <key>width2</key>
+ <key>width10</key>
<value>1</value>
</param>
<param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
<key>color2</key>
<value>"red"</value>
</param>
<param>
- <key>style2</key>
- <value>1</value>
+ <key>label2</key>
+ <value></value>
</param>
<param>
- <key>marker2</key>
- <value>-1</value>
+ <key>width2</key>
+ <value>1</value>
</param>
<param>
- <key>alpha2</key>
+ <key>alpha3</key>
<value>1.0</value>
</param>
<param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
<key>label3</key>
<value></value>
</param>
@@ -448,20 +534,12 @@
<value>1</value>
</param>
<param>
- <key>color3</key>
- <value>"green"</value>
- </param>
- <param>
- <key>style3</key>
- <value>1</value>
- </param>
- <param>
- <key>marker3</key>
- <value>-1</value>
+ <key>alpha4</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha3</key>
- <value>1.0</value>
+ <key>color4</key>
+ <value>"black"</value>
</param>
<param>
<key>label4</key>
@@ -472,20 +550,12 @@
<value>1</value>
</param>
<param>
- <key>color4</key>
- <value>"black"</value>
- </param>
- <param>
- <key>style4</key>
- <value>1</value>
- </param>
- <param>
- <key>marker4</key>
- <value>-1</value>
+ <key>alpha5</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha4</key>
- <value>1.0</value>
+ <key>color5</key>
+ <value>"cyan"</value>
</param>
<param>
<key>label5</key>
@@ -496,20 +566,12 @@
<value>1</value>
</param>
<param>
- <key>color5</key>
- <value>"cyan"</value>
- </param>
- <param>
- <key>style5</key>
- <value>1</value>
- </param>
- <param>
- <key>marker5</key>
- <value>-1</value>
+ <key>alpha6</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha5</key>
- <value>1.0</value>
+ <key>color6</key>
+ <value>"magenta"</value>
</param>
<param>
<key>label6</key>
@@ -520,20 +582,12 @@
<value>1</value>
</param>
<param>
- <key>color6</key>
- <value>"magenta"</value>
- </param>
- <param>
- <key>style6</key>
- <value>1</value>
- </param>
- <param>
- <key>marker6</key>
- <value>-1</value>
+ <key>alpha7</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha6</key>
- <value>1.0</value>
+ <key>color7</key>
+ <value>"yellow"</value>
</param>
<param>
<key>label7</key>
@@ -544,20 +598,12 @@
<value>1</value>
</param>
<param>
- <key>color7</key>
- <value>"yellow"</value>
- </param>
- <param>
- <key>style7</key>
- <value>1</value>
- </param>
- <param>
- <key>marker7</key>
- <value>-1</value>
+ <key>alpha8</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha7</key>
- <value>1.0</value>
+ <key>color8</key>
+ <value>"dark red"</value>
</param>
<param>
<key>label8</key>
@@ -568,20 +614,12 @@
<value>1</value>
</param>
<param>
- <key>color8</key>
- <value>"dark red"</value>
- </param>
- <param>
- <key>style8</key>
- <value>1</value>
- </param>
- <param>
- <key>marker8</key>
- <value>-1</value>
+ <key>alpha9</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha8</key>
- <value>1.0</value>
+ <key>color9</key>
+ <value>"dark green"</value>
</param>
<param>
<key>label9</key>
@@ -592,317 +630,349 @@
<value>1</value>
</param>
<param>
- <key>color9</key>
- <value>"dark green"</value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>style9</key>
- <value>1</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>marker9</key>
- <value>-1</value>
+ <key>name</key>
+ <value>""</value>
</param>
<param>
- <key>alpha9</key>
- <value>1.0</value>
+ <key>nconnections</key>
+ <value>1</value>
</param>
<param>
- <key>label10</key>
- <value></value>
+ <key>showports</key>
+ <value>False</value>
</param>
<param>
- <key>width10</key>
- <value>1</value>
+ <key>freqhalf</key>
+ <value>True</value>
</param>
<param>
- <key>color10</key>
- <value>"blue"</value>
+ <key>tr_chan</key>
+ <value>0</value>
</param>
<param>
- <key>style10</key>
- <value>1</value>
+ <key>tr_level</key>
+ <value>0.0</value>
</param>
<param>
- <key>marker10</key>
- <value>-1</value>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_FREE</value>
</param>
<param>
- <key>alpha10</key>
- <value>1.0</value>
+ <key>tr_tag</key>
+ <value>""</value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>type</key>
+ <value>complex</value>
</param>
<param>
- <key>affinity</key>
- <value></value>
+ <key>update_time</key>
+ <value>0.10</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(644, 13)</value>
+ <key>wintype</key>
+ <value>firdes.WIN_BLACKMAN_hARRIS</value>
</param>
<param>
- <key>_rotation</key>
- <value>0</value>
+ <key>ymax</key>
+ <value>10</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-140</value>
</param>
</block>
<block>
- <key>qtgui_freq_sink_x</key>
+ <key>qtgui_waterfall_sink_x</key>
<param>
- <key>id</key>
- <value>qtgui_freq_sink_x_0</value>
+ <key>bw</key>
+ <value>samp_rate</value>
</param>
<param>
- <key>_enabled</key>
- <value>True</value>
+ <key>alias</key>
+ <value></value>
</param>
<param>
- <key>type</key>
- <value>float</value>
+ <key>fc</key>
+ <value>0</value>
</param>
<param>
- <key>name</key>
- <value>Spectrum Plot</value>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>1</value>
</param>
<param>
<key>fftsize</key>
<value>1024</value>
</param>
<param>
- <key>wintype</key>
- <value>firdes.WIN_BLACKMAN_hARRIS</value>
+ <key>_coordinate</key>
+ <value>(512, 115)</value>
</param>
<param>
- <key>fc</key>
- <value>0</value>
+ <key>gui_hint</key>
+ <value>2,0,1,2</value>
</param>
<param>
- <key>bw</key>
- <value>samp_rate</value>
+ <key>_rotation</key>
+ <value>0</value>
</param>
<param>
- <key>autoscale</key>
+ <key>grid</key>
<value>False</value>
</param>
<param>
- <key>average</key>
- <value>1.0</value>
+ <key>id</key>
+ <value>qtgui_waterfall_sink_x_0</value>
</param>
<param>
- <key>ymin</key>
- <value>-140</value>
+ <key>int_max</key>
+ <value>10</value>
</param>
<param>
- <key>ymax</key>
- <value>10</value>
+ <key>int_min</key>
+ <value>-140</value>
</param>
<param>
- <key>nconnections</key>
- <value>1</value>
+ <key>legend</key>
+ <value>True</value>
</param>
<param>
- <key>update_time</key>
- <value>0.10</value>
+ <key>alpha1</key>
+ <value>1.0</value>
</param>
<param>
- <key>gui_hint</key>
- <value>2, 0, 2, 4</value>
+ <key>color1</key>
+ <value>0</value>
</param>
<param>
<key>label1</key>
<value></value>
</param>
<param>
- <key>width1</key>
- <value>1</value>
- </param>
- <param>
- <key>color1</key>
- <value>"blue"</value>
+ <key>alpha10</key>
+ <value>1.0</value>
</param>
<param>
- <key>alpha1</key>
- <value>1.0</value>
+ <key>color10</key>
+ <value>0</value>
</param>
<param>
- <key>label2</key>
+ <key>label10</key>
<value></value>
</param>
<param>
- <key>width2</key>
- <value>1</value>
+ <key>alpha2</key>
+ <value>1.0</value>
</param>
<param>
<key>color2</key>
- <value>"red"</value>
- </param>
- <param>
- <key>alpha2</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label3</key>
+ <key>label2</key>
<value></value>
</param>
<param>
- <key>width3</key>
- <value>1</value>
+ <key>alpha3</key>
+ <value>1.0</value>
</param>
<param>
<key>color3</key>
- <value>"green"</value>
- </param>
- <param>
- <key>alpha3</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label4</key>
+ <key>label3</key>
<value></value>
</param>
<param>
- <key>width4</key>
- <value>1</value>
+ <key>alpha4</key>
+ <value>1.0</value>
</param>
<param>
<key>color4</key>
- <value>"black"</value>
- </param>
- <param>
- <key>alpha4</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label5</key>
+ <key>label4</key>
<value></value>
</param>
<param>
- <key>width5</key>
- <value>1</value>
+ <key>alpha5</key>
+ <value>1.0</value>
</param>
<param>
<key>color5</key>
- <value>"cyan"</value>
- </param>
- <param>
- <key>alpha5</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label6</key>
+ <key>label5</key>
<value></value>
</param>
<param>
- <key>width6</key>
- <value>1</value>
+ <key>alpha6</key>
+ <value>1.0</value>
</param>
<param>
<key>color6</key>
- <value>"magenta"</value>
- </param>
- <param>
- <key>alpha6</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label7</key>
+ <key>label6</key>
<value></value>
</param>
<param>
- <key>width7</key>
- <value>1</value>
+ <key>alpha7</key>
+ <value>1.0</value>
</param>
<param>
<key>color7</key>
- <value>"yellow"</value>
- </param>
- <param>
- <key>alpha7</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label8</key>
+ <key>label7</key>
<value></value>
</param>
<param>
- <key>width8</key>
- <value>1</value>
+ <key>alpha8</key>
+ <value>1.0</value>
</param>
<param>
<key>color8</key>
- <value>"dark red"</value>
- </param>
- <param>
- <key>alpha8</key>
- <value>1.0</value>
+ <value>0</value>
</param>
<param>
- <key>label9</key>
+ <key>label8</key>
<value></value>
</param>
<param>
- <key>width9</key>
- <value>1</value>
+ <key>alpha9</key>
+ <value>1.0</value>
</param>
<param>
<key>color9</key>
- <value>"dark green"</value>
+ <value>0</value>
</param>
<param>
- <key>alpha9</key>
- <value>1.0</value>
+ <key>label9</key>
+ <value></value>
</param>
<param>
- <key>label10</key>
- <value></value>
+ <key>maxoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>width10</key>
- <value>1</value>
+ <key>minoutbuf</key>
+ <value>0</value>
</param>
<param>
- <key>color10</key>
- <value>"dark blue"</value>
+ <key>name</key>
+ <value>""</value>
</param>
<param>
- <key>alpha10</key>
- <value>1.0</value>
+ <key>nconnections</key>
+ <value>1</value>
</param>
<param>
- <key>alias</key>
- <value></value>
+ <key>showports</key>
+ <value>False</value>
</param>
<param>
- <key>affinity</key>
- <value></value>
+ <key>freqhalf</key>
+ <value>True</value>
</param>
<param>
- <key>_coordinate</key>
- <value>(644, 126)</value>
+ <key>type</key>
+ <value>complex</value>
</param>
<param>
- <key>_rotation</key>
- <value>0</value>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>wintype</key>
+ <value>firdes.WIN_BLACKMAN_hARRIS</value>
</param>
</block>
<connection>
<source_block_id>analog_sig_source_x_0</source_block_id>
- <sink_block_id>blocks_throttle</sink_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>blocks_throttle</source_block_id>
- <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
- <source_block_id>blocks_throttle</source_block_id>
+ <source_block_id>qtgui_edit_box_msg_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>
+ <source_key>msg</source_key>
+ <sink_key>freq</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_edit_box_msg_0</source_block_id>
+ <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
+ <source_key>msg</source_key>
+ <sink_key>freq</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_edit_box_msg_0_0</source_block_id>
+ <sink_block_id>qtgui_edit_box_msg_0_0_0</sink_block_id>
+ <source_key>msg</source_key>
+ <sink_key>val</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_edit_box_msg_0_0_0</source_block_id>
+ <sink_block_id>blocks_message_debug_0</sink_block_id>
+ <source_key>msg</source_key>
+ <sink_key>print</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_edit_box_msg_0_0_0</source_block_id>
+ <sink_block_id>qtgui_edit_box_msg_0_0</sink_block_id>
+ <source_key>msg</source_key>
+ <sink_key>val</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_freq_sink_x_0</source_block_id>
+ <sink_block_id>qtgui_edit_box_msg_0</sink_block_id>
+ <source_key>freq</source_key>
+ <sink_key>val</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_freq_sink_x_0</source_block_id>
+ <sink_block_id>qtgui_freq_sink_x_0</sink_block_id>
+ <source_key>freq</source_key>
+ <sink_key>freq</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_waterfall_sink_x_0</source_block_id>
+ <sink_block_id>qtgui_edit_box_msg_0</sink_block_id>
+ <source_key>freq</source_key>
+ <sink_key>val</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>qtgui_waterfall_sink_x_0</source_block_id>
+ <sink_block_id>qtgui_waterfall_sink_x_0</sink_block_id>
+ <source_key>freq</source_key>
+ <sink_key>freq</sink_key>
</connection>
</flow_graph>
diff --git a/gr-qtgui/grc/qtgui_block_tree.xml b/gr-qtgui/grc/qtgui_block_tree.xml
index 03db638d61..33fb12a7b5 100644
--- a/gr-qtgui/grc/qtgui_block_tree.xml
+++ b/gr-qtgui/grc/qtgui_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Instrumentation</name>
<cat>
@@ -55,6 +55,7 @@
<block>variable_qtgui_push_button</block>
<block>variable_qtgui_entry</block>
<block>variable_qtgui_label</block>
+ <block>qtgui_edit_box_msg</block>
</cat>
</cat>
</cat>
diff --git a/gr-qtgui/grc/qtgui_const_sink_x.xml b/gr-qtgui/grc/qtgui_const_sink_x.xml
index 956a1694ec..755f12f964 100644
--- a/gr-qtgui/grc/qtgui_const_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_const_sink_x.xml
@@ -22,6 +22,7 @@ self.$(id).set_x_axis($xmin, $xmax)
self.$(id).set_trigger_mode($tr_mode, $tr_slope, $tr_level, $tr_chan, $tr_tag)
self.$(id).enable_autoscale($autoscale)
self.$(id).enable_grid($grid)
+self.$(id).enable_axis_labels($axislabels)
if not $legend:
self.$(id).disable_legend()
@@ -276,6 +277,23 @@ $(gui_hint()($win))</make>
</param>
<param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
+
+ <param>
<name>Line 1 Label</name>
<key>label1</key>
<type>string</type>
diff --git a/gr-qtgui/grc/qtgui_edit_box_msg.xml b/gr-qtgui/grc/qtgui_edit_box_msg.xml
new file mode 100644
index 0000000000..c7c758a612
--- /dev/null
+++ b/gr-qtgui/grc/qtgui_edit_box_msg.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##QT GUI Edit Box that sends messages
+###################################################
+ -->
+<block>
+ <name>QT GUI Message Edit Box</name>
+ <key>qtgui_edit_box_msg</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.edit_box_msg($(type.t), $value, $label, $is_pair, $is_static, $key)
+self._$(id)_win = sip.wrapinstance(self.$(id).pyqwidget(), Qt.QWidget)
+$(gui_hint()($win))</make>
+
+ <param>
+ <name>Type</name>
+ <key>type</key>
+ <value>string</value>
+ <type>enum</type>
+ <option>
+ <name>String</name>
+ <key>string</key>
+ <opt>t:qtgui.STRING</opt>
+ </option>
+ <option>
+ <name>Int</name>
+ <key>int</key>
+ <opt>t:qtgui.INT</opt>
+ </option>
+ <option>
+ <name>Float</name>
+ <key>float</key>
+ <opt>t:qtgui.FLOAT</opt>
+ </option>
+ <option>
+ <name>Double</name>
+ <key>double</key>
+ <opt>t:qtgui.DOUBLE</opt>
+ </option>
+ <option>
+ <name>Complex</name>
+ <key>complex</key>
+ <opt>t:qtgui.COMPLEX</opt>
+ </option>
+ <option>
+ <name>Int (Vec)</name>
+ <key>int_vec</key>
+ <opt>t:qtgui.INT_VEC</opt>
+ </option>
+ <option>
+ <name>Float (Vec)</name>
+ <key>flt_vec</key>
+ <opt>t:qtgui.FLOAT_VEC</opt>
+ </option>
+ <option>
+ <name>Double (Vec)</name>
+ <key>dbl_vec</key>
+ <opt>t:qtgui.DOUBLE_VEC</opt>
+ </option>
+ <option>
+ <name>Complex (Vec)</name>
+ <key>cpx_vec</key>
+ <opt>t:qtgui.COMPLEX_VEC</opt>
+ </option>
+ </param>
+
+ <param>
+ <name>Value</name>
+ <key>value</key>
+ <value></value>
+ <type>string</type>
+ </param>
+
+ <param>
+ <name>Label</name>
+ <key>label</key>
+ <value></value>
+ <type>string</type>
+ </param>
+
+ <param>
+ <name>Pair Mode</name>
+ <key>is_pair</key>
+ <value>True</value>
+ <type>enum</type>
+ <option>
+ <name>False</name>
+ <key>False</key>
+ </option>
+ <option>
+ <name>True</name>
+ <key>True</key>
+ </option>
+ </param>
+
+ <param>
+ <name>Static Mode</name>
+ <key>is_static</key>
+ <value>True</value>
+ <type>enum</type>
+ <option>
+ <name>False</name>
+ <key>False</key>
+ </option>
+ <option>
+ <name>True</name>
+ <key>True</key>
+ </option>
+ </param>
+
+ <param>
+ <name>Key</name>
+ <key>key</key>
+ <value></value>
+ <type>string</type>
+ <hide>#if $is_pair() == 'True' then 'none' else 'all'#</hide>
+ </param>
+
+ <param>
+ <name>GUI Hint</name>
+ <key>gui_hint</key>
+ <value></value>
+ <type>gui_hint</type>
+ <hide>part</hide>
+ </param>
+
+ <!-- If both is_pair and is_static are True, we require a default key.
+ If either or both are false, we don't care about a default key.
+ -->
+ <check>($is_pair and $is_static and len($key) &gt; 0) or not ($is_pair and $is_static)</check>
+
+ <sink>
+ <name>val</name>
+ <type>message</type>
+ <optional>1</optional>
+ </sink>
+
+ <source>
+ <name>msg</name>
+ <type>message</type>
+ <optional>1</optional>
+ </source>
+
+ <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/grc/qtgui_freq_sink_x.xml b/gr-qtgui/grc/qtgui_freq_sink_x.xml
index d7c3139849..009a184327 100644
--- a/gr-qtgui/grc/qtgui_freq_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_freq_sink_x.xml
@@ -22,10 +22,12 @@ qtgui.$(type.fcn)(
)
self.$(id).set_update_time($update_time)
self.$(id).set_y_axis($ymin, $ymax)
+self.$(id).set_y_label($label, $units)
self.$(id).set_trigger_mode($tr_mode, $tr_level, $tr_chan, $tr_tag)
self.$(id).enable_autoscale($autoscale)
self.$(id).enable_grid($grid)
self.$(id).set_fft_average($average)
+self.$(id).enable_axis_labels($axislabels)
self.$(id).enable_control_panel($ctrlpanel)
if not $legend:
@@ -252,6 +254,22 @@ $(gui_hint()($win))</make>
</param>
<param>
+ <name>Y label</name>
+ <key>label</key>
+ <value>Relative Gain</value>
+ <type>string</type>
+ <hide>part</hide>
+ </param>
+
+ <param>
+ <name>Y units</name>
+ <key>units</key>
+ <value>dB</value>
+ <type>string</type>
+ <hide>part</hide>
+ </param>
+
+ <param>
<name>Number of Inputs</name>
<key>nconnections</key>
<value>1</value>
@@ -383,6 +401,23 @@ $(gui_hint()($win))</make>
</param>
<param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
+
+ <param>
<name>Line 1 Label</name>
<key>label1</key>
<type>string</type>
diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.xml b/gr-qtgui/grc/qtgui_histogram_sink_x.xml
index a9966fd7ec..a789d2e4fa 100644
--- a/gr-qtgui/grc/qtgui_histogram_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_histogram_sink_x.xml
@@ -24,6 +24,7 @@ self.$(id).set_update_time($update_time)
self.$(id).enable_autoscale($autoscale)
self.$(id).enable_accumulate($accum)
self.$(id).enable_grid($grid)
+self.$(id).enable_axis_labels($axislabels)
if not $legend:
self.$(id).disable_legend()
@@ -211,6 +212,23 @@ $(gui_hint()($win))
</param>
<param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
+
+ <param>
<name>Line 1 Label</name>
<key>label1</key>
<type>string</type>
diff --git a/gr-qtgui/grc/qtgui_time_raster_x.xml b/gr-qtgui/grc/qtgui_time_raster_x.xml
index b36944c1e5..0359dc3b71 100644
--- a/gr-qtgui/grc/qtgui_time_raster_x.xml
+++ b/gr-qtgui/grc/qtgui_time_raster_x.xml
@@ -24,6 +24,7 @@ qtgui.$(type.fcn)(
self.$(id).set_update_time($update_time)
self.$(id).set_intensity_range($zmin, $zmax)
self.$(id).enable_grid($grid)
+self.$(id).enable_axis_labels($axislabels)
labels = [$label1, $label2, $label3, $label4, $label5,
$label6, $label7, $label8, $label9, $label10]
@@ -185,6 +186,22 @@ $(gui_hint()($win))</make>
<hide>part</hide>
</param>
+ <param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
<param>
<name>Line 1 Label</name>
diff --git a/gr-qtgui/grc/qtgui_time_sink_x.xml b/gr-qtgui/grc/qtgui_time_sink_x.xml
index b17b55fc48..c0584b6d34 100644
--- a/gr-qtgui/grc/qtgui_time_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_time_sink_x.xml
@@ -27,6 +27,7 @@ self.$(id).enable_tags(-1, $entags)
self.$(id).set_trigger_mode($tr_mode, $tr_slope, $tr_level, $tr_delay, $tr_chan, $tr_tag)
self.$(id).enable_autoscale($autoscale)
self.$(id).enable_grid($grid)
+self.$(id).enable_axis_labels($axislabels)
self.$(id).enable_control_panel($ctrlpanel)
if not $legend:
@@ -363,6 +364,23 @@ $(gui_hint()($win))</make>
</param>
<param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
+
+ <param>
<name>Line 1 Label</name>
<key>label1</key>
<type>string</type>
diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml
index 1d8461b8c4..cdecd5cce1 100644
--- a/gr-qtgui/grc/qtgui_waterfall_sink_x.xml
+++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.xml
@@ -22,6 +22,7 @@ qtgui.$(type.fcn)(
)
self.$(id).set_update_time($update_time)
self.$(id).enable_grid($grid)
+self.$(id).enable_axis_labels($axislabels)
if not $legend:
self.$(id).disable_legend()
@@ -271,6 +272,23 @@ $(gui_hint()($win))</make>
</param>
<param>
+ <name>Axis Labels</name>
+ <key>axislabels</key>
+ <value>True</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>False</key>
+ </option>
+ <tab>Config</tab>
+ </param>
+
+ <param>
<name>Line 1 Color</name>
<key>color1</key>
<type>enum</type>
diff --git a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
index 1e0c9f35f2..5d22f112af 100644
--- a/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
+++ b/gr-qtgui/include/gnuradio/qtgui/CMakeLists.txt
@@ -38,6 +38,7 @@ install(FILES
histogram_sink_f.h
histogramdisplayform.h
HistogramDisplayPlot.h
+ edit_box_msg.h
number_sink.h
numberdisplayform.h
plot_raster.h
diff --git a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
index 9edff7b183..eba12e2635 100644
--- a/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
+++ b/gr-qtgui/include/gnuradio/qtgui/DisplayPlot.h
@@ -190,6 +190,7 @@ public:
public slots:
virtual void disableLegend();
+ virtual void setAxisLabels(bool en);
virtual void setYaxis(double min, double max);
virtual void setXaxis(double min, double max);
virtual void setLineLabel(int which, QString label);
diff --git a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h
index 8b2ef457fb..5c6b2c71b0 100644
--- a/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h
+++ b/gr-qtgui/include/gnuradio/qtgui/FrequencyDisplayPlot.h
@@ -118,6 +118,9 @@ public slots:
void setPlotPosHalf(bool half);
+ void setYLabel(const std::string &label,
+ const std::string &unit);
+
void clearMaxData();
void clearMinData();
diff --git a/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h
index 851f3be7ca..9905eb7690 100644
--- a/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h
+++ b/gr-qtgui/include/gnuradio/qtgui/const_sink_c.h
@@ -144,6 +144,7 @@ namespace gr {
virtual void enable_menu(bool en=true) = 0;
virtual void enable_autoscale(bool en) = 0;
virtual void enable_grid(bool en) = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
virtual void disable_legend() = 0;
virtual int nsamps() const = 0;
virtual void reset() = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/displayform.h b/gr-qtgui/include/gnuradio/qtgui/displayform.h
index 2ef4b801cf..1da1383370 100644
--- a/gr-qtgui/include/gnuradio/qtgui/displayform.h
+++ b/gr-qtgui/include/gnuradio/qtgui/displayform.h
@@ -83,6 +83,7 @@ public slots:
void setStop();
void setGrid(bool on);
+ void setAxisLabels(bool en);
void saveFigure();
@@ -117,6 +118,8 @@ protected:
bool d_stop_state;
QAction *d_grid_act;
bool d_grid_state;
+ QAction *d_axislabelsmenu;
+ bool d_axislabels;
QAction *d_autoscale_act;
bool d_autoscale_state;
diff --git a/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h b/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h
new file mode 100644
index 0000000000..2976cfb2be
--- /dev/null
+++ b/gr-qtgui/include/gnuradio/qtgui/edit_box_msg.h
@@ -0,0 +1,151 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 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_EDIT_BOX_MSG_H
+#define INCLUDED_QTGUI_EDIT_BOX_MSG_H
+
+#ifdef ENABLE_PYTHON
+#include <Python.h>
+#endif
+
+#include <gnuradio/qtgui/qtgui_types.h>
+#include <gnuradio/qtgui/api.h>
+#include <gnuradio/block.h>
+#include <qapplication.h>
+
+namespace gr {
+ namespace qtgui {
+
+ /*!
+ * \brief Create a QT Edit Box widget where the value is posted as a message.
+ * \ingroup qtgui_blk
+ *
+ * \details
+ * This block creates a QT Edit Box widget that manages data
+ * through message passing interfaces. The 'msg' output port
+ * produces messages based on the text in the edit box and the
+ * data type set by the \p type argument (see
+ * gr::qtgui::data_type_t). The data types are checked, and WARN
+ * log messages are produced when the data is in the wrong
+ * format. Not all errors are explicitly checked for, only that
+ * conversions happen correctly. Failures are either produces as
+ * log messages or the action is simply silently dropped.
+ *
+ * The value of the edit boxes can be programmatically updated
+ * through the 'val' input message port. It is also checked for
+ * the correct data type.
+ *
+ * The \p is_pair argument to the constructor determines if the
+ * edit box handles a key:value pair. If set to True, two edit
+ * boxes are created with the left for the key and right for the
+ * value. The key is always assumed to be a string and the value
+ * is restricted by the data type setting as above.
+ *
+ * The block can take a default value. Because the block is
+ * capable of handling multiple different data types, we enter the
+ * default value as a string in the same way we expect the user to
+ * enter it into the Value edit box of the widget. We convert this
+ * default exactly the same way we convert the user-entered text
+ * in the edit box. See the next paragraph for an explanation for
+ * how to handle complex numbers.
+ *
+ * Complex numbers are currently handled a bit differently than
+ * expected. Because we use the Boost lexical_cast function,
+ * complex numbers MUST be in the form "(a,b)" to represent "a +
+ * jb". Note that you cannot even have a space after the comma, so
+ * "(1.23,10.56)" is correct while "(1.23, 10.56)" will not parse.
+ *
+ * The 'static' mode prevents the user from changing the data type
+ * or the key used in the widget. If also in 'pair' mode, the key
+ * is not displayed and so must be set in the constructor. It is
+ * an error if using static and pair modes with no default key
+ * set.
+ *
+ * Message Ports:
+ *
+ * - msg (output):
+ * Produces a PMT message from the data in the edit box. It
+ * is packaged in the PMT container determined by the \p
+ * type argument to the ctor. If the data in the box is not of
+ * the correct type and the conversion fails, the block
+ * produces a log WARN message but does nothing else with
+ * the data. If the \p is_pair flag is set on this block, it
+ * will produce a PMT pair object where the key (car) is
+ * assumed to be a string and the value (cdr) is determined
+ * by \p type.
+ *
+ * - val (input):
+ * Accepts messages to update the value in the edit
+ * boxes. The messages, as PMTs, are first checked to make
+ * sure that they are the correct type (integer, float,
+ * string, or complex), and unpacks them and converts them
+ * to QStrings to display in the edit box. When using \p
+ * is_pair, the PMT is checked to make sure it is a PMT
+ * pair. Then the key (car) is extracted as a string before
+ * the value (cdr) is processed based on the set data type
+ * of the box.
+ */
+ class QTGUI_API edit_box_msg : virtual public block
+ {
+ public:
+ // gr::qtgui::edit_box_msg::sptr
+ typedef boost::shared_ptr<edit_box_msg> sptr;
+
+ /*!
+ * \brief Constructs the Edit box block.
+ *
+ * \param type the data type of data in the value box.
+ * \param value the default value of the message. This is
+ * entered as a string regardless of the type and
+ * converted internally -- much like how the block
+ * extracts the value from the edit box and converts it.
+ * \param label a label to identify the box on screen.
+ * \param is_pair if we are using a key:value pair.
+ * \param is_static sets the key edit box as a static text box
+ * (cannot be edited live).
+ * \param key Set the key used in a key:value pair message.
+ * \param parent a QWidget parent in the QT app.
+ */
+ static sptr make(gr::qtgui::data_type_t type,
+ const std::string &value="",
+ const std::string &label="",
+ bool is_pair=true,
+ bool is_static=true,
+ const std::string &key="",
+ QWidget *parent=NULL);
+
+ virtual void exec_() = 0;
+ virtual QWidget* qwidget() = 0;
+
+#ifdef ENABLE_PYTHON
+ virtual PyObject* pyqwidget() = 0;
+#else
+ virtual void* pyqwidget() = 0;
+#endif
+
+ QApplication *d_qApplication;
+ };
+
+ } /* namespace qtgui */
+} /* namespace gr */
+
+#endif /* INCLUDED_QTGUI_EDIT_BOX_MSG_H */
diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
index afb836ccf3..f2fc571acb 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_c.h
@@ -128,6 +128,7 @@ namespace gr {
virtual void set_update_time(double t) = 0;
virtual void set_title(const std::string &title) = 0;
+ virtual void set_y_label(const std::string &label, const std::string &unit) = 0;
virtual void set_line_label(int which, const std::string &label) = 0;
virtual void set_line_color(int which, const std::string &color) = 0;
virtual void set_line_width(int which, int width) = 0;
@@ -182,6 +183,7 @@ namespace gr {
virtual void clear_min_hold() = 0;
virtual void disable_legend() = 0;
virtual void reset() = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
QApplication *d_qApplication;
};
diff --git a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
index 01f3cc4ae8..f13653731d 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freq_sink_f.h
@@ -126,7 +126,9 @@ namespace gr {
virtual void set_y_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_y_label(const std::string &label, const std::string &unit) = 0;
virtual void set_line_label(int which, const std::string &label) = 0;
virtual void set_line_color(int which, const std::string &color) = 0;
virtual void set_line_width(int which, int width) = 0;
@@ -188,6 +190,7 @@ namespace gr {
virtual void clear_min_hold() = 0;
virtual void disable_legend() = 0;
virtual void reset() = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
QApplication *d_qApplication;
};
diff --git a/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h
index ce0aeedf9f..ec3ef6cfd1 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freqcontrolpanel.h
@@ -76,6 +76,7 @@ private:
QVBoxLayout *d_axes_layout;
QCheckBox *d_grid_check;
+ QCheckBox *d_axislabels_check;
QHBoxLayout *d_yrange_layout;
QLabel *d_yrange_label;
QPushButton *d_yrange_plus;
diff --git a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
index e7b95cb30e..4d8ed3e2a1 100644
--- a/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
+++ b/gr-qtgui/include/gnuradio/qtgui/freqdisplayform.h
@@ -75,6 +75,8 @@ public slots:
void setFrequencyRange(const double centerfreq,
const double bandwidth);
void setYaxis(double min, double max);
+ void setYLabel(const std::string &label,
+ const std::string &unit="");
void setYMax(const QString &m);
void setYMin(const QString &m);
void autoScale(bool en);
@@ -108,7 +110,6 @@ public slots:
void notifyTriggerLevelPlus();
void notifyTriggerLevelMinus();
-
signals:
void signalFFTSize(int size);
void signalFFTWindow(gr::filter::firdes::win_type win);
diff --git a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
index 431941a414..6e7dee005d 100644
--- a/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/histogram_sink_f.h
@@ -121,6 +121,7 @@ namespace gr {
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 void enable_axis_labels(bool en=true) = 0;
virtual void autoscalex() = 0;
virtual int nsamps() const = 0;
virtual int bins() const = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h b/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h
index e55746c48c..ae7d081013 100644
--- a/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h
+++ b/gr-qtgui/include/gnuradio/qtgui/qtgui_types.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2012 Free Software Foundation, Inc.
+ * Copyright 2012,2016 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -27,6 +27,24 @@
#include <qwt_scale_draw.h>
#include <gnuradio/high_res_timer.h>
+namespace gr {
+ namespace qtgui {
+
+ enum data_type_t {
+ INT = 0,
+ FLOAT,
+ DOUBLE,
+ COMPLEX,
+ STRING,
+ INT_VEC,
+ FLOAT_VEC,
+ DOUBLE_VEC,
+ COMPLEX_VEC,
+ };
+
+ } /* namespace qtgui */
+} /* namespace gr */
+
class FreqOffsetAndPrecisionClass
{
public:
diff --git a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h
index ed55e2ed50..efaef1cc4b 100644
--- a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h
+++ b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_b.h
@@ -131,6 +131,7 @@ namespace gr {
virtual void enable_menu(bool en) = 0;
virtual void enable_grid(bool en) = 0;
virtual void enable_autoscale(bool en) = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
virtual void reset() = 0;
QApplication *d_qApplication;
diff --git a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h
index 5610dabdda..ae2ec8d11b 100644
--- a/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/time_raster_sink_f.h
@@ -127,6 +127,7 @@ namespace gr {
virtual void enable_menu(bool en) = 0;
virtual void enable_grid(bool en) = 0;
virtual void enable_autoscale(bool en) = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
virtual void reset() = 0;
QApplication *d_qApplication;
diff --git a/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h
index 10c87c8bf2..af921afc1b 100644
--- a/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h
+++ b/gr-qtgui/include/gnuradio/qtgui/time_sink_c.h
@@ -170,6 +170,7 @@ namespace gr {
virtual void enable_semilogy(bool en=true) = 0;
virtual void enable_control_panel(bool en=true) = 0;
virtual void enable_tags(int which, bool en) = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
virtual void disable_legend() = 0;
virtual int nsamps() const = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h
index d96383c0e8..7ddca46297 100644
--- a/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/time_sink_f.h
@@ -160,6 +160,7 @@ namespace gr {
virtual void enable_semilogy(bool en=true) = 0;
virtual void enable_control_panel(bool en=true) = 0;
virtual void enable_tags(int which, bool en) = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
virtual void disable_legend() = 0;
virtual int nsamps() const = 0;
diff --git a/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h b/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h
index aabd890e6e..d7cbf5431b 100644
--- a/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h
+++ b/gr-qtgui/include/gnuradio/qtgui/timecontrolpanel.h
@@ -75,6 +75,8 @@ private:
QCheckBox *d_autoscale_check;
QCheckBox *d_grid_check;
+ QCheckBox *d_axislabels_check;
+
QPushButton *d_yoff_plus, *d_yoff_minus;
QPushButton *d_yrange_plus, *d_yrange_minus;
QPushButton *d_xmax_plus, *d_xmax_minus;
diff --git a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h
index 16fa9c5c2d..c0bdf1623b 100644
--- a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h
+++ b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_c.h
@@ -156,6 +156,7 @@ namespace gr {
virtual void enable_menu(bool en=true) = 0;
virtual void enable_grid(bool en=true) = 0;
virtual void disable_legend() = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
QApplication *d_qApplication;
};
diff --git a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h
index dff2b29d6e..d38cb2cae7 100644
--- a/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h
+++ b/gr-qtgui/include/gnuradio/qtgui/waterfall_sink_f.h
@@ -164,6 +164,7 @@ namespace gr {
virtual void enable_menu(bool en=true) = 0;
virtual void enable_grid(bool en=true) = 0;
virtual void disable_legend() = 0;
+ virtual void enable_axis_labels(bool en=true) = 0;
QApplication *d_qApplication;
};
diff --git a/gr-qtgui/lib/CMakeLists.txt b/gr-qtgui/lib/CMakeLists.txt
index 0ac5a599d0..b1ee580398 100644
--- a/gr-qtgui/lib/CMakeLists.txt
+++ b/gr-qtgui/lib/CMakeLists.txt
@@ -43,6 +43,7 @@ set(qtgui_moc_hdrs
${qtgui_mod_includedir}/ConstellationDisplayPlot.h
${qtgui_mod_includedir}/HistogramDisplayPlot.h
${qtgui_mod_includedir}/VectorDisplayPlot.h
+ edit_box_msg_impl.h
)
QT4_WRAP_CPP(qtgui_moc_sources ${qtgui_moc_hdrs})
QT4_WRAP_UI(qtgui_ui_hdrs spectrumdisplayform.ui)
@@ -99,6 +100,7 @@ set(qtgui_sources
ber_sink_b_impl.cc
vectordisplayform.cc
vector_sink_f_impl.cc
+ edit_box_msg_impl.cc
)
#Add Windows DLL resource file if using MSVC
diff --git a/gr-qtgui/lib/DisplayPlot.cc b/gr-qtgui/lib/DisplayPlot.cc
index 30fd837772..59384c88f6 100644
--- a/gr-qtgui/lib/DisplayPlot.cc
+++ b/gr-qtgui/lib/DisplayPlot.cc
@@ -443,3 +443,12 @@ DisplayPlot::onPickerPointSelected6(const QPointF & p)
//fprintf(stderr,"onPickerPointSelected %f %f\n", point.x(), point.y());
emit plotPointSelected(point);
}
+
+void
+DisplayPlot::setAxisLabels(bool en)
+{
+ enableAxis(0,en);
+ enableAxis(2,en);
+}
+
+
diff --git a/gr-qtgui/lib/FrequencyDisplayPlot.cc b/gr-qtgui/lib/FrequencyDisplayPlot.cc
index aef975d332..233c786d0a 100644
--- a/gr-qtgui/lib/FrequencyDisplayPlot.cc
+++ b/gr-qtgui/lib/FrequencyDisplayPlot.cc
@@ -97,7 +97,7 @@ FrequencyDisplayPlot::FrequencyDisplayPlot(int nplots, QWidget* parent)
d_ymax = 10;
setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
setAxisScale(QwtPlot::yLeft, d_ymin, d_ymax);
- setAxisTitle(QwtPlot::yLeft, "Power (dB)");
+ setAxisTitle(QwtPlot::yLeft, "Relative Gain (dB)");
QList<QColor> default_colors;
default_colors << QColor(Qt::blue) << QColor(Qt::red) << QColor(Qt::green)
@@ -600,6 +600,17 @@ FrequencyDisplayPlot::onPickerPointSelected6(const QPointF & p)
}
void
+FrequencyDisplayPlot::setYLabel(const std::string &label,
+ const std::string &unit)
+{
+ std::string l = label;
+ if(unit.length() > 0)
+ l += " (" + unit + ")";
+ setAxisTitle(QwtPlot::yLeft, QString(l.c_str()));
+ ((FreqDisplayZoomer*)d_zoomer)->setUnitType(unit);
+}
+
+void
FrequencyDisplayPlot::setMinFFTColor (QColor c)
{
d_min_fft_color = c;
diff --git a/gr-qtgui/lib/WaterfallDisplayPlot.cc b/gr-qtgui/lib/WaterfallDisplayPlot.cc
index 676e4077db..b16c32bf9d 100644
--- a/gr-qtgui/lib/WaterfallDisplayPlot.cc
+++ b/gr-qtgui/lib/WaterfallDisplayPlot.cc
@@ -657,8 +657,6 @@ WaterfallDisplayPlot::_updateIntensityRangeDisplay()
setAxisScale(QwtPlot::yRight, intv.minValue(), intv.maxValue());
#endif
- enableAxis(d_legend_enabled);
-
plotLayout()->setAlignCanvasToScales(true);
// Tell the display to redraw everything
diff --git a/gr-qtgui/lib/const_sink_c_impl.cc b/gr-qtgui/lib/const_sink_c_impl.cc
index 7ef8db393d..eaaf5f570a 100644
--- a/gr-qtgui/lib/const_sink_c_impl.cc
+++ b/gr-qtgui/lib/const_sink_c_impl.cc
@@ -375,6 +375,12 @@ namespace gr {
}
void
+ const_sink_c_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
const_sink_c_impl::disable_legend()
{
d_main_gui->disableLegend();
diff --git a/gr-qtgui/lib/const_sink_c_impl.h b/gr-qtgui/lib/const_sink_c_impl.h
index 7d52c3ae15..f2dcb6e73e 100644
--- a/gr-qtgui/lib/const_sink_c_impl.h
+++ b/gr-qtgui/lib/const_sink_c_impl.h
@@ -118,6 +118,7 @@ namespace gr {
void enable_menu(bool en);
void enable_autoscale(bool en);
void enable_grid(bool en);
+ void enable_axis_labels(bool en);
void disable_legend();
void reset();
diff --git a/gr-qtgui/lib/displayform.cc b/gr-qtgui/lib/displayform.cc
index 27a09512fc..13c2d8a193 100644
--- a/gr-qtgui/lib/displayform.cc
+++ b/gr-qtgui/lib/displayform.cc
@@ -29,6 +29,7 @@ DisplayForm::DisplayForm(int nplots, QWidget* parent)
: QWidget(parent), d_nplots(nplots), d_system_specified_flag(false)
{
d_isclosed = false;
+ d_axislabels = true;
// Set the initial plot size
resize(QSize(800, 600));
@@ -53,11 +54,18 @@ DisplayForm::DisplayForm(int nplots, QWidget* parent)
this, SLOT(setGrid(bool)));
d_grid_state = false;
+ d_axislabelsmenu = new QAction("Axis Labels", this);
+ d_axislabelsmenu->setCheckable(true);
+ d_axislabelsmenu->setStatusTip(tr("Toggle Axis Labels on/off"));
+ connect(d_axislabelsmenu, SIGNAL(triggered(bool)),
+ this, SLOT(setAxisLabels(bool)));
+
// Create a pop-up menu for manipulating the figure
d_menu_on = true;
d_menu = new QMenu(this);
d_menu->addAction(d_stop_act);
d_menu->addAction(d_grid_act);
+ d_menu->addAction(d_axislabelsmenu);
for(int i = 0; i < d_nplots; i++) {
d_line_title_act.push_back(new LineTitleAction(i, this));
@@ -339,6 +347,14 @@ DisplayForm::setGrid(bool on)
}
void
+DisplayForm::setAxisLabels(bool en)
+{
+ d_axislabels = en;
+ d_axislabelsmenu->setChecked(en);
+ getPlot()->setAxisLabels(d_axislabels);
+}
+
+void
DisplayForm::saveFigure()
{
QPixmap qpix = QPixmap::grabWidget(this);
diff --git a/gr-qtgui/lib/edit_box_msg_impl.cc b/gr-qtgui/lib/edit_box_msg_impl.cc
new file mode 100644
index 0000000000..e0c5f64b3d
--- /dev/null
+++ b/gr-qtgui/lib/edit_box_msg_impl.cc
@@ -0,0 +1,571 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 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 "edit_box_msg_impl.h"
+#include <gnuradio/io_signature.h>
+#include <gnuradio/prefs.h>
+#include <gnuradio/qtgui/utils.h>
+#include <boost/lexical_cast.hpp>
+
+namespace gr {
+ namespace qtgui {
+
+ edit_box_msg::sptr
+ edit_box_msg::make(data_type_t type, const std::string &label,
+ const std::string &value,
+ bool is_pair, bool is_static,
+ const std::string &key, QWidget* parent)
+ {
+ return gnuradio::get_initial_sptr
+ (new edit_box_msg_impl(type, value, label, is_pair,
+ is_static, key, parent));
+ }
+
+ edit_box_msg_impl::edit_box_msg_impl(data_type_t type, const std::string &label,
+ const std::string &value,
+ bool is_pair, bool is_static,
+ const std::string &key, QWidget* parent)
+ : block("edit_box_msg",
+ io_signature::make(0, 0, 0),
+ io_signature::make(0, 0, 0)),
+ QObject(parent)
+ {
+ // Required now for Qt; argc must be greater than 0 and argv
+ // must have at least one valid character. Must be valid through
+ // life of the qApplication:
+ // http://harmattan-dev.nokia.com/docs/library/html/qt4/qapplication.html
+ d_argc = 1;
+ d_argv = new char;
+ d_argv[0] = '\0';
+
+ if(qApp != NULL) {
+ d_qApplication = qApp;
+ }
+ else {
+#if QT_VERSION >= 0x040500
+ std::string style = prefs::singleton()->get_string("qtgui", "style", "raster");
+ QApplication::setGraphicsSystem(QString(style.c_str()));
+#endif
+ d_qApplication = new QApplication(d_argc, &d_argv);
+ }
+
+ // If a style sheet is set in the prefs file, enable it here.
+ std::string qssfile = prefs::singleton()->get_string("qtgui","qss","");
+ if(qssfile.size() > 0) {
+ QString sstext = get_qt_style_sheet(QString(qssfile.c_str()));
+ d_qApplication->setStyleSheet(sstext);
+ }
+
+ d_is_pair = is_pair;
+ d_is_static = is_static;
+
+ d_val = new QLineEdit();
+ d_val->setObjectName("qtgui_editboxmsg_val"); // used to set background color
+ d_val->setText(QString(value.c_str()));
+
+ set_type(type);
+
+ d_group = new QGroupBox();
+ d_vlayout = new QVBoxLayout(parent);
+ d_hlayout = new QHBoxLayout(parent);
+
+ if(d_is_pair) {
+ d_key = new QLineEdit();
+
+ QString key_text = QString(key.c_str());
+ d_key->setText(key_text);
+
+ // If static, we create the d_key object, which we use later
+ // to be consistent about getting the key string. But we do
+ // not add it to the layout.
+ if(d_is_static) {
+ d_key->setEnabled(false);
+
+ QFontMetrics fm = d_key->fontMetrics();
+ int width = 15 + fm.width(key_text);
+
+ d_key->setFixedWidth(width);
+
+ // Verify that a default key has been set or emit an error
+ if(key.size() == 0) {
+ throw std::runtime_error("When using static + pair mode, please set a default key.");
+ }
+ }
+ else {
+ // Adding it to the layout if in non-static mode so users
+ // can see and update the key.
+ d_hlayout->addWidget(d_key);
+ }
+ }
+
+ d_label = NULL;
+ if(label != "") {
+ d_label = new QLabel(QString(label.c_str()));
+ d_vlayout->addWidget(d_label);
+ }
+
+ d_hlayout->addWidget(d_val);
+
+ if(!d_is_static) {
+ // If not static, we can change the key and the data type of
+ // the value box.
+ d_type_box = new QComboBox();
+ d_type_box->setEditable(false);
+
+ // Items listed in order of enum data_type_t
+ d_type_box->addItem("Int");
+ d_type_box->addItem("Float");
+ d_type_box->addItem("Double");
+ d_type_box->addItem("Complex");
+ d_type_box->addItem("String");
+ d_type_box->addItem("Int (vec)");
+ d_type_box->addItem("Float (vec)");
+ d_type_box->addItem("Double (vec)");
+ d_type_box->addItem("Complex (vec)");
+ d_type_box->setCurrentIndex(d_type);
+ d_hlayout->addWidget(d_type_box);
+
+ QObject::connect(d_type_box, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(set_type(int)));
+ }
+
+ d_vlayout->addItem(d_hlayout);
+ d_group->setLayout(d_vlayout);
+
+ QObject::connect(d_val, SIGNAL(editingFinished()),
+ this, SLOT(edit_finished()));
+
+ d_msg = pmt::PMT_NIL;
+
+ message_port_register_out(pmt::mp("msg"));
+ message_port_register_in(pmt::mp("val"));
+
+ set_msg_handler(pmt::mp("val"),
+ boost::bind(&edit_box_msg_impl::set_value, this, _1));
+ }
+
+ edit_box_msg_impl::~edit_box_msg_impl()
+ {
+ delete d_argv;
+ delete d_group;
+ delete d_hlayout;
+ delete d_vlayout;
+ delete d_val;
+ if(d_is_pair)
+ delete d_key;
+ if(d_label)
+ delete d_label;
+ }
+
+ bool
+ edit_box_msg_impl::start()
+ {
+ QString text = d_val->text();
+ if(!text.isEmpty()) {
+ edit_finished();
+ }
+
+ return block::start();
+ }
+
+ void
+ edit_box_msg_impl::exec_()
+ {
+ d_qApplication->exec();
+ }
+
+ QWidget*
+ edit_box_msg_impl::qwidget()
+ {
+ return (QWidget*)d_group;
+ }
+
+#ifdef ENABLE_PYTHON
+ PyObject*
+ edit_box_msg_impl::pyqwidget()
+ {
+ PyObject *w = PyLong_FromVoidPtr((void*)d_group);
+ PyObject *retarg = Py_BuildValue("N", w);
+ return retarg;
+ }
+#else
+ void *
+ edit_box_msg_impl::pyqwidget()
+ {
+ return NULL;
+ }
+#endif
+
+ void
+ edit_box_msg_impl::set_type(int type)
+ {
+ set_type(static_cast<data_type_t>(type));
+ }
+
+ void
+ edit_box_msg_impl::set_type(gr::qtgui::data_type_t type)
+ {
+ d_type = type;
+
+ switch(d_type) {
+ case INT:
+ case INT_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #4CAF50;}");
+ break;
+ case FLOAT:
+ case FLOAT_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #F57C00;}");
+ break;
+ case DOUBLE:
+ case DOUBLE_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #00BCD4;}");
+ break;
+ case COMPLEX:
+ case COMPLEX_VEC:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #2196F3;}");
+ break;
+ case STRING:
+ d_val->setStyleSheet("QLineEdit#qtgui_editboxmsg_val {background-color: #FFFFFF; color: #000000;}");
+ break;
+ }
+ }
+
+ void
+ edit_box_msg_impl::set_value(pmt::pmt_t val)
+ {
+ // If the contents of the new value are the same as we already
+ // had, don't update anything, just exit and move on.
+ if(pmt::eqv(val, d_msg)) {
+ return;
+ }
+
+ int xi;
+ float xf;
+ double xd;
+ std::string xs;
+ gr_complex xc;
+
+ d_msg = val;
+
+ // Only update key if we're expecting a pair
+ if(d_is_pair) {
+ // If we are, make sure that the PMT is actually a pair
+ if(pmt::is_pair(val)) {
+ pmt::pmt_t key = pmt::car(val);
+ std::string skey = pmt::symbol_to_string(key);
+
+ // If static, check to make sure that the key of the
+ // incoming message matches our key. If it doesn't, emit a
+ // warning and exit without changing anything.
+ if(d_is_static) {
+ std::string cur_key = d_key->text().toStdString();
+ if(skey != cur_key) {
+ GR_LOG_WARN(d_logger, boost::format("Got key '%1%' but expected '%2%'") \
+ % skey % cur_key);
+ return;
+ }
+ }
+ val = pmt::cdr(val);
+ d_key->setText(QString(skey.c_str()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Did not find PMT pair");
+ return;
+ }
+ }
+
+ switch(d_type) {
+ case INT:
+ if(pmt::is_integer(val)) {
+ xi = pmt::to_long(val);
+ d_val->setText(QString::number(xi));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from integer failed");
+ return;
+ }
+ break;
+ case INT_VEC:
+ if(pmt::is_s32vector(val)) {
+ QStringList text_list;
+ const std::vector<int32_t> xv = pmt::s32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from integer vector failed");
+ return;
+ }
+ break;
+ case FLOAT:
+ if(pmt::is_real(val)) {
+ xf = pmt::to_float(val);
+ d_val->setText(QString::number(xf));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from float failed");
+ return;
+ }
+ break;
+ case FLOAT_VEC:
+ if(pmt::is_f32vector(val)) {
+ QStringList text_list;
+ const std::vector<float> xv = pmt::f32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from float vector failed");
+ return;
+ }
+ break;
+ case DOUBLE:
+ if(pmt::is_real(val)) {
+ xd = pmt::to_double(val);
+ d_val->setText(QString::number(xd));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from double failed");
+ return;
+ }
+ break;
+ case DOUBLE_VEC:
+ if(pmt::is_f64vector(val)) {
+ QStringList text_list;
+ const std::vector<double> xv = pmt::f64vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString::number(xv[i]));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from double vector failed");
+ return;
+ }
+ break;
+ case COMPLEX:
+ if(pmt::is_complex(val)) {
+ xc = pmt::to_complex(val);
+ d_val->setText(QString("(%1,%2)").arg(xc.real()).arg(xc.imag()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from complex failed");
+ return;
+ }
+ break;
+ case COMPLEX_VEC:
+ if(pmt::is_c32vector(val)) {
+ QStringList text_list;
+ const std::vector<gr_complex> xv = pmt::c32vector_elements(val);
+ for(size_t i = 0; i < xv.size(); i++) {
+ text_list.append(QString("(%1,%2)").arg(xv[i].real()).arg(xv[i].imag()));
+ }
+ d_val->setText(text_list.join(", "));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from complex vector failed");
+ return;
+ }
+ break;
+ case STRING:
+ if(pmt::is_symbol(val)) {
+ xs = pmt::symbol_to_string(val);
+ d_val->setText(QString(xs.c_str()));
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion from string failed");
+ return;
+ }
+ break;
+ }
+
+ // Emit the new message to pass updates downstream.
+ // Loops are prevented by the early exit if d_msg == val.
+ message_port_pub(pmt::mp("msg"), d_msg);
+ }
+
+ void
+ edit_box_msg_impl::edit_finished()
+ {
+ QString text = d_val->text();
+ bool conv_ok = true;
+ int xi;
+ float xf;
+ double xd;
+ std::string xs;
+ gr_complex xc;
+
+ switch(d_type) {
+ case INT:
+ xi = text.toInt(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_long(xi);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to integer failed");
+ return;
+ }
+ break;
+ case INT_VEC:
+ {
+ std::vector<int32_t> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ int t = s.toInt(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to integer vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_s32vector(xv.size(), xv);
+ }
+ break;
+ case FLOAT:
+ xf = text.toFloat(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_float(xf);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to float failed");
+ return;
+ }
+ break;
+ case FLOAT_VEC:
+ {
+ std::vector<float> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ float t = s.toFloat(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to float vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_f32vector(xv.size(), xv);
+ }
+ break;
+ case DOUBLE:
+ xd = text.toDouble(&conv_ok);
+ if(conv_ok) {
+ d_msg = pmt::from_double(xd);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to double failed");
+ return;
+ }
+ break;
+ case DOUBLE_VEC:
+ {
+ std::vector<double> xv;
+ QStringList text_list = text.split(",");
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ double t = s.toDouble(&conv_ok);
+ if(conv_ok) {
+ xv.push_back(t);
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to double vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_f64vector(xv.size(), xv);
+ }
+ break;
+ case COMPLEX:
+ try {
+ xc = boost::lexical_cast<gr_complex>(text.toStdString());
+ }
+ catch(boost::bad_lexical_cast const & e) {
+ GR_LOG_WARN(d_logger, boost::format("Conversion to complex failed (%1%)") \
+ % e.what());
+ return;
+ }
+ d_msg = pmt::from_complex(xc.real(), xc.imag());
+ break;
+ case COMPLEX_VEC:
+ {
+ std::vector<gr_complex> xv;
+ QStringList text_list = text.split(",");
+ bool even = false;
+ gr_complex c;
+ float re, im;
+ for(int i = 0; i < text_list.size(); ++i) {
+ QString s = text_list.at(i);
+ s = s.remove(QChar(' '));
+ s = s.remove(QChar(')'));
+ s = s.remove(QChar('('));
+ float t = s.toFloat(&conv_ok);
+ if(conv_ok) {
+ if(even) {
+ im = t;
+ xv.push_back(gr_complex(re, im));
+ even = false;
+ }
+ else {
+ re = t;
+ even = true;
+ }
+ }
+ else {
+ GR_LOG_WARN(d_logger, "Conversion to complex vector failed");
+ return;
+ }
+ }
+ d_msg = pmt::init_c32vector(xv.size(), xv);
+ }
+ break;
+ case STRING:
+ xs = text.toStdString();
+ d_msg = pmt::intern(xs);
+ break;
+ }
+
+ if(d_is_pair) {
+ std::string key = d_key->text().toStdString();
+ d_msg = pmt::cons(pmt::intern(key), d_msg);
+ }
+
+ message_port_pub(pmt::mp("msg"), d_msg);
+ }
+
+ } /* namespace qtgui */
+} /* namespace gr */
diff --git a/gr-qtgui/lib/edit_box_msg_impl.h b/gr-qtgui/lib/edit_box_msg_impl.h
new file mode 100644
index 0000000000..c60b3de9b0
--- /dev/null
+++ b/gr-qtgui/lib/edit_box_msg_impl.h
@@ -0,0 +1,93 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2016 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_EDIT_BOX_MSG_IMPL_H
+#define INCLUDED_QTGUI_EDIT_BOX_MSG_IMPL_H
+
+#include <gnuradio/qtgui/edit_box_msg.h>
+#include <QGroupBox>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QLabel>
+
+namespace gr {
+ namespace qtgui {
+
+ class QTGUI_API edit_box_msg_impl
+ : public QObject, public edit_box_msg
+ {
+ Q_OBJECT
+
+ private:
+ int d_argc;
+ char *d_argv;
+ data_type_t d_type;
+ bool d_is_pair;
+ bool d_is_static;
+
+ QGroupBox *d_group;
+ QVBoxLayout *d_vlayout;
+ QHBoxLayout *d_hlayout;
+ QLabel *d_label;
+ QLineEdit *d_val;
+ QLineEdit *d_key;
+ QComboBox *d_type_box;
+
+ pmt::pmt_t d_msg;
+
+ public:
+ edit_box_msg_impl(gr::qtgui::data_type_t type,
+ const std::string &value="",
+ const std::string &label="",
+ bool is_pair=false,
+ bool is_static=true,
+ const std::string &key="",
+ QWidget* parent=0);
+ ~edit_box_msg_impl();
+
+ // Overload the start method of gr::block to emit a message if a
+ // default value is provided.
+ bool start();
+
+ void exec_();
+ QWidget* qwidget();
+
+#ifdef ENABLE_PYTHON
+ PyObject* pyqwidget();
+#else
+ void* pyqwidget();
+#endif
+
+ void set_value(pmt::pmt_t val);
+
+ public slots:
+ void edit_finished();
+ void set_type(int);
+ void set_type(gr::qtgui::data_type_t type);
+ };
+
+ } /* namespace qtgui */
+} /* namespace gr */
+
+#endif /* INCLUDED_QTGUI_EDIT_BOX_MSG_IMPL_H */
diff --git a/gr-qtgui/lib/freq_sink_c_impl.cc b/gr-qtgui/lib/freq_sink_c_impl.cc
index 7dc0b2cf89..517786d58d 100644
--- a/gr-qtgui/lib/freq_sink_c_impl.cc
+++ b/gr-qtgui/lib/freq_sink_c_impl.cc
@@ -266,6 +266,13 @@ namespace gr {
}
void
+ freq_sink_c_impl::set_y_label(const std::string &label,
+ const std::string &unit)
+ {
+ d_main_gui->setYLabel(label, unit);
+ }
+
+ void
freq_sink_c_impl::set_update_time(double t)
{
//convert update time to ticks
@@ -407,6 +414,12 @@ namespace gr {
}
void
+ freq_sink_c_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
freq_sink_c_impl::enable_control_panel(bool en)
{
if(en)
diff --git a/gr-qtgui/lib/freq_sink_c_impl.h b/gr-qtgui/lib/freq_sink_c_impl.h
index 8da193bf29..b102209359 100644
--- a/gr-qtgui/lib/freq_sink_c_impl.h
+++ b/gr-qtgui/lib/freq_sink_c_impl.h
@@ -123,6 +123,7 @@ namespace gr {
void set_update_time(double t);
void set_title(const std::string &title);
+ void set_y_label(const std::string &label, const std::string &unit);
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);
@@ -153,6 +154,7 @@ namespace gr {
void clear_min_hold();
void disable_legend();
void reset();
+ void enable_axis_labels(bool en);
int work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-qtgui/lib/freq_sink_f_impl.cc b/gr-qtgui/lib/freq_sink_f_impl.cc
index 5418eca9ec..90624e78eb 100644
--- a/gr-qtgui/lib/freq_sink_f_impl.cc
+++ b/gr-qtgui/lib/freq_sink_f_impl.cc
@@ -265,6 +265,13 @@ namespace gr {
}
void
+ freq_sink_f_impl::set_y_label(const std::string &label,
+ const std::string &unit)
+ {
+ d_main_gui->setYLabel(label, unit);
+ }
+
+ void
freq_sink_f_impl::set_update_time(double t)
{
//convert update time to ticks
@@ -412,6 +419,12 @@ namespace gr {
}
void
+ freq_sink_f_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
freq_sink_f_impl::enable_control_panel(bool en)
{
if(en)
diff --git a/gr-qtgui/lib/freq_sink_f_impl.h b/gr-qtgui/lib/freq_sink_f_impl.h
index 39e5c92eac..85d45b3f4c 100644
--- a/gr-qtgui/lib/freq_sink_f_impl.h
+++ b/gr-qtgui/lib/freq_sink_f_impl.h
@@ -122,6 +122,7 @@ namespace gr {
void set_update_time(double t);
void set_title(const std::string &title);
+ void set_y_label(const std::string &label, const std::string &unit);
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);
@@ -153,6 +154,7 @@ namespace gr {
void clear_min_hold();
void disable_legend();
void reset();
+ void enable_axis_labels(bool en);
int work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-qtgui/lib/freqcontrolpanel.cc b/gr-qtgui/lib/freqcontrolpanel.cc
index 5840989949..9729005f50 100644
--- a/gr-qtgui/lib/freqcontrolpanel.cc
+++ b/gr-qtgui/lib/freqcontrolpanel.cc
@@ -50,6 +50,7 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form)
d_axes_layout = new QVBoxLayout;
d_grid_check = new QCheckBox("Grid");
+ d_axislabels_check = new QCheckBox("Axis Labels");
d_yrange_layout = new QHBoxLayout;
d_yrange_label = new QLabel("Y Range:");
d_yrange_plus = new QPushButton("+");
@@ -133,6 +134,7 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form)
d_trace_box->setLayout(d_trace_layout);
d_axes_layout->addWidget(d_grid_check);
+ d_axes_layout->addWidget(d_axislabels_check);
d_axes_layout->addLayout(d_yrange_layout);
d_axes_layout->addLayout(d_ymin_layout);
d_axes_layout->addWidget(d_autoscale_button);
@@ -171,6 +173,9 @@ FreqControlPanel::FreqControlPanel(FreqDisplayForm *form)
connect(d_grid_check, SIGNAL(clicked(bool)),
d_parent, SLOT(setGrid(bool)));
+ connect(d_axislabels_check, SIGNAL(clicked(bool)),
+ d_parent, SLOT(setAxisLabels(bool)));
+
connect(d_ymin_plus, SIGNAL(pressed(void)),
d_parent, SLOT(notifyYAxisPlus(void)));
connect(d_ymin_minus, SIGNAL(pressed(void)),
diff --git a/gr-qtgui/lib/freqdisplayform.cc b/gr-qtgui/lib/freqdisplayform.cc
index a51da3f35d..141df5475c 100644
--- a/gr-qtgui/lib/freqdisplayform.cc
+++ b/gr-qtgui/lib/freqdisplayform.cc
@@ -323,6 +323,12 @@ FreqDisplayForm::setYaxis(double min, double max)
getPlot()->setYaxis(min, max);
}
+void FreqDisplayForm::setYLabel(const std::string &label,
+ const std::string &unit)
+{
+ getPlot()->setYLabel(label, unit);
+}
+
void
FreqDisplayForm::setYMax(const QString &m)
{
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.cc b/gr-qtgui/lib/histogram_sink_f_impl.cc
index 0ac494d751..4a1267c129 100644
--- a/gr-qtgui/lib/histogram_sink_f_impl.cc
+++ b/gr-qtgui/lib/histogram_sink_f_impl.cc
@@ -346,6 +346,12 @@ namespace gr {
}
void
+ histogram_sink_f_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
histogram_sink_f_impl::enable_autoscale(bool en)
{
d_main_gui->autoScale(en);
diff --git a/gr-qtgui/lib/histogram_sink_f_impl.h b/gr-qtgui/lib/histogram_sink_f_impl.h
index acacf1a745..d397beeb6b 100644
--- a/gr-qtgui/lib/histogram_sink_f_impl.h
+++ b/gr-qtgui/lib/histogram_sink_f_impl.h
@@ -88,6 +88,7 @@ namespace gr {
void set_line_alpha(int which, double alpha);
void set_nsamps(const int newsize);
void set_bins(const int bins);
+ void enable_axis_labels(bool en);
std::string title();
std::string line_label(int which);
diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.cc b/gr-qtgui/lib/time_raster_sink_b_impl.cc
index 26fed4b062..c0990a9890 100644
--- a/gr-qtgui/lib/time_raster_sink_b_impl.cc
+++ b/gr-qtgui/lib/time_raster_sink_b_impl.cc
@@ -418,6 +418,12 @@ namespace gr {
}
void
+ time_raster_sink_b_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
time_raster_sink_b_impl::enable_autoscale(bool en)
{
d_main_gui->autoScale(en);
diff --git a/gr-qtgui/lib/time_raster_sink_b_impl.h b/gr-qtgui/lib/time_raster_sink_b_impl.h
index 4da6990a18..48037b5e5e 100644
--- a/gr-qtgui/lib/time_raster_sink_b_impl.h
+++ b/gr-qtgui/lib/time_raster_sink_b_impl.h
@@ -122,6 +122,7 @@ namespace gr {
void enable_menu(bool en);
void enable_grid(bool en);
void enable_autoscale(bool en);
+ void enable_axis_labels(bool en);
void reset();
int work(int noutput_items,
diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.cc b/gr-qtgui/lib/time_raster_sink_f_impl.cc
index 419d52cad6..2fb3e7db68 100644
--- a/gr-qtgui/lib/time_raster_sink_f_impl.cc
+++ b/gr-qtgui/lib/time_raster_sink_f_impl.cc
@@ -408,6 +408,12 @@ namespace gr {
}
void
+ time_raster_sink_f_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
time_raster_sink_f_impl::enable_autoscale(bool en)
{
d_main_gui->autoScale(en);
diff --git a/gr-qtgui/lib/time_raster_sink_f_impl.h b/gr-qtgui/lib/time_raster_sink_f_impl.h
index ad63e4d777..1f25dc5534 100644
--- a/gr-qtgui/lib/time_raster_sink_f_impl.h
+++ b/gr-qtgui/lib/time_raster_sink_f_impl.h
@@ -121,6 +121,7 @@ namespace gr {
void enable_menu(bool en);
void enable_grid(bool en);
void enable_autoscale(bool en);
+ void enable_axis_labels(bool en);
void reset();
int work(int noutput_items,
diff --git a/gr-qtgui/lib/time_sink_c_impl.cc b/gr-qtgui/lib/time_sink_c_impl.cc
index fff12b070a..98f603a8b0 100644
--- a/gr-qtgui/lib/time_sink_c_impl.cc
+++ b/gr-qtgui/lib/time_sink_c_impl.cc
@@ -441,10 +441,16 @@ namespace gr {
d_main_gui->setTagMenu(which, en);
}
+ void
+ time_sink_c_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
void
time_sink_c_impl::disable_legend()
{
- d_main_gui->disableLegend();
+ d_main_gui->disableLegend();
}
void
diff --git a/gr-qtgui/lib/time_sink_c_impl.h b/gr-qtgui/lib/time_sink_c_impl.h
index ce6bd94d51..ff938f8ea1 100644
--- a/gr-qtgui/lib/time_sink_c_impl.h
+++ b/gr-qtgui/lib/time_sink_c_impl.h
@@ -130,6 +130,7 @@ namespace gr {
void enable_semilogy(bool en);
void enable_control_panel(bool en);
void enable_tags(int which, bool en);
+ void enable_axis_labels(bool en);
void disable_legend();
void reset();
diff --git a/gr-qtgui/lib/time_sink_f_impl.cc b/gr-qtgui/lib/time_sink_f_impl.cc
index 579dfd9906..50a86d7dff 100644
--- a/gr-qtgui/lib/time_sink_f_impl.cc
+++ b/gr-qtgui/lib/time_sink_f_impl.cc
@@ -437,6 +437,12 @@ namespace gr {
}
void
+ time_sink_f_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
time_sink_f_impl::disable_legend()
{
d_main_gui->disableLegend();
diff --git a/gr-qtgui/lib/time_sink_f_impl.h b/gr-qtgui/lib/time_sink_f_impl.h
index 25d920c0da..a7a304aee1 100644
--- a/gr-qtgui/lib/time_sink_f_impl.h
+++ b/gr-qtgui/lib/time_sink_f_impl.h
@@ -130,6 +130,7 @@ namespace gr {
void enable_semilogy(bool en);
void enable_control_panel(bool en);
void enable_tags(int which, bool en);
+ void enable_axis_labels(bool en);
void disable_legend();
void reset();
diff --git a/gr-qtgui/lib/timecontrolpanel.cc b/gr-qtgui/lib/timecontrolpanel.cc
index 4c5a718f97..95d2cb7a1c 100644
--- a/gr-qtgui/lib/timecontrolpanel.cc
+++ b/gr-qtgui/lib/timecontrolpanel.cc
@@ -31,6 +31,8 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form)
d_axes_layout = new QVBoxLayout;
d_autoscale_check = new QCheckBox("Autoscale");
d_grid_check = new QCheckBox("Grid");
+ d_axislabels_check = new QCheckBox("Axis Labels");
+ d_axislabels_check->setChecked(true);
d_yoff_layout = new QHBoxLayout;
d_yoff_label = new QLabel("Y Offset:");
@@ -106,6 +108,7 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form)
// Set up the boxes into the layout
d_axes_layout->addWidget(d_autoscale_check);
d_axes_layout->addWidget(d_grid_check);
+ d_axes_layout->addWidget(d_axislabels_check);
d_axes_layout->addLayout(d_yoff_layout);
d_axes_layout->addLayout(d_yrange_layout);
d_axes_layout->addLayout(d_xmax_layout);
@@ -132,6 +135,8 @@ TimeControlPanel::TimeControlPanel(TimeDisplayForm *form)
d_parent, SLOT(autoScale(bool)));
connect(d_grid_check, SIGNAL(clicked(bool)),
d_parent, SLOT(setGrid(bool)));
+ connect(d_axislabels_check, SIGNAL(clicked(bool)),
+ d_parent, SLOT(setAxisLabels(bool)));
connect(d_yoff_plus, SIGNAL(pressed(void)),
d_parent, SLOT(notifyYAxisPlus(void)));
connect(d_yoff_minus, SIGNAL(pressed(void)),
diff --git a/gr-qtgui/lib/waterfall_sink_c_impl.cc b/gr-qtgui/lib/waterfall_sink_c_impl.cc
index 694ef4dac7..7395aaf2a9 100644
--- a/gr-qtgui/lib/waterfall_sink_c_impl.cc
+++ b/gr-qtgui/lib/waterfall_sink_c_impl.cc
@@ -368,6 +368,12 @@ namespace gr {
}
void
+ waterfall_sink_c_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
waterfall_sink_c_impl::disable_legend()
{
d_main_gui->disableLegend();
diff --git a/gr-qtgui/lib/waterfall_sink_c_impl.h b/gr-qtgui/lib/waterfall_sink_c_impl.h
index 3e7f9ddd2d..49766cd3dc 100644
--- a/gr-qtgui/lib/waterfall_sink_c_impl.h
+++ b/gr-qtgui/lib/waterfall_sink_c_impl.h
@@ -132,6 +132,7 @@ namespace gr {
void enable_menu(bool en);
void enable_grid(bool en);
void disable_legend();
+ void enable_axis_labels(bool en);
int work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-qtgui/lib/waterfall_sink_f_impl.cc b/gr-qtgui/lib/waterfall_sink_f_impl.cc
index 56c2061f25..b6f50de31d 100644
--- a/gr-qtgui/lib/waterfall_sink_f_impl.cc
+++ b/gr-qtgui/lib/waterfall_sink_f_impl.cc
@@ -374,6 +374,12 @@ namespace gr {
}
void
+ waterfall_sink_f_impl::enable_axis_labels(bool en)
+ {
+ d_main_gui->setAxisLabels(en);
+ }
+
+ void
waterfall_sink_f_impl::disable_legend()
{
d_main_gui->disableLegend();
diff --git a/gr-qtgui/lib/waterfall_sink_f_impl.h b/gr-qtgui/lib/waterfall_sink_f_impl.h
index e4f855c9f5..db0f4239bc 100644
--- a/gr-qtgui/lib/waterfall_sink_f_impl.h
+++ b/gr-qtgui/lib/waterfall_sink_f_impl.h
@@ -133,6 +133,7 @@ namespace gr {
void enable_menu(bool en);
void enable_grid(bool en);
void disable_legend();
+ void enable_axis_labels(bool en);
int work(int noutput_items,
gr_vector_const_void_star &input_items,
diff --git a/gr-qtgui/swig/qtgui_swig.i b/gr-qtgui/swig/qtgui_swig.i
index 9664a71786..d9595e4d66 100644
--- a/gr-qtgui/swig/qtgui_swig.i
+++ b/gr-qtgui/swig/qtgui_swig.i
@@ -37,6 +37,18 @@ namespace gr {
NUM_GRAPH_VERT,
};
+ enum data_type_t {
+ INT = 0,
+ FLOAT,
+ DOUBLE,
+ COMPLEX,
+ STRING,
+ INT_VEC,
+ FLOAT_VEC,
+ DOUBLE_VEC,
+ COMPLEX_VEC,
+ };
+
} /* namespace qtgui */
} /* namespace gr */
@@ -75,6 +87,7 @@ enum{
#include "gnuradio/qtgui/number_sink.h"
#include "gnuradio/qtgui/ber_sink_b.h"
#include "gnuradio/qtgui/vector_sink_f.h"
+#include "gnuradio/qtgui/edit_box_msg.h"
%}
%include "gnuradio/qtgui/sink_c.h"
@@ -92,6 +105,7 @@ enum{
%include "gnuradio/qtgui/number_sink.h"
%include "gnuradio/qtgui/ber_sink_b.h"
%include "gnuradio/qtgui/vector_sink_f.h"
+%include "gnuradio/qtgui/edit_box_msg.h"
GR_SWIG_BLOCK_MAGIC2(qtgui, sink_c);
GR_SWIG_BLOCK_MAGIC2(qtgui, sink_f);
@@ -108,3 +122,4 @@ GR_SWIG_BLOCK_MAGIC2(qtgui, histogram_sink_f);
GR_SWIG_BLOCK_MAGIC2(qtgui, number_sink);
GR_SWIG_BLOCK_MAGIC2(qtgui, ber_sink_b);
GR_SWIG_BLOCK_MAGIC2(qtgui, vector_sink_f);
+GR_SWIG_BLOCK_MAGIC2(qtgui, edit_box_msg);
diff --git a/gr-trellis/grc/trellis_encoder_xx.xml b/gr-trellis/grc/trellis_encoder_xx.xml
index d59903ca2d..ab7d5226e9 100644
--- a/gr-trellis/grc/trellis_encoder_xx.xml
+++ b/gr-trellis/grc/trellis_encoder_xx.xml
@@ -8,7 +8,7 @@
<block>
<name>Trellis Encoder</name>
<key>trellis_encoder_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make> trellis.encoder_$(type)(trellis.fsm($fsm_args), $init_state, $blocklength) if $blockwise else trellis.encoder_$(type)(trellis.fsm($fsm_args), $init_state) </make>
<callback>set_FSM(trellis.fsm($fsm_args))</callback>
diff --git a/gr-trellis/grc/trellis_metrics_x.xml b/gr-trellis/grc/trellis_metrics_x.xml
index 8bb978f275..15e7338098 100644
--- a/gr-trellis/grc/trellis_metrics_x.xml
+++ b/gr-trellis/grc/trellis_metrics_x.xml
@@ -9,7 +9,7 @@
<block>
<name>Trellis Metrics</name>
<key>trellis_metrics_x</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis, digital</import>
<make>trellis.metrics_$(type)($card, $dim, $table, $metric_type)</make>
<callback>set_O($card)</callback>
diff --git a/gr-trellis/grc/trellis_pccc_decoder_combined_xx.xml b/gr-trellis/grc/trellis_pccc_decoder_combined_xx.xml
index ff727fbf8b..7bb38db893 100644
--- a/gr-trellis/grc/trellis_pccc_decoder_combined_xx.xml
+++ b/gr-trellis/grc/trellis_pccc_decoder_combined_xx.xml
@@ -9,7 +9,7 @@
<block>
<name>PCCC Decoder Combo</name>
<key>trellis_pccc_decoder_combined_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis, digital</import>
<make>trellis.pccc_decoder_combined_$(type)$(out_type)(
trellis.fsm($o_fsm_args), $o_init_state, $o_final_state,
diff --git a/gr-trellis/grc/trellis_pccc_decoder_x.xml b/gr-trellis/grc/trellis_pccc_decoder_x.xml
index 81f4282728..08d1f526af 100644
--- a/gr-trellis/grc/trellis_pccc_decoder_x.xml
+++ b/gr-trellis/grc/trellis_pccc_decoder_x.xml
@@ -9,7 +9,7 @@
<block>
<name>PCCC Decoder</name>
<key>trellis_pccc_decoder_x</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.pccc_decoder_$(out_type)(
trellis.fsm($o_fsm_args), $o_init_state, $o_final_state,
diff --git a/gr-trellis/grc/trellis_pccc_encoder_xx.xml b/gr-trellis/grc/trellis_pccc_encoder_xx.xml
index faaa0c1233..85348e6e9b 100644
--- a/gr-trellis/grc/trellis_pccc_encoder_xx.xml
+++ b/gr-trellis/grc/trellis_pccc_encoder_xx.xml
@@ -8,7 +8,7 @@
<block>
<name>PCCC Encoder</name>
<key>trellis_pccc_encoder_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.pccc_encoder_$(type)(trellis.fsm($o_fsm_args), $o_init_state, trellis.fsm($i_fsm_args), $i_init_state, trellis.interleaver($interleaver_args), $bl)</make>
<param>
diff --git a/gr-trellis/grc/trellis_permutation.xml b/gr-trellis/grc/trellis_permutation.xml
index 0f118e889f..99eb2d291c 100644
--- a/gr-trellis/grc/trellis_permutation.xml
+++ b/gr-trellis/grc/trellis_permutation.xml
@@ -9,7 +9,7 @@
<block>
<name>Trellis Permutation</name>
<key>trellis_permutation</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.permutation($interleaver_size, $table, $syms_per_block, $type.size*$vlen)</make>
<callback>set_K($interleaver_size)</callback>
diff --git a/gr-trellis/grc/trellis_sccc_decoder_combined_xx.xml b/gr-trellis/grc/trellis_sccc_decoder_combined_xx.xml
index 4947376d94..79be0b8b5d 100644
--- a/gr-trellis/grc/trellis_sccc_decoder_combined_xx.xml
+++ b/gr-trellis/grc/trellis_sccc_decoder_combined_xx.xml
@@ -9,7 +9,7 @@
<block>
<name>SCCC Decoder Combo</name>
<key>trellis_sccc_decoder_combined_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis, digital</import>
<make>trellis.sccc_decoder_combined_$(type)$(out_type)(
trellis.fsm($o_fsm_args), $o_init_state, $o_final_state,
diff --git a/gr-trellis/grc/trellis_sccc_decoder_x.xml b/gr-trellis/grc/trellis_sccc_decoder_x.xml
index 38348cbb51..584ff0b0af 100644
--- a/gr-trellis/grc/trellis_sccc_decoder_x.xml
+++ b/gr-trellis/grc/trellis_sccc_decoder_x.xml
@@ -9,7 +9,7 @@
<block>
<name>SCCC Decoder</name>
<key>trellis_sccc_decoder_x</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.sccc_decoder_$(out_type)(
trellis.fsm($o_fsm_args), $o_init_state, $o_final_state,
diff --git a/gr-trellis/grc/trellis_sccc_encoder_xx.xml b/gr-trellis/grc/trellis_sccc_encoder_xx.xml
index a87db79ac2..7b4ab30c75 100644
--- a/gr-trellis/grc/trellis_sccc_encoder_xx.xml
+++ b/gr-trellis/grc/trellis_sccc_encoder_xx.xml
@@ -8,7 +8,7 @@
<block>
<name>SCCC Encoder</name>
<key>trellis_sccc_encoder_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.sccc_encoder_$(type)(trellis.fsm($o_fsm_args), $o_init_state, trellis.fsm($i_fsm_args), $i_init_state, trellis.interleaver($interleaver_args), $bl)</make>
<param>
diff --git a/gr-trellis/grc/trellis_siso_combined_f.xml b/gr-trellis/grc/trellis_siso_combined_f.xml
index 542bba6d8b..f8ec9c2d21 100644
--- a/gr-trellis/grc/trellis_siso_combined_f.xml
+++ b/gr-trellis/grc/trellis_siso_combined_f.xml
@@ -9,7 +9,7 @@
<block>
<name>SISO Combo</name>
<key>trellis_siso_combined_f</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.siso_combined_f(trellis.fsm($fsm_args), $block_size, $init_state, $final_state, $a_post_in, $a_post_out, $siso_type, $dim, $table, $metric_type)</make>
<callback>set_FSM(trellis.fsm($fsm_args))</callback>
diff --git a/gr-trellis/grc/trellis_siso_f.xml b/gr-trellis/grc/trellis_siso_f.xml
index 30849d2723..e121643e3f 100644
--- a/gr-trellis/grc/trellis_siso_f.xml
+++ b/gr-trellis/grc/trellis_siso_f.xml
@@ -9,7 +9,7 @@
<block>
<name>SISO</name>
<key>trellis_siso_f</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.siso_f(trellis.fsm($fsm_args), $block_size, $init_state, $final_state, $a_post_in, $a_post_out, $siso_type)</make>
<callback>set_FSM(trellis.fsm($fsm_args))</callback>
diff --git a/gr-trellis/grc/trellis_viterbi_combined_xx.xml b/gr-trellis/grc/trellis_viterbi_combined_xx.xml
index 9c755dc524..a52e5ed2b5 100644
--- a/gr-trellis/grc/trellis_viterbi_combined_xx.xml
+++ b/gr-trellis/grc/trellis_viterbi_combined_xx.xml
@@ -9,7 +9,7 @@
<block>
<name>Viterbi Combo</name>
<key>trellis_viterbi_combined_xx</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis, digital</import>
<make>trellis.viterbi_combined_$(type)$(out_type)(trellis.fsm($fsm_args), $block_size, $init_state, $final_state, $dim, $table, $metric_type)</make>
<callback>set_FSM(trellis.fsm($fsm_args))</callback>
diff --git a/gr-trellis/grc/trellis_viterbi_x.xml b/gr-trellis/grc/trellis_viterbi_x.xml
index 9083061e6b..21611ee51d 100644
--- a/gr-trellis/grc/trellis_viterbi_x.xml
+++ b/gr-trellis/grc/trellis_viterbi_x.xml
@@ -9,7 +9,7 @@
<block>
<name>Viterbi</name>
<key>trellis_viterbi_x</key>
- <category>Trellis Coding</category>
+ <category>[Core]/Trellis Coding</category>
<import>from gnuradio import trellis</import>
<make>trellis.viterbi_$(type)(trellis.fsm($fsm_args), $block_size, $init_state, $final_state)</make>
<callback>set_FSM(trellis.fsm($fsm_args))</callback>
diff --git a/gr-uhd/apps/uhd_app.py b/gr-uhd/apps/uhd_app.py
index 59bebe24ec..ff4412a140 100644
--- a/gr-uhd/apps/uhd_app.py
+++ b/gr-uhd/apps/uhd_app.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2015 Free Software Foundation, Inc.
+# Copyright 2015-2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -141,6 +141,9 @@ class UHDApp(object):
if args.spec:
for mb_idx in xrange(self.usrp.get_num_mboards()):
self.usrp.set_subdev_spec(args.spec, mb_idx)
+ # Set the clock source:
+ if args.clock_source is not None:
+ self.usrp.set_clock_source(args.clock_source)
# Sampling rate:
self.usrp.set_samp_rate(args.samp_rate)
self.samp_rate = self.usrp.get_samp_rate()
@@ -305,5 +308,7 @@ class UHDApp(object):
help="Show asynchronous message notifications from UHD")
group.add_argument("--sync", choices=('default', 'pps', 'auto'),
default='auto', help="Set to 'pps' to sync devices to PPS")
+ group.add_argument("--clock-source",
+ help="Set the clock source; typically 'internal', 'external' or 'gpsdo'")
return parser
diff --git a/gr-uhd/examples/python/fm_tx4.py b/gr-uhd/examples/python/fm_tx4.py
index fefa67861b..516033dae1 100755
--- a/gr-uhd/examples/python/fm_tx4.py
+++ b/gr-uhd/examples/python/fm_tx4.py
@@ -63,7 +63,8 @@ class pipeline(gr.hier_block2):
sys.exit(1)
print audio_rate, if_rate
- fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3, tau=75e-6)
+ fmtx = analog.nbfm_tx(audio_rate, if_rate, max_dev=5e3,
+ tau=75e-6, fh=0.925*if_rate/2.0)
# Local oscillator
lo = analog.sig_source_c(if_rate, # sample rate
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index fd2e77707e..e99de0d7d0 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -82,6 +82,12 @@ self.\$(id).set_antenna(\$ant$(n), $n)
self.\$(id).set_bandwidth(\$bw$(n), $n)
\#end if
#if $sourk == 'source'
+ \#if \$lo_export$(n)() and not \$hide_lo_controls()
+self.\$(id).set_lo_export_enabled(\$lo_export$(n), uhd.ALL_LOS, $n)
+ \#end if
+ \#if \$lo_source$(n)() and not \$hide_lo_controls()
+self.\$(id).set_lo_source(\$lo_source$(n), uhd.ALL_LOS, $n)
+ \#end if
\#if \$dc_offs_enb$(n)()
self.\$(id).set_auto_dc_offset(\$dc_offs_enb$(n), $n)
\#end if
@@ -101,6 +107,14 @@ self.\$(id).set_normalized_gain(\$gain$(n), $n)
self.\$(id).set_gain(\$gain$(n), $n)
\#end if
</callback>
+ <callback>\#if not \$hide_lo_controls()
+set_lo_source(\$lo_source$(n), uhd.ALL_LOS, $n)
+\#end if
+ </callback>
+ <callback>\#if not \$hide_lo_controls()
+set_lo_export_enabled(\$lo_export$(n), uhd.ALL_LOS, $n)
+\#end if
+ </callback>
<callback>set_antenna(\$ant$(n), $n)</callback>
<callback>set_bandwidth(\$bw$(n), $n)</callback>
#end for
@@ -524,6 +538,62 @@ PARAMS_TMPL = """ <param>
</param>
#if $sourk == 'source'
<param>
+ <name>Ch$(n): LO Source</name>
+ <key>lo_source$(n)</key>
+ <value>internal</value>
+ <type>string</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$hide_lo_controls()
+ all
+ \#else
+ none
+ \#end if
+ </hide>
+ <option>
+ <name>Internal</name>
+ <key>internal</key>
+ </option>
+ <option>
+ <name>External</name>
+ <key>external</key>
+ </option>
+ <option>
+ <name>Companion</name>
+ <key>companion</key>
+ </option>
+ <tab>RF Options</tab>
+ </param>
+#end if
+#if $sourk == 'source'
+ <param>
+ <name>Ch$(n): LO Export</name>
+ <key>lo_export$(n)</key>
+ <value>False</value>
+ <type>bool</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$hide_lo_controls()
+ all
+ \#else
+ none
+ \#end if
+ </hide>
+ <option>
+ <name>True</name>
+ <key>True</key>
+ </option>
+ <option>
+ <name>False</name>
+ <key>False</key>
+ </option>
+ <tab>RF Options</tab>
+ </param>
+#end if
+#if $sourk == 'source'
+ <param>
<name>Ch$(n): Enable DC Offset Correction</name>
<key>dc_offs_enb$(n)</key>
<value>""</value>
@@ -573,6 +643,25 @@ SHOW_CMD_PORT_PARAM = """
</param>
"""
+SHOW_LO_CONTROLS_PARAM = """
+ <param>
+ <name>Show LO Controls</name>
+ <key>hide_lo_controls</key>
+ <value>True</value>
+ <type>bool</type>
+ <hide>part</hide>
+ <option>
+ <name>Yes</name>
+ <key>False</key>
+ </option>
+ <option>
+ <name>No</name>
+ <key>True</key>
+ </option>
+ <tab>Advanced</tab>
+ </param>
+"""
+
TSBTAG_PARAM = """ <param>
<name>TSB tag name</name>
<key>len_tag_name</key>
@@ -605,7 +694,8 @@ if __name__ == '__main__':
else: raise Exception, 'is %s a source or sink?'%file
params = ''.join([parse_tmpl(PARAMS_TMPL, n=n, sourk=sourk) for n in range(max_num_channels)])
- params += SHOW_CMD_PORT_PARAM
+ params += SHOW_CMD_PORT_PARAM
+ params += SHOW_LO_CONTROLS_PARAM
if sourk == 'sink':
params += TSBTAG_PARAM
lentag_arg = TSBTAG_ARG
diff --git a/gr-uhd/grc/uhd_block_tree.xml b/gr-uhd/grc/uhd_block_tree.xml
index 5d3b493936..c598645526 100644
--- a/gr-uhd/grc/uhd_block_tree.xml
+++ b/gr-uhd/grc/uhd_block_tree.xml
@@ -5,7 +5,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name> <!-- Blank for Root Name -->
<cat>
<name>UHD</name>
<block>uhd_usrp_source</block>
diff --git a/gr-uhd/include/gnuradio/uhd/usrp_source.h b/gr-uhd/include/gnuradio/uhd/usrp_source.h
index 19b3feb61f..a0022b3876 100644
--- a/gr-uhd/include/gnuradio/uhd/usrp_source.h
+++ b/gr-uhd/include/gnuradio/uhd/usrp_source.h
@@ -96,10 +96,13 @@ namespace gr {
/*!
* \param device_addr the address to identify the hardware
* \param stream_args the IO format and channel specification
+ * \param issue_stream_cmd_on_start enable or disable continuous streaming when flowgraph
+ * starts (default true)
* \return a new USRP source block object
*/
static sptr make(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args);
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start = true);
/*!
* Set the start time for incoming samples.
@@ -137,6 +140,83 @@ namespace gr {
*/
virtual ::uhd::dict<std::string, std::string> get_usrp_info(size_t chan = 0) = 0;
+
+ /*!
+ * Get a list of possible LO stage names
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible LO names
+ */
+ virtual std::vector<std::string> get_lo_names(size_t chan = 0) = 0;
+
+ /*!
+ * Set the LO source for the usrp device.
+ * For usrps that support selectable LOs, this function
+ * allows switching between them.
+ * Typical options for source: internal, external.
+ * \param src a string representing the LO source
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_lo_source(const std::string &src, const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the currently set LO source.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO source
+ */
+ virtual const std::string get_lo_source(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get a list of possible LO sources.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_lo_sources(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Set whether the LO used by the usrp device is exported
+ * For usrps that support exportable LOs, this function
+ * configures if the LO used by chan is exported or not.
+ * \param enabled if true then export the LO
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1 for the source channel
+ */
+ virtual void set_lo_export_enabled(bool enabled, const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Returns true if the currently selected LO is being exported.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ */
+ virtual bool get_lo_export_enabled(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Set the RX LO frequency (Advanced).
+ * \param freq the frequency to set the LO to
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ * \return a coerced LO frequency
+ */
+ virtual double set_lo_freq(double freq, const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the current RX LO frequency (Advanced).
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO frequency
+ */
+ virtual double get_lo_freq(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the LO frequency range of the RX LO.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a frequency range object
+ */
+ virtual ::uhd::freq_range_t get_lo_freq_range(const std::string &name, size_t chan = 0) = 0;
+
/*!
* Enable/disable the automatic DC offset correction.
* The automatic correction subtracts out the long-run average.
diff --git a/gr-uhd/lib/usrp_block_impl.h b/gr-uhd/lib/usrp_block_impl.h
index cb07fb356d..a1bbf97826 100644
--- a/gr-uhd/lib/usrp_block_impl.h
+++ b/gr-uhd/lib/usrp_block_impl.h
@@ -40,6 +40,14 @@
namespace gr {
namespace uhd {
+ static const size_t ALL_MBOARDS = ::uhd::usrp::multi_usrp::ALL_MBOARDS;
+ static const size_t ALL_CHANS = ::uhd::usrp::multi_usrp::ALL_CHANS;
+ static const std::string ALL_GAINS = ::uhd::usrp::multi_usrp::ALL_GAINS;
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ static const std::string ALL_LOS = ::uhd::usrp::multi_usrp::ALL_LOS;
+#else
+ static const std::string ALL_LOS;
+#endif
class usrp_block_impl : virtual public usrp_block
{
public:
diff --git a/gr-uhd/lib/usrp_sink_impl.cc b/gr-uhd/lib/usrp_sink_impl.cc
index 666f09cbf5..8b3412b025 100644
--- a/gr-uhd/lib/usrp_sink_impl.cc
+++ b/gr-uhd/lib/usrp_sink_impl.cc
@@ -29,8 +29,6 @@
namespace gr {
namespace uhd {
- static const size_t ALL_CHANS = ::uhd::usrp::multi_usrp::ALL_CHANS;
-
usrp_sink::sptr
usrp_sink::make(const ::uhd::device_addr_t &device_addr,
const ::uhd::io_type_t &io_type,
diff --git a/gr-uhd/lib/usrp_source_impl.cc b/gr-uhd/lib/usrp_source_impl.cc
index eeb9521a5a..f0450a604d 100644
--- a/gr-uhd/lib/usrp_source_impl.cc
+++ b/gr-uhd/lib/usrp_source_impl.cc
@@ -31,6 +31,8 @@
namespace gr {
namespace uhd {
+ const pmt::pmt_t CMD_TAG_KEY = pmt::mp("tag");
+
usrp_source::sptr
usrp_source::make(const ::uhd::device_addr_t &device_addr,
const ::uhd::io_type_t &io_type,
@@ -53,20 +55,23 @@ namespace gr {
usrp_source::sptr
usrp_source::make(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args)
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start)
{
check_abi();
return usrp_source::sptr
- (new usrp_source_impl(device_addr, stream_args_ensure(stream_args)));
+ (new usrp_source_impl(device_addr, stream_args_ensure(stream_args), issue_stream_cmd_on_start));
}
usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args):
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start):
usrp_block("gr uhd usrp source",
io_signature::make(0, 0, 0),
args_to_io_sig(stream_args)),
usrp_block_impl(device_addr, stream_args, ""),
- _tag_now(false)
+ _tag_now(false),
+ _issue_stream_cmd_on_start(issue_stream_cmd_on_start)
{
std::stringstream str;
str << name() << unique_id();
@@ -77,6 +82,7 @@ namespace gr {
#ifdef GR_UHD_USE_STREAM_API
_samps_per_packet = 1;
#endif
+ register_msg_cmd_handler(CMD_TAG_KEY, boost::bind(&usrp_source_impl::_cmd_handler_tag, this, _1));
}
usrp_source_impl::~usrp_source_impl()
@@ -275,6 +281,104 @@ namespace gr {
return _dev->get_rx_bandwidth_range(chan);
}
+ std::vector<std::string>
+ usrp_source_impl::get_lo_names(size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_names(chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ const std::string
+ usrp_source_impl::get_lo_source(const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_source(name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ std::vector<std::string>
+ usrp_source_impl::get_lo_sources(const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_sources(name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ void
+ usrp_source_impl::set_lo_source(const std::string &src, const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->set_rx_lo_source(src, name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ bool
+ usrp_source_impl::get_lo_export_enabled(const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_export_enabled(name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ void
+ usrp_source_impl::set_lo_export_enabled(bool enabled, const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->set_rx_lo_export_enabled(enabled, name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ ::uhd::freq_range_t
+ usrp_source_impl::get_lo_freq_range(const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_freq_range(name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ double
+ usrp_source_impl::get_lo_freq(const std::string &name, size_t chan)
+ {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->get_rx_lo_freq(name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
+ double
+ usrp_source_impl::set_lo_freq(double freq, const std::string &name, size_t chan) {
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+ chan = _stream_args.channels[chan];
+ return _dev->set_rx_lo_freq(freq, name, chan);
+#else
+ throw std::runtime_error("not implemented in this version");
+#endif
+ }
+
void
usrp_source_impl::set_auto_dc_offset(const bool enable, size_t chan)
{
@@ -356,6 +460,12 @@ namespace gr {
}
void
+ usrp_source_impl::_cmd_handler_tag(const pmt::pmt_t &tag)
+ {
+ _tag_now = true;
+ }
+
+ void
usrp_source_impl::set_start_time(const ::uhd::time_spec_t &time)
{
_start_time = time;
@@ -382,18 +492,20 @@ namespace gr {
_samps_per_packet = _rx_stream->get_max_num_samps();
}
#endif
- //setup a stream command that starts streaming slightly in the future
- static const double reasonable_delay = 0.1; //order of magnitude over RTT
- ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- stream_cmd.stream_now = _stream_now;
- if(_start_time_set) {
- _start_time_set = false; //cleared for next run
- stream_cmd.time_spec = _start_time;
- }
- else {
- stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
+ if(_issue_stream_cmd_on_start){
+ //setup a stream command that starts streaming slightly in the future
+ static const double reasonable_delay = 0.1; //order of magnitude over RTT
+ ::uhd::stream_cmd_t stream_cmd(::uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ stream_cmd.stream_now = _stream_now;
+ if(_start_time_set) {
+ _start_time_set = false; //cleared for next run
+ stream_cmd.time_spec = _start_time;
+ }
+ else {
+ stream_cmd.time_spec = get_time_now() + ::uhd::time_spec_t(reasonable_delay);
+ }
+ this->issue_stream_cmd(stream_cmd);
}
- this->issue_stream_cmd(stream_cmd);
_tag_now = true;
return true;
}
diff --git a/gr-uhd/lib/usrp_source_impl.h b/gr-uhd/lib/usrp_source_impl.h
index 98af816c02..f6225a7e35 100644
--- a/gr-uhd/lib/usrp_source_impl.h
+++ b/gr-uhd/lib/usrp_source_impl.h
@@ -55,7 +55,8 @@ namespace gr {
{
public:
usrp_source_impl(const ::uhd::device_addr_t &device_addr,
- const ::uhd::stream_args_t &stream_args);
+ const ::uhd::stream_args_t &stream_args,
+ const bool issue_stream_cmd_on_start = true);
~usrp_source_impl();
// Get Commands
@@ -76,6 +77,12 @@ namespace gr {
::uhd::sensor_value_t get_sensor(const std::string &name, size_t chan);
std::vector<std::string> get_sensor_names(size_t chan);
::uhd::usrp::dboard_iface::sptr get_dboard_iface(size_t chan);
+ std::vector<std::string> get_lo_names(size_t chan);
+ const std::string get_lo_source(const std::string &name, size_t chan);
+ std::vector<std::string> get_lo_sources(const std::string &name, size_t chan);
+ bool get_lo_export_enabled(const std::string &name, size_t chan);
+ double get_lo_freq(const std::string &name, size_t chan);
+ ::uhd::freq_range_t get_lo_freq_range(const std::string &name, size_t chan);
// Set Commands
void set_subdev_spec(const std::string &spec, size_t mboard);
@@ -95,6 +102,9 @@ namespace gr {
void set_iq_balance(const std::complex<double> &correction, size_t chan);
void set_stream_args(const ::uhd::stream_args_t &stream_args);
void set_start_time(const ::uhd::time_spec_t &time);
+ void set_lo_source(const std::string &src, const std::string &name = ALL_LOS, size_t chan = 0);
+ void set_lo_export_enabled(bool enabled, const std::string &name = ALL_LOS, size_t chan = 0);
+ double set_lo_freq(double freq, const std::string &name, size_t chan);
void issue_stream_cmd(const ::uhd::stream_cmd_t &cmd);
void flush(void);
@@ -111,6 +121,7 @@ namespace gr {
private:
//! Like set_center_freq(), but uses _curr_freq and _curr_lo_offset
::uhd::tune_result_t _set_center_freq_from_internals(size_t chan);
+ void _cmd_handler_tag(const pmt::pmt_t &tag);
#ifdef GR_UHD_USE_STREAM_API
::uhd::rx_streamer::sptr _rx_stream;
@@ -119,6 +130,7 @@ namespace gr {
bool _tag_now;
::uhd::rx_metadata_t _metadata;
pmt::pmt_t _id;
+ bool _issue_stream_cmd_on_start;
//tag shadows
double _samp_rate;
diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i
index 108f544da3..b82d0fdae9 100644
--- a/gr-uhd/swig/uhd_swig.i
+++ b/gr-uhd/swig/uhd_swig.i
@@ -155,8 +155,20 @@ static uhd::device_addrs_t find_devices_raw(const uhd::device_addr_t &dev_addr =
////////////////////////////////////////////////////////////////////////
%{
static const size_t ALL_MBOARDS = uhd::usrp::multi_usrp::ALL_MBOARDS;
+static const size_t ALL_CHANS = uhd::usrp::multi_usrp::ALL_CHANS;
+static const std::string ALL_GAINS = uhd::usrp::multi_usrp::ALL_GAINS;
+
+#ifdef UHD_USRP_MULTI_USRP_LO_CONFIG_API
+static const std::string ALL_LOS = uhd::usrp::multi_usrp::ALL_LOS;
+#else
+static const std::string ALL_LOS;
+#endif
%}
+
static const size_t ALL_MBOARDS;
+static const size_t ALL_CHANS;
+static const std::string ALL_GAINS;
+static const std::string ALL_LOS;
%{
#include <uhd/version.hpp>
diff --git a/gr-utils/python/modtool/gr-newmod/CMakeLists.txt b/gr-utils/python/modtool/gr-newmod/CMakeLists.txt
index 9b41b99f14..bde9dc0c0f 100644
--- a/gr-utils/python/modtool/gr-newmod/CMakeLists.txt
+++ b/gr-utils/python/modtool/gr-newmod/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011,2012,2014 Free Software Foundation, Inc.
+# Copyright 2011,2012,2014,2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -24,6 +24,12 @@ cmake_minimum_required(VERSION 2.6)
project(gr-howto CXX C)
enable_testing()
+#install to PyBOMBS target prefix if defined
+if(DEFINED ENV{PYBOMBS_PREFIX})
+ set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX})
+ message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}")
+endif()
+
#select the release build type by default to get optimization flags
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
@@ -34,6 +40,12 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
#make sure our local CMake Modules path comes first
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
+# Set the version information here
+set(VERSION_INFO_MAJOR_VERSION 1)
+set(VERSION_INFO_API_COMPAT 0)
+set(VERSION_INFO_MINOR_VERSION 0)
+set(VERSION_INFO_MAINT_VERSION git)
+
########################################################################
# Compiler specific setup
########################################################################
@@ -113,6 +125,7 @@ find_package(Doxygen)
set(GR_REQUIRED_COMPONENTS RUNTIME)
find_package(Gnuradio "3.7.2" REQUIRED)
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
+include(GrVersion)
if(NOT CPPUNIT_FOUND)
message(FATAL_ERROR "CppUnit required to compile howto")
diff --git a/gr-utils/python/modtool/gr-newmod/lib/CMakeLists.txt b/gr-utils/python/modtool/gr-newmod/lib/CMakeLists.txt
index 6192c51f04..10a15b7dd9 100644
--- a/gr-utils/python/modtool/gr-newmod/lib/CMakeLists.txt
+++ b/gr-utils/python/modtool/gr-newmod/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright 2011,2012 Free Software Foundation, Inc.
+# Copyright 2011,2012,2016 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -47,11 +47,8 @@ endif(APPLE)
########################################################################
# Install built library files
########################################################################
-install(TARGETS gnuradio-howto
- LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
- ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
- RUNTIME DESTINATION bin # .dll file
-)
+include(GrMiscUtils)
+GR_LIBRARY_FOO(gnuradio-howto RUNTIME_COMPONENT "howto_runtime" DEVEL_COMPONENT "howto_devel")
########################################################################
# Build and register unit test
@@ -76,3 +73,10 @@ target_link_libraries(
)
GR_ADD_TEST(test_howto test-howto)
+
+########################################################################
+# Print summary
+########################################################################
+message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
+message(STATUS "Building for version: ${VERSION} / ${LIBVER}")
+
diff --git a/gr-utils/python/modtool/modtool_add.py b/gr-utils/python/modtool/modtool_add.py
index 77f82aaae9..b60474740c 100644
--- a/gr-utils/python/modtool/modtool_add.py
+++ b/gr-utils/python/modtool/modtool_add.py
@@ -53,6 +53,8 @@ class ModToolAdd(ModTool):
choices=self._block_types, default=None, help="One of %s." % ', '.join(self._block_types))
ogroup.add_option("--license-file", type="string", default=None,
help="File containing the license header for every source code file.")
+ ogroup.add_option("--copyright", type="string", default=None,
+ help="Name of the copyright holder (you or your company) MUST be a quoted string.")
ogroup.add_option("--argument-list", type="string", default=None,
help="The argument list for the constructor and make functions.")
ogroup.add_option("--add-python-qa", action="store_true", default=None,
@@ -77,7 +79,6 @@ class ModToolAdd(ModTool):
self._info['blocktype'] = raw_input("Enter block type: ")
if self._info['blocktype'] not in self._block_types:
print 'Must be one of ' + str(self._block_types)
-
# Allow user to specify language interactively if not set
self._info['lang'] = options.lang
if self._info['lang'] is None:
@@ -101,8 +102,14 @@ class ModToolAdd(ModTool):
raise ModToolException('Invalid block name.')
print "Block/code identifier: " + self._info['blockname']
self._info['fullblockname'] = self._info['modname'] + '_' + self._info['blockname']
+ if not options.license_file:
+ self._info['copyrightholder'] = options.copyright
+ if self._info['copyrightholder'] is None:
+ self._info['copyrightholder'] = '<+YOU OR YOUR COMPANY+>'
+ elif self._info['is_component']:
+ print "For GNU Radio components the FSF is added as copyright holder"
+ self._license_file = options.license_file
self._info['license'] = self.setup_choose_license()
-
if options.argument_list is not None:
self._info['arglist'] = options.argument_list
else:
@@ -121,7 +128,6 @@ class ModToolAdd(ModTool):
print "Warning: Autotools modules are not supported. ",
print "Files will be created, but Makefiles will not be edited."
self._skip_cmakefiles = True
- self._license_file = options.license_file
def setup_choose_license(self):
""" Select a license by the following rules, in this order:
@@ -139,7 +145,7 @@ class ModToolAdd(ModTool):
elif self._info['is_component']:
return Templates['grlicense']
else:
- return Templates['defaultlicense']
+ return get_template('defaultlicense', **self._info)
def _write_tpl(self, tpl, path, fname):
""" Shorthand for writing a substituted template to a file"""
diff --git a/gr-utils/python/modtool/templates.py b/gr-utils/python/modtool/templates.py
index dc840df392..9caf658194 100644
--- a/gr-utils/python/modtool/templates.py
+++ b/gr-utils/python/modtool/templates.py
@@ -26,7 +26,7 @@ Templates = {}
# Default licence
Templates['defaultlicense'] = '''
-Copyright %d <+YOU OR YOUR COMPANY+>.
+Copyright %d ${copyrightholder}.
This is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gr-video-sdl/grc/video_block_tree.xml b/gr-video-sdl/grc/video_block_tree.xml
index 442c68a787..f4f3e4199c 100644
--- a/gr-video-sdl/grc/video_block_tree.xml
+++ b/gr-video-sdl/grc/video_block_tree.xml
@@ -5,7 +5,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Video</name>
<block>video_sdl_sink</block>
diff --git a/gr-vocoder/grc/vocoder_block_tree.xml b/gr-vocoder/grc/vocoder_block_tree.xml
index c96a5cc687..07d8ba8fd1 100644
--- a/gr-vocoder/grc/vocoder_block_tree.xml
+++ b/gr-vocoder/grc/vocoder_block_tree.xml
@@ -27,7 +27,7 @@
###################################################
-->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Audio</name>
<block>vocoder_alaw_decode_bs</block>
diff --git a/gr-wxgui/grc/notebook.xml b/gr-wxgui/grc/notebook.xml
index 5f30c06201..1e4b0d0679 100644
--- a/gr-wxgui/grc/notebook.xml
+++ b/gr-wxgui/grc/notebook.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Notebook</name>
<key>notebook</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from grc_gnuradio import wxgui as grc_wxgui</import>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
self.$(id) = wx.Notebook($(parent).GetWin(), style=$style)
diff --git a/gr-wxgui/grc/variable_check_box.xml b/gr-wxgui/grc/variable_check_box.xml
index 75dae78215..da8bb8b8d5 100644
--- a/gr-wxgui/grc/variable_check_box.xml
+++ b/gr-wxgui/grc/variable_check_box.xml
@@ -8,7 +8,7 @@
<block>
<name>WX GUI Check Box</name>
<key>variable_check_box</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from gnuradio.wxgui import forms</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/variable_chooser.xml b/gr-wxgui/grc/variable_chooser.xml
index ef75a04337..216be01e08 100644
--- a/gr-wxgui/grc/variable_chooser.xml
+++ b/gr-wxgui/grc/variable_chooser.xml
@@ -9,7 +9,7 @@
<block>
<name>WX GUI Chooser</name>
<key>variable_chooser</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from gnuradio.wxgui import forms</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/variable_slider.xml b/gr-wxgui/grc/variable_slider.xml
index 96c0b5ec70..29f3182d0a 100644
--- a/gr-wxgui/grc/variable_slider.xml
+++ b/gr-wxgui/grc/variable_slider.xml
@@ -8,7 +8,7 @@
<block>
<name>WX GUI Slider</name>
<key>variable_slider</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from gnuradio.wxgui import forms</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/variable_static_text.xml b/gr-wxgui/grc/variable_static_text.xml
index d68b00a1dd..e47f5c3731 100644
--- a/gr-wxgui/grc/variable_static_text.xml
+++ b/gr-wxgui/grc/variable_static_text.xml
@@ -8,7 +8,7 @@
<block>
<name>WX GUI Static Text</name>
<key>variable_static_text</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from gnuradio.wxgui import forms</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/variable_text_box.xml b/gr-wxgui/grc/variable_text_box.xml
index a2cf1a8220..8c8119433a 100644
--- a/gr-wxgui/grc/variable_text_box.xml
+++ b/gr-wxgui/grc/variable_text_box.xml
@@ -8,7 +8,7 @@
<block>
<name>WX GUI Text Box</name>
<key>variable_text_box</key>
- <category>GUI Widgets/WX</category>
+ <category>[Core]/GUI Widgets/WX</category>
<import>from gnuradio.wxgui import forms</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/wxgui_constellationsink2.xml b/gr-wxgui/grc/wxgui_constellationsink2.xml
index d0314ca547..999ebbe2cf 100644
--- a/gr-wxgui/grc/wxgui_constellationsink2.xml
+++ b/gr-wxgui/grc/wxgui_constellationsink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Constellation Sink</name>
<key>wxgui_constellationsink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.wxgui import constsink_gl</import>
<import>from gnuradio import wxgui</import>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/wxgui_fftsink2.xml b/gr-wxgui/grc/wxgui_fftsink2.xml
index 5f82670ac5..11e9c7255e 100644
--- a/gr-wxgui/grc/wxgui_fftsink2.xml
+++ b/gr-wxgui/grc/wxgui_fftsink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI FFT Sink</name>
<key>wxgui_fftsink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.fft import window</import>
<import>from gnuradio.wxgui import fftsink2</import>
<import>from gnuradio import wxgui</import>
diff --git a/gr-wxgui/grc/wxgui_histosink2.xml b/gr-wxgui/grc/wxgui_histosink2.xml
index 4fc331ab8e..63bfc000ae 100644
--- a/gr-wxgui/grc/wxgui_histosink2.xml
+++ b/gr-wxgui/grc/wxgui_histosink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Histo Sink</name>
<key>wxgui_histosink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.wxgui import histosink_gl</import>
<import>from gnuradio import wxgui</import>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/wxgui_numbersink2.xml b/gr-wxgui/grc/wxgui_numbersink2.xml
index 4697164088..6f4d4a574a 100644
--- a/gr-wxgui/grc/wxgui_numbersink2.xml
+++ b/gr-wxgui/grc/wxgui_numbersink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Number Sink</name>
<key>wxgui_numbersink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.wxgui import numbersink2</import>
<import>from gnuradio import wxgui</import>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/wxgui_scopesink2.xml b/gr-wxgui/grc/wxgui_scopesink2.xml
index ea43d3a690..7e896897d6 100644
--- a/gr-wxgui/grc/wxgui_scopesink2.xml
+++ b/gr-wxgui/grc/wxgui_scopesink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Scope Sink</name>
<key>wxgui_scopesink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.wxgui import scopesink2</import>
<import>from gnuradio import wxgui</import>
<make>#set $parent = $notebook() and 'self.%s.GetPage(%s)'%$notebook() or 'self'
diff --git a/gr-wxgui/grc/wxgui_termsink.xml b/gr-wxgui/grc/wxgui_termsink.xml
index 1367f4af8a..54fedde081 100644
--- a/gr-wxgui/grc/wxgui_termsink.xml
+++ b/gr-wxgui/grc/wxgui_termsink.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Terminal Sink</name>
<key>wxgui_termsink</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.wxgui import termsink</import>
<import>from gnuradio import wxgui</import>
diff --git a/gr-wxgui/grc/wxgui_waterfallsink2.xml b/gr-wxgui/grc/wxgui_waterfallsink2.xml
index bee28f23fa..5b56f98ebe 100644
--- a/gr-wxgui/grc/wxgui_waterfallsink2.xml
+++ b/gr-wxgui/grc/wxgui_waterfallsink2.xml
@@ -7,7 +7,7 @@
<block>
<name>WX GUI Waterfall Sink</name>
<key>wxgui_waterfallsink2</key>
- <category>Instrumentation/WX</category>
+ <category>[Core]/Instrumentation/WX</category>
<import>from gnuradio.fft import window</import>
<import>from gnuradio.wxgui import waterfallsink2</import>
<import>from gnuradio import wxgui</import>
diff --git a/gr-zeromq/grc/zeromq_pub_msg_sink.xml b/gr-zeromq/grc/zeromq_pub_msg_sink.xml
index 8f541ce731..245ac37180 100644
--- a/gr-zeromq/grc/zeromq_pub_msg_sink.xml
+++ b/gr-zeromq/grc/zeromq_pub_msg_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PUB Message Sink</name>
<key>zeromq_pub_msg_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.pub_msg_sink($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_pub_sink.xml b/gr-zeromq/grc/zeromq_pub_sink.xml
index 1b2f9ec52a..af130eeb21 100644
--- a/gr-zeromq/grc/zeromq_pub_sink.xml
+++ b/gr-zeromq/grc/zeromq_pub_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PUB Sink</name>
<key>zeromq_pub_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.pub_sink($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/gr-zeromq/grc/zeromq_pull_msg_source.xml b/gr-zeromq/grc/zeromq_pull_msg_source.xml
index c0a6ca5a17..c6004d987e 100644
--- a/gr-zeromq/grc/zeromq_pull_msg_source.xml
+++ b/gr-zeromq/grc/zeromq_pull_msg_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PULL Message Source</name>
<key>zeromq_pull_msg_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.pull_msg_source($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_pull_source.xml b/gr-zeromq/grc/zeromq_pull_source.xml
index 8158b47361..f2c8b61d86 100644
--- a/gr-zeromq/grc/zeromq_pull_source.xml
+++ b/gr-zeromq/grc/zeromq_pull_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PULL Source</name>
<key>zeromq_pull_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.pull_source($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/gr-zeromq/grc/zeromq_push_msg_sink.xml b/gr-zeromq/grc/zeromq_push_msg_sink.xml
index 65626c0761..283a250064 100644
--- a/gr-zeromq/grc/zeromq_push_msg_sink.xml
+++ b/gr-zeromq/grc/zeromq_push_msg_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PUSH Message Sink</name>
<key>zeromq_push_msg_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.push_msg_sink($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_push_sink.xml b/gr-zeromq/grc/zeromq_push_sink.xml
index 528da94ee6..8277c02c22 100644
--- a/gr-zeromq/grc/zeromq_push_sink.xml
+++ b/gr-zeromq/grc/zeromq_push_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ PUSH Sink</name>
<key>zeromq_push_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.push_sink($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/gr-zeromq/grc/zeromq_rep_msg_sink.xml b/gr-zeromq/grc/zeromq_rep_msg_sink.xml
index f978f442a7..37515b39bc 100644
--- a/gr-zeromq/grc/zeromq_rep_msg_sink.xml
+++ b/gr-zeromq/grc/zeromq_rep_msg_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ REP Message Sink</name>
<key>zeromq_rep_msg_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.rep_msg_sink($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_rep_sink.xml b/gr-zeromq/grc/zeromq_rep_sink.xml
index db735a37bb..17c824156c 100644
--- a/gr-zeromq/grc/zeromq_rep_sink.xml
+++ b/gr-zeromq/grc/zeromq_rep_sink.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ REP Sink</name>
<key>zeromq_rep_sink</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.rep_sink($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/gr-zeromq/grc/zeromq_req_msg_source.xml b/gr-zeromq/grc/zeromq_req_msg_source.xml
index 3ba7488223..ae34c30dd0 100644
--- a/gr-zeromq/grc/zeromq_req_msg_source.xml
+++ b/gr-zeromq/grc/zeromq_req_msg_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ REQ Message Source</name>
<key>zeromq_req_msg_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.req_msg_source($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_req_source.xml b/gr-zeromq/grc/zeromq_req_source.xml
index 2ef224399d..0fc1aa1488 100644
--- a/gr-zeromq/grc/zeromq_req_source.xml
+++ b/gr-zeromq/grc/zeromq_req_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ REQ Source</name>
<key>zeromq_req_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.req_source($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/gr-zeromq/grc/zeromq_sub_msg_source.xml b/gr-zeromq/grc/zeromq_sub_msg_source.xml
index 32a1c9862b..475537f5fe 100644
--- a/gr-zeromq/grc/zeromq_sub_msg_source.xml
+++ b/gr-zeromq/grc/zeromq_sub_msg_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ SUB Message Source</name>
<key>zeromq_sub_msg_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.sub_msg_source($address, $timeout)</make>
diff --git a/gr-zeromq/grc/zeromq_sub_source.xml b/gr-zeromq/grc/zeromq_sub_source.xml
index 268a8938d5..31e6170c6a 100644
--- a/gr-zeromq/grc/zeromq_sub_source.xml
+++ b/gr-zeromq/grc/zeromq_sub_source.xml
@@ -2,7 +2,7 @@
<block>
<name>ZMQ SUB Source</name>
<key>zeromq_sub_source</key>
- <category>ZeroMQ Interfaces</category>
+ <category>[Core]/ZeroMQ Interfaces</category>
<import>from gnuradio import zeromq</import>
<make>zeromq.sub_source($type.itemsize, $vlen, $address, $timeout, $pass_tags, $hwm)</make>
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 859b9e9045..4c782a7f7d 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -96,8 +96,10 @@ install(
COMPONENT "grc"
)
+file(GLOB py_files "*.py")
+
GR_PYTHON_INSTALL(
- FILES __init__.py
+ FILES ${py_files}
DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc
COMPONENT "grc"
)
@@ -133,13 +135,9 @@ endif(WIN32)
########################################################################
# Add subdirectories
########################################################################
-add_subdirectory(base)
add_subdirectory(blocks)
-add_subdirectory(freedesktop)
-add_subdirectory(grc_gnuradio)
add_subdirectory(gui)
-add_subdirectory(python)
+add_subdirectory(core)
add_subdirectory(scripts)
-add_subdirectory(examples)
endif(ENABLE_GRC)
diff --git a/grc/__main__.py b/grc/__main__.py
new file mode 100644
index 0000000000..899d0195d1
--- /dev/null
+++ b/grc/__main__.py
@@ -0,0 +1,20 @@
+# Copyright 2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+from .main import main
+
+main()
diff --git a/grc/base/Block.py b/grc/base/Block.py
deleted file mode 100644
index 77c3145173..0000000000
--- a/grc/base/Block.py
+++ /dev/null
@@ -1,542 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-from . import odict
-from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB
-from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS
-from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
-from Element import Element
-
-from Cheetah.Template import Template
-from UserDict import UserDict
-from itertools import imap
-
-
-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()
-
-
-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))
-
-
-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._flags = n.find('flags') or ''
- # Backwards compatibility
- if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags:
- self._flags += BLOCK_FLAG_THROTTLE
- 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')
- self._var_value = n.find('var_value') or '$value'
-
- # get list of param tabs
- n_tabs = n.find('param_tab_order') or None
- self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB]
-
- #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 imap(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_virtual_or_pad = self._key in (
- "virtual_source", "virtual_sink", "pad_source", "pad_sink")
- is_variable = self._key.startswith('variable')
-
- # Disable blocks that are virtual/pads or variables
- if is_virtual_or_pad or is_variable:
- self._flags += BLOCK_FLAG_DISABLE_BYPASS
-
- if not (is_virtual_or_pad or is_variable or self._key == 'options'):
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({'name': 'Block Alias',
- 'key': 'alias',
- 'type': 'string',
- 'hide': 'part',
- 'tab': ADVANCED_PARAM_TAB
- })
- ))
-
- if (len(sources) or len(sinks)) and not is_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',
- 'tab': ADVANCED_PARAM_TAB
- })
- ))
- if len(sources) and not is_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',
- 'tab': ADVANCED_PARAM_TAB
- })
- ))
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({'name': 'Max Output Buffer',
- 'key': 'maxoutbuf',
- 'type': 'int',
- 'hide': 'part',
- 'value': '0',
- 'tab': ADVANCED_PARAM_TAB
- })
- ))
-
- self.get_params().append(self.get_parent().get_parent().Param(
- block=self,
- n=odict({'name': 'Comment',
- 'key': 'comment',
- 'type': '_multiline',
- 'hide': 'part',
- 'value': '',
- 'tab': ADVANCED_PARAM_TAB
- })
- ))
-
- def back_ofthe_bus(self, portlist):
- portlist.sort(key=lambda p: p._type == 'bus')
-
- def filter_bus_port(self, ports):
- buslist = [p for p in ports if p._type == 'bus']
- return buslist or ports
-
- # Main functions to get and set the block state
- # Also kept get_enabled and set_enabled to keep compatibility
- def get_state(self):
- """
- Gets the block's current state.
-
- Returns:
- ENABLED - 0
- BYPASSED - 1
- DISABLED - 2
- """
- try: return int(eval(self.get_param('_enabled').get_value()))
- except: return BLOCK_ENABLED
-
- def set_state(self, state):
- """
- Sets the state for the block.
-
- Args:
- ENABLED - 0
- BYPASSED - 1
- DISABLED - 2
- """
- if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]:
- self.get_param('_enabled').set_value(str(state))
- else:
- self.get_param('_enabled').set_value(str(BLOCK_ENABLED))
-
- # Enable/Disable Aliases
- def get_enabled(self):
- """
- Get the enabled state of the block.
-
- Returns:
- true for enabled
- """
- return not (self.get_state() == BLOCK_DISABLED)
-
- def set_enabled(self, enabled):
- """
- Set the enabled state of the block.
-
- Args:
- enabled: true for enabled
-
- Returns:
- True if block changed state
- """
- old_state = self.get_state()
- new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED
- self.set_state(new_state)
- return old_state != new_state
-
- # Block bypassing
- def get_bypassed(self):
- """
- Check if the block is bypassed
- """
- return self.get_state() == BLOCK_BYPASSED
-
- def set_bypassed(self):
- """
- Bypass the block
-
- Returns:
- True if block chagnes state
- """
- if self.get_state() != BLOCK_BYPASSED and self.can_bypass():
- self.set_state(BLOCK_BYPASSED)
- return True
- return False
-
- def can_bypass(self):
- """ Check the number of sinks and sources and see if this block can be bypassed """
- # Check to make sure this is a single path block
- # Could possibly support 1 to many blocks
- if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1:
- return False
- if not (self.get_sources()[0].get_type() == self.get_sinks()[0].get_type()):
- return False
- if self.bypass_disabled():
- return False
- return True
-
- 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 set_category(self, cat): self._category = cat
- 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
- def get_comment(self): return self.get_param('comment').get_value()
-
- def get_flags(self): return self._flags
- def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags
- def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags
-
- ##############################################
- # Access Params
- ##############################################
- def get_param_tab_labels(self): return self._param_tab_labels
- 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 as err:
- return "Template error: %s\n %s" % (tmpl, err)
-
- ##############################################
- # 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(), sorted(self.get_params(), key=str))
- 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/Constants.py b/grc/base/Constants.py
deleted file mode 100644
index 1e83de63b5..0000000000
--- a/grc/base/Constants.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""
-Copyright 2008, 2009 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import os
-
-#data files
-DATA_DIR = os.path.dirname(__file__)
-FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd')
-BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd')
-
-# file format versions:
-# 0: undefined / legacy
-# 1: non-numeric message port keys (label is used instead)
-FLOW_GRAPH_FILE_FORMAT_VERSION = 1
-
-# Param tabs
-DEFAULT_PARAM_TAB = "General"
-ADVANCED_PARAM_TAB = "Advanced"
-
-# Port domains
-DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd')
-GR_STREAM_DOMAIN = "gr_stream"
-GR_MESSAGE_DOMAIN = "gr_message"
-DEFAULT_DOMAIN = GR_STREAM_DOMAIN
-
-BLOCK_FLAG_THROTTLE = 'throttle'
-BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
-BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui'
-BLOCK_FLAG_NEED_WX_GUI = 'need_ex_gui'
-
-# Block States
-BLOCK_DISABLED = 0
-BLOCK_ENABLED = 1
-BLOCK_BYPASSED = 2
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
deleted file mode 100644
index 0398dfd011..0000000000
--- a/grc/base/FlowGraph.py
+++ /dev/null
@@ -1,484 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import time
-from operator import methodcaller
-from itertools import ifilter
-
-from .. gui import Messages
-
-from . import odict
-from .Element import Element
-from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION
-
-
-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)
- self._elements = []
- self._timestamp = time.ctime()
- #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 += 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_complexity(self):
- """
- Determines the complexity of a flowgraph
- """
- dbal = 0
- block_list = self.get_blocks()
- for block in block_list:
- # Skip options block
- if block.get_key() == 'options':
- continue
-
- # Don't worry about optional sinks?
- sink_list = filter(lambda c: not c.get_optional(), block.get_sinks())
- source_list = filter(lambda c: not c.get_optional(), block.get_sources())
- sinks = float(len(sink_list))
- sources = float(len(source_list))
- base = max(min(sinks, sources), 1)
-
- # Port ratio multiplier
- if min(sinks, sources) > 0:
- multi = sinks / sources
- multi = (1 / multi) if multi > 1 else multi
- else:
- multi = 1
-
- # Connection ratio multiplier
- sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0)
- source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0)
- dbal = dbal + (base * multi * sink_multi * source_multi)
-
- elements = float(len(self.get_elements()))
- connections = float(len(self.get_connections()))
- disabled_connections = len(filter(lambda c: not c.get_enabled(), self.get_connections()))
- blocks = float(len(block_list))
- variables = elements - blocks - connections
- enabled = float(len(self.get_enabled_blocks()))
-
- # Disabled multiplier
- if enabled > 0:
- disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05))
- else:
- disabled_multi = 1
-
- # Connection multiplier (How many connections )
- if (connections - disabled_connections) > 0:
- conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05))
- else:
- conn_multi = 1
-
- final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6)
- return final
-
- 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):
- for block in self.iter_blocks():
- if block.get_id() == id:
- return block
- raise KeyError('No block with ID {0!r}'.format(id))
-
- def iter_blocks(self):
- return ifilter(methodcaller('is_block'), self.get_elements())
-
- def get_blocks(self):
- return list(self.iter_blocks())
-
- def iter_connections(self):
- return ifilter(methodcaller('is_connection'), self.get_elements())
-
- def get_connections(self):
- return list(self.iter_connections())
-
- 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
-
- get_children = get_elements
-
- def iter_enabled_blocks(self):
- """
- Get an iterator of all blocks that are enabled and not bypassed.
- """
- return ifilter(methodcaller('get_enabled'), self.iter_blocks())
-
- def get_enabled_blocks(self):
- """
- Get a list of all blocks that are enabled and not bypassed.
-
- Returns:
- a list of blocks
- """
- return list(self.iter_enabled_blocks())
-
- def get_bypassed_blocks(self):
- """
- Get a list of all blocks that are bypassed.
-
- Returns:
- a list of blocks
- """
- return filter(methodcaller('get_bypassed'), self.iter_blocks())
-
- def get_enabled_connections(self):
- """
- Get a list of all connections that are enabled.
-
- Returns:
- a list of connections
- """
- return filter(methodcaller('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
- """
- # sort blocks and connections for nicer diffs
- blocks = sorted(self.iter_blocks(), key=lambda b: (
- b.get_key() != 'options', # options to the front
- not b.get_key().startswith('variable'), # then vars
- str(b)
- ))
- connections = sorted(self.get_connections(), key=str)
- n = odict()
- n['timestamp'] = self._timestamp
- n['block'] = [b.export_data() for b in blocks]
- n['connection'] = [c.export_data() for c in connections]
- instructions = odict({
- 'created': self.get_parent().get_version_short(),
- 'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
- })
- return odict({'flow_graph': n, '_instructions': instructions})
-
- 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
- """
- errors = False
- self._elements = list() # remove previous elements
- # set file format
- try:
- instructions = n.find('_instructions') or {}
- file_format = int(instructions.get('format', '0')) or _guess_file_format_1(n)
- except:
- file_format = 0
-
- fg_n = n and n.find('flow_graph') or odict() # use blank data if none provided
- self._timestamp = fg_n.find('timestamp') or time.ctime()
-
- # build the blocks
- self._options_block = self.get_parent().get_new_block(self, 'options')
- for block_n in fg_n.findall('block'):
- key = block_n.find('key')
- block = self._options_block if key == 'options' else self.get_new_block(key)
-
- if not block: # looks like this block key cannot be found
- # create a dummy block instead
- block = self.get_new_block('dummy_block')
- # Ugly ugly ugly
- _initialize_dummy_block(block, block_n)
- Messages.send_error_msg_load('Block key "%s" not found' % key)
-
- block.import_data(block_n)
-
- self.rewrite() # evaluate stuff like nports before adding connections
-
- # build the connections
- def verify_and_get_port(key, block, dir):
- ports = block.get_sinks() if dir == 'sink' else block.get_sources()
- for port in ports:
- if key == port.get_key():
- break
- if not key.isdigit() and port.get_type() == '' and key == port.get_name():
- break
- else:
- if block.is_dummy_block():
- port = _dummy_block_add_port(block, key, dir)
- else:
- raise LookupError('%s key %r not in %s block keys' % (dir, key, dir))
- return port
-
- for connection_n in fg_n.findall('connection'):
- # get the block ids and port keys
- source_block_id = connection_n.find('source_block_id')
- sink_block_id = connection_n.find('sink_block_id')
- source_key = connection_n.find('source_key')
- sink_key = connection_n.find('sink_key')
- try:
- source_block = self.get_block(source_block_id)
- sink_block = self.get_block(sink_block_id)
-
- # fix old, numeric message ports keys
- if file_format < 1:
- source_key, sink_key = _update_old_message_port_keys(
- source_key, sink_key, source_block, sink_block)
-
- # build the connection
- source_port = verify_and_get_port(source_key, source_block, 'source')
- sink_port = verify_and_get_port(sink_key, sink_block, 'sink')
- self.connect(source_port, sink_port)
- except LookupError as 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))
- errors = True
-
- self.rewrite() # global rewrite
- return errors
-
-
-def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block):
- """Backward compatibility for message port keys
-
- Message ports use their names as key (like in the 'connect' method).
- Flowgraph files from former versions still have numeric keys stored for
- message connections. These have to be replaced by the name of the
- respective port. The correct message port is deduced from the integer
- value of the key (assuming the order has not changed).
-
- The connection ends are updated only if both ends translate into a
- message port.
- """
- try:
- # get ports using the "old way" (assuming liner indexed keys)
- source_port = source_block.get_sources()[int(source_key)]
- sink_port = sink_block.get_sinks()[int(sink_key)]
- if source_port.get_type() == "message" and sink_port.get_type() == "message":
- source_key, sink_key = source_port.get_key(), sink_port.get_key()
- except (ValueError, IndexError):
- pass
- return source_key, sink_key # do nothing
-
-
-def _guess_file_format_1(n):
- """Try to guess the file format for flow-graph files without version tag"""
- try:
- has_non_numeric_message_keys = any(not (
- connection_n.find('source_key').isdigit() and
- connection_n.find('sink_key').isdigit()
- ) for connection_n in n.find('flow_graph').findall('connection'))
- if has_non_numeric_message_keys:
- return 1
- except:
- pass
- return 0
-
-
-def _initialize_dummy_block(block, block_n):
- """This is so ugly... dummy-fy a block
-
- Modify block object to get the behaviour for a missing block
- """
- block._key = block_n.find('key')
- block.is_dummy_block = lambda: True
- block.is_valid = lambda: False
- block.get_enabled = lambda: False
- for param_n in block_n.findall('param'):
- if param_n['key'] not in block.get_param_keys():
- new_param_n = odict({'key': param_n['key'], 'name': param_n['key'], 'type': 'string'})
- block.get_params().append(block.get_parent().get_parent().Param(block=block, n=new_param_n))
-
-
-def _dummy_block_add_port(block, key, dir):
- """This is so ugly... Add a port to a dummy-field block"""
- port_n = odict({'name': '?', 'key': key, 'type': ''})
- port = block.get_parent().get_parent().Port(block=block, n=port_n, dir=dir)
- if port.is_source():
- block.get_sources().append(port)
- else:
- block.get_sinks().append(port)
- return port
diff --git a/grc/base/Param.py b/grc/base/Param.py
deleted file mode 100644
index 34dd36e790..0000000000
--- a/grc/base/Param.py
+++ /dev/null
@@ -1,205 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-from . import odict
-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))
-
-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()
-
-class Param(Element):
-
- def __init__(self, block, n):
- """
- Make a new param from nested data.
-
- Args:
- block: the parent element
- n: the nested odict
- """
- # if the base key is a valid param key, copy its data and overlay this params data
- base_key = n.find('base_key')
- if base_key and base_key in block.get_param_keys():
- n_expanded = block.get_param(base_key)._n.copy()
- n_expanded.update(n)
- n = n_expanded
- # save odict in case this param will be base for another
- self._n = n
- # parse the data
- self._name = n.find('name')
- self._key = n.find('key')
- value = n.find('value') or ''
- self._type = n.find('type') or 'raw'
- self._hide = n.find('hide') or ''
- self._tab_label = n.find('tab') or block.get_param_tab_labels()[0]
- if not self._tab_label in block.get_param_tab_labels():
- block.get_param_tab_labels().append(self._tab_label)
- #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 ''
- self._default = value
-
- 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.get_parent().resolve_dependencies(self._name).strip()
- 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 set_default(self, value):
- if self._default == self._value:
- self.set_value(value)
- self._default = str(value)
-
- def get_type(self): return self.get_parent().resolve_dependencies(self._type)
- def get_tab_label(self): return self._tab_label
- 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/Platform.py b/grc/base/Platform.py
deleted file mode 100644
index 0cc3fcf1dd..0000000000
--- a/grc/base/Platform.py
+++ /dev/null
@@ -1,271 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import os
-import sys
-from .. base import ParseXML, odict
-from Element import Element as _Element
-from FlowGraph import FlowGraph as _FlowGraph
-from Connection import Connection as _Connection
-from Block import Block as _Block
-from Port import Port as _Port
-from Param import Param as _Param
-from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD, DOMAIN_DTD
-
-
-class Platform(_Element):
- def __init__(self, name, version, key,
- block_paths, block_dtd, default_flow_graph, generator,
- license='', website=None, colors=None):
- """
- 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
- # Save the verion string to the first
- self._version = version[0]
- self._version_major = version[1]
- self._version_api = version[2]
- self._version_minor = version[3]
- self._version_short = version[1] + "." + version[2] + "." + version[3]
-
- self._key = key
- self._license = license
- self._website = website
- self._block_paths = list(set(block_paths))
- self._block_dtd = block_dtd
- self._default_flow_graph = default_flow_graph
- self._generator = generator
- self._colors = colors or []
- #create a dummy flow graph for the blocks
- self._flow_graph = _Element(self)
-
- self._blocks = None
- self._blocks_n = None
- self._category_trees_n = None
- self._domains = dict()
- self._connection_templates = dict()
- self.load_blocks()
-
- def load_blocks(self):
- """load the blocks and block tree from the search paths"""
- # reset
- self._blocks = odict()
- self._blocks_n = odict()
- self._category_trees_n = list()
- self._domains.clear()
- self._connection_templates.clear()
- ParseXML.xml_failures.clear()
- # try to parse and load blocks
- for xml_file in self.iter_xml_files():
- try:
- if xml_file.endswith("block_tree.xml"):
- self.load_category_tree_xml(xml_file)
- elif xml_file.endswith('domain.xml'):
- self.load_domain_xml(xml_file)
- else:
- self.load_block_xml(xml_file)
- except ParseXML.XMLSyntaxError as e:
- # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
- pass
- except Exception as e:
- print >> sys.stderr, 'Warning: XML parsing failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
-
- def iter_xml_files(self):
- """Iterator for block descriptions and category trees"""
- get_path = lambda x: os.path.abspath(os.path.expanduser(x))
- for block_path in map(get_path, self._block_paths):
- if os.path.isfile(block_path):
- yield 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)):
- yield os.path.join(dirpath, filename)
-
- def load_block_xml(self, xml_file):
- """Load block description from xml file"""
- # validate and import
- ParseXML.validate_dtd(xml_file, self._block_dtd)
- n = ParseXML.from_file(xml_file).find('block')
- n['block_wrapper_path'] = xml_file # inject block wrapper path
- # get block instance and add it to the list of blocks
- block = self.Block(self._flow_graph, n)
- key = block.get_key()
- if key in self._blocks:
- print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
- else: # store the block
- self._blocks[key] = block
- self._blocks_n[key] = n
- return block
-
- def load_category_tree_xml(self, xml_file):
- """Validate and parse category tree file and add it to list"""
- ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
- n = ParseXML.from_file(xml_file).find('cat')
- self._category_trees_n.append(n)
-
- def load_domain_xml(self, xml_file):
- """Load a domain properties and connection templates from XML"""
- ParseXML.validate_dtd(xml_file, DOMAIN_DTD)
- n = ParseXML.from_file(xml_file).find('domain')
-
- key = n.find('key')
- if not key:
- print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: %s' % xml_file
- return
- if key in self.get_domains(): # test against repeated keys
- print >> sys.stderr, 'Warning: Domain with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
- return
-
- to_bool = lambda s, d: d if s is None else \
- s.lower() not in ('false', 'off', '0', '')
-
- color = n.find('color') or ''
- try:
- import gtk # ugly but handy
- gtk.gdk.color_parse(color)
- except (ValueError, ImportError):
- if color: # no color is okay, default set in GUI
- print >> sys.stderr, 'Warning: Can\'t parse color code "%s" for domain "%s" ' % (color, key)
- color = None
-
- self._domains[key] = dict(
- name=n.find('name') or key,
- multiple_sinks=to_bool(n.find('multiple_sinks'), True),
- multiple_sources=to_bool(n.find('multiple_sources'), False),
- color=color
- )
- for connection_n in n.findall('connection'):
- key = (connection_n.find('source_domain'), connection_n.find('sink_domain'))
- if not all(key):
- print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t%s' % xml_file
- elif key in self._connection_templates:
- print >> sys.stderr, 'Warning: Connection template "%s" already exists.\n\t%s' % (key, xml_file)
- else:
- self._connection_templates[key] = connection_n.find('make') or ''
-
- 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=None):
- #add this category
- parent = (parent or []) + [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 shall not be overridden by the xml tree
- if not block.get_category():
- block.set_category(parent)
-
- # recursively load the category trees and update the categories for each block
- for category_tree_n in self._category_trees_n:
- load_category(category_tree_n)
-
- #add blocks to block tree
- for block in self.get_blocks():
- #blocks with empty categories are 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_domains(self): return self._domains
- def get_domain(self, key): return self._domains.get(key)
- def get_connection_templates(self): return self._connection_templates
-
- def get_name(self): return self._name
- def get_version(self): return self._version
- def get_version_major(self): return self._version_major
- def get_version_api(self): return self._version_api
- def get_version_minor(self): return self._version_minor
- def get_version_short(self): return self._version_short
-
- 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
- def get_block_paths(self): return self._block_paths
-
- ##############################################
- # Constructors
- ##############################################
- FlowGraph = _FlowGraph
- Connection = _Connection
- Block = _Block
- Port = _Port
- Param = _Param
diff --git a/grc/base/Port.py b/grc/base/Port.py
deleted file mode 100644
index d1c35163f5..0000000000
--- a/grc/base/Port.py
+++ /dev/null
@@ -1,136 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-from Element import Element
-from . Constants import GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
-
-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'] or ''
- self._domain = n['domain']
- self._hide = n.find('hide') or ''
- self._dir = dir
- self._hide_evaluated = False # updated on rewrite()
-
- 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())
- platform = self.get_parent().get_parent().get_parent()
- if self.get_domain() not in platform.get_domains():
- self.add_error_message('Domain key "%s" is not registered.' % self.get_domain())
-
- def rewrite(self):
- """resolve dependencies in for type and hide"""
- Element.rewrite(self)
- hide = self.get_parent().resolve_dependencies(self._hide).strip().lower()
- self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide)
- # update domain if was deduced from (dynamic) port type
- type_ = self.get_type()
- if self._domain == GR_STREAM_DOMAIN and type_ == "message":
- self._domain = GR_MESSAGE_DOMAIN
- self._key = self._name
- if self._domain == GR_MESSAGE_DOMAIN and type_ != "message":
- self._domain = GR_STREAM_DOMAIN
- self._key = '0' # is rectified in rewrite()
-
- 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 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_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_domain(self): return self._domain
- def get_hide(self): return self._hide_evaluated
-
- 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_ports = self.get_parent().get_sources
- bus_structure = self.get_parent().current_bus_structure['source']
- else:
- get_ports = self.get_parent().get_sinks
- bus_structure = self.get_parent().current_bus_structure['sink']
-
- ports = [i for i in get_ports() if not i.get_type() == 'bus']
- if bus_structure:
- busses = [i for i in get_ports() 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/__init__.py b/grc/base/__init__.py
deleted file mode 100644
index 2682db8125..0000000000
--- a/grc/base/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""
-Copyright 2009 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-from odict import odict
diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml
index d07c52e9c5..3125864d4d 100644
--- a/grc/blocks/block_tree.xml
+++ b/grc/blocks/block_tree.xml
@@ -1,11 +1,6 @@
<?xml version="1.0"?>
-<!--
-###################################################
-##Block Tree for platform gnuradio python.
-###################################################
- -->
<cat>
- <name></name> <!-- Blank for Root Name -->
+ <name>[Core]</name>
<cat>
<name>Misc</name>
<block>pad_source</block>
@@ -18,29 +13,16 @@
<block>bus_structure_sink</block>
<block>bus_structure_source</block>
+ <block>epy_block</block>
+ <block>epy_module</block>
+
<block>note</block>
<block>import</block>
-
- <block>blks2_selector</block>
- <block>blks2_valve</block>
- <block>blks2_error_rate</block>
-
- <block>xmlrpc_server</block>
- <block>xmlrpc_client</block>
- </cat>
- <cat>
- <name>Networking Tools</name>
- <block>blks2_tcp_source</block>
- <block>blks2_tcp_sink</block>
- </cat>
- <cat>
- <name>Packet Operators</name>
- <block>blks2_packet_decoder</block>
- <block>blks2_packet_encoder</block>
</cat>
<cat>
<name>Variables</name>
<block>variable</block>
+ <block>variable_struct</block>
<block>variable_config</block>
<block>variable_function_probe</block>
<block>parameter</block>
diff --git a/grc/blocks/epy_block.xml b/grc/blocks/epy_block.xml
index d443d29c31..65e78c4062 100644
--- a/grc/blocks/epy_block.xml
+++ b/grc/blocks/epy_block.xml
@@ -2,7 +2,6 @@
<block>
<name>Python Block</name>
<key>epy_block</key>
- <category>Misc</category>
<import></import>
<make></make>
<param><!-- Cache the last working block IO to keep FG sane -->
@@ -25,7 +24,8 @@ be the parameters. All of them are required to have default values!
import numpy as np
from gnuradio import gr
-class blk(gr.sync_block):
+
+class blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block
"""Embedded Python Block example - a simple multiply const"""
def __init__(self, example_param=1.0): # only default arguments here
@@ -36,11 +36,13 @@ class blk(gr.sync_block):
in_sig=[np.complex64],
out_sig=[np.complex64]
)
- self.factor = example_param
+ # if an attribute with the same name as a parameter is found,
+ # a callback is registered (properties work, too).
+ self.example_param = example_param
def work(self, input_items, output_items):
"""example: multiply with constant"""
- output_items[0][:] = input_items[0] * self.factor
+ output_items[0][:] = input_items[0] * self.example_param
return len(output_items[0])
</value>
<type>_multiline_python_external</type>
diff --git a/grc/blocks/epy_module.xml b/grc/blocks/epy_module.xml
index 6d6d71804c..fa3e5f91f4 100644
--- a/grc/blocks/epy_module.xml
+++ b/grc/blocks/epy_module.xml
@@ -2,7 +2,6 @@
<block>
<name>Python Module</name>
<key>epy_module</key>
- <category>Misc</category>
<import>import $id # embedded python module</import>
<make></make>
<param>
diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml
index 937cfe82ea..1dee986c5c 100644
--- a/grc/blocks/options.xml
+++ b/grc/blocks/options.xml
@@ -84,7 +84,7 @@ else: self.stop(); self.wait()</callback>
<param>
<name>Category</name>
<key>category</key>
- <value>Custom</value>
+ <value>[GRC Hier Blocks]</value>
<type>string</type>
<hide>#if $generate_options().startswith('hb') then 'none' else 'all'#</hide>
</param>
diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml
index b022fa3d0d..8ea8871d2e 100644
--- a/grc/blocks/pad_sink.xml
+++ b/grc/blocks/pad_sink.xml
@@ -44,6 +44,11 @@
<opt>size:gr.sizeof_char</opt>
</option>
<option>
+ <name>Bits</name>
+ <key>bit</key>
+ <opt>size:gr.sizeof_char</opt>
+ </option>
+ <option>
<name>Message</name>
<key>message</key>
<opt>size:0</opt>
diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml
index c0fb19eee7..3d8ccbed6a 100644
--- a/grc/blocks/pad_source.xml
+++ b/grc/blocks/pad_source.xml
@@ -44,6 +44,11 @@
<opt>size:gr.sizeof_char</opt>
</option>
<option>
+ <name>Bits</name>
+ <key>bit</key>
+ <opt>size:gr.sizeof_char</opt>
+ </option>
+ <option>
<name>Message</name>
<key>message</key>
<opt>size:0</opt>
diff --git a/grc/blocks/variable_function_probe.xml b/grc/blocks/variable_function_probe.xml
index baa996c0ec..47c11b29fe 100644
--- a/grc/blocks/variable_function_probe.xml
+++ b/grc/blocks/variable_function_probe.xml
@@ -10,7 +10,7 @@
<import>import time</import>
<import>import threading</import>
<var_make>self.$(id) = $(id) = $value</var_make>
- <make>#slurp
+ <make>
def _$(id)_probe():
while True:
#set $obj = 'self' + ('.' + $block_id() if $block_id() else '')
@@ -22,15 +22,10 @@ def _$(id)_probe():
time.sleep(1.0 / ($poll_rate))
_$(id)_thread = threading.Thread(target=_$(id)_probe)
_$(id)_thread.daemon = True
-_$(id)_thread.start()</make>
+_$(id)_thread.start()
+ </make>
<callback>self.set_$(id)($value)</callback>
<param>
- <name>Value</name>
- <key>value</key>
- <value>0</value>
- <type>raw</type>
- </param>
- <param>
<name>Block ID</name>
<key>block_id</key>
<value>my_block_0</value>
@@ -55,6 +50,13 @@ _$(id)_thread.start()</make>
<value>10</value>
<type>real</type>
</param>
+ <param>
+ <name>Initial Value</name>
+ <key>value</key>
+ <value>0</value>
+ <type>raw</type>
+ <hide>part</hide>
+ </param>
<doc>
Periodically probe a function and set its value to this variable.
diff --git a/grc/blocks/variable_struct.xml.py b/grc/blocks/variable_struct.xml.py
index e43200828b..de4411e975 100644
--- a/grc/blocks/variable_struct.xml.py
+++ b/grc/blocks/variable_struct.xml.py
@@ -6,7 +6,6 @@ HEADER = """\
<block>
<name>Struct Variable</name>
<key>variable_struct</key>
- <category>Variables</category>
<import>def struct(data): return type('Struct', (object,), data)()</import>
<var_make>self.$id = $id = struct({{#slurp
#for $i in range({0}):
diff --git a/grc/checks.py b/grc/checks.py
new file mode 100755
index 0000000000..fd0e5de06a
--- /dev/null
+++ b/grc/checks.py
@@ -0,0 +1,80 @@
+# Copyright 2009-2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import os
+import warnings
+
+
+GR_IMPORT_ERROR_MESSAGE = """\
+Cannot import gnuradio.
+
+Is the model path environment variable set correctly?
+ All OS: PYTHONPATH
+
+Is the library path environment variable set correctly?
+ Linux: LD_LIBRARY_PATH
+ Windows: PATH
+ MacOSX: DYLD_LIBRARY_PATH
+"""
+
+
+def die(error, message):
+ msg = "{0}\n\n({1})".format(message, error)
+ try:
+ import gtk
+ d = gtk.MessageDialog(
+ type=gtk.MESSAGE_ERROR,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format=msg,
+ )
+ d.set_title(type(error).__name__)
+ d.run()
+ exit(1)
+ except ImportError:
+ exit(type(error).__name__ + '\n\n' + msg)
+
+
+def check_gtk():
+ try:
+ warnings.filterwarnings("error")
+ import pygtk
+ pygtk.require('2.0')
+ import gtk
+ gtk.init_check()
+ warnings.filterwarnings("always")
+ except Exception as err:
+ die(err, "Failed to initialize GTK. If you are running over ssh, "
+ "did you enable X forwarding and start ssh with -X?")
+
+
+def check_gnuradio_import():
+ try:
+ from gnuradio import gr
+ except ImportError as err:
+ die(err, GR_IMPORT_ERROR_MESSAGE)
+
+
+def check_blocks_path():
+ if 'GR_DONT_LOAD_PREFS' in os.environ and not os.environ.get('GRC_BLOCKS_PATH', ''):
+ die(EnvironmentError("No block definitions available"),
+ "Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH.")
+
+
+def do_all():
+ check_gnuradio_import()
+ check_gtk()
+ check_blocks_path()
diff --git a/grc/core/Block.py b/grc/core/Block.py
new file mode 100644
index 0000000000..8a683a2b6b
--- /dev/null
+++ b/grc/core/Block.py
@@ -0,0 +1,850 @@
+"""
+Copyright 2008-2015 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import collections
+import itertools
+
+from Cheetah.Template import Template
+
+from .utils import epy_block_io, odict
+from . Constants import (
+ BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI,
+ ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB,
+ BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS,
+ BLOCK_FLAG_DEPRECATED,
+ BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
+)
+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 "{}" not found in {}.'.format(key, _get_keys(lst)))
+
+
+class Block(Element):
+
+ is_block = True
+
+ 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 '').strip('\n').replace('\\\n', '')
+ 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._bus_structure_source = n.find('bus_structure_source') or ''
+ self._bus_structure_sink = n.find('bus_structure_sink') or ''
+ self.port_counters = [itertools.count(), itertools.count()]
+
+ # 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')
+ category = (n.find('category') or '').split('/')
+ self.category = [cat.strip() for cat in category if cat.strip()]
+ self._flags = n.find('flags') or ''
+ # Backwards compatibility
+ if n.find('throttle') and BLOCK_FLAG_THROTTLE not in self._flags:
+ self._flags += BLOCK_FLAG_THROTTLE
+ 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')
+ self._var_value = n.find('var_value') or '$value'
+
+ # Get list of param tabs
+ n_tabs = n.find('param_tab_order') or None
+ self._param_tab_labels = n_tabs.findall('tab') if n_tabs is not None else [DEFAULT_PARAM_TAB]
+
+ # 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 itertools.imap(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 "{}" already exists in params'.format(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 "{}" already exists in sources'.format(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 "{}" already exists in sinks'.format(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.
+ self.is_virtual_or_pad = self._key in (
+ "virtual_source", "virtual_sink", "pad_source", "pad_sink")
+ self.is_variable = self._key.startswith('variable')
+ self.is_import = (self._key == 'import')
+
+ # Disable blocks that are virtual/pads or variables
+ if self.is_virtual_or_pad or self.is_variable:
+ self._flags += BLOCK_FLAG_DISABLE_BYPASS
+
+ if not (self.is_virtual_or_pad or self.is_variable or self._key == 'options'):
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({'name': 'Block Alias',
+ 'key': 'alias',
+ 'type': 'string',
+ 'hide': 'part',
+ 'tab': ADVANCED_PARAM_TAB
+ })
+ ))
+
+ if (len(sources) or len(sinks)) and not self.is_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',
+ 'tab': ADVANCED_PARAM_TAB
+ })
+ ))
+ if len(sources) and not self.is_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',
+ 'tab': ADVANCED_PARAM_TAB
+ })
+ ))
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({'name': 'Max Output Buffer',
+ 'key': 'maxoutbuf',
+ 'type': 'int',
+ 'hide': 'part',
+ 'value': '0',
+ 'tab': ADVANCED_PARAM_TAB
+ })
+ ))
+
+ self.get_params().append(self.get_parent().get_parent().Param(
+ block=self,
+ n=odict({'name': 'Comment',
+ 'key': 'comment',
+ 'type': '_multiline',
+ 'hide': 'part',
+ 'value': '',
+ 'tab': ADVANCED_PARAM_TAB
+ })
+ ))
+
+ self._epy_source_hash = -1 # for epy blocks
+ self._epy_reload_error = None
+
+ if self._bussify_sink:
+ self.bussify({'name': 'bus', 'type': 'bus'}, 'sink')
+ if self._bussify_source:
+ self.bussify({'name': 'bus', 'type': 'bus'}, 'source')
+
+ 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 '' # TODO: Don't like empty strings. should change this to None eventually
+
+ try:
+ clean_bus_structure = self.get_parent().evaluate(bus_structure)
+ return clean_bus_structure
+ except:
+ return ''
+
+ def validate(self):
+ """
+ Validate this block.
+ Call the base class validate.
+ Evaluate the checks: each check must evaluate to True.
+ """
+ Element.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 "{}" failed.'.format(check))
+ except:
+ self.add_error_message('Check "{}" did not evaluate.'.format(check))
+
+ # For variables check the value (only if var_value is used
+ if self.is_variable and self._var_value != '$value':
+ value = self._var_value
+ try:
+ value = self.get_var_value()
+ self.get_parent().evaluate(value)
+ except Exception as err:
+ self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err))
+
+ # check if this is a GUI block and matches the selected generate option
+ current_generate_option = self.get_parent().get_option('generate_options')
+
+ def check_generate_mode(label, flag, valid_options):
+ block_requires_mode = (
+ flag in self.get_flags() or
+ self.get_name().upper().startswith(label)
+ )
+ if block_requires_mode and current_generate_option not in valid_options:
+ self.add_error_message("Can't generate this block in mode: {} ".format(
+ repr(current_generate_option)))
+
+ check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',))
+ check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui'))
+ if self._epy_reload_error:
+ self.get_param('_source_code').add_error_message(str(self._epy_reload_error))
+
+ def rewrite(self):
+ """
+ Add and remove ports to adjust for the nports.
+ """
+ Element.rewrite(self)
+ # Check and run any custom rewrite function for this block
+ getattr(self, 'rewrite_' + self._key, lambda: None)()
+
+ # Adjust nports, disconnect hidden ports
+ for ports in (self.get_sources(), self.get_sinks()):
+ for i, master_port in enumerate(ports):
+ nports = master_port.get_nports() or 1
+ num_ports = 1 + len(master_port.get_clones())
+ if master_port.get_hide():
+ for connection in master_port.get_connections():
+ self.get_parent().remove_element(connection)
+ if not nports and num_ports == 1: # Not a master port and no left-over clones
+ continue
+ # Remove excess cloned ports
+ for port in master_port.get_clones()[nports-1:]:
+ # Remove excess connections
+ for connection in port.get_connections():
+ self.get_parent().remove_element(connection)
+ master_port.remove_clone(port)
+ ports.remove(port)
+ # Add more cloned ports
+ for j in range(num_ports, nports):
+ port = master_port.add_clone()
+ ports.insert(ports.index(master_port) + j, port)
+
+ self.back_ofthe_bus(ports)
+ # Renumber non-message/message ports
+ domain_specific_port_index = collections.defaultdict(int)
+ for port in filter(lambda p: p.get_key().isdigit(), ports):
+ domain = port.get_domain()
+ port._key = str(domain_specific_port_index[domain])
+ domain_specific_port_index[domain] += 1
+
+ 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):
+ platform = self.get_parent().get_parent()
+ documentation = platform.block_docstrings.get(self._key, {})
+ from_xml = self._doc.strip()
+ if from_xml:
+ documentation[''] = from_xml
+ return documentation
+
+ def get_imports(self, raw=False):
+ """
+ Resolve all import statements.
+ Split each import statement at newlines.
+ Combine all import statements into a list.
+ Filter empty imports.
+
+ Returns:
+ a list of import statements
+ """
+ if raw:
+ return self._imports
+ return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), []))
+
+ def get_make(self, raw=False):
+ if raw:
+ return self._make
+ return self.resolve_dependencies(self._make)
+
+ def get_var_make(self):
+ return self.resolve_dependencies(self._var_make)
+
+ def get_var_value(self):
+ return self.resolve_dependencies(self._var_value)
+
+ 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.{}.{}'.format(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'
+
+ ###########################################################################
+ # Custom rewrite functions
+ ###########################################################################
+
+ def rewrite_epy_block(self):
+ flowgraph = self.get_parent()
+ platform = flowgraph.get_parent()
+ param_blk = self.get_param('_io_cache')
+ param_src = self.get_param('_source_code')
+
+ src = param_src.get_value()
+ src_hash = hash((self.get_id(), src))
+ if src_hash == self._epy_source_hash:
+ return
+
+ try:
+ blk_io = epy_block_io.extract(src)
+
+ except Exception as e:
+ self._epy_reload_error = ValueError(str(e))
+ try: # Load last working block io
+ blk_io_args = eval(param_blk.get_value())
+ if len(blk_io_args) == 6:
+ blk_io_args += ([],) # add empty callbacks
+ blk_io = epy_block_io.BlockIO(*blk_io_args)
+ except Exception:
+ return
+ else:
+ self._epy_reload_error = None # Clear previous errors
+ param_blk.set_value(repr(tuple(blk_io)))
+
+ # print "Rewriting embedded python block {!r}".format(self.get_id())
+
+ self._epy_source_hash = src_hash
+ self._name = blk_io.name or blk_io.cls
+ self._doc = blk_io.doc
+ self._imports[0] = 'import ' + self.get_id()
+ self._make = '{0}.{1}({2})'.format(self.get_id(), blk_io.cls, ', '.join(
+ '{0}=${{ {0} }}'.format(key) for key, _ in blk_io.params))
+ self._callbacks = ['{0} = ${{ {0} }}'.format(attr) for attr in blk_io.callbacks]
+
+ params = {}
+ for param in list(self._params):
+ if hasattr(param, '__epy_param__'):
+ params[param.get_key()] = param
+ self._params.remove(param)
+
+ for key, value in blk_io.params:
+ try:
+ param = params[key]
+ param.set_default(value)
+ except KeyError: # need to make a new param
+ name = key.replace('_', ' ').title()
+ n = odict(dict(name=name, key=key, type='raw', value=value))
+ param = platform.Param(block=self, n=n)
+ setattr(param, '__epy_param__', True)
+ self._params.append(param)
+
+ def update_ports(label, ports, port_specs, direction):
+ ports_to_remove = list(ports)
+ iter_ports = iter(ports)
+ ports_new = []
+ port_current = next(iter_ports, None)
+ for key, port_type in port_specs:
+ reuse_port = (
+ port_current is not None and
+ port_current.get_type() == port_type and
+ (key.isdigit() or port_current.get_key() == key)
+ )
+ if reuse_port:
+ ports_to_remove.remove(port_current)
+ port, port_current = port_current, next(iter_ports, None)
+ else:
+ n = odict(dict(name=label + str(key), type=port_type, key=key))
+ if port_type == 'message':
+ n['name'] = key
+ n['optional'] = '1'
+ port = platform.Port(block=self, n=n, dir=direction)
+ ports_new.append(port)
+ # replace old port list with new one
+ del ports[:]
+ ports.extend(ports_new)
+ # remove excess port connections
+ for port in ports_to_remove:
+ for connection in port.get_connections():
+ flowgraph.remove_element(connection)
+
+ update_ports('in', self.get_sinks(), blk_io.sinks, 'sink')
+ update_ports('out', self.get_sources(), blk_io.sources, 'source')
+ self.rewrite()
+
+ def back_ofthe_bus(self, portlist):
+ portlist.sort(key=lambda p: p._type == 'bus')
+
+ def filter_bus_port(self, ports):
+ buslist = [p for p in ports if p._type == 'bus']
+ return buslist or ports
+
+ # Main functions to get and set the block state
+ # Also kept get_enabled and set_enabled to keep compatibility
+ def get_state(self):
+ """
+ Gets the block's current state.
+
+ Returns:
+ ENABLED - 0
+ BYPASSED - 1
+ DISABLED - 2
+ """
+ try:
+ return int(eval(self.get_param('_enabled').get_value()))
+ except:
+ return BLOCK_ENABLED
+
+ def set_state(self, state):
+ """
+ Sets the state for the block.
+
+ Args:
+ ENABLED - 0
+ BYPASSED - 1
+ DISABLED - 2
+ """
+ if state in [BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED]:
+ self.get_param('_enabled').set_value(str(state))
+ else:
+ self.get_param('_enabled').set_value(str(BLOCK_ENABLED))
+
+ # Enable/Disable Aliases
+ def get_enabled(self):
+ """
+ Get the enabled state of the block.
+
+ Returns:
+ true for enabled
+ """
+ return not (self.get_state() == BLOCK_DISABLED)
+
+ def set_enabled(self, enabled):
+ """
+ Set the enabled state of the block.
+
+ Args:
+ enabled: true for enabled
+
+ Returns:
+ True if block changed state
+ """
+ old_state = self.get_state()
+ new_state = BLOCK_ENABLED if enabled else BLOCK_DISABLED
+ self.set_state(new_state)
+ return old_state != new_state
+
+ # Block bypassing
+ def get_bypassed(self):
+ """
+ Check if the block is bypassed
+ """
+ return self.get_state() == BLOCK_BYPASSED
+
+ def set_bypassed(self):
+ """
+ Bypass the block
+
+ Returns:
+ True if block chagnes state
+ """
+ if self.get_state() != BLOCK_BYPASSED and self.can_bypass():
+ self.set_state(BLOCK_BYPASSED)
+ return True
+ return False
+
+ def can_bypass(self):
+ """ Check the number of sinks and sources and see if this block can be bypassed """
+ # Check to make sure this is a single path block
+ # Could possibly support 1 to many blocks
+ if len(self.get_sources()) != 1 or len(self.get_sinks()) != 1:
+ return False
+ if not (self.get_sources()[0].get_type() == self.get_sinks()[0].get_type()):
+ return False
+ if self.bypass_disabled():
+ return False
+ return True
+
+ def __str__(self):
+ return 'Block - {} - {}({})'.format(self.get_id(), self.get_name(), self.get_key())
+
+ def get_id(self):
+ return self.get_param('id').get_value()
+
+ def get_name(self):
+ return self._name
+
+ def get_key(self):
+ return self._key
+
+ 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
+
+ def get_comment(self):
+ return self.get_param('comment').get_value()
+
+ def get_flags(self):
+ return self._flags
+
+ def throtteling(self):
+ return BLOCK_FLAG_THROTTLE in self._flags
+
+ def bypass_disabled(self):
+ return BLOCK_FLAG_DISABLE_BYPASS in self._flags
+
+ @property
+ def is_deprecated(self):
+ return BLOCK_FLAG_DEPRECATED in self._flags
+
+ ##############################################
+ # Access Params
+ ##############################################
+ def get_param_tab_labels(self):
+ return self._param_tab_labels
+
+ 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((param.get_key(), param.template_arg)
+ for param in self.get_params()) # TODO: cache that
+ try:
+ return str(Template(tmpl, n))
+ except Exception as err:
+ return "Template error: {}\n {}".format(tmpl, err)
+
+ ##############################################
+ # 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 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 ('bus' not 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(), sorted(self.get_params(), key=str))
+ 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 get_hash(self):
+ return hash(tuple(map(hash, self.get_params())))
+
+ 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
+ """
+ my_hash = 0
+ while self.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 = self.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/examples/CMakeLists.txt b/grc/core/CMakeLists.txt
index a218dbe500..51b0dacba6 100644
--- a/grc/examples/CMakeLists.txt
+++ b/grc/core/CMakeLists.txt
@@ -17,21 +17,21 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
-# SIMPLE
-install(
- FILES
- simple/variable_config.grc
- DESTINATION ${GR_PKG_DATA_DIR}/examples/grc/simple
+file(GLOB py_files "*.py")
+
+GR_PYTHON_INSTALL(
+ FILES ${py_files}
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core
COMPONENT "grc"
)
-# XMLRPC
+file(GLOB dtd_files "*.dtd")
+
install(
- FILES
- xmlrpc/readme.txt
- xmlrpc/xmlrpc_client.grc
- xmlrpc/xmlrpc_client_script.py
- xmlrpc/xmlrpc_server.grc
- DESTINATION ${GR_PKG_DATA_DIR}/examples/grc/xmlrpc
+ FILES ${dtd_files} default_flow_graph.grc
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core
COMPONENT "grc"
)
+
+add_subdirectory(generator)
+add_subdirectory(utils)
diff --git a/grc/core/Config.py b/grc/core/Config.py
new file mode 100644
index 0000000000..ac38d9978c
--- /dev/null
+++ b/grc/core/Config.py
@@ -0,0 +1,55 @@
+"""
+Copyright 2016 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import os
+from os.path import expanduser, normpath, expandvars, exists
+
+
+class Config(object):
+
+ key = 'grc'
+ name = 'GNU Radio Companion (no gui)'
+ license = __doc__.strip()
+ website = 'http://gnuradio.org'
+
+ hier_block_lib_dir = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio'))
+
+ def __init__(self, prefs_file, version, version_parts=None):
+ self.prefs = prefs_file
+ self.version = version
+ self.version_parts = version_parts or version[1:].split('-', 1)[0].split('.')[:3]
+
+ @property
+ def block_paths(self):
+ path_list_sep = {'/': ':', '\\': ';'}[os.path.sep]
+
+ paths_sources = (
+ self.hier_block_lib_dir,
+ os.environ.get('GRC_BLOCKS_PATH', ''),
+ self.prefs.get_string('grc', 'local_blocks_path', ''),
+ self.prefs.get_string('grc', 'global_blocks_path', ''),
+ )
+
+ collected_paths = sum((paths.split(path_list_sep)
+ for paths in paths_sources), [])
+
+ valid_paths = [normpath(expanduser(expandvars(path)))
+ for path in collected_paths if exists(path)]
+
+ return valid_paths
diff --git a/grc/base/Connection.py b/grc/core/Connection.py
index bf3c75277c..3aa32ef183 100644
--- a/grc/base/Connection.py
+++ b/grc/core/Connection.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008-2011 Free Software Foundation, Inc.
+Copyright 2008-2015 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,11 +17,15 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Element import Element
-from . import odict
+from . import Constants
+from .Element import Element
+from .utils import odict
+
class Connection(Element):
+ is_connection = True
+
def __init__(self, flow_graph, porta, portb):
"""
Make a new connection given the parent and 2 ports.
@@ -37,72 +41,88 @@ class Connection(Element):
"""
Element.__init__(self, flow_graph)
source = sink = None
- #separate the source and sink
+ # 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')
+ if port.is_source:
+ source = port
+ else:
+ 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')
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():
+ raise ValueError('port connections must have same cardinality')
+ # Ensure that this connection (source -> sink) is unique
+ for connection in flow_graph.connections:
if connection.get_source() is source and connection.get_sink() is sink:
raise LookupError('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();
+ sources = source.get_associated_ports()
+ sinks = sink.get_associated_ports()
for i in range(len(sources)):
try:
- flow_graph.connect(sources[i], sinks[i]);
+ flow_graph.connect(sources[i], sinks[i])
except:
pass
def __str__(self):
- return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%(
+ return 'Connection (\n\t{}\n\t\t{}\n\t{}\n\t\t{}\n)'.format(
self.get_source().get_parent(),
self.get_source(),
self.get_sink().get_parent(),
self.get_sink(),
)
- def is_connection(self): return True
+ def is_msg(self):
+ return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
+
+ 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.
+ """
+ """
+ Validate the connections.
The ports must match in type.
"""
Element.validate(self)
platform = self.get_parent().get_parent()
source_domain = self.get_source().get_domain()
sink_domain = self.get_sink().get_domain()
- if (source_domain, sink_domain) not in platform.get_connection_templates():
- self.add_error_message('No connection known for domains "%s", "%s"'
- % (source_domain, sink_domain))
+ if (source_domain, sink_domain) not in platform.connection_templates:
+ self.add_error_message('No connection known for domains "{}", "{}"'.format(
+ source_domain, sink_domain))
too_many_other_sinks = (
- source_domain in platform.get_domains() and
- not platform.get_domain(key=source_domain)['multiple_sinks'] and
+ not platform.domains.get(source_domain, []).get('multiple_sinks', False) and
len(self.get_source().get_enabled_connections()) > 1
)
too_many_other_sources = (
- sink_domain in platform.get_domains() and
- not platform.get_domain(key=sink_domain)['multiple_sources'] and
+ not platform.domains.get(sink_domain, []).get('multiple_sources', False) and
len(self.get_sink().get_enabled_connections()) > 1
)
if too_many_other_sinks:
self.add_error_message(
- 'Domain "%s" can have only one downstream block' % source_domain)
+ 'Domain "{}" can have only one downstream block'.format(source_domain))
if too_many_other_sources:
self.add_error_message(
- 'Domain "%s" can have only one upstream block' % sink_domain)
+ 'Domain "{}" can have only one upstream block'.format(sink_domain))
+
+ 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 "{}" does not match sink IO size "{}".'.format(source_size, sink_size))
def get_enabled(self):
"""
@@ -117,11 +137,14 @@ class Connection(Element):
#############################
# Access Ports
#############################
- def get_sink(self): return self._sink
- def get_source(self): return self._source
+ def get_sink(self):
+ return self._sink
+
+ def get_source(self):
+ return self._source
##############################################
- ## Import/Export Methods
+ # Import/Export Methods
##############################################
def export_data(self):
"""
diff --git a/grc/python/Constants.py b/grc/core/Constants.py
index b7a370cad7..eeb1d7f848 100644
--- a/grc/python/Constants.py
+++ b/grc/core/Constants.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008-2011 Free Software Foundation, Inc.
+Copyright 2008-2016 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -18,49 +18,55 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
import os
-from os.path import expanduser
import numpy
import stat
-from gnuradio import gr
-_gr_prefs = gr.prefs()
-
-# setup paths
-PATH_SEP = {'/': ':', '\\': ';'}[os.path.sep]
-
-HIER_BLOCKS_LIB_DIR = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio'))
-
-PREFS_FILE = os.environ.get('GRC_PREFS_PATH', expanduser('~/.gnuradio/grc.conf'))
-PREFS_FILE_OLD = os.environ.get('GRC_PREFS_PATH', expanduser('~/.grc'))
-
-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),
-) + [HIER_BLOCKS_LIB_DIR]
-
-# user settings
-XTERM_EXECUTABLE = _gr_prefs.get_string('grc', 'xterm_executable', 'xterm')
-
-# file creation modes
-TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH
-HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH
-
-# data files
+# Data files
DATA_DIR = os.path.dirname(__file__)
-FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl')
+FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd')
+BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd')
BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd')
DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc')
+DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd')
+
+# File format versions:
+# 0: undefined / legacy
+# 1: non-numeric message port keys (label is used instead)
+FLOW_GRAPH_FILE_FORMAT_VERSION = 1
+
+# Param tabs
+DEFAULT_PARAM_TAB = "General"
+ADVANCED_PARAM_TAB = "Advanced"
+DEFAULT_BLOCK_MODULE_NAME = '(no module specified)'
+
+# Port domains
+GR_STREAM_DOMAIN = "gr_stream"
+GR_MESSAGE_DOMAIN = "gr_message"
+DEFAULT_DOMAIN = GR_STREAM_DOMAIN
+
+BLOCK_FLAG_THROTTLE = 'throttle'
+BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
+BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui'
+BLOCK_FLAG_NEED_WX_GUI = 'need_wx_gui'
+BLOCK_FLAG_DEPRECATED = 'deprecated'
+
+# Block States
+BLOCK_DISABLED = 0
+BLOCK_ENABLED = 1
+BLOCK_BYPASSED = 2
+
+# File creation modes
+TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | \
+ stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH
+HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH
-#define types, native python + numpy
+# 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]
-#cast to tuple for isinstance, concat subtypes
+ 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)
INT_TYPES = tuple(INT_TYPES)
@@ -82,12 +88,12 @@ GRC_COLOR_LIME = '#CDDC39'
GRC_COLOR_TEAL = '#009688'
GRC_COLOR_YELLOW = '#FFEB3B'
GRC_COLOR_PINK = '#F50057'
-GRC_COLOR_LIGHT_PURPLE = '#E040FB'
+GRC_COLOR_PURPLE_A100 = '#EA80FC'
+GRC_COLOR_PURPLE_A400 = '#D500F9'
GRC_COLOR_DARK_GREY = '#72706F'
GRC_COLOR_GREY = '#BDBDBD'
GRC_COLOR_WHITE = '#FFFFFF'
-
CORE_TYPES = ( # name, key, sizeof, color
('Complex Float 64', 'fc64', 16, GRC_COLOR_BROWN),
('Complex Float 32', 'fc32', 8, GRC_COLOR_BLUE),
@@ -100,7 +106,8 @@ CORE_TYPES = ( # name, key, sizeof, color
('Integer 64', 's64', 8, GRC_COLOR_LIME),
('Integer 32', 's32', 4, GRC_COLOR_TEAL),
('Integer 16', 's16', 2, GRC_COLOR_YELLOW),
- ('Integer 8', 's8', 1, GRC_COLOR_LIGHT_PURPLE),
+ ('Integer 8', 's8', 1, GRC_COLOR_PURPLE_A400),
+ ('Bits (unpacked byte)', 'bit', 1, GRC_COLOR_PURPLE_A100),
('Message Queue', 'msg', 0, GRC_COLOR_DARK_GREY),
('Async Message', 'message', 0, GRC_COLOR_GREY),
('Bus Connection', 'bus', 0, GRC_COLOR_WHITE),
@@ -108,23 +115,26 @@ CORE_TYPES = ( # name, key, sizeof, color
)
ALIAS_TYPES = {
- 'complex' : (8, GRC_COLOR_BLUE),
- 'float' : (4, GRC_COLOR_ORANGE),
- 'int' : (4, GRC_COLOR_TEAL),
- 'short' : (2, GRC_COLOR_YELLOW),
- 'byte' : (1, GRC_COLOR_LIGHT_PURPLE),
+ 'complex': (8, GRC_COLOR_BLUE),
+ 'float': (4, GRC_COLOR_ORANGE),
+ 'int': (4, GRC_COLOR_TEAL),
+ 'short': (2, GRC_COLOR_YELLOW),
+ 'byte': (1, GRC_COLOR_PURPLE_A400),
+ 'bits': (1, GRC_COLOR_PURPLE_A100),
}
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
+
for key, (sizeof, color) in ALIAS_TYPES.iteritems():
TYPE_TO_COLOR[key] = color
TYPE_TO_SIZEOF[key] = sizeof
-#coloring
+# Coloring
COMPLEX_COLOR_SPEC = '#3399FF'
FLOAT_COLOR_SPEC = '#FF8C69'
INT_COLOR_SPEC = '#00FF99'
diff --git a/grc/base/Element.py b/grc/core/Element.py
index b0f94d0183..67c36e12b4 100644
--- a/grc/base/Element.py
+++ b/grc/core/Element.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008, 2009 Free Software Foundation, Inc.
+Copyright 2008, 2009, 2015 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
+
class Element(object):
def __init__(self, parent=None):
@@ -32,7 +33,8 @@ class Element(object):
Call this base method before adding error messages in the subclass.
"""
del self._error_messages[:]
- for child in self.get_children(): child.validate()
+ for child in self.get_children():
+ child.validate()
def is_valid(self):
"""
@@ -61,10 +63,10 @@ class Element(object):
Returns:
a list of error message strings
"""
- error_messages = list(self._error_messages) #make a copy
+ error_messages = list(self._error_messages) # Make a copy
for child in filter(lambda c: c.get_enabled() and not c.get_bypassed(), self.get_children()):
for msg in child.get_error_messages():
- error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
+ error_messages.append("{}:\n\t{}".format(child, msg.replace("\n", "\n\t")))
return error_messages
def rewrite(self):
@@ -72,27 +74,41 @@ class Element(object):
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()
+ for child in self.get_children():
+ child.rewrite()
+
+ def get_enabled(self):
+ return True
- def get_enabled(self): return True
- def get_bypassed(self): return False
+ def get_bypassed(self):
+ return False
##############################################
- ## Tree-like API
+ # Tree-like API
##############################################
- def get_parent(self): return self._parent
- def get_children(self): return list()
+ def get_parent(self):
+ return self._parent
+
+ def get_children(self):
+ return list()
##############################################
- ## Type testing methods
+ # Type testing
##############################################
- 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_dummy_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
+ is_platform = False
+
+ is_flow_graph = False
+
+ is_block = False
+
+ is_dummy_block = False
+
+ is_connection = False
+
+ is_port = False
+
+ is_param = False
+
+ is_variable = False
+
+ is_import = False
diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py
new file mode 100644
index 0000000000..949eecaa71
--- /dev/null
+++ b/grc/core/FlowGraph.py
@@ -0,0 +1,592 @@
+# Copyright 2008-2015 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import imp
+import time
+from itertools import ifilter, chain
+from operator import methodcaller, attrgetter
+
+import re
+
+from . import Messages
+from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION
+from .Element import Element
+from .utils import odict, expr_utils
+
+_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(Element):
+
+ is_flow_graph = True
+
+ def __init__(self, platform):
+ """
+ Make a flow graph from the arguments.
+
+ Args:
+ platform: a platforms with blocks and contrcutors
+
+ Returns:
+ the flow graph object
+ """
+ Element.__init__(self, platform)
+ self._elements = []
+ self._timestamp = time.ctime()
+
+ self.platform = platform # todo: make this a lazy prop
+ self.blocks = []
+ self.connections = []
+
+ self._eval_cache = {}
+ self.namespace = {}
+
+ self.grc_file_path = ''
+ self._options_block = self.new_block('options')
+
+ def __str__(self):
+ return 'FlowGraph - {}({})'.format(self.get_option('title'), self.get_option('id'))
+
+ ##############################################
+ # TODO: Move these to new generator package
+ ##############################################
+ def get_imports(self):
+ """
+ Get a set of all import statements in this flow graph namespace.
+
+ Returns:
+ a set of import statements
+ """
+ imports = sum([block.get_imports() for block in self.iter_enabled_blocks()], [])
+ return sorted(set(imports))
+
+ def get_variables(self):
+ """
+ Get a list of all variables in this flow graph namespace.
+ Exclude parameterized variables.
+
+ Returns:
+ a sorted list of variable blocks in order of dependency (indep -> dep)
+ """
+ variables = filter(attrgetter('is_variable'), self.iter_enabled_blocks())
+ return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('get_var_make'))
+
+ def get_parameters(self):
+ """
+ Get a list of all parameterized variables in this flow graph namespace.
+
+ Returns:
+ a list of parameterized variables
+ """
+ parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.iter_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.iter_enabled_blocks())
+ return monitors
+
+ def get_python_modules(self):
+ """Iterate over custom code block ID and Source"""
+ for block in self.iter_enabled_blocks():
+ if block.get_key() == 'epy_module':
+ yield block.get_id(), block.get_param('source_code').get_value()
+
+ def get_bussink(self):
+ bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks())
+
+ 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
+
+ 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())
+ return bussrc
+
+ def iter_enabled_blocks(self):
+ """
+ Get an iterator of all blocks that are enabled and not bypassed.
+ """
+ return ifilter(methodcaller('get_enabled'), self.blocks)
+
+ def get_enabled_blocks(self):
+ """
+ Get a list of all blocks that are enabled and not bypassed.
+
+ Returns:
+ a list of blocks
+ """
+ return list(self.iter_enabled_blocks())
+
+ def get_bypassed_blocks(self):
+ """
+ Get a list of all blocks that are bypassed.
+
+ Returns:
+ a list of blocks
+ """
+ return filter(methodcaller('get_bypassed'), self.blocks)
+
+ def get_enabled_connections(self):
+ """
+ Get a list of all connections that are enabled.
+
+ Returns:
+ a list of connections
+ """
+ return filter(methodcaller('get_enabled'), self.connections)
+
+ 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()
+
+ ##############################################
+ # Access Elements
+ ##############################################
+ def get_block(self, id):
+ for block in self.blocks:
+ if block.get_id() == id:
+ return block
+ raise KeyError('No block with ID {!r}'.format(id))
+
+ 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.blocks.count(self._options_block)
+ if not options_block_count:
+ self.blocks.append(self._options_block)
+ for i in range(options_block_count-1):
+ self.blocks.remove(self._options_block)
+
+ return self.blocks + self.connections
+
+ get_children = get_elements
+
+ def rewrite(self):
+ """
+ Flag the namespace to be renewed.
+ """
+
+ self.renew_namespace()
+ for child in chain(self.blocks, self.connections):
+ child.rewrite()
+
+ self.bus_ports_rewrite()
+
+ def renew_namespace(self):
+ namespace = {}
+ # Load imports
+ for expr in self.get_imports():
+ try:
+ exec expr in namespace
+ except:
+ pass
+
+ for id, expr in self.get_python_modules():
+ try:
+ module = imp.new_module(id)
+ exec expr in module.__dict__
+ namespace[id] = module
+ except:
+ pass
+
+ # Load parameters
+ np = {} # params don't know each other
+ for parameter in self.get_parameters():
+ try:
+ value = eval(parameter.get_param('value').to_code(), namespace)
+ np[parameter.get_id()] = value
+ except:
+ pass
+ namespace.update(np) # Merge param namespace
+
+ # Load variables
+ for variable in self.get_variables():
+ try:
+ value = eval(variable.get_var_value(), namespace)
+ namespace[variable.get_id()] = value
+ except:
+ pass
+
+ self.namespace.clear()
+ self._eval_cache.clear()
+ self.namespace.update(namespace)
+
+ def evaluate(self, expr):
+ """
+ Evaluate the expression.
+
+ Args:
+ expr: the string expression
+ @throw Exception bad expression
+
+ Returns:
+ the evaluated data
+ """
+ # Evaluate
+ if not expr:
+ raise Exception('Cannot evaluate empty statement.')
+ return self._eval_cache.setdefault(expr, eval(expr, self.namespace))
+
+ ##############################################
+ # Add/remove stuff
+ ##############################################
+
+ def 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
+ """
+ try:
+ block = self.platform.get_new_block(self, key)
+ self.blocks.append(block)
+ except KeyError:
+ block = None
+ 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.platform.Connection(
+ flow_graph=self, porta=porta, portb=portb)
+ self.connections.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.is_port:
+ # Found a port, set to parent signal block
+ element = element.get_parent()
+
+ if element in self.blocks:
+ # Remove block, remove all involved connections
+ for port in element.get_ports():
+ map(self.remove_element, port.get_connections())
+ self.blocks.remove(element)
+
+ elif element in self.connections:
+ 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.connections.remove(element)
+
+ ##############################################
+ # 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
+ """
+ # sort blocks and connections for nicer diffs
+ blocks = sorted(self.blocks, key=lambda b: (
+ b.get_key() != 'options', # options to the front
+ not b.get_key().startswith('variable'), # then vars
+ str(b)
+ ))
+ connections = sorted(self.connections, key=str)
+ n = odict()
+ n['timestamp'] = self._timestamp
+ n['block'] = [b.export_data() for b in blocks]
+ n['connection'] = [c.export_data() for c in connections]
+ instructions = odict({
+ 'created': '.'.join(self.get_parent().config.version_parts),
+ 'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
+ })
+ return odict({'flow_graph': n, '_instructions': instructions})
+
+ def import_data(self, n):
+ """
+ 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
+ del self.blocks[:]
+ del self.connections[:]
+ # set file format
+ try:
+ instructions = n.find('_instructions') or {}
+ file_format = int(instructions.get('format', '0')) or _guess_file_format_1(n)
+ except:
+ file_format = 0
+
+ fg_n = n and n.find('flow_graph') or odict() # use blank data if none provided
+ self._timestamp = fg_n.find('timestamp') or time.ctime()
+
+ # build the blocks
+ self._options_block = self.new_block('options')
+ for block_n in fg_n.findall('block'):
+ key = block_n.find('key')
+ block = self._options_block if key == 'options' else self.new_block(key)
+
+ if not block:
+ # we're before the initial fg update(), so no evaluated values!
+ # --> use raw value instead
+ path_param = self._options_block.get_param('hier_block_src_path')
+ file_path = self.platform.find_file_in_paths(
+ filename=key + '.grc',
+ paths=path_param.get_value(),
+ cwd=self.grc_file_path
+ )
+ if file_path: # grc file found. load and get block
+ self.platform.load_and_generate_flow_graph(file_path)
+ block = self.new_block(key) # can be None
+
+ if not block: # looks like this block key cannot be found
+ # create a dummy block instead
+ block = self.new_block('dummy_block')
+ # Ugly ugly ugly
+ _initialize_dummy_block(block, block_n)
+ print('Block key "%s" not found' % key)
+
+ block.import_data(block_n)
+
+ self.rewrite() # evaluate stuff like nports before adding connections
+
+ # build the connections
+ def verify_and_get_port(key, block, dir):
+ ports = block.get_sinks() if dir == 'sink' else block.get_sources()
+ for port in ports:
+ if key == port.get_key():
+ break
+ if not key.isdigit() and port.get_type() == '' and key == port.get_name():
+ break
+ else:
+ if block.is_dummy_block:
+ port = _dummy_block_add_port(block, key, dir)
+ else:
+ raise LookupError('%s key %r not in %s block keys' % (dir, key, dir))
+ return port
+
+ errors = False
+ for connection_n in fg_n.findall('connection'):
+ # get the block ids and port keys
+ source_block_id = connection_n.find('source_block_id')
+ sink_block_id = connection_n.find('sink_block_id')
+ source_key = connection_n.find('source_key')
+ sink_key = connection_n.find('sink_key')
+ try:
+ source_block = self.get_block(source_block_id)
+ sink_block = self.get_block(sink_block_id)
+
+ # fix old, numeric message ports keys
+ if file_format < 1:
+ source_key, sink_key = _update_old_message_port_keys(
+ source_key, sink_key, source_block, sink_block)
+
+ # build the connection
+ source_port = verify_and_get_port(source_key, source_block, 'source')
+ sink_port = verify_and_get_port(sink_key, sink_block, 'sink')
+ self.connect(source_port, sink_port)
+ except LookupError as e:
+ Messages.send_error_load(
+ 'Connection between {}({}) and {}({}) could not be made.\n\t{}'.format(
+ source_block_id, source_key, sink_block_id, sink_key, e))
+ errors = True
+
+ self.rewrite() # global rewrite
+ return errors
+
+ ##############################################
+ # Needs to go
+ ##############################################
+ def bus_ports_rewrite(self):
+ # todo: move to block.rewrite()
+ for block in self.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)
+
+ 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)
+
+
+def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block):
+ """
+ Backward compatibility for message port keys
+
+ Message ports use their names as key (like in the 'connect' method).
+ Flowgraph files from former versions still have numeric keys stored for
+ message connections. These have to be replaced by the name of the
+ respective port. The correct message port is deduced from the integer
+ value of the key (assuming the order has not changed).
+
+ The connection ends are updated only if both ends translate into a
+ message port.
+ """
+ try:
+ # get ports using the "old way" (assuming liner indexed keys)
+ source_port = source_block.get_sources()[int(source_key)]
+ sink_port = sink_block.get_sinks()[int(sink_key)]
+ if source_port.get_type() == "message" and sink_port.get_type() == "message":
+ source_key, sink_key = source_port.get_key(), sink_port.get_key()
+ except (ValueError, IndexError):
+ pass
+ return source_key, sink_key # do nothing
+
+
+def _guess_file_format_1(n):
+ """
+ Try to guess the file format for flow-graph files without version tag
+ """
+ try:
+ has_non_numeric_message_keys = any(not (
+ connection_n.find('source_key').isdigit() and
+ connection_n.find('sink_key').isdigit()
+ ) for connection_n in n.find('flow_graph').findall('connection'))
+ if has_non_numeric_message_keys:
+ return 1
+ except:
+ pass
+ return 0
+
+
+def _initialize_dummy_block(block, block_n):
+ """
+ This is so ugly... dummy-fy a block
+ Modify block object to get the behaviour for a missing block
+ """
+
+ block._key = block_n.find('key')
+ block.is_dummy_block = lambda: True
+ block.is_valid = lambda: False
+ block.get_enabled = lambda: False
+ for param_n in block_n.findall('param'):
+ if param_n['key'] not in block.get_param_keys():
+ new_param_n = odict({'key': param_n['key'], 'name': param_n['key'], 'type': 'string'})
+ params = block.get_parent().get_parent().Param(block=block, n=new_param_n)
+ block.get_params().append(params)
+
+
+def _dummy_block_add_port(block, key, dir):
+ """ This is so ugly... Add a port to a dummy-field block """
+ port_n = odict({'name': '?', 'key': key, 'type': ''})
+ port = block.get_parent().get_parent().Port(block=block, n=port_n, dir=dir)
+ if port.is_source:
+ block.get_sources().append(port)
+ else:
+ block.get_sinks().append(port)
+ return port
diff --git a/grc/gui/Messages.py b/grc/core/Messages.py
index 551a8ce753..8daa12c33f 100644
--- a/grc/gui/Messages.py
+++ b/grc/core/Messages.py
@@ -1,21 +1,20 @@
-"""
-Copyright 2007 Free Software Foundation, Inc.
-This file is part of GNU Radio
+# Copyright 2007, 2015 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
import traceback
import sys
@@ -59,24 +58,12 @@ register_messenger(sys.stdout.write)
# Special functions for specific program functionalities
###########################################################################
def send_init(platform):
- p = platform
-
- def get_paths(x):
- return os.path.abspath(os.path.expanduser(x)), x
-
- send('\n'.join([
- "<<< Welcome to %s %s >>>" % (p.get_name(), p.get_version()),
- "",
- "Preferences file: " + p.get_prefs_file(),
- "Block paths:"
- ] + [
- "\t%s" % path + (" (%s)" % opath if opath != path else "")
- for path, opath in map(get_paths, p.get_block_paths())
- ]) + "\n")
-
-
-def send_page_switch(file_path):
- send('\nShowing: "%s"\n' % file_path)
+ msg = "<<< Welcome to {config.name} {config.version} >>>\n\n" \
+ "Block paths:\n\t{paths}\n"
+ send(msg.format(
+ config=platform.config,
+ paths="\n\t".join(platform.config.block_paths))
+ )
def send_xml_errors_if_any(xml_failures):
diff --git a/grc/core/Param.py b/grc/core/Param.py
new file mode 100644
index 0000000000..d155800c43
--- /dev/null
+++ b/grc/core/Param.py
@@ -0,0 +1,740 @@
+"""
+Copyright 2008-2015 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import ast
+import weakref
+import re
+
+from . import Constants
+from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES
+from .Element import Element
+from .utils import odict
+
+# Blacklist certain ids, its not complete, but should help
+import __builtin__
+
+
+ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__)
+try:
+ from gnuradio import gr
+ ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_'))
+except ImportError:
+ pass
+
+_check_id_matcher = re.compile('^[a-z|A-Z]\w*$')
+_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook)$')
+
+
+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 "{}" not found in {}.'.format(key, _get_keys(lst)))
+
+
+def num_to_str(num):
+ """ Display logic for numbers """
+ def eng_notation(value, fmt='g'):
+ """Convert a number to a string in engineering notation. E.g., 5e-9 -> 5n"""
+ template = '{:' + fmt + '}{}'
+ magnitude = abs(value)
+ for exp, symbol in zip(range(9, -15-1, -3), 'GMk munpf'):
+ factor = 10 ** exp
+ if magnitude >= factor:
+ return template.format(value / factor, symbol.strip())
+ return template.format(value, '')
+
+ if isinstance(num, COMPLEX_TYPES):
+ num = complex(num) # Cast to python complex
+ if num == 0:
+ return '0'
+ output = eng_notation(num.real) if num.real else ''
+ output += eng_notation(num.imag, '+g' if output else 'g') + 'j' if num.imag else ''
+ return output
+ else:
+ return str(num)
+
+
+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 "{}" into key:value'.format(opt))
+ # Test against repeated keys
+ if key in self._opts:
+ raise Exception('Key "{}" already exists in option'.format(key))
+ # Store the option
+ self._opts[key] = value
+
+ def __str__(self):
+ return 'Option {}({})'.format(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 TemplateArg(object):
+ """
+ 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):
+ self._param = weakref.proxy(param)
+
+ def __getitem__(self, item):
+ return str(self._param.get_opt(item)) if self._param.is_enum() else NotImplemented
+
+ def __str__(self):
+ return str(self._param.to_code())
+
+ def __call__(self):
+ return self._param.get_evaluated()
+
+
+class Param(Element):
+
+ is_param = True
+
+ def __init__(self, block, n):
+ """
+ Make a new param from nested data.
+
+ Args:
+ block: the parent element
+ n: the nested odict
+ """
+ # If the base key is a valid param key, copy its data and overlay this params data
+ base_key = n.find('base_key')
+ if base_key and base_key in block.get_param_keys():
+ n_expanded = block.get_param(base_key)._n.copy()
+ n_expanded.update(n)
+ n = n_expanded
+ # Save odict in case this param will be base for another
+ self._n = n
+ # Parse the data
+ self._name = n.find('name')
+ self._key = n.find('key')
+ value = n.find('value') or ''
+ self._type = n.find('type') or 'raw'
+ self._hide = n.find('hide') or ''
+ self._tab_label = n.find('tab') or block.get_param_tab_labels()[0]
+ if self._tab_label not in block.get_param_tab_labels():
+ block.get_param_tab_labels().append(self._tab_label)
+ # Build the param
+ Element.__init__(self, block)
+ # Create the Option objects from the n data
+ self._options = list()
+ self._evaluated = None
+ 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 "{}" already exists in options'.format(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 "{}" are not unique.'.format(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 "{}" are not identical across all options.'.format(opt_keys))
+ # If a value is specified, it must be in the options keys
+ if value or value in self.get_option_keys():
+ self._value = value
+ else:
+ self._value = self.get_option_keys()[0]
+ if self.get_value() not in self.get_option_keys():
+ raise Exception('The value "{}" is not in the possible values of "{}".'.format(self.get_value(), self.get_option_keys()))
+ else:
+ self._value = value or ''
+ self._default = value
+ self._init = False
+ self._hostage_cells = list()
+ self.template_arg = TemplateArg(self)
+
+ 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', '_multiline', '_multiline_python_external',
+ '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()
+
+ ##################################################
+ # Split up formatting by type
+ ##################################################
+ # Default center truncate
+ truncate = 0
+ 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:
+ # Large vectors use code
+ dt_str = self.get_value()
+ truncate = 1
+ else:
+ # Small vectors use eval
+ dt_str = ', '.join(map(num_to_str, e))
+ elif t in ('file_open', 'file_save'):
+ dt_str = self.get_value()
+ truncate = -1
+ else:
+ # Other types
+ dt_str = str(e)
+
+ # Done
+ return _truncate(dt_str, truncate)
+
+ def __repr2__(self):
+ """
+ Get the repr (nice string format) for this param.
+
+ Returns:
+ the string representation
+ """
+ if self.is_enum():
+ return self.get_option(self.get_value()).get_name()
+ return self.get_value()
+
+ def __str__(self):
+ return 'Param - {}({})'.format(self.get_name(), self.get_key())
+
+ 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 '#FFFFFF'
+
+ 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 = self.get_parent().resolve_dependencies(self._hide).strip()
+ 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.
+ 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 "{}" is not a possible type.'.format(self.get_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 evaluate(self):
+ """
+ Evaluate the value.
+
+ Returns:
+ evaluated type
+ """
+ self._init = True
+ self._lisitify_flag = False
+ self._stringify_flag = False
+ self._hostage_cells = list()
+ 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 "{}" cannot be evaluated:\n{}'.format(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 "{}" is invalid for type complex.'.format(str(e)))
+ return e
+ elif t == 'real' or t == 'float':
+ if not isinstance(e, REAL_TYPES):
+ raise Exception('Expression "{}" is invalid for type float.'.format(str(e)))
+ return e
+ elif t == 'int':
+ if not isinstance(e, INT_TYPES):
+ raise Exception('Expression "{}" is invalid for type integer.'.format(str(e)))
+ return e
+ elif t == 'hex':
+ return hex(e)
+ elif t == 'bool':
+ if not isinstance(e, bool):
+ raise Exception('Expression "{}" is invalid for type bool.'.format(str(e)))
+ return e
+ else:
+ raise TypeError('Type "{}" not handled'.format(t))
+ #########################
+ # Numeric Vector Types
+ #########################
+ elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'):
+ if not v:
+ # Turn a blank string into an empty list, so it will eval
+ v = '()'
+ # Raise exception if python cannot evaluate this value
+ try:
+ e = self.get_parent().get_parent().evaluate(v)
+ except Exception, e:
+ raise Exception('Value "{}" cannot be evaluated:\n{}'.format(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 "{}" is invalid for type complex vector.'.format(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 "{}" is invalid for type float vector.'.format(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 "{}" is invalid for type integer vector.'.format(str(e)))
+ return e
+ #########################
+ # String Types
+ #########################
+ elif t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'):
+ # Do not check if file/directory exists, that is a runtime issue
+ try:
+ e = self.get_parent().get_parent().evaluate(v)
+ if not isinstance(e, str):
+ raise Exception()
+ except:
+ self._stringify_flag = True
+ e = str(v)
+ if t == '_multiline_python_external':
+ ast.parse(e) # Raises SyntaxError
+ return e
+ #########################
+ # Unique ID Type
+ #########################
+ elif t == 'id':
+ # Can python use this as a variable?
+ if not _check_id_matcher.match(v):
+ raise Exception('ID "{}" must begin with a letter and may contain letters, numbers, and underscores.'.format(v))
+ ids = [param.get_value() for param in self.get_all_params(t)]
+
+ # Id should only appear once, or zero times if block is disabled
+ if ids.count(v) > 1:
+ raise Exception('ID "{}" is not unique.'.format(v))
+ if v in ID_BLACKLIST:
+ raise Exception('ID "{}" is blacklisted.'.format(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():
+ # Id should only appear once, or zero times if block is disabled
+ if ids.count(v) > 1:
+ raise Exception('Stream ID "{}" is not unique.'.format(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 "{}" is not found.'.format(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 = '?'
+
+ # TODO: Problem with this code. Produces bad tabs
+ 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}
+
+ # FIXME: Move replace(...) into the make template of the qtgui blocks
+ # Return a string here
+ class GuiHint(object):
+ def __init__(self, ws):
+ self._ws = ws
+
+ def __call__(self, w):
+ return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w
+
+ def __str__(self):
+ return self._ws
+ return GuiHint(widget_str)
+ #########################
+ # Grid Position Type
+ #########################
+ elif t == 'grid_pos':
+ if not v:
+ # Allow for empty grid pos
+ return ''
+ 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 "{}", cell "{}".'.format(str(parent), str(cell)))
+ return e
+ #########################
+ # Notebook Page Type
+ #########################
+ elif t == 'notebook':
+ if not v:
+ # Allow for empty notebook
+ return ''
+
+ # 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 "{}" is not an existing notebook id.'.format(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 "{}" is not a valid index number.'.format(page_index))
+ return notebook_id, page_index
+
+ #########################
+ # Import Type
+ #########################
+ elif t == 'import':
+ # New namespace
+ n = dict()
+ try:
+ exec v in n
+ except ImportError:
+ raise Exception('Import "{}" failed.'.format(v))
+ except Exception:
+ raise Exception('Bad import syntax: "{}".'.format(v))
+ return filter(lambda k: str(k) != '__builtins__', n.keys())
+
+ #########################
+ else:
+ raise TypeError('Type "{}" not handled'.format(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()
+ # String types
+ if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'):
+ if not self._init:
+ self.evaluate()
+ if self._stringify_flag:
+ return '"%s"' % v.replace('"', '\"')
+ else:
+ return v
+ # Vector types
+ elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'):
+ 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 is_enum(self):
+ return self._type == 'enum'
+
+ 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):
+ # Must be a string
+ self._value = str(value)
+
+ def set_default(self, value):
+ if self._default == self._value:
+ self.set_value(value)
+ self._default = str(value)
+
+ def get_type(self):
+ return self.get_parent().resolve_dependencies(self._type)
+
+ def get_tab_label(self):
+ return self._tab_label
+
+ def get_name(self):
+ return self.get_parent().resolve_dependencies(self._name).strip()
+
+ def get_key(self):
+ return self._key
+
+ ##############################################
+ # 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/core/ParseXML.py
index e05fc1428d..c9f6541ee7 100644
--- a/grc/base/ParseXML.py
+++ b/grc/core/ParseXML.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2015 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -18,7 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from lxml import etree
-from . import odict
+
+from .utils import odict
xml_failures = {}
etree.set_default_parser(etree.XMLParser(remove_comments=True))
@@ -42,7 +43,7 @@ def validate_dtd(xml_file, dtd_file=None):
dtd_file: the optional dtd file
@throws Exception validation fails
"""
- # perform parsing, use dtd validation if dtd file is not specified
+ # Perform parsing, use dtd validation if dtd file is not specified
parser = etree.XMLParser(dtd_validation=not dtd_file)
try:
xml = etree.parse(xml_file, parser=parser)
@@ -51,7 +52,7 @@ def validate_dtd(xml_file, dtd_file=None):
if parser.error_log:
raise XMLSyntaxError(parser.error_log)
- # perform dtd validation if the dtd file is specified
+ # Perform dtd validation if the dtd file is specified
if not dtd_file:
return
try:
@@ -100,9 +101,11 @@ def _from_file(xml):
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
+ if key in nested_data:
+ 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]
@@ -120,7 +123,8 @@ def to_file(nested_data, xml_file):
"""
xml_data = ""
instructions = nested_data.pop('_instructions', None)
- if instructions: # create the processing instruction from the array
+ # Create the processing instruction from the array
+ if instructions:
xml_data += etree.tostring(etree.ProcessingInstruction(
'grc', ' '.join(
"{0}='{1}'".format(*item) for item in instructions.iteritems())
@@ -143,7 +147,7 @@ def _to_file(nested_data):
"""
nodes = list()
for key, values in nested_data.iteritems():
- # listify the values if not a list
+ # Listify the values if not a list
if not isinstance(values, (list, set, tuple)):
values = [values]
for value in values:
diff --git a/grc/core/Platform.py b/grc/core/Platform.py
new file mode 100644
index 0000000000..9b25e67d65
--- /dev/null
+++ b/grc/core/Platform.py
@@ -0,0 +1,309 @@
+"""
+Copyright 2008-2016 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import os
+import sys
+
+from . import ParseXML, Messages, Constants
+
+from .Config import Config
+from .Element import Element
+from .generator import Generator
+from .FlowGraph import FlowGraph
+from .Connection import Connection
+from .Block import Block
+from .Port import Port
+from .Param import Param
+
+from .utils import odict, extract_docs
+
+
+class Platform(Element):
+
+ Config = Config
+ Generator = Generator
+ FlowGraph = FlowGraph
+ Connection = Connection
+ Block = Block
+ Port = Port
+ Param = Param
+
+ is_platform = True
+
+ def __init__(self, *args, **kwargs):
+ """ Make a platform for GNU Radio """
+ Element.__init__(self)
+
+ self.config = self.Config(*args, **kwargs)
+
+ self.block_docstrings = {}
+ self.block_docstrings_loaded_callback = lambda: None # dummy to be replaced by BlockTreeWindow
+
+ self._docstring_extractor = extract_docs.SubprocessLoader(
+ callback_query_result=self._save_docstring_extraction_result,
+ callback_finished=lambda: self.block_docstrings_loaded_callback()
+ )
+
+ self._block_dtd = Constants.BLOCK_DTD
+ self._default_flow_graph = Constants.DEFAULT_FLOW_GRAPH
+
+ # Create a dummy flow graph for the blocks
+ self._flow_graph = Element(self)
+ self._flow_graph.connections = []
+
+ self.blocks = odict()
+ self._blocks_n = odict()
+ self._block_categories = {}
+ self.domains = {}
+ self.connection_templates = {}
+
+ self._auto_hier_block_generate_chain = set()
+
+ self.build_block_library()
+
+ def __str__(self):
+ return 'Platform - {}({})'.format(self.config.key, self.config.name)
+
+ @staticmethod
+ def find_file_in_paths(filename, paths, cwd):
+ """Checks the provided paths relative to cwd for a certain filename"""
+ if not os.path.isdir(cwd):
+ cwd = os.path.dirname(cwd)
+ if isinstance(paths, str):
+ paths = (p for p in paths.split(':') if p)
+
+ for path in paths:
+ path = os.path.expanduser(path)
+ if not os.path.isabs(path):
+ path = os.path.normpath(os.path.join(cwd, path))
+ file_path = os.path.join(path, filename)
+ if os.path.exists(os.path.normpath(file_path)):
+ return file_path
+
+ def load_and_generate_flow_graph(self, file_path):
+ """Loads a flow graph from file and generates it"""
+ Messages.set_indent(len(self._auto_hier_block_generate_chain))
+ Messages.send('>>> Loading: %r\n' % file_path)
+ if file_path in self._auto_hier_block_generate_chain:
+ Messages.send(' >>> Warning: cyclic hier_block dependency\n')
+ return False
+ self._auto_hier_block_generate_chain.add(file_path)
+ try:
+ flow_graph = self.get_new_flow_graph()
+ flow_graph.grc_file_path = file_path
+ # Other, nested higiter_blocks might be auto-loaded here
+ flow_graph.import_data(self.parse_flow_graph(file_path))
+ flow_graph.rewrite()
+ flow_graph.validate()
+ if not flow_graph.is_valid():
+ raise Exception('Flowgraph invalid')
+ if not flow_graph.get_option('generate_options').startswith('hb'):
+ raise Exception('Not a hier block')
+ except Exception as e:
+ Messages.send('>>> Load Error: {}: {}\n'.format(file_path, str(e)))
+ return False
+ finally:
+ self._auto_hier_block_generate_chain.discard(file_path)
+ Messages.set_indent(len(self._auto_hier_block_generate_chain))
+
+ try:
+ Messages.send('>>> Generating: {}\n'.format(file_path))
+ generator = self.Generator(flow_graph, file_path)
+ generator.write()
+ except Exception as e:
+ Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e)))
+ return False
+
+ self.load_block_xml(generator.get_file_path_xml())
+ return True
+
+ def build_block_library(self):
+ """load the blocks and block tree from the search paths"""
+ self._docstring_extractor.start()
+ # Reset
+ self.blocks.clear()
+ self._blocks_n.clear()
+ self._block_categories.clear()
+ self.domains.clear()
+ self.connection_templates.clear()
+ ParseXML.xml_failures.clear()
+
+ # Try to parse and load blocks
+ for xml_file in self.iter_xml_files():
+ try:
+ if xml_file.endswith("block_tree.xml"):
+ self.load_category_tree_xml(xml_file)
+ elif xml_file.endswith('domain.xml'):
+ self.load_domain_xml(xml_file)
+ else:
+ self.load_block_xml(xml_file)
+ except ParseXML.XMLSyntaxError as e:
+ # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
+ pass
+ except Exception as e:
+ print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file)
+
+ # Add blocks to block tree
+ for key, block in self.blocks.iteritems():
+ category = self._block_categories.get(key, block.category)
+ # Blocks with empty categories are hidden
+ if not category:
+ continue
+ root = category[0]
+ if root.startswith('[') and root.endswith(']'):
+ category[0] = root[1:-1]
+ else:
+ category.insert(0, Constants.DEFAULT_BLOCK_MODULE_NAME)
+ block.category = category
+
+ self._docstring_extractor.finish()
+ # self._docstring_extractor.wait()
+
+ def iter_xml_files(self):
+ """Iterator for block descriptions and category trees"""
+ for block_path in self.config.block_paths:
+ if os.path.isfile(block_path):
+ yield 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)):
+ yield os.path.join(dirpath, filename)
+
+ def load_block_xml(self, xml_file):
+ """Load block description from xml file"""
+ # Validate and import
+ ParseXML.validate_dtd(xml_file, self._block_dtd)
+ n = ParseXML.from_file(xml_file).find('block')
+ n['block_wrapper_path'] = xml_file # inject block wrapper path
+ # Get block instance and add it to the list of blocks
+ block = self.Block(self._flow_graph, n)
+ key = block.get_key()
+ if key in self.blocks:
+ print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file)
+ else: # Store the block
+ self.blocks[key] = block
+ self._blocks_n[key] = n
+
+ self._docstring_extractor.query(
+ block.get_key(),
+ block.get_imports(raw=True),
+ block.get_make(raw=True)
+ )
+
+ def load_category_tree_xml(self, xml_file):
+ """Validate and parse category tree file and add it to list"""
+ ParseXML.validate_dtd(xml_file, Constants.BLOCK_TREE_DTD)
+ xml = ParseXML.from_file(xml_file)
+ path = []
+
+ def load_category(cat_n):
+ path.append(cat_n.find('name').strip())
+ for block_key in cat_n.findall('block'):
+ if block_key not in self._block_categories:
+ self._block_categories[block_key] = list(path)
+ for sub_cat_n in cat_n.findall('cat'):
+ load_category(sub_cat_n)
+ path.pop()
+
+ load_category(xml.find('cat'))
+
+ def load_domain_xml(self, xml_file):
+ """Load a domain properties and connection templates from XML"""
+ ParseXML.validate_dtd(xml_file, Constants.DOMAIN_DTD)
+ n = ParseXML.from_file(xml_file).find('domain')
+
+ key = n.find('key')
+ if not key:
+ print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file)
+ return
+ if key in self.domains: # test against repeated keys
+ print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file)
+ return
+
+ #to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '')
+ def to_bool(s, d):
+ if s is not None:
+ return s.lower() not in ('false', 'off', '0', '')
+ return d
+
+ color = n.find('color') or ''
+ try:
+ import gtk # ugly but handy
+ gtk.gdk.color_parse(color)
+ except (ValueError, ImportError):
+ if color: # no color is okay, default set in GUI
+ print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key)
+ color = None
+
+ self.domains[key] = dict(
+ name=n.find('name') or key,
+ multiple_sinks=to_bool(n.find('multiple_sinks'), True),
+ multiple_sources=to_bool(n.find('multiple_sources'), False),
+ color=color
+ )
+ for connection_n in n.findall('connection'):
+ key = (connection_n.find('source_domain'), connection_n.find('sink_domain'))
+ if not all(key):
+ print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file)
+ elif key in self.connection_templates:
+ print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file)
+ else:
+ self.connection_templates[key] = connection_n.find('make') or ''
+
+ def _save_docstring_extraction_result(self, key, docstrings):
+ docs = {}
+ for match, docstring in docstrings.iteritems():
+ if not docstring or match.endswith('_sptr'):
+ continue
+ docstring = docstring.replace('\n\n', '\n').strip()
+ docs[match] = docstring
+ self.block_docstrings[key] = docs
+
+ ##############################################
+ # Access
+ ##############################################
+
+ 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, Constants.FLOW_GRAPH_DTD)
+ return ParseXML.from_file(flow_graph_file)
+
+ def get_new_flow_graph(self):
+ return self.FlowGraph(platform=self)
+
+ 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_colors(self):
+ return [(name, color) for name, key, sizeof, color in Constants.CORE_TYPES]
diff --git a/grc/core/Port.py b/grc/core/Port.py
new file mode 100644
index 0000000000..6a8f484082
--- /dev/null
+++ b/grc/core/Port.py
@@ -0,0 +1,404 @@
+"""
+Copyright 2008-2015 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+from .Constants import DEFAULT_DOMAIN, GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
+from .Element import Element
+
+from . 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 {}'.format(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 {}'.format(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 {}'.format(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:
+ # Could have many connections, but use first
+ return _get_sink_from_virtual_sink_port(
+ vsp.get_enabled_connections()[0].get_sink())
+ except:
+ raise Exception('Could not resolve source for virtual source port {}'.format(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 {}'.format(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 {}'.format(vsp))
+
+
+class Port(Element):
+
+ is_port = True
+
+ 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'] == 'message':
+ n['domain'] = GR_MESSAGE_DOMAIN
+ if 'domain' not in n:
+ n['domain'] = DEFAULT_DOMAIN
+ elif n['domain'] == GR_MESSAGE_DOMAIN:
+ n['key'] = n['name']
+ n['type'] = 'message' # For port color
+ if n['type'] == 'msg':
+ n['key'] = 'msg'
+ if not n.find('key'):
+ n['key'] = str(next(block.port_counters[dir == 'source']))
+
+ # Build the port
+ Element.__init__(self, block)
+ # Grab the data
+ self._name = n['name']
+ self._key = n['key']
+ self._type = n['type'] or ''
+ self._domain = n['domain']
+ self._hide = n.find('hide') or ''
+ self._dir = dir
+ self._hide_evaluated = False # Updated on rewrite()
+
+ self._nports = n.find('nports') or ''
+ self._vlen = n.find('vlen') or ''
+ self._optional = bool(n.find('optional'))
+ self._clones = [] # References to cloned ports (for nports > 1)
+
+ def __str__(self):
+ if self.is_source:
+ return 'Source - {}({})'.format(self.get_name(), self.get_key())
+ if self.is_sink:
+ return 'Sink - {}({})'.format(self.get_name(), self.get_key())
+
+ def get_types(self):
+ return Constants.TYPE_TO_SIZEOF.keys()
+
+ def is_type_empty(self):
+ return not self._n['type']
+
+ def validate(self):
+ Element.validate(self)
+ if self.get_type() not in self.get_types():
+ self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type()))
+ platform = self.get_parent().get_parent().get_parent()
+ if self.get_domain() not in platform.domains:
+ self.add_error_message('Domain key "{}" is not registered.'.format(self.get_domain()))
+ if not self.get_enabled_connections() and not self.get_optional():
+ self.add_error_message('Port is not connected.')
+ # 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.
+ """
+ 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 = ''
+
+ Element.rewrite(self)
+ hide = self.get_parent().resolve_dependencies(self._hide).strip().lower()
+ self._hide_evaluated = False if hide in ('false', 'off', '0') else bool(hide)
+
+ # Update domain if was deduced from (dynamic) port type
+ type_ = self.get_type()
+ if self._domain == GR_STREAM_DOMAIN and type_ == "message":
+ self._domain = GR_MESSAGE_DOMAIN
+ self._key = self._name
+ if self._domain == GR_MESSAGE_DOMAIN and type_ != "message":
+ self._domain = GR_STREAM_DOMAIN
+ self._key = '0' # Is rectified in rewrite()
+
+ 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 a positive integer, return 1.
+
+ Returns:
+ the number of ports or 1
+ """
+ if self._nports == '':
+ return ''
+
+ nports = self.get_parent().resolve_dependencies(self._nports)
+ try:
+ return max(1, int(self.get_parent().get_parent().evaluate(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)
+ # TODO: Change this to .format()
+ return '#%.2x%.2x%.2x' % (r, g, b)
+ except:
+ return '#FFFFFF'
+
+ def get_clones(self):
+ """
+ Get the clones of this master port (nports > 1)
+
+ Returns:
+ a list of ports
+ """
+ return self._clones
+
+ def add_clone(self):
+ """
+ Create a clone of this (master) port and store a reference in self._clones.
+
+ The new port name (and key for message ports) will have index 1... appended.
+ If this is the first clone, this (master) port will get a 0 appended to its name (and key)
+
+ Returns:
+ the cloned port
+ """
+ # Add index to master port name if there are no clones yet
+ if not self._clones:
+ self._name = self._n['name'] + '0'
+ # Also update key for none stream ports
+ if not self._key.isdigit():
+ self._key = self._name
+
+ # Prepare a copy of the odict for the clone
+ n = self._n.copy()
+ # Remove nports from the key so the copy cannot be a duplicator
+ if 'nports' in n:
+ n.pop('nports')
+ n['name'] = self._n['name'] + str(len(self._clones) + 1)
+ # Dummy value 99999 will be fixed later
+ n['key'] = '99999' if self._key.isdigit() else n['name']
+
+ # Clone
+ port = self.__class__(self.get_parent(), n, self._dir)
+ self._clones.append(port)
+ return port
+
+ def remove_clone(self, port):
+ """
+ Remove a cloned port (from the list of clones only)
+ Remove the index 0 of the master port name (and key9 if there are no more clones left
+ """
+ self._clones.remove(port)
+ # Remove index from master port name if there are no more clones
+ if not self._clones:
+ self._name = self._n['name']
+ # Also update key for none stream ports
+ if not self._key.isdigit():
+ self._key = self._name
+
+ 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_key(self):
+ return self._key
+
+ @property
+ def is_sink(self):
+ return self._dir == 'sink'
+
+ @property
+ def is_source(self):
+ return self._dir == 'source'
+
+ def get_type(self):
+ return self.get_parent().resolve_dependencies(self._type)
+
+ def get_domain(self):
+ return self._domain
+
+ def get_hide(self):
+ return self._hide_evaluated
+
+ def get_connections(self):
+ """
+ Get all connections that use this port.
+
+ Returns:
+ a list of connection objects
+ """
+ connections = self.get_parent().get_parent().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_ports = self.get_parent().get_sources
+ bus_structure = self.get_parent().current_bus_structure['source']
+ else:
+ get_ports = self.get_parent().get_sinks
+ bus_structure = self.get_parent().current_bus_structure['sink']
+
+ ports = [i for i in get_ports() if not i.get_type() == 'bus']
+ if bus_structure:
+ busses = [i for i in get_ports() 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/python/__init__.py b/grc/core/__init__.py
index 8b13789179..8b13789179 100644
--- a/grc/python/__init__.py
+++ b/grc/core/__init__.py
diff --git a/grc/python/block.dtd b/grc/core/block.dtd
index 145f4d8610..145f4d8610 100644
--- a/grc/python/block.dtd
+++ b/grc/core/block.dtd
diff --git a/grc/base/block_tree.dtd b/grc/core/block_tree.dtd
index 9e23576477..9e23576477 100644
--- a/grc/base/block_tree.dtd
+++ b/grc/core/block_tree.dtd
diff --git a/grc/python/default_flow_graph.grc b/grc/core/default_flow_graph.grc
index 059509d34b..059509d34b 100644
--- a/grc/python/default_flow_graph.grc
+++ b/grc/core/default_flow_graph.grc
diff --git a/grc/base/domain.dtd b/grc/core/domain.dtd
index b5b0b8bf39..b5b0b8bf39 100644
--- a/grc/base/domain.dtd
+++ b/grc/core/domain.dtd
diff --git a/grc/base/flow_graph.dtd b/grc/core/flow_graph.dtd
index bdfe1dc059..bdfe1dc059 100644
--- a/grc/base/flow_graph.dtd
+++ b/grc/core/flow_graph.dtd
diff --git a/grc/python/CMakeLists.txt b/grc/core/generator/CMakeLists.txt
index 3f9e273146..4bdd59a7a2 100644
--- a/grc/python/CMakeLists.txt
+++ b/grc/core/generator/CMakeLists.txt
@@ -17,28 +17,16 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
-########################################################################
-GR_PYTHON_INSTALL(FILES
- expr_utils.py
- extract_docs.py
- epy_block_io.py
- Block.py
- Connection.py
- Constants.py
- FlowGraph.py
- Generator.py
- Param.py
- Platform.py
- Port.py
- __init__.py
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python
+file(GLOB py_files "*.py")
+
+GR_PYTHON_INSTALL(
+ FILES ${py_files}
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator
COMPONENT "grc"
)
install(FILES
- block.dtd
- default_flow_graph.grc
flow_graph.tmpl
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator
COMPONENT "grc"
)
diff --git a/grc/core/generator/FlowGraphProxy.py b/grc/core/generator/FlowGraphProxy.py
new file mode 100644
index 0000000000..3723005576
--- /dev/null
+++ b/grc/core/generator/FlowGraphProxy.py
@@ -0,0 +1,126 @@
+# Copyright 2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+class FlowGraphProxy(object):
+
+ def __init__(self, fg):
+ self._fg = fg
+
+ def __getattr__(self, item):
+ return getattr(self._fg, item)
+
+ def get_hier_block_stream_io(self, direction):
+ """
+ Get a list of stream io signatures for this flow graph.
+
+ Args:
+ direction: a string of 'in' or 'out'
+
+ Returns:
+ a list of dicts with: type, label, vlen, size, optional
+ """
+ return filter(lambda p: p['type'] != "message", self.get_hier_block_io(direction))
+
+ def get_hier_block_message_io(self, direction):
+ """
+ Get a list of message io signatures for this flow graph.
+
+ Args:
+ direction: a string of 'in' or 'out'
+
+ Returns:
+ a list of dicts with: type, label, vlen, size, optional
+ """
+ return filter(lambda p: p['type'] == "message", self.get_hier_block_io(direction))
+
+ def get_hier_block_io(self, direction):
+ """
+ Get a list of io ports for this flow graph.
+
+ Args:
+ direction: a string of 'in' or 'out'
+
+ Returns:
+ a list of dicts with: type, label, vlen, size, optional
+ """
+ pads = self.get_pad_sources() if direction in ('sink', 'in') else \
+ self.get_pad_sinks() if direction in ('source', 'out') else []
+ ports = []
+ for pad in pads:
+ master = {
+ 'label': str(pad.get_param('label').get_evaluated()),
+ 'type': str(pad.get_param('type').get_evaluated()),
+ 'vlen': str(pad.get_param('vlen').get_value()),
+ 'size': pad.get_param('type').get_opt('size'),
+ 'optional': bool(pad.get_param('optional').get_evaluated()),
+ }
+ num_ports = pad.get_param('num_streams').get_evaluated()
+ if num_ports > 1:
+ for i in xrange(num_ports):
+ clone = master.copy()
+ clone['label'] += str(i)
+ ports.append(clone)
+ else:
+ ports.append(master)
+ return ports
+
+ 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_pad_port_global_key(self, port):
+ """
+ Get the key for a port of a pad source/sink to use in connect()
+ This takes into account that pad blocks may have multiple ports
+
+ Returns:
+ the key (str)
+ """
+ key_offset = 0
+ pads = self.get_pad_sources() if port.is_source else self.get_pad_sinks()
+ for pad in pads:
+ # using the block param 'type' instead of the port domain here
+ # to emphasize that hier block generation is domain agnostic
+ is_message_pad = pad.get_param('type').get_evaluated() == "message"
+ if port.get_parent() == pad:
+ if is_message_pad:
+ key = pad.get_param('label').get_value()
+ else:
+ key = str(key_offset + int(port.get_key()))
+ return key
+ else:
+ # assuming we have either only sources or sinks
+ if not is_message_pad:
+ key_offset += len(pad.get_ports())
+ return -1 \ No newline at end of file
diff --git a/grc/python/Generator.py b/grc/core/generator/Generator.py
index 56e3a6e78f..fb7a3afb99 100644
--- a/grc/python/Generator.py
+++ b/grc/core/generator/Generator.py
@@ -1,41 +1,37 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
+# Copyright 2008-2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
+import codecs
import os
-import sys
-import subprocess
import tempfile
-import shlex
-import codecs
-import re # for shlex_quote
-from distutils.spawn import find_executable
from Cheetah.Template import Template
-from .. gui import Messages
-from .. base import ParseXML
-from .. base import odict
-from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI
+from .FlowGraphProxy import FlowGraphProxy
+from .. import ParseXML, Messages
+from ..Constants import (
+ TOP_BLOCK_FILE_MODE, BLOCK_FLAG_NEED_QT_GUI,
+ HIER_BLOCK_FILE_MODE, BLOCK_DTD
+)
+from ..utils import expr_utils, odict
-from . Constants import TOP_BLOCK_FILE_MODE, FLOW_GRAPH_TEMPLATE, \
- XTERM_EXECUTABLE, HIER_BLOCK_FILE_MODE, HIER_BLOCKS_LIB_DIR, BLOCK_DTD
-from . import expr_utils
+DATA_DIR = os.path.dirname(__file__)
+FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl')
class Generator(object):
@@ -50,19 +46,16 @@ class Generator(object):
flow_graph: the flow graph object
file_path: the path to the grc file
"""
- self._generate_options = flow_graph.get_option('generate_options')
- if self._generate_options == 'hb':
+ self.generate_options = flow_graph.get_option('generate_options')
+ if self.generate_options == 'hb':
generator_cls = HierBlockGenerator
- elif self._generate_options == 'hb_qt_gui':
+ elif self.generate_options == 'hb_qt_gui':
generator_cls = QtHierBlockGenerator
else:
generator_cls = TopBlockGenerator
self._generator = generator_cls(flow_graph, file_path)
- def get_generate_options(self):
- return self._generate_options
-
def __getattr__(self, item):
"""get all other attrib from actual generator object"""
return getattr(self._generator, item)
@@ -78,23 +71,23 @@ class TopBlockGenerator(object):
flow_graph: the flow graph object
file_path: the path to write the file to
"""
- self._flow_graph = flow_graph
+ self._flow_graph = FlowGraphProxy(flow_graph)
self._generate_options = self._flow_graph.get_option('generate_options')
self._mode = TOP_BLOCK_FILE_MODE
dirname = self._dirname = os.path.dirname(file_path)
- # handle the case where the directory is read-only
- # in this case, use the system's temp directory
+ # 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)
+ self.file_path = os.path.join(dirname, filename)
def get_file_path(self):
- return self._file_path
+ return self.file_path
def write(self):
"""generate output and write it to files"""
- # do throttle warning
+ # Do throttle warning
throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks())
if not throttling_blocks and not self._generate_options.startswith('hb'):
Messages.send_warning("This flow graph may not have flow control: "
@@ -109,48 +102,16 @@ class TopBlockGenerator(object):
"e.g. a hardware source or sink. "
"This is usually undesired. Consider "
"removing the throttle block.")
- # generate
+ # Generate
for filename, data in self._build_python_code_from_template():
with codecs.open(filename, 'w', encoding='utf-8') as fp:
fp.write(data)
- if filename == self.get_file_path():
+ if filename == self.file_path:
try:
os.chmod(filename, self._mode)
except:
pass
- def get_popen(self):
- """
- Execute this python flow graph.
-
- Returns:
- a popen object
- """
- run_command = self._flow_graph.get_option('run_command')
- try:
- run_command = run_command.format(
- python=shlex_quote(sys.executable),
- filename=shlex_quote(self.get_file_path()))
- run_command_args = shlex.split(run_command)
- except Exception as e:
- raise ValueError("Can't parse run command {!r}: {}".format(run_command, e))
-
- # when in no gui mode on linux, use a graphical terminal (looks nice)
- xterm_executable = find_executable(XTERM_EXECUTABLE)
- if self._generate_options == 'no_gui' and xterm_executable:
- run_command_args = [xterm_executable, '-e', run_command]
-
- # this does not reproduce a shell executable command string, if a graphical
- # terminal is used. Passing run_command though shlex_quote would do it but
- # it looks really ugly and confusing in the console panel.
- Messages.send_start_exec(' '.join(run_command_args))
-
- return subprocess.Popen(
- args=run_command_args,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
- shell=False, universal_newlines=True
- )
-
def _build_python_code_from_template(self):
"""
Convert the flow graph to python code.
@@ -167,25 +128,29 @@ class TopBlockGenerator(object):
parameters = fg.get_parameters()
monitors = fg.get_monitors()
- # list of blocks not including variables and imports and parameters and disabled
+ # 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
+ 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
+ code += block.get_param('gui_hint').get_value() # Newer gui markup w/ qtgui
except:
pass
return code
- blocks = expr_utils.sort_objects(
- filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.iter_blocks()),
+ blocks_all = expr_utils.sort_objects(
+ filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.blocks),
lambda b: b.get_id(), _get_block_sort_text
)
+ deprecated_block_keys = set(block.get_name() for block in blocks_all if block.is_deprecated)
+ for key in deprecated_block_keys:
+ Messages.send_warning("The block {!r} is deprecated.".format(key))
+
# List of regular blocks (all blocks minus the special ones)
- blocks = filter(lambda b: b not in (imports + parameters), blocks)
+ blocks = filter(lambda b: b not in (imports + parameters), blocks_all)
for block in blocks:
key = block.get_key()
@@ -198,7 +163,8 @@ class TopBlockGenerator(object):
output.append((file_path, src))
# Filter out virtual sink connections
- cf = lambda c: not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink())
+ def cf(c):
+ return not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink())
connections = filter(cf, fg.get_enabled_connections())
# Get the virtual blocks and resolve their connections
@@ -220,8 +186,7 @@ class TopBlockGenerator(object):
for block in bypassed_blocks:
# Get the upstream connection (off of the sink ports)
# Use *connections* not get_connections()
- get_source_connection = lambda c: c.get_sink() == block.get_sinks()[0]
- source_connection = filter(get_source_connection, connections)
+ source_connection = filter(lambda c: c.get_sink() == block.get_sinks()[0], connections)
# The source connection should never have more than one element.
assert (len(source_connection) == 1)
@@ -229,8 +194,7 @@ class TopBlockGenerator(object):
source_port = source_connection[0].get_source()
# Loop through all the downstream connections
- get_sink_connections = lambda c: c.get_source() == block.get_sources()[0]
- for sink in filter(get_sink_connections, connections):
+ for sink in filter(lambda c: c.get_source() == block.get_sources()[0], connections):
if not sink.get_enabled():
# Ignore disabled connections
continue
@@ -248,23 +212,26 @@ class TopBlockGenerator(object):
c.get_source().get_parent().get_id(), c.get_sink().get_parent().get_id()
))
- connection_templates = fg.get_parent().get_connection_templates()
+ connection_templates = fg.get_parent().connection_templates
msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections())
- # list of variable names
+
+ # 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 fg.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
+ replace_dict = dict((var_id, 'self.' + var_id) for var_id in var_ids)
+ callbacks_all = []
+ for block in blocks_all:
+ callbacks_all.extend(expr_utils.expr_replace(cb, replace_dict) for cb in block.get_callbacks())
+
+ # Map var id to callbacks
+ def uses_var_id():
+ used = expr_utils.get_variable_dependencies(callback, [var_id])
+ return used and 'self.' + var_id in callback # callback might contain var_id itself
+
+ callbacks = {}
+ for var_id in var_ids:
+ callbacks[var_id] = [callback for callback in callbacks_all if uses_var_id()]
+
+ # Load the namespace
namespace = {
'title': title,
'imports': imports,
@@ -277,11 +244,11 @@ class TopBlockGenerator(object):
'connection_templates': connection_templates,
'msgs': msgs,
'generate_options': self._generate_options,
- 'var_id2cbs': var_id2cbs,
+ 'callbacks': callbacks,
}
- # build the template
+ # Build the template
t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace)
- output.append((self.get_file_path(), str(t)))
+ output.append((self.file_path, str(t)))
return output
@@ -297,10 +264,15 @@ class HierBlockGenerator(TopBlockGenerator):
file_path: where to write the py file (the xml goes into HIER_BLOCK_LIB_DIR)
"""
TopBlockGenerator.__init__(self, flow_graph, file_path)
+ platform = flow_graph.get_parent()
+
+ hier_block_lib_dir = platform.config.hier_block_lib_dir
+ if not os.path.exists(hier_block_lib_dir):
+ os.mkdir(hier_block_lib_dir)
+
self._mode = HIER_BLOCK_FILE_MODE
- self._file_path = os.path.join(HIER_BLOCKS_LIB_DIR,
- self._flow_graph.get_option('id') + '.py')
- self._file_path_xml = self._file_path + '.xml'
+ self.file_path = os.path.join(hier_block_lib_dir, self._flow_graph.get_option('id') + '.py')
+ self._file_path_xml = self.file_path + '.xml'
def get_file_path_xml(self):
return self._file_path_xml
@@ -322,7 +294,7 @@ class HierBlockGenerator(TopBlockGenerator):
Returns:
a xml node tree
"""
- # extract info from the flow graph
+ # Extract info from the flow graph
block_key = self._flow_graph.get_option('id')
parameters = self._flow_graph.get_parameters()
@@ -331,7 +303,7 @@ class HierBlockGenerator(TopBlockGenerator):
return "$"+name
return name
- # build the nested data
+ # Build the nested data
block_n = odict()
block_n['name'] = self._flow_graph.get_option('title') or \
self._flow_graph.get_option('id').replace('_', ' ').title()
@@ -339,7 +311,7 @@ class HierBlockGenerator(TopBlockGenerator):
block_n['category'] = self._flow_graph.get_option('category')
block_n['import'] = "from {0} import {0} # grc-generated hier_block".format(
self._flow_graph.get_option('id'))
- # make data
+ # Make data
if parameters:
block_n['make'] = '{cls}(\n {kwargs},\n)'.format(
cls=block_key,
@@ -349,7 +321,7 @@ class HierBlockGenerator(TopBlockGenerator):
)
else:
block_n['make'] = '{cls}()'.format(cls=block_key)
- # callback data
+ # Callback data
block_n['callback'] = [
'set_{key}(${key})'.format(key=param.get_id()) for param in parameters
]
@@ -364,13 +336,13 @@ class HierBlockGenerator(TopBlockGenerator):
param_n['type'] = 'raw'
block_n['param'].append(param_n)
- # bus stuff
+ # Bus stuff
if self._flow_graph.get_bussink():
block_n['bus_sink'] = '1'
if self._flow_graph.get_bussrc():
block_n['bus_source'] = '1'
- # sink/source ports
+ # Sink/source ports
for direction in ('sink', 'source'):
block_n[direction] = list()
for port in self._flow_graph.get_hier_block_io(direction):
@@ -383,7 +355,7 @@ class HierBlockGenerator(TopBlockGenerator):
port_n['optional'] = '1'
block_n[direction].append(port_n)
- # more bus stuff
+ # More bus stuff
bus_struct_sink = self._flow_graph.get_bus_structure_sink()
if bus_struct_sink:
block_n['bus_structure_sink'] = bus_struct_sink[0].get_param('struct').get_value()
@@ -391,11 +363,11 @@ class HierBlockGenerator(TopBlockGenerator):
if bus_struct_src:
block_n['bus_structure_source'] = bus_struct_src[0].get_param('struct').get_value()
- # documentation
+ # Documentation
block_n['doc'] = "\n".join(field for field in (
self._flow_graph.get_option('author'),
self._flow_graph.get_option('description'),
- self.get_file_path()
+ self.file_path
) if field)
block_n['grc_source'] = str(self._flow_graph.grc_file_path)
@@ -427,21 +399,3 @@ class QtHierBlockGenerator(HierBlockGenerator):
"\n${gui_hint()($win)}"
)
return n
-
-
-###########################################################
-# back-port from python3
-###########################################################
-_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
-
-
-def shlex_quote(s):
- """Return a shell-escaped version of the string *s*."""
- if not s:
- return "''"
- if _find_unsafe(s) is None:
- return s
-
- # use single quotes, and put single quotes into double quotes
- # the string $'b is then quoted as '$'"'"'b'
- return "'" + s.replace("'", "'\"'\"'") + "'"
diff --git a/grc/core/generator/__init__.py b/grc/core/generator/__init__.py
new file mode 100644
index 0000000000..f44b94a85d
--- /dev/null
+++ b/grc/core/generator/__init__.py
@@ -0,0 +1,18 @@
+# Copyright 2008-2015 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+from Generator import Generator
diff --git a/grc/python/flow_graph.tmpl b/grc/core/generator/flow_graph.tmpl
index bd8025b676..07c4169525 100644
--- a/grc/python/flow_graph.tmpl
+++ b/grc/core/generator/flow_graph.tmpl
@@ -13,7 +13,7 @@
##@param connections the connections
##@param msgs the msg type connections
##@param generate_options the type of flow graph
-##@param var_id2cbs variable id map to callback strings
+##@param callbacks variable id map to callback strings
########################################################
#def indent($code)
#set $code = '\n '.join(str($code).splitlines())
@@ -274,8 +274,8 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])
self.settings = Qt.QSettings("GNU Radio", "$class_name")
self.settings.setValue("geometry", self.saveGeometry())
event.accept()
-
#if $flow_graph.get_option('qt_qss_theme')
+
def setStyleSheetFromFile(self, filename):
try:
if not os.path.exists(filename):
@@ -301,12 +301,12 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])
#if $flow_graph.get_option('thread_safe_setters')
with self._lock:
self.$id = $id
- #for $callback in $var_id2cbs[$id]
+ #for $callback in $callbacks[$id]
$indent($callback)
#end for
#else
self.$id = $id
- #for $callback in $var_id2cbs[$id]
+ #for $callback in $callbacks[$id]
$indent($callback)
#end for
#end if
@@ -336,7 +336,12 @@ $short_id#slurp
def argument_parser():
- parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+ #set $desc_args = 'usage="%prog: [options]", option_class=eng_option'
+ #if $flow_graph.get_option('description')
+ #set $desc_args += ', description=description'
+ description = $repr($flow_graph.get_option('description'))
+ #end if
+ parser = OptionParser($desc_args)
#for $param in $parameters
#set $type = $param.get_param('type').get_value()
#if $type
diff --git a/grc/core/utils/CMakeLists.txt b/grc/core/utils/CMakeLists.txt
new file mode 100644
index 0000000000..2528fbc43c
--- /dev/null
+++ b/grc/core/utils/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright 2015 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.
+
+file(GLOB py_files "*.py")
+
+GR_PYTHON_INSTALL(
+ FILES ${py_files}
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/utils
+ COMPONENT "grc"
+)
diff --git a/grc/core/utils/__init__.py b/grc/core/utils/__init__.py
new file mode 100644
index 0000000000..6b23da2723
--- /dev/null
+++ b/grc/core/utils/__init__.py
@@ -0,0 +1,22 @@
+# Copyright 2008-2015 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import expr_utils
+import epy_block_io
+import extract_docs
+
+from odict import odict
diff --git a/grc/core/utils/complexity.py b/grc/core/utils/complexity.py
new file mode 100644
index 0000000000..baa8040db4
--- /dev/null
+++ b/grc/core/utils/complexity.py
@@ -0,0 +1,49 @@
+
+def calculate_flowgraph_complexity(flowgraph):
+ """ Determines the complexity of a flowgraph """
+ dbal = 0
+ for block in flowgraph.blocks:
+ # Skip options block
+ if block.get_key() == 'options':
+ continue
+
+ # Don't worry about optional sinks?
+ sink_list = filter(lambda c: not c.get_optional(), block.get_sinks())
+ source_list = filter(lambda c: not c.get_optional(), block.get_sources())
+ sinks = float(len(sink_list))
+ sources = float(len(source_list))
+ base = max(min(sinks, sources), 1)
+
+ # Port ratio multiplier
+ if min(sinks, sources) > 0:
+ multi = sinks / sources
+ multi = (1 / multi) if multi > 1 else multi
+ else:
+ multi = 1
+
+ # Connection ratio multiplier
+ sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0)
+ source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0)
+ dbal = dbal + (base * multi * sink_multi * source_multi)
+
+ blocks = float(len(flowgraph.blocks))
+ connections = float(len(flowgraph.connections))
+ elements = blocks + connections
+ disabled_connections = len(filter(lambda c: not c.get_enabled(), flowgraph.connections))
+ variables = elements - blocks - connections
+ enabled = float(len(flowgraph.get_enabled_blocks()))
+
+ # Disabled multiplier
+ if enabled > 0:
+ disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05))
+ else:
+ disabled_multi = 1
+
+ # Connection multiplier (How many connections )
+ if (connections - disabled_connections) > 0:
+ conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05))
+ else:
+ conn_multi = 1
+
+ final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6)
+ return final
diff --git a/grc/python/epy_block_io.py b/grc/core/utils/epy_block_io.py
index e089908a01..76b50051db 100644
--- a/grc/python/epy_block_io.py
+++ b/grc/core/utils/epy_block_io.py
@@ -2,9 +2,6 @@
import inspect
import collections
-from gnuradio import gr
-import pmt
-
TYPE_MAP = {
'complex64': 'complex', 'complex': 'complex',
@@ -14,7 +11,7 @@ TYPE_MAP = {
'int8': 'byte', 'uint8': 'byte',
}
-BlockIO = collections.namedtuple('BlockIO', 'name cls params sinks sources doc')
+BlockIO = collections.namedtuple('BlockIO', 'name cls params sinks sources doc callbacks')
def _ports(sigs, msgs):
@@ -31,23 +28,30 @@ def _ports(sigs, msgs):
return ports
-def _blk_class(source_code):
+def _find_block_class(source_code, cls):
ns = {}
try:
exec source_code in ns
except Exception as e:
raise ValueError("Can't interpret source code: " + str(e))
for var in ns.itervalues():
- if inspect.isclass(var)and issubclass(var, gr.gateway.gateway_block):
+ if inspect.isclass(var) and issubclass(var, cls):
return var
raise ValueError('No python block class found in code')
def extract(cls):
+ try:
+ from gnuradio import gr
+ import pmt
+ except ImportError:
+ raise EnvironmentError("Can't import GNU Radio")
+
if not inspect.isclass(cls):
- cls = _blk_class(cls)
+ cls = _find_block_class(cls, gr.gateway.gateway_block)
spec = inspect.getargspec(cls.__init__)
+ init_args = spec.args[1:]
defaults = map(repr, spec.defaults or ())
doc = cls.__doc__ or cls.__init__.__doc__ or ''
cls_name = cls.__name__
@@ -61,14 +65,23 @@ def extract(cls):
raise RuntimeError("Can't create an instance of your block: " + str(e))
name = instance.name()
- params = list(zip(spec.args[1:], defaults))
+
+ params = list(zip(init_args, defaults))
+
+ def settable(attr):
+ try:
+ return callable(getattr(cls, attr).fset) # check for a property with setter
+ except AttributeError:
+ return attr in instance.__dict__ # not dir() - only the instance attribs
+
+ callbacks = [attr for attr in dir(instance) if attr in init_args and settable(attr)]
sinks = _ports(instance.in_sig(),
pmt.to_python(instance.message_ports_in()))
sources = _ports(instance.out_sig(),
pmt.to_python(instance.message_ports_out()))
- return BlockIO(name, cls_name, params, sinks, sources, doc)
+ return BlockIO(name, cls_name, params, sinks, sources, doc, callbacks)
if __name__ == '__main__':
@@ -78,7 +91,7 @@ from gnuradio import gr
import pmt
class blk(gr.sync_block):
- def __init__(self, param1=None, param2=None):
+ def __init__(self, param1=None, param2=None, param3=None):
"Test Docu"
gr.sync_block.__init__(
self,
@@ -88,8 +101,25 @@ class blk(gr.sync_block):
)
self.message_port_register_in(pmt.intern('msg_in'))
self.message_port_register_out(pmt.intern('msg_out'))
+ self.param1 = param1
+ self._param2 = param2
+ self._param3 = param3
+
+ @property
+ def param2(self):
+ return self._param2
+
+ @property
+ def param3(self):
+ return self._param3
+
+ @param3.setter
+ def param3(self, value):
+ self._param3 = value
def work(self, inputs_items, output_items):
return 10
"""
- print extract(blk_code)
+ from pprint import pprint
+ pprint(dict(extract(blk_code)._asdict()))
+
diff --git a/grc/python/expr_utils.py b/grc/core/utils/expr_utils.py
index 9e0b2a4a0a..2059ceff9f 100644
--- a/grc/python/expr_utils.py
+++ b/grc/core/utils/expr_utils.py
@@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import string
VAR_CHARS = string.letters + string.digits + '_'
+
class graph(object):
"""
Simple graph structure held in a dictionary.
@@ -30,13 +31,16 @@ class graph(object):
def __str__(self): return str(self._graph)
def add_node(self, node_key):
- if self._graph.has_key(node_key): return
+ if node_key in self._graph:
+ return
self._graph[node_key] = set()
def remove_node(self, node_key):
- if not self._graph.has_key(node_key): return
+ if node_key not in self._graph:
+ return
for edges in self._graph.values():
- if node_key in edges: edges.remove(node_key)
+ if node_key in edges:
+ edges.remove(node_key)
self._graph.pop(node_key)
def add_edge(self, src_node_key, dest_node_key):
@@ -45,11 +49,14 @@ class graph(object):
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):
+def expr_split(expr, var_chars=VAR_CHARS):
"""
Split up an expression by non alphanumeric characters, including underscore.
Leave strings in-tact.
@@ -65,8 +72,9 @@ def expr_split(expr):
tok = ''
quote = ''
for char in expr:
- if quote or char in VAR_CHARS:
- if char == quote: quote = ''
+ if quote or char in var_chars:
+ if char == quote:
+ quote = ''
tok += char
elif char in ("'", '"'):
toks.append(tok)
@@ -79,6 +87,7 @@ def expr_split(expr):
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.
@@ -90,12 +99,13 @@ def expr_replace(expr, replace_dict):
Returns:
a new expression with the prepend
"""
- expr_splits = expr_split(expr)
+ expr_splits = expr_split(expr, var_chars=VAR_CHARS + '.')
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.
@@ -108,7 +118,8 @@ def get_variable_dependencies(expr, vars):
a subset of vars used in the expression
"""
expr_toks = expr_split(expr)
- return set(filter(lambda v: v in expr_toks, vars))
+ return set(var for var in vars if var in expr_toks)
+
def get_graph(exprs):
"""
@@ -121,14 +132,17 @@ def get_graph(exprs):
a graph of variable deps
"""
vars = exprs.keys()
- #get dependencies for each expression, load into graph
+ # Get dependencies for each expression, load into graph
var_graph = graph()
- for var in vars: var_graph.add_node(var)
+ 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)
+ 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.
@@ -142,17 +156,20 @@ def sort_variables(exprs):
"""
var_graph = get_graph(exprs)
sorted_vars = list()
- #determine dependency order
+ # Determine dependency order
while var_graph.get_nodes():
- #get a list of nodes with no edges
+ # 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
+ 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)
+ # 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.
@@ -166,12 +183,9 @@ def sort_objects(objects, get_id, get_expr):
a list of sorted objects
"""
id2obj = dict([(get_id(obj), obj) for obj in objects])
- #map obj id to expression code
+ # Map obj id to expression code
id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects])
- #sort according to dependency
+ # Sort according to dependency
sorted_ids = sort_variables(id2expr)
- #return list of sorted objects
+ # 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
diff --git a/grc/python/extract_docs.py b/grc/core/utils/extract_docs.py
index d8dc4f4e8f..a6e0bc971e 100644
--- a/grc/python/extract_docs.py
+++ b/grc/core/utils/extract_docs.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008-2011 Free Software Foundation, Inc.
+Copyright 2008-2015 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -32,8 +32,8 @@ import itertools
###############################################################################
def docstring_guess_from_key(key):
- """Extract the documentation from the python __doc__ strings
-
+ """
+ Extract the documentation from the python __doc__ strings
By guessing module and constructor names from key
Args:
@@ -65,12 +65,10 @@ def docstring_guess_from_key(key):
else:
return doc_strings
- pattern = re.compile(
- '^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$'
- )
+ pattern = re.compile('^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$')
for match in filter(pattern.match, dir(module)):
try:
- doc_strings[match] = getattr(module, match).__doc__.strip()
+ doc_strings[match] = getattr(module, match).__doc__
except AttributeError:
continue
@@ -78,8 +76,8 @@ def docstring_guess_from_key(key):
def docstring_from_make(key, imports, make):
- """Extract the documentation from the python __doc__ strings
-
+ """
+ Extract the documentation from the python __doc__ strings
By importing it and checking a truncated make
Args:
@@ -95,12 +93,10 @@ def docstring_from_make(key, imports, make):
blk_cls = make.partition('(')[0].strip()
if '$' in blk_cls:
raise ValueError('Not an identifier')
-
ns = dict()
for _import in imports:
exec(_import.strip(), ns)
blk = eval(blk_cls, ns)
-
doc_strings = {key: blk.__doc__}
except (ImportError, AttributeError, SyntaxError, ValueError):
@@ -114,10 +110,11 @@ def docstring_from_make(key, imports, make):
###############################################################################
class SubprocessLoader(object):
- """Start and manage docstring extraction process
-
+ """
+ Start and manage docstring extraction process
Manages subprocess and handles RPC.
"""
+
BOOTSTRAP = "import runpy; runpy.run_path({!r}, run_name='__worker__')"
AUTH_CODE = random.random() # sort out unwanted output of worker process
RESTART = 5 # number of worker restarts before giving up
@@ -134,7 +131,7 @@ class SubprocessLoader(object):
self._last_cmd = None
def start(self):
- """Start the worker process handler thread"""
+ """ Start the worker process handler thread """
if self._thread is not None:
return
self._shutdown.clear()
@@ -143,7 +140,7 @@ class SubprocessLoader(object):
thread.start()
def run_worker(self):
- """Read docstring back from worker stdout and execute callback."""
+ """ Read docstring back from worker stdout and execute callback. """
for _ in range(self.RESTART):
if self._shutdown.is_set():
break
@@ -173,7 +170,7 @@ class SubprocessLoader(object):
self.callback_finished()
def _handle_worker(self):
- """Send commands and responses back from worker."""
+ """ Send commands and responses back from worker. """
assert '1' == self._worker.stdout.read(1)
for cmd, args in iter(self._queue.get, self.DONE):
self._last_cmd = cmd, args
@@ -182,13 +179,13 @@ class SubprocessLoader(object):
self._handle_response(cmd, args)
def _send(self, cmd, args):
- """send a command to worker's stdin"""
+ """ Send a command to worker's stdin """
fd = self._worker.stdin
json.dump((self.AUTH_CODE, cmd, args), fd)
fd.write('\n'.encode())
def _receive(self):
- """receive response from worker's stdout"""
+ """ Receive response from worker's stdout """
for line in iter(self._worker.stdout.readline, ''):
try:
key, cmd, args = json.loads(line, encoding='utf-8')
@@ -201,7 +198,7 @@ class SubprocessLoader(object):
raise IOError("Can't read worker response")
def _handle_response(self, cmd, args):
- """Handle response from worker, call the callback"""
+ """ Handle response from worker, call the callback """
if cmd == 'result':
key, docs = args
self.callback_query_result(key, docs)
@@ -211,7 +208,7 @@ class SubprocessLoader(object):
print >> sys.stderr, "Unknown response:", cmd, args
def query(self, key, imports=None, make=None):
- """request docstring extraction for a certain key"""
+ """ Request docstring extraction for a certain key """
if self._thread is None:
self.start()
if imports and make:
@@ -220,16 +217,16 @@ class SubprocessLoader(object):
self._queue.put(('query_key_only', (key,)))
def finish(self):
- """signal end of requests"""
+ """ Signal end of requests """
self._queue.put(self.DONE)
def wait(self):
- """Wait for the handler thread to die"""
+ """ Wait for the handler thread to die """
if self._thread:
self._thread.join()
def terminate(self):
- """Terminate the worker and wait"""
+ """ Terminate the worker and wait """
self._shutdown.set()
try:
self._worker.terminate()
@@ -243,8 +240,8 @@ class SubprocessLoader(object):
###############################################################################
def worker_main():
- """Main entry point for the docstring extraction process.
-
+ """
+ Main entry point for the docstring extraction process.
Manages RPC with main process through.
Runs a docstring extraction for each key it read on stdin.
"""
diff --git a/grc/base/odict.py b/grc/core/utils/odict.py
index 70ab67d053..85927e869f 100644
--- a/grc/base/odict.py
+++ b/grc/core/utils/odict.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008-2011 Free Software Foundation, Inc.
+Copyright 2008-2015 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from UserDict import DictMixin
+
class odict(DictMixin):
def __init__(self, d={}):
@@ -57,7 +58,8 @@ class odict(DictMixin):
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))
+ if key in self._keys:
+ raise KeyError('Cannot insert, key "{}" already exists'.format(str(key)))
self._keys.insert(index+1, key)
self._data[key] = val
@@ -72,7 +74,8 @@ class odict(DictMixin):
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))
+ if key in self._keys:
+ raise KeyError('Cannot insert, key "{}" already exists'.format(str(key)))
self._keys.insert(index, key)
self._data[key] = val
@@ -86,7 +89,8 @@ class odict(DictMixin):
Returns:
the value or None
"""
- if self.has_key(key): return self[key]
+ if key in self:
+ return self[key]
return None
def findall(self, key):
@@ -100,6 +104,12 @@ class odict(DictMixin):
a list of values or empty list
"""
obj = self.find(key)
- if obj is None: obj = list()
- if isinstance(obj, list): return obj
+ if obj is None:
+ obj = list()
+ if isinstance(obj, list):
+ return obj
return [obj]
+
+ def clear(self):
+ self._data.clear()
+ del self._keys[:] \ No newline at end of file
diff --git a/grc/cpp/README b/grc/cpp/README
deleted file mode 100644
index 3eccc5dbf7..0000000000
--- a/grc/cpp/README
+++ /dev/null
@@ -1,5 +0,0 @@
-GRC could be used to generate c++ based flowgraphs:
-
-* A few base and gui classes would be overridden.
-* Block info could be extracted from the doxygen xml.
-* New flowgraph templates would be designed.
diff --git a/grc/examples/simple/variable_config.grc b/grc/examples/simple/variable_config.grc
deleted file mode 100644
index 0b60abc813..0000000000
--- a/grc/examples/simple/variable_config.grc
+++ /dev/null
@@ -1,561 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
- <timestamp>Sat Jul 12 16:15:51 2014</timestamp>
- <block>
- <key>options</key>
- <param>
- <key>id</key>
- <value>variable_config_demo</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>title</key>
- <value>Variable Config Block Demonstration</value>
- </param>
- <param>
- <key>author</key>
- <value>Example</value>
- </param>
- <param>
- <key>description</key>
- <value>Save/Load freq from a config file.</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>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(-1, 2)</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>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(-1, 125)</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>freq</value>
- </param>
- <param>
- <key>amp</key>
- <value>1</value>
- </param>
- <param>
- <key>offset</key>
- <value>0</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>affinity</key>
- <value></value>
- </param>
- <param>
- <key>minoutbuf</key>
- <value>0</value>
- </param>
- <param>
- <key>maxoutbuf</key>
- <value>0</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(173, 201)</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>ignoretag</key>
- <value>True</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>affinity</key>
- <value></value>
- </param>
- <param>
- <key>minoutbuf</key>
- <value>0</value>
- </param>
- <param>
- <key>maxoutbuf</key>
- <value>0</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(392, 233)</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>autoscale</key>
- <value>False</value>
- </param>
- <param>
- <key>average</key>
- <value>1.0</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></value>
- </param>
- <param>
- <key>label1</key>
- <value></value>
- </param>
- <param>
- <key>width1</key>
- <value>1</value>
- </param>
- <param>
- <key>color1</key>
- <value>"blue"</value>
- </param>
- <param>
- <key>alpha1</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label2</key>
- <value></value>
- </param>
- <param>
- <key>width2</key>
- <value>1</value>
- </param>
- <param>
- <key>color2</key>
- <value>"red"</value>
- </param>
- <param>
- <key>alpha2</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label3</key>
- <value></value>
- </param>
- <param>
- <key>width3</key>
- <value>1</value>
- </param>
- <param>
- <key>color3</key>
- <value>"green"</value>
- </param>
- <param>
- <key>alpha3</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label4</key>
- <value></value>
- </param>
- <param>
- <key>width4</key>
- <value>1</value>
- </param>
- <param>
- <key>color4</key>
- <value>"black"</value>
- </param>
- <param>
- <key>alpha4</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label5</key>
- <value></value>
- </param>
- <param>
- <key>width5</key>
- <value>1</value>
- </param>
- <param>
- <key>color5</key>
- <value>"cyan"</value>
- </param>
- <param>
- <key>alpha5</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label6</key>
- <value></value>
- </param>
- <param>
- <key>width6</key>
- <value>1</value>
- </param>
- <param>
- <key>color6</key>
- <value>"magenta"</value>
- </param>
- <param>
- <key>alpha6</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label7</key>
- <value></value>
- </param>
- <param>
- <key>width7</key>
- <value>1</value>
- </param>
- <param>
- <key>color7</key>
- <value>"yellow"</value>
- </param>
- <param>
- <key>alpha7</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label8</key>
- <value></value>
- </param>
- <param>
- <key>width8</key>
- <value>1</value>
- </param>
- <param>
- <key>color8</key>
- <value>"dark red"</value>
- </param>
- <param>
- <key>alpha8</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label9</key>
- <value></value>
- </param>
- <param>
- <key>width9</key>
- <value>1</value>
- </param>
- <param>
- <key>color9</key>
- <value>"dark green"</value>
- </param>
- <param>
- <key>alpha9</key>
- <value>1.0</value>
- </param>
- <param>
- <key>label10</key>
- <value></value>
- </param>
- <param>
- <key>width10</key>
- <value>1</value>
- </param>
- <param>
- <key>color10</key>
- <value>"dark blue"</value>
- </param>
- <param>
- <key>alpha10</key>
- <value>1.0</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>affinity</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(643, 221)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable_qtgui_range</key>
- <param>
- <key>id</key>
- <value>freq</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>label</key>
- <value>Frequency (Hz)</value>
- </param>
- <param>
- <key>value</key>
- <value>1e3</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></value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(339, 9)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable_config</key>
- <param>
- <key>id</key>
- <value>freq_init</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>value</key>
- <value>1000</value>
- </param>
- <param>
- <key>type</key>
- <value>real</value>
- </param>
- <param>
- <key>config_file</key>
- <value>/home/mbant/.gnuradio/config.conf</value>
- </param>
- <param>
- <key>section</key>
- <value>main</value>
- </param>
- <param>
- <key>option</key>
- <value>freq</value>
- </param>
- <param>
- <key>writeback</key>
- <value>freq</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(168, 0)</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_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>qtgui_freq_sink_x_0</sink_block_id>
- <source_key>0</source_key>
- <sink_key>0</sink_key>
- </connection>
-</flow_graph>
diff --git a/grc/examples/xmlrpc/readme.txt b/grc/examples/xmlrpc/readme.txt
deleted file mode 100644
index 056ad1e823..0000000000
--- a/grc/examples/xmlrpc/readme.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-##################################################
-# XMLRPC example
-##################################################
-
-XMLRPC allows software to make remote function calls over http.
-In the case of GRC, one can use XMLRPC to modify variables in a running flow graph.
-See http://www.xmlrpc.com/
-
---- Server Example ---
-Place an "XMLRPC Server" block inside of any flow graph.
-The server will provide set functions for every variable in the flow graph.
-If a variable is called "freq", the server will provide a function set_freq(new_freq).
-Run the server example and experiment with the example client script.
-
--- Client Example --
-The "XMLRPC Client" block will give a variable control over one remove function.
-In the example client, there is one client block and gui control per variable.
-This technique can be used to remotely control a flow graph, perhaps running on a non-gui machine.
diff --git a/grc/examples/xmlrpc/xmlrpc_client.grc b/grc/examples/xmlrpc/xmlrpc_client.grc
deleted file mode 100644
index 45d8af2824..0000000000
--- a/grc/examples/xmlrpc/xmlrpc_client.grc
+++ /dev/null
@@ -1,428 +0,0 @@
-<?xml version='1.0' encoding='ASCII'?>
-<flow_graph>
- <timestamp>Sat Jul 12 17:10:55 2014</timestamp>
- <block>
- <key>options</key>
- <param>
- <key>id</key>
- <value>client_block</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>title</key>
- <value>XMLRPC Client</value>
- </param>
- <param>
- <key>author</key>
- <value>Example</value>
- </param>
- <param>
- <key>description</key>
- <value>example flow graph</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>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(-2, 0)</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>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(13, 172)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>xmlrpc_client</key>
- <param>
- <key>id</key>
- <value>xmlrpc_client</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>addr</key>
- <value>localhost</value>
- </param>
- <param>
- <key>port</key>
- <value>1234</value>
- </param>
- <param>
- <key>callback</key>
- <value>set_freq</value>
- </param>
- <param>
- <key>variable</key>
- <value>freq</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(177, 0)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>xmlrpc_client</key>
- <param>
- <key>id</key>
- <value>xmlrpc_client0</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>addr</key>
- <value>localhost</value>
- </param>
- <param>
- <key>port</key>
- <value>1234</value>
- </param>
- <param>
- <key>callback</key>
- <value>set_ampl</value>
- </param>
- <param>
- <key>variable</key>
- <value>ampl</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(308, 0)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>xmlrpc_client</key>
- <param>
- <key>id</key>
- <value>xmlrpc_client1</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>addr</key>
- <value>localhost</value>
- </param>
- <param>
- <key>port</key>
- <value>1234</value>
- </param>
- <param>
- <key>callback</key>
- <value>set_offset</value>
- </param>
- <param>
- <key>variable</key>
- <value>offset*ampl</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(440, 4)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable_qtgui_range</key>
- <param>
- <key>id</key>
- <value>freq</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>label</key>
- <value>Frequency (Hz)</value>
- </param>
- <param>
- <key>value</key>
- <value>1000</value>
- </param>
- <param>
- <key>start</key>
- <value>0</value>
- </param>
- <param>
- <key>stop</key>
- <value>5e3</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,2</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(209, 165)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable_qtgui_range</key>
- <param>
- <key>id</key>
- <value>ampl</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>label</key>
- <value>Amplitude</value>
- </param>
- <param>
- <key>value</key>
- <value>1</value>
- </param>
- <param>
- <key>start</key>
- <value>0</value>
- </param>
- <param>
- <key>stop</key>
- <value>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>1,0,1,2</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(367, 158)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable_qtgui_chooser</key>
- <param>
- <key>id</key>
- <value>offset</value>
- </param>
- <param>
- <key>_enabled</key>
- <value>True</value>
- </param>
- <param>
- <key>label</key>
- <value>Offset</value>
- </param>
- <param>
- <key>type</key>
- <value>int</value>
- </param>
- <param>
- <key>num_opts</key>
- <value>3</value>
- </param>
- <param>
- <key>value</key>
- <value>0</value>
- </param>
- <param>
- <key>options</key>
- <value>[0, 1, 2]</value>
- </param>
- <param>
- <key>labels</key>
- <value>[]</value>
- </param>
- <param>
- <key>option0</key>
- <value>-1</value>
- </param>
- <param>
- <key>label0</key>
- <value>neg</value>
- </param>
- <param>
- <key>option1</key>
- <value>0</value>
- </param>
- <param>
- <key>label1</key>
- <value>zero</value>
- </param>
- <param>
- <key>option2</key>
- <value>1</value>
- </param>
- <param>
- <key>label2</key>
- <value>pos</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>2,0,1,2</value>
- </param>
- <param>
- <key>alias</key>
- <value></value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(531, 145)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
-</flow_graph>
diff --git a/grc/examples/xmlrpc/xmlrpc_client_script.py b/grc/examples/xmlrpc/xmlrpc_client_script.py
deleted file mode 100644
index e96c4cbf83..0000000000
--- a/grc/examples/xmlrpc/xmlrpc_client_script.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-
-import time
-import random
-import xmlrpclib
-
-#create server object
-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)
-
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 7766a0a853..11e81c4613 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -17,26 +17,21 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import os
-import subprocess
-from threading import Thread
-import pygtk
-pygtk.require('2.0')
-import gtk
import gobject
+import gtk
+import os
+import subprocess
-from .. base import ParseXML, Constants
-from .. python.Constants import XTERM_EXECUTABLE
-
-from . import Dialogs, Messages, Preferences, Actions
-from .ParserErrorsDialog import ParserErrorsDialog
-from .MainWindow import MainWindow
-from .PropsDialog import PropsDialog
+from . import Dialogs, Preferences, Actions, Executor, Constants
from .FileDialogs import (OpenFlowGraphFileDialog, SaveFlowGraphFileDialog,
- SaveReportsFileDialog, SaveImageFileDialog,
+ SaveConsoleFileDialog, SaveScreenShotDialog,
OpenQSSFileDialog)
-from .Constants import DEFAULT_CANVAS_SIZE, IMAGE_FILE_EXTENSION, GR_PREFIX
+from .MainWindow import MainWindow
+from .ParserErrorsDialog import ParserErrorsDialog
+from .PropsDialog import PropsDialog
+
+from ..core import ParseXML, Messages
gobject.threads_init()
@@ -66,16 +61,14 @@ class ActionHandler:
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.register_messenger(self.main_window.add_console_line)
Messages.send_init(platform)
#initialize
self.init_file_paths = file_paths
+ self.init = False
Actions.APPLICATION_INITIALIZE()
- #enter the mainloop
- gtk.main()
def _handle_key_press(self, widget, event):
"""
@@ -111,6 +104,14 @@ class ActionHandler:
def _handle_action(self, action, *args):
#print action
+ main = self.main_window
+ page = main.get_page()
+ flow_graph = page.get_flow_graph() if page else None
+
+ def flow_graph_update(fg=flow_graph):
+ main.vars.update_gui()
+ fg.update()
+
##################################################
# Initialize/Quit
##################################################
@@ -119,12 +120,13 @@ class ActionHandler:
self.init_file_paths = filter(os.path.exists, Preferences.get_open_files())
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 file_path: main.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
+ main.new_page(Preferences.file_open(), show=True)
+ if not self.get_page():
+ main.new_page() # ensure that at least a blank page exists
- self.main_window.btwin.search_entry.hide()
+ main.btwin.search_entry.hide()
# Disable all actions, then re-enable a few
for action in Actions.get_all_actions():
@@ -135,14 +137,18 @@ class ActionHandler:
Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW,
- Actions.TOGGLE_REPORTS_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
+ Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
Actions.TOOLS_RUN_FDESIGN, Actions.TOGGLE_SCROLL_LOCK,
- Actions.CLEAR_REPORTS, Actions.SAVE_REPORTS,
+ Actions.CLEAR_CONSOLE, Actions.SAVE_CONSOLE,
Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
Actions.FLOW_GRAPH_OPEN_QSS_THEME,
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
+ Actions.TOGGLE_HIDE_VARIABLES,
+ Actions.SELECT_ALL,
):
action.set_sensitive(True)
if hasattr(action, 'load_from_preferences'):
@@ -150,9 +156,9 @@ class ActionHandler:
if ParseXML.xml_failures:
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(True)
-
+ self.init = True
elif action == Actions.APPLICATION_QUIT:
- if self.main_window.close_pages():
+ if main.close_pages():
gtk.main_quit()
exit(0)
##################################################
@@ -161,25 +167,27 @@ class ActionHandler:
elif action == Actions.ELEMENT_SELECT:
pass #do nothing, update routines below
elif action == Actions.NOTHING_SELECT:
- self.get_flow_graph().unselect()
+ flow_graph.unselect()
+ elif action == Actions.SELECT_ALL:
+ flow_graph.select_all()
##################################################
# 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)
+ if flow_graph.enable_selected(True):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.enable_selected(False):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ page.set_saved(False)
elif action == Actions.BLOCK_BYPASS:
- if self.get_flow_graph().bypass_selected():
- 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)
+ if flow_graph.bypass_selected():
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ page.set_saved(False)
##################################################
# Cut/Copy/Paste
##################################################
@@ -187,20 +195,20 @@ class ActionHandler:
Actions.BLOCK_COPY()
Actions.ELEMENT_DELETE()
elif action == Actions.BLOCK_COPY:
- self.clipboard = self.get_flow_graph().copy_to_clipboard()
+ self.clipboard = 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)
+ flow_graph.paste_from_clipboard(self.clipboard)
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ page.set_saved(False)
##################################################
# Create heir block
##################################################
elif action == Actions.BLOCK_CREATE_HIER:
# keeping track of coordinates for pasting later
- coords = self.get_flow_graph().get_selected_blocks()[0].get_coordinate()
+ coords = flow_graph.get_selected_blocks()[0].get_coordinate()
x,y = coords
x_min = x
y_min = y
@@ -209,15 +217,15 @@ class ActionHandler:
params = [];
# Save the state of the leaf blocks
- for block in self.get_flow_graph().get_selected_blocks():
+ for block in flow_graph.get_selected_blocks():
# Check for string variables within the blocks
for param in block.get_params():
- for variable in self.get_flow_graph().get_variables():
+ for variable in flow_graph.get_variables():
# If a block parameter exists that is a variable, create a parameter for it
if param.get_value() == variable.get_id():
params.append(param.get_value())
- for flow_param in self.get_flow_graph().get_parameters():
+ for flow_param in flow_graph.get_parameters():
# If a block parameter exists that is a parameter, create a parameter for it
if param.get_value() == flow_param.get_id():
params.append(param.get_value())
@@ -230,46 +238,46 @@ class ActionHandler:
if y < y_min:
y_min = y
- for connection in block.get_connections():
+ for connection in block.connections:
# Get id of connected blocks
source_id = connection.get_source().get_parent().get_id()
sink_id = connection.get_sink().get_parent().get_id()
# If connected block is not in the list of selected blocks create a pad for it
- if self.get_flow_graph().get_block(source_id) not in self.get_flow_graph().get_selected_blocks():
+ if flow_graph.get_block(source_id) not in flow_graph.get_selected_blocks():
pads.append({'key': connection.get_sink().get_key(), 'coord': connection.get_source().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'source'})
- if self.get_flow_graph().get_block(sink_id) not in self.get_flow_graph().get_selected_blocks():
+ if flow_graph.get_block(sink_id) not in flow_graph.get_selected_blocks():
pads.append({'key': connection.get_source().get_key(), 'coord': connection.get_sink().get_coordinate(), 'block_id' : block.get_id(), 'direction': 'sink'})
# Copy the selected blocks and paste them into a new page
# then move the flowgraph to a reasonable position
Actions.BLOCK_COPY()
- self.main_window.new_page()
+ main.new_page()
Actions.BLOCK_PASTE()
coords = (x_min,y_min)
- self.get_flow_graph().move_selected(coords)
+ flow_graph.move_selected(coords)
# Set flow graph to heir block type
- top_block = self.get_flow_graph().get_block("top_block")
+ top_block = flow_graph.get_block("top_block")
top_block.get_param('generate_options').set_value('hb')
# this needs to be a unique name
top_block.get_param('id').set_value('new_heir')
# Remove the default samp_rate variable block that is created
- remove_me = self.get_flow_graph().get_block("samp_rate")
- self.get_flow_graph().remove_element(remove_me)
+ remove_me = flow_graph.get_block("samp_rate")
+ flow_graph.remove_element(remove_me)
# Add the param blocks along the top of the window
x_pos = 150
for param in params:
- param_id = self.get_flow_graph().add_new_block('parameter',(x_pos,10))
- param_block = self.get_flow_graph().get_block(param_id)
+ param_id = flow_graph.add_new_block('parameter',(x_pos,10))
+ param_block = flow_graph.get_block(param_id)
param_block.get_param('id').set_value(param)
x_pos = x_pos + 100
@@ -278,13 +286,13 @@ class ActionHandler:
if pad['direction'] == 'sink':
# Add new PAD_SINK block to the canvas
- pad_id = self.get_flow_graph().add_new_block('pad_sink', pad['coord'])
+ pad_id = flow_graph.add_new_block('pad_sink', pad['coord'])
# setup the references to the sink and source
- pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_block = flow_graph.get_block(pad_id)
pad_sink = pad_block.get_sinks()[0]
- source_block = self.get_flow_graph().get_block(pad['block_id'])
+ source_block = flow_graph.get_block(pad['block_id'])
source = source_block.get_source(pad['key'])
# Ensure the port types match
@@ -296,16 +304,16 @@ class ActionHandler:
pad_block.type_controller_modify(1)
# Connect the pad to the proper sinks
- new_connection = self.get_flow_graph().connect(source,pad_sink)
+ new_connection = flow_graph.connect(source,pad_sink)
elif pad['direction'] == 'source':
- pad_id = self.get_flow_graph().add_new_block('pad_source', pad['coord'])
+ pad_id = flow_graph.add_new_block('pad_source', pad['coord'])
# setup the references to the sink and source
- pad_block = self.get_flow_graph().get_block(pad_id)
+ pad_block = flow_graph.get_block(pad_id)
pad_source = pad_block.get_sources()[0]
- sink_block = self.get_flow_graph().get_block(pad['block_id'])
+ sink_block = flow_graph.get_block(pad['block_id'])
sink = sink_block.get_sink(pad['key'])
# Ensure the port types match
@@ -316,139 +324,172 @@ class ActionHandler:
pad_block.type_controller_modify(1)
# Connect the pad to the proper sinks
- new_connection = self.get_flow_graph().connect(pad_source,sink)
+ new_connection = flow_graph.connect(pad_source,sink)
# update the new heir block flow graph
- self.get_flow_graph().update()
+ 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)
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ page.set_saved(False)
+ elif action in Actions.BLOCK_ALIGNMENTS:
+ if flow_graph.align_selected(action):
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.rotate_selected(90):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.rotate_selected(-90):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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())
+ if flow_graph.remove_selected():
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
Actions.NOTHING_SELECT()
- self.get_page().set_saved(False)
+ 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())
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
Actions.NOTHING_SELECT()
- self.get_page().set_saved(False)
+ 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)
+ if flow_graph.type_controller_modify_selected(1):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.type_controller_modify_selected(-1):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.port_controller_modify_selected(1):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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)
+ if flow_graph.port_controller_modify_selected(-1):
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ page.set_saved(False)
##################################################
# Window stuff
##################################################
elif action == Actions.ABOUT_WINDOW_DISPLAY:
- Dialogs.AboutDialog(self.get_flow_graph().get_parent())
+ platform = flow_graph.get_parent()
+ Dialogs.AboutDialog(platform.config)
elif action == Actions.HELP_WINDOW_DISPLAY:
Dialogs.HelpDialog()
elif action == Actions.TYPES_WINDOW_DISPLAY:
- Dialogs.TypesDialog(self.get_flow_graph().get_parent())
+ Dialogs.TypesDialog(flow_graph.get_parent())
elif action == Actions.ERRORS_WINDOW_DISPLAY:
- Dialogs.ErrorsDialog(self.get_flow_graph())
- elif action == Actions.TOGGLE_REPORTS_WINDOW:
- if action.get_active():
- self.main_window.reports_scrolled_window.show()
- else:
- self.main_window.reports_scrolled_window.hide()
+ Dialogs.ErrorsDialog(flow_graph)
+ elif action == Actions.TOGGLE_CONSOLE_WINDOW:
+ main.update_panel_visibility(main.CONSOLE, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_BLOCKS_WINDOW:
- if action.get_active():
- self.main_window.btwin.show()
- else:
- self.main_window.btwin.hide()
+ main.update_panel_visibility(main.BLOCKS, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_SCROLL_LOCK:
active = action.get_active()
- self.main_window.text_display.scroll_lock = active
+ main.text_display.scroll_lock = active
if active:
- self.main_window.text_display.scroll_to_end()
+ main.text_display.scroll_to_end()
action.save_to_preferences()
- elif action == Actions.CLEAR_REPORTS:
- self.main_window.text_display.clear()
- elif action == Actions.SAVE_REPORTS:
- file_path = SaveReportsFileDialog(self.get_page().get_file_path()).run()
+ elif action == Actions.CLEAR_CONSOLE:
+ main.text_display.clear()
+ elif action == Actions.SAVE_CONSOLE:
+ file_path = SaveConsoleFileDialog(page.get_file_path()).run()
if file_path is not None:
- self.main_window.text_display.save(file_path)
+ main.text_display.save(file_path)
elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS:
Actions.NOTHING_SELECT()
elif action == Actions.TOGGLE_AUTO_HIDE_PORT_LABELS:
action.save_to_preferences()
- for page in self.main_window.get_pages():
+ for page in main.get_pages():
page.get_flow_graph().create_shapes()
- elif action == Actions.TOGGLE_SNAP_TO_GRID:
+ elif action in (Actions.TOGGLE_SNAP_TO_GRID,
+ Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
+ Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB):
action.save_to_preferences()
- elif action == Actions.TOGGLE_SHOW_BLOCK_COMMENTS:
+ elif action == Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY:
action.save_to_preferences()
- elif action == Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB:
+ for page in main.get_pages():
+ flow_graph_update(page.get_flow_graph())
+ elif action == Actions.TOGGLE_HIDE_VARIABLES:
+ # Call the variable editor TOGGLE in case it needs to be showing
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR()
+ Actions.NOTHING_SELECT()
action.save_to_preferences()
- elif action == Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY:
+ elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR:
+ # See if the variables are hidden
+ if Actions.TOGGLE_HIDE_VARIABLES.get_active():
+ # Force this to be shown
+ main.update_panel_visibility(main.VARIABLES, True)
+ action.set_active(True)
+ action.set_sensitive(False)
+ else:
+ if action.get_sensitive():
+ main.update_panel_visibility(main.VARIABLES, action.get_active())
+ else: # This is occurring after variables are un-hidden
+ # Leave it enabled
+ action.set_sensitive(True)
+ action.set_active(True)
+ #Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
action.save_to_preferences()
- for page in self.main_window.get_pages():
- page.get_flow_graph().update()
+ elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
+ if self.init:
+ md = gtk.MessageDialog(main,
+ gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO,
+ gtk.BUTTONS_CLOSE, "Moving the variable editor requires a restart of GRC.")
+ md.run()
+ md.destroy()
+ action.save_to_preferences()
##################################################
# Param Modifications
##################################################
elif action == Actions.BLOCK_PARAM_MODIFY:
- selected_block = self.get_flow_graph().get_selected_block()
+ if action.args:
+ selected_block = action.args[0]
+ else:
+ selected_block = flow_graph.get_selected_block()
if selected_block:
self.dialog = PropsDialog(selected_block)
response = gtk.RESPONSE_APPLY
while response == gtk.RESPONSE_APPLY: # rerun the dialog if Apply was hit
response = self.dialog.run()
if response in (gtk.RESPONSE_APPLY, gtk.RESPONSE_ACCEPT):
- 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)
+ flow_graph_update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ 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()
+ n = page.get_state_cache().get_current_state()
+ flow_graph.import_data(n)
+ flow_graph_update()
if response == gtk.RESPONSE_APPLY:
# null action, that updates the main window
Actions.ELEMENT_SELECT()
self.dialog.destroy()
self.dialog = None
elif action == Actions.EXTERNAL_UPDATE:
- self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
- self.get_flow_graph().update()
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ flow_graph_update()
if self.dialog is not None:
self.dialog.update_gui(force=True)
- self.get_page().set_saved(False)
+ page.set_saved(False)
+ elif action == Actions.VARIABLE_EDITOR_UPDATE:
+ page.get_state_cache().save_new_state(flow_graph.export_data())
+ flow_graph_update()
+ page.set_saved(False)
##################################################
# View Parser Errors
##################################################
@@ -458,135 +499,144 @@ class ActionHandler:
# Undo/Redo
##################################################
elif action == Actions.FLOW_GRAPH_UNDO:
- n = self.get_page().get_state_cache().get_prev_state()
+ n = 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)
+ flow_graph.unselect()
+ flow_graph.import_data(n)
+ flow_graph_update()
+ page.set_saved(False)
elif action == Actions.FLOW_GRAPH_REDO:
- n = self.get_page().get_state_cache().get_next_state()
+ n = 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)
+ flow_graph.unselect()
+ flow_graph.import_data(n)
+ flow_graph_update()
+ page.set_saved(False)
##################################################
# New/Open/Save/Close
##################################################
elif action == Actions.FLOW_GRAPH_NEW:
- self.main_window.new_page()
+ main.new_page()
if args:
- self.get_flow_graph()._options_block.get_param('generate_options').set_value(args[0])
- self.get_flow_graph().update()
+ flow_graph._options_block.get_param('generate_options').set_value(args[0])
+ flow_graph_update()
elif action == Actions.FLOW_GRAPH_OPEN:
- file_paths = args if args else OpenFlowGraphFileDialog(self.get_page().get_file_path()).run()
+ file_paths = args if args else OpenFlowGraphFileDialog(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))
+ main.new_page(file_path, show=(i==0))
Preferences.add_recent_file(file_path)
- self.main_window.tool_bar.refresh_submenus()
- self.main_window.menu_bar.refresh_submenus()
+ main.tool_bar.refresh_submenus()
+ main.menu_bar.refresh_submenus()
+ main.vars.update_gui()
elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME:
- file_paths = OpenQSSFileDialog(GR_PREFIX + '/share/gnuradio/themes/').run()
+ file_paths = OpenQSSFileDialog(self.platform.config.install_prefix +
+ '/share/gnuradio/themes/').run()
if file_paths:
try:
- from gnuradio import gr
- gr.prefs().set_string("qtgui", "qss", file_paths[0])
- gr.prefs().save()
+ prefs = self.platform.config.prefs
+ prefs.set_string("qtgui", "qss", file_paths[0])
+ prefs.save()
except Exception as e:
Messages.send("Failed to save QSS preference: " + str(e))
elif action == Actions.FLOW_GRAPH_CLOSE:
- self.main_window.close_page()
+ main.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():
+ if page.get_read_only() or not 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)
+ ParseXML.to_file(flow_graph.export_data(), page.get_file_path())
+ flow_graph.grc_file_path = page.get_file_path()
+ page.set_saved(True)
except IOError:
- Messages.send_fail_save(self.get_page().get_file_path())
- self.get_page().set_saved(False)
+ Messages.send_fail_save(page.get_file_path())
+ page.set_saved(False)
elif action == Actions.FLOW_GRAPH_SAVE_AS:
- file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run()
+ file_path = SaveFlowGraphFileDialog(page.get_file_path()).run()
if file_path is not None:
- self.get_page().set_file_path(file_path)
+ page.set_file_path(file_path)
Actions.FLOW_GRAPH_SAVE()
Preferences.add_recent_file(file_path)
- self.main_window.tool_bar.refresh_submenus()
- self.main_window.menu_bar.refresh_submenus()
+ main.tool_bar.refresh_submenus()
+ main.menu_bar.refresh_submenus()
elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
- file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
+ file_path, background_transparent = SaveScreenShotDialog(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:])
+ pixbuf = flow_graph.get_drawing_area().get_screenshot(background_transparent)
+ pixbuf.save(file_path, Constants.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():
+ if not page.get_proc():
+ if not page.get_saved() or not 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()
+ if page.get_saved() and page.get_file_path():
+ generator = 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
+ except Exception as e:
+ Messages.send_fail_gen(e)
+ else:
+ self.generator = None
elif action == Actions.FLOW_GRAPH_EXEC:
- if not self.get_page().get_proc():
+ if not page.get_proc():
Actions.FLOW_GRAPH_GEN()
- if Preferences.xterm_missing() != XTERM_EXECUTABLE:
- if not os.path.exists(XTERM_EXECUTABLE):
- Dialogs.MissingXTermDialog(XTERM_EXECUTABLE)
- Preferences.xterm_missing(XTERM_EXECUTABLE)
- if self.get_page().get_saved() and self.get_page().get_file_path():
- ExecFlowGraphThread(self)
+ xterm = self.platform.config.xterm_executable
+ if Preferences.xterm_missing() != xterm:
+ if not os.path.exists(xterm):
+ Dialogs.MissingXTermDialog(xterm)
+ Preferences.xterm_missing(xterm)
+ if page.get_saved() and page.get_file_path():
+ Executor.ExecFlowGraphThread(
+ flow_graph_page=page,
+ xterm_executable=xterm,
+ callback=self.update_exec_stop
+ )
elif action == Actions.FLOW_GRAPH_KILL:
- if self.get_page().get_proc():
+ if page.get_proc():
try:
- self.get_page().get_proc().kill()
+ page.get_proc().kill()
except:
- print "could not kill process: %d" % self.get_page().get_proc().pid
+ print "could not kill process: %d" % page.get_proc().pid
elif action == Actions.PAGE_CHANGE: # pass and run the global actions
pass
elif action == Actions.RELOAD_BLOCKS:
- self.platform.load_blocks()
- self.main_window.btwin.clear()
- self.platform.load_block_tree(self.main_window.btwin)
- Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(ParseXML.xml_failures))
+ self.platform.build_block_library()
+ main.btwin.repopulate()
+ Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(
+ ParseXML.xml_failures))
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
# Force a redraw of the graph, by getting the current state and re-importing it
- self.main_window.update_pages()
+ main.update_pages()
elif action == Actions.FIND_BLOCKS:
- self.main_window.btwin.show()
- self.main_window.btwin.search_entry.show()
- self.main_window.btwin.search_entry.grab_focus()
+ main.update_panel_visibility(main.BLOCKS, True)
+ main.btwin.search_entry.show()
+ main.btwin.search_entry.grab_focus()
elif action == Actions.OPEN_HIER:
- for b in self.get_flow_graph().get_selected_blocks():
+ for b in flow_graph.get_selected_blocks():
if b._grc_source:
- self.main_window.new_page(b._grc_source, show=True)
+ main.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():
+ for b in 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
+ flow_graph._old_selected_port = None
+ 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():
+ for b in 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
+ flow_graph._old_selected_port = None
+ flow_graph._new_selected_port = None
Actions.ELEMENT_CREATE()
elif action == Actions.TOOLS_RUN_FDESIGN:
@@ -598,15 +648,22 @@ class ActionHandler:
##################################################
# Global Actions for all States
##################################################
- selected_block = self.get_flow_graph().get_selected_block()
- selected_blocks = self.get_flow_graph().get_selected_blocks()
+ page = main.get_page() # page and flowgraph might have changed
+ flow_graph = page.get_flow_graph() if page else None
+
+ selected_blocks = flow_graph.get_selected_blocks()
+ selected_block = selected_blocks[0] if selected_blocks else None
#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.ERRORS_WINDOW_DISPLAY.set_sensitive(not flow_graph.is_valid())
+ Actions.ELEMENT_DELETE.set_sensitive(bool(flow_graph.get_selected_elements()))
Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block))
Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks))
Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks))
+ #update alignment options
+ for act in Actions.BLOCK_ALIGNMENTS:
+ if act:
+ act.set_sensitive(len(selected_blocks) > 1)
#update cut/copy/paste
Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks))
Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks))
@@ -631,17 +688,17 @@ class ActionHandler:
#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()
+ Actions.FLOW_GRAPH_SAVE.set_sensitive(not page.get_saved())
+ main.update()
try: #set the size of the flow graph area (if changed)
- new_size = (self.get_flow_graph().get_option('window_size') or
- DEFAULT_CANVAS_SIZE)
- if self.get_flow_graph().get_size() != tuple(new_size):
- self.get_flow_graph().set_size(*new_size)
+ new_size = (flow_graph.get_option('window_size') or
+ self.platform.config.default_canvas_size)
+ if flow_graph.get_size() != tuple(new_size):
+ flow_graph.set_size(*new_size)
except: pass
#draw the flow graph
- self.get_flow_graph().update_selected()
- self.get_flow_graph().queue_draw()
+ flow_graph.update_selected()
+ flow_graph.queue_draw()
return True #action was handled
def update_exec_stop(self):
@@ -649,52 +706,7 @@ class ActionHandler:
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()
+ sensitive = self.main_window.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() is not 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()
- #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)
- self.p.poll()
- gobject.idle_add(self.done)
-
- def done(self):
- """Perform end of execution tasks."""
- Messages.send_end_exec(self.p.returncode)
- self.page.set_proc(None)
- self.update_exec_stop()
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 9b32b3e601..9b2af36b93 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -92,6 +92,7 @@ class _ActionBase(object):
self.set_accel_group(get_accel_group())
self.set_accel_path(accel_path)
gtk.accel_map_add_entry(accel_path, keyval, mod_mask)
+ self.args = None
def __str__(self):
"""
@@ -105,10 +106,11 @@ class _ActionBase(object):
def __repr__(self): return str(self)
- def __call__(self):
+ def __call__(self, *args):
"""
Emit the activate signal when called with ().
"""
+ self.args = args
self.emit('activate')
@@ -171,6 +173,7 @@ class ToggleAction(gtk.ToggleAction, _ActionBase):
########################################################################
PAGE_CHANGE = Action()
EXTERNAL_UPDATE = Action()
+VARIABLE_EDITOR_UPDATE = Action()
FLOW_GRAPH_NEW = Action(
label='_New',
tooltip='Create a new flow graph',
@@ -226,6 +229,12 @@ FLOW_GRAPH_REDO = Action(
keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK),
)
NOTHING_SELECT = Action()
+SELECT_ALL = Action(
+ label='Select _All',
+ tooltip='Select all blocks and connections in the flow graph',
+ stock_id=gtk.STOCK_SELECT_ALL,
+ keypresses=(gtk.keysyms.a, gtk.gdk.CONTROL_MASK),
+)
ELEMENT_SELECT = Action()
ELEMENT_CREATE = Action()
ELEMENT_DELETE = Action(
@@ -247,6 +256,45 @@ BLOCK_ROTATE_CW = Action(
stock_id=gtk.STOCK_GO_FORWARD,
keypresses=(gtk.keysyms.Right, NO_MODS_MASK),
)
+BLOCK_VALIGN_TOP = Action(
+ label='Vertical Align Top',
+ tooltip='Align tops of selected blocks',
+ keypresses=(gtk.keysyms.t, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_VALIGN_MIDDLE = Action(
+ label='Vertical Align Middle',
+ tooltip='Align centers of selected blocks vertically',
+ keypresses=(gtk.keysyms.m, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_VALIGN_BOTTOM = Action(
+ label='Vertical Align Bottom',
+ tooltip='Align bottoms of selected blocks',
+ keypresses=(gtk.keysyms.b, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_HALIGN_LEFT = Action(
+ label='Horizontal Align Left',
+ tooltip='Align left edges of blocks selected blocks',
+ keypresses=(gtk.keysyms.l, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_HALIGN_CENTER = Action(
+ label='Horizontal Align Center',
+ tooltip='Align centers of selected blocks horizontally',
+ keypresses=(gtk.keysyms.c, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_HALIGN_RIGHT = Action(
+ label='Horizontal Align Right',
+ tooltip='Align right edges of selected blocks',
+ keypresses=(gtk.keysyms.r, gtk.gdk.SHIFT_MASK),
+)
+BLOCK_ALIGNMENTS = [
+ BLOCK_VALIGN_TOP,
+ BLOCK_VALIGN_MIDDLE,
+ BLOCK_VALIGN_BOTTOM,
+ None,
+ BLOCK_HALIGN_LEFT,
+ BLOCK_HALIGN_CENTER,
+ BLOCK_HALIGN_RIGHT,
+]
BLOCK_PARAM_MODIFY = Action(
label='_Properties',
tooltip='Modify params for the selected block',
@@ -282,6 +330,26 @@ TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction(
stock_id=gtk.STOCK_MISSING_IMAGE,
keypresses=(gtk.keysyms.d, gtk.gdk.CONTROL_MASK),
)
+TOGGLE_HIDE_VARIABLES = ToggleAction(
+ label='Hide Variables',
+ tooltip='Hide all variable blocks',
+ preference_name='hide_variables',
+ default=False,
+)
+TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction(
+ label='Show _Variable Editor',
+ tooltip='Show the variable editor. Modify variables and imports in this flow graph',
+ stock_id=gtk.STOCK_EDIT,
+ default=True,
+ keypresses=(gtk.keysyms.e, gtk.gdk.CONTROL_MASK),
+ preference_name='variable_editor_visable',
+)
+TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction(
+ label='Move the Variable Editor to the Sidebar',
+ tooltip='Move the variable editor to the sidebar',
+ default=False,
+ preference_name='variable_editor_sidebar',
+)
TOGGLE_AUTO_HIDE_PORT_LABELS = ToggleAction(
label='Auto-Hide _Port Labels',
tooltip='Automatically hide port labels',
@@ -334,11 +402,11 @@ ERRORS_WINDOW_DISPLAY = Action(
tooltip='View flow graph errors',
stock_id=gtk.STOCK_DIALOG_ERROR,
)
-TOGGLE_REPORTS_WINDOW = ToggleAction(
- label='Show _Reports Panel',
- tooltip='Toggle visibility of the Report widget',
+TOGGLE_CONSOLE_WINDOW = ToggleAction(
+ label='Show _Console Panel',
+ tooltip='Toggle visibility of the console',
keypresses=(gtk.keysyms.r, gtk.gdk.CONTROL_MASK),
- preference_name='reports_window_visible'
+ preference_name='console_window_visible'
)
TOGGLE_BLOCKS_WINDOW = ToggleAction(
label='Show _Block Tree Panel',
@@ -347,8 +415,8 @@ TOGGLE_BLOCKS_WINDOW = ToggleAction(
preference_name='blocks_window_visible'
)
TOGGLE_SCROLL_LOCK = ToggleAction(
- label='Reports Scroll _Lock',
- tooltip='Toggle scroll lock for the report window',
+ label='Console Scroll _Lock',
+ tooltip='Toggle scroll lock for the console window',
preference_name='scroll_lock'
)
ABOUT_WINDOW_DISPLAY = Action(
@@ -386,7 +454,7 @@ FLOW_GRAPH_KILL = Action(
keypresses=(gtk.keysyms.F7, NO_MODS_MASK),
)
FLOW_GRAPH_SCREEN_CAPTURE = Action(
- label='Sc_reen Capture',
+ label='Screen Ca_pture',
tooltip='Create a screen capture of the flow graph',
stock_id=gtk.STOCK_PRINT,
keypresses=(gtk.keysyms.Print, NO_MODS_MASK),
@@ -415,14 +483,14 @@ FIND_BLOCKS = Action(
keypresses=(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
gtk.keysyms.slash, NO_MODS_MASK),
)
-CLEAR_REPORTS = Action(
- label='_Clear Reports',
- tooltip='Clear Reports',
+CLEAR_CONSOLE = Action(
+ label='_Clear Console',
+ tooltip='Clear Console',
stock_id=gtk.STOCK_CLEAR,
)
-SAVE_REPORTS = Action(
- label='_Save Reports',
- tooltip='Save Reports',
+SAVE_CONSOLE = Action(
+ label='_Save Console',
+ tooltip='Save Console',
stock_id=gtk.STOCK_SAVE,
)
OPEN_HIER = Action(
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 8b389a797c..a4819b973c 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -31,6 +31,7 @@ TOOLBAR_LIST = (
Actions.FLOW_GRAPH_SAVE,
Actions.FLOW_GRAPH_CLOSE,
None,
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
Actions.FLOW_GRAPH_SCREEN_CAPTURE,
None,
Actions.BLOCK_CUT,
@@ -82,9 +83,11 @@ MENU_BAR_LIST = (
Actions.BLOCK_COPY,
Actions.BLOCK_PASTE,
Actions.ELEMENT_DELETE,
+ Actions.SELECT_ALL,
None,
Actions.BLOCK_ROTATE_CCW,
Actions.BLOCK_ROTATE_CW,
+ (gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS),
None,
Actions.BLOCK_ENABLE,
Actions.BLOCK_DISABLE,
@@ -95,10 +98,14 @@ MENU_BAR_LIST = (
(gtk.Action('View', '_View', None, None), [
Actions.TOGGLE_BLOCKS_WINDOW,
None,
- Actions.TOGGLE_REPORTS_WINDOW,
+ Actions.TOGGLE_CONSOLE_WINDOW,
Actions.TOGGLE_SCROLL_LOCK,
- Actions.SAVE_REPORTS,
- Actions.CLEAR_REPORTS,
+ Actions.SAVE_CONSOLE,
+ Actions.CLEAR_CONSOLE,
+ None,
+ Actions.TOGGLE_HIDE_VARIABLES,
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
+ Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
None,
Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
diff --git a/grc/gui/Block.py b/grc/gui/Block.py
index 67b80695fa..55c8805fae 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -17,22 +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
"""
-from Element import Element
-import Utils
-import Colors
-from .. base import odict
-from .. python.Param import num_to_str
-from Constants import BORDER_PROXIMITY_SENSITIVITY
-from Constants import (
- BLOCK_LABEL_PADDING, PORT_SPACING, PORT_SEPARATION, LABEL_SEPARATION,
- PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS, BLOCK_FONT, PARAM_FONT
-)
-import Actions
import pygtk
pygtk.require('2.0')
import gtk
import pango
+from . import Actions, Colors, Utils, Constants
+
+from . Element import Element
+from ..core.Param import num_to_str
+from ..core.utils import odict
+from ..core.utils.complexity import calculate_flowgraph_complexity
+from ..core.Block import Block as _Block
+
BLOCK_MARKUP_TMPL="""\
#set $foreground = $block.is_valid() and 'black' or 'red'
<span foreground="$foreground" font_desc="$font"><b>$encode($block.get_name())</b></span>"""
@@ -52,15 +49,16 @@ COMMENT_COMPLEXITY_MARKUP_TMPL="""\
"""
-
-class Block(Element):
+class Block(Element, _Block):
"""The graphical signal block."""
- def __init__(self):
+ def __init__(self, flow_graph, n):
"""
Block contructor.
Add graphics related params to the block.
"""
+ _Block.__init__(self, flow_graph, n)
+
self.W = 0
self.H = 0
#add the position param
@@ -95,18 +93,19 @@ class Block(Element):
Returns:
the coordinate tuple (x, y) or (0, 0) if failure
"""
+ proximity = Constants.BORDER_PROXIMITY_SENSITIVITY
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
+ elif x >= fgW - proximity:
+ x = fgW - proximity
if y <= 0:
y = 0
- elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
- y = fgH - BORDER_PROXIMITY_SENSITIVITY
+ elif y >= fgH - proximity:
+ y = fgH - proximity
return (x, y)
except:
self.set_coordinate((0, 0))
@@ -135,10 +134,10 @@ class Block(Element):
delta_coor: requested delta coordinate (dX, dY) to move
Returns:
- The delta coordinate possible to move while keeping the block on the canvas
+ The delta coordinate possible to move while keeping the block on the canvas
or the input (dX, dY) on failure
"""
- dX, dY = delta_coor
+ dX, dY = delta_coor
try:
fgW, fgH = self.get_parent().get_size()
@@ -147,7 +146,7 @@ class Block(Element):
sW, sH = self.W, self.H
else:
sW, sH = self.H, self.W
-
+
if x + dX < 0:
dX = -x
elif dX + x + sW >= fgW:
@@ -159,7 +158,7 @@ class Block(Element):
except:
pass
- return ( dX, dY )
+ return ( dX, dY )
def get_rotation(self):
"""
@@ -172,8 +171,8 @@ class Block(Element):
rotation = eval(self.get_param('_rotation').get_value())
return int(rotation)
except:
- self.set_rotation(POSSIBLE_ROTATIONS[0])
- return POSSIBLE_ROTATIONS[0]
+ self.set_rotation(Constants.POSSIBLE_ROTATIONS[0])
+ return Constants.POSSIBLE_ROTATIONS[0]
def set_rotation(self, rot):
"""
@@ -193,7 +192,7 @@ class Block(Element):
def create_labels(self):
"""Create the labels for the signal block."""
Element.create_labels(self)
- self._bg_color = self.is_dummy_block() and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \
+ self._bg_color = self.is_dummy_block and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \
self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR or \
self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
@@ -201,23 +200,24 @@ class Block(Element):
#create the main layout
layout = gtk.DrawingArea().create_pango_layout('')
layouts.append(layout)
- layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self, font=BLOCK_FONT))
+ layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self, font=Constants.BLOCK_FONT))
self.label_width, self.label_height = layout.get_pixel_size()
#display the params
- if self.is_dummy_block():
+ if self.is_dummy_block:
markups = [
- '<span foreground="black" font_desc="{font}"><b>key: </b>{key}</span>'.format(font=PARAM_FONT, key=self._key)
+ '<span foreground="black" font_desc="{font}"><b>key: </b>{key}</span>'
+ ''.format(font=Constants.PARAM_FONT, key=self._key)
]
else:
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_spacing(Constants.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
+ self.label_height += h + Constants.LABEL_SEPARATION
width = self.label_width
height = self.label_height
#setup the pixmap
@@ -232,33 +232,35 @@ class Block(Element):
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
+ h_off = h + h_off + Constants.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
+ W = self.label_width + 2 * Constants.BLOCK_LABEL_PADDING
def get_min_height_for_ports():
visible_ports = filter(lambda p: not p.get_hide(), ports)
- H = 2*PORT_BORDER_SEPARATION + len(visible_ports) * PORT_SEPARATION
- if visible_ports: H -= ports[0].H
- return H
- self.H = max(
+ min_height = 2*Constants.PORT_BORDER_SEPARATION + len(visible_ports) * Constants.PORT_SEPARATION
+ if visible_ports:
+ min_height -= ports[0].H
+ return min_height
+ H = max(
[ # labels
- self.label_height + 2 * BLOCK_LABEL_PADDING
+ self.label_height + 2 * Constants.BLOCK_LABEL_PADDING
] +
[ # ports
get_min_height_for_ports() for ports in (self.get_sources_gui(), self.get_sinks_gui())
] +
[ # bus ports only
- 2 * PORT_BORDER_SEPARATION +
- sum([port.H + PORT_SPACING for port in ports if port.get_type() == 'bus']) - PORT_SPACING
+ 2 * Constants.PORT_BORDER_SEPARATION +
+ sum([port.H + Constants.PORT_SPACING for port in ports if port.get_type() == 'bus']) - Constants.PORT_SPACING
for ports in (self.get_sources_gui(), self.get_sinks_gui())
]
)
+ self.W, self.H = Utils.align_to_grid((W, H))
self.has_busses = [
any(port.get_type() == 'bus' for port in ports)
for ports in (self.get_sources_gui(), self.get_sinks_gui())
@@ -271,19 +273,20 @@ class Block(Element):
# Show the flowgraph complexity on the top block if enabled
if Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY.get_active() and self.get_key() == "options":
- complexity = "Complexity: {}bal".format(num_to_str(self.get_parent().get_complexity()))
+ complexity = calculate_flowgraph_complexity(self.get_parent())
+ complexity = "Complexity: {}bal".format(num_to_str(complexity))
layout = gtk.DrawingArea().create_pango_layout('')
layout.set_markup(Utils.parse_template(COMMENT_COMPLEXITY_MARKUP_TMPL,
block=self,
comment=comment,
complexity=complexity,
- font=BLOCK_FONT))
+ font=Constants.BLOCK_FONT))
# Setup the pixel map. Make sure that layout not empty
width, height = layout.get_pixel_size()
if width and height:
- padding = BLOCK_LABEL_PADDING
+ padding = Constants.BLOCK_LABEL_PADDING
pixmap = self.get_parent().new_pixmap(width + 2 * padding,
height + 2 * padding)
gc = pixmap.new_gc()
@@ -311,13 +314,13 @@ class Block(Element):
Element.draw(
self, gc, window, bg_color=self._bg_color,
border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or
- self.is_dummy_block() and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR,
+ self.is_dummy_block and Colors.MISSING_BLOCK_BORDER_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)
+ window.draw_drawable(gc, self.horizontal_label, 0, 0, x+Constants.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)
+ window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+Constants.BLOCK_LABEL_PADDING, -1, -1)
def what_is_selected(self, coor, coor_m=None):
"""
@@ -339,6 +342,10 @@ class Block(Element):
if not self._comment_pixmap:
return
x, y = self.get_coordinate()
- y += self.H if self.is_horizontal() else self.W
- window.draw_drawable(gc, self._comment_pixmap, 0, 0, x,
- y + BLOCK_LABEL_PADDING, -1, -1)
+
+ if self.is_horizontal():
+ y += self.H + Constants.BLOCK_LABEL_PADDING
+ else:
+ x += self.H + Constants.BLOCK_LABEL_PADDING
+
+ window.draw_drawable(gc, self._comment_pixmap, 0, 0, x, y, -1, -1)
diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py
index 6b3ebf7807..f49eb6c4fe 100644
--- a/grc/gui/BlockTreeWindow.py
+++ b/grc/gui/BlockTreeWindow.py
@@ -23,23 +23,59 @@ import gtk
import gobject
from . import Actions, Utils
-from .Constants import DEFAULT_BLOCKS_WINDOW_WIDTH, DND_TARGETS
+from . import Constants
+
NAME_INDEX = 0
KEY_INDEX = 1
DOC_INDEX = 2
DOC_MARKUP_TMPL = """\
-#if $doc
-#if len($doc) > 1000
-#set $doc = $doc[:1000] + '...'
+#set $docs = []
+#if $doc.get('')
+ #set $docs += $doc.pop('').splitlines() + ['']
#end if
-$encode($doc)#slurp
-#else
+#for b, d in $doc.iteritems()
+ #set $docs += ['--- {0} ---'.format(b)] + d.splitlines() + ['']
+#end for
+#set $len_out = 0
+#for $n, $line in $enumerate($docs[:-1])
+#if $n
+
+#end if
+$encode($line)#slurp
+#set $len_out += $len($line)
+#if $n > 10 or $len_out > 500
+
+...#slurp
+#break
+#end if
+#end for
+#if $len_out == 0
undocumented#slurp
#end if"""
-CAT_MARKUP_TMPL = """Category: $cat"""
+CAT_MARKUP_TMPL = """
+#set $name = $cat[-1]
+#if len($cat) > 1
+Category: $cat[-1]
+##
+#elif $name == 'Core'
+Module: Core
+
+This subtree is meant for blocks included with GNU Radio (in-tree).
+##
+#elif $name == $default_module
+This subtree holds all blocks (from OOT modules) that specify no module name. \
+The module name is the root category enclosed in square brackets.
+
+Please consider contacting OOT module maintainer for any block in here \
+and kindly ask to update their GRC Block Descriptions or Block Tree to include a module name.
+#else
+Module: $name
+##
+#end if
+""".strip()
class BlockTreeWindow(gtk.VBox):
@@ -98,57 +134,69 @@ class BlockTreeWindow(gtk.VBox):
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.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, Constants.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)
+ scrolled_window.set_size_request(Constants.DEFAULT_BLOCKS_WINDOW_WIDTH, -1)
self.pack_start(scrolled_window)
# map categories to iters, automatic mapping for root
self._categories = {tuple(): None}
self._categories_search = {tuple(): None}
- # add blocks and categories
- self.platform.load_block_tree(self)
self.platform.block_docstrings_loaded_callback = self.update_docs
+ self.repopulate()
def clear(self):
- self.treestore.clear();
- self._categories = {tuple(): None}
+ self.treestore.clear()
+ self._categories = {(): None}
+
+ def repopulate(self):
+ self.clear()
+ for block in self.platform.blocks.itervalues():
+ if block.category:
+ self.add_block(block)
+ self.expand_module_in_tree()
+
+ def expand_module_in_tree(self, module_name='Core'):
+ self.treeview.collapse_all()
+ core_module_iter = self._categories.get((module_name,))
+ if core_module_iter:
+ self.treeview.expand_row(self.treestore.get_path(core_module_iter), False)
############################################################
## Block Tree Methods
############################################################
- def add_block(self, category, block=None, treestore=None, categories=None):
+ def add_block(self, block, treestore=None, categories=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 treestore is None: treestore = self.treestore
- if categories is None: categories = self._categories
+ treestore = treestore or self.treestore
+ categories = categories or self._categories
+
+ category = tuple(filter(str, block.category)) # tuple is hashable, remove empty cats
- if isinstance(category, (str, unicode)): 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 categories:
- iter = treestore.insert_before(categories[sub_category[:-1]], None)
- treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
- treestore.set_value(iter, KEY_INDEX, '')
- treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
- categories[sub_category] = iter
+ for level, parent_cat_name in enumerate(category, 1):
+ parent_category = category[:level]
+ if parent_category not in categories:
+ iter_ = treestore.insert_before(categories[parent_category[:-1]], None)
+ treestore.set_value(iter_, NAME_INDEX, parent_cat_name)
+ treestore.set_value(iter_, KEY_INDEX, '')
+ treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(
+ CAT_MARKUP_TMPL, cat=parent_category, default_module=Constants.DEFAULT_BLOCK_MODULE_NAME))
+ categories[parent_category] = iter_
+
# add block
- if block is None: return
- iter = treestore.insert_before(categories[category], None)
- treestore.set_value(iter, NAME_INDEX, block.get_name())
- treestore.set_value(iter, KEY_INDEX, block.get_key())
- treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
+ iter_ = treestore.insert_before(categories[category], None)
+ treestore.set_value(iter_, NAME_INDEX, block.get_name())
+ treestore.set_value(iter_, KEY_INDEX, block.get_key())
+ treestore.set_value(iter_, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
def update_docs(self):
"""Update the documentation column of every block"""
@@ -157,7 +205,7 @@ class BlockTreeWindow(gtk.VBox):
if model.iter_has_child(iter_):
return # category node, no doc string
key = model.get_value(iter_, KEY_INDEX)
- block = self.platform.get_block(key)
+ block = self.platform.blocks[key]
doc = Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())
model.set_value(iter_, DOC_INDEX, doc)
@@ -208,16 +256,15 @@ class BlockTreeWindow(gtk.VBox):
key = widget.get_text().lower()
if not key:
self.treeview.set_model(self.treestore)
- self.treeview.collapse_all()
+ self.expand_module_in_tree()
else:
- blocks = self.get_flow_graph().get_parent().get_blocks()
- matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(), blocks)
+ matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(),
+ self.platform.blocks.values())
self.treestore_search.clear()
self._categories_search = {tuple(): None}
for block in matching_blocks:
- self.add_block(block.get_category() or 'None', block,
- self.treestore_search, self._categories_search)
+ self.add_block(block, self.treestore_search, self._categories_search)
self.treeview.set_model(self.treestore_search)
self.treeview.expand_all()
diff --git a/grc/gui/CMakeLists.txt b/grc/gui/CMakeLists.txt
index 99140df7c4..aa9592b351 100644
--- a/grc/gui/CMakeLists.txt
+++ b/grc/gui/CMakeLists.txt
@@ -17,34 +17,10 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
-########################################################################
-GR_PYTHON_INSTALL(FILES
- external_editor.py
- Block.py
- Colors.py
- Constants.py
- Connection.py
- Element.py
- FlowGraph.py
- Param.py
- Platform.py
- Port.py
- Utils.py
- ActionHandler.py
- Actions.py
- Bars.py
- BlockTreeWindow.py
- Dialogs.py
- DrawingArea.py
- FileDialogs.py
- MainWindow.py
- Messages.py
- NotebookPage.py
- ParserErrorsDialog.py
- PropsDialog.py
- Preferences.py
- StateCache.py
- __init__.py
+file(GLOB py_files "*.py")
+
+GR_PYTHON_INSTALL(
+ FILES ${py_files}
DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/gui
COMPONENT "grc"
)
diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py
index 52c95e8edf..d322afa410 100644
--- a/grc/gui/Colors.py
+++ b/grc/gui/Colors.py
@@ -33,12 +33,13 @@ try:
PARAM_ENTRY_TEXT_COLOR = get_color('black')
ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE')
#flow graph color constants
- FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFF9FF')
+ FLOWGRAPH_BACKGROUND_COLOR = get_color('#FFFFFF')
COMMENT_BACKGROUND_COLOR = get_color('#F3F3F3')
+ FLOWGRAPH_EDGE_COLOR = COMMENT_BACKGROUND_COLOR
#block color constants
BLOCK_ENABLED_COLOR = get_color('#F1ECFF')
BLOCK_DISABLED_COLOR = get_color('#CCCCCC')
- BLOCK_BYPASSED_COLOR = get_color('#FFFFE6')
+ BLOCK_BYPASSED_COLOR = get_color('#F4FF81')
#connection color constants
CONNECTION_ENABLED_COLOR = get_color('black')
CONNECTION_DISABLED_COLOR = get_color('#BBBBBB')
diff --git a/grc/gui/Config.py b/grc/gui/Config.py
new file mode 100644
index 0000000000..9b0c5d4afe
--- /dev/null
+++ b/grc/gui/Config.py
@@ -0,0 +1,74 @@
+"""
+Copyright 2016 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import sys
+import os
+from ..core.Config import Config as _Config
+from . import Constants
+
+
+class Config(_Config):
+
+ name = 'GNU Radio Companion'
+
+ gui_prefs_file = os.environ.get(
+ 'GRC_PREFS_PATH', os.path.expanduser('~/.gnuradio/grc.conf'))
+
+ def __init__(self, install_prefix, *args, **kwargs):
+ _Config.__init__(self, *args, **kwargs)
+ self.install_prefix = install_prefix
+ Constants.update_font_size(self.font_size)
+
+ @property
+ def editor(self):
+ return self.prefs.get_string('grc', 'editor', '')
+
+ @editor.setter
+ def editor(self, value):
+ self.prefs.get_string('grc', 'editor', value)
+ self.prefs.save()
+
+ @property
+ def xterm_executable(self):
+ return self.prefs.get_string('grc', 'xterm_executable', 'xterm')
+
+ @property
+ def default_canvas_size(self):
+ try: # ugly, but matches current code style
+ raw = self.prefs.get_string('grc', 'canvas_default_size', '1280, 1024')
+ value = tuple(int(x.strip('() ')) for x in raw.split(','))
+ if len(value) != 2 or not all(300 < x < 4096 for x in value):
+ raise Exception()
+ return value
+ except:
+ print >> sys.stderr, "Error: invalid 'canvas_default_size' setting."
+ return Constants.DEFAULT_CANVAS_SIZE_DEFAULT
+
+ @property
+ def font_size(self):
+ try: # ugly, but matches current code style
+ font_size = self.prefs.get_long('grc', 'canvas_font_size',
+ Constants.DEFAULT_FONT_SIZE)
+ if font_size <= 0:
+ raise Exception()
+ except:
+ font_size = Constants.DEFAULT_FONT_SIZE
+ print >> sys.stderr, "Error: invalid 'canvas_font_size' setting."
+
+ return font_size
diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py
index badf8e8a82..50361c19d0 100644
--- a/grc/gui/Connection.py
+++ b/grc/gui/Connection.py
@@ -17,15 +17,18 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import Utils
-from Element import Element
+import gtk
+
import Colors
+import Utils
from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT
-import gtk
+from Element import Element
+
+from ..core.Constants import GR_MESSAGE_DOMAIN
+from ..core.Connection import Connection as _Connection
-from .. base.Constants import GR_MESSAGE_DOMAIN
-class Connection(Element):
+class Connection(Element, _Connection):
"""
A graphical connection for ports.
The connection has 2 parts, the arrow and the wire.
@@ -35,8 +38,9 @@ class Connection(Element):
The arrow coloring exposes the enabled and valid states.
"""
- def __init__(self):
+ def __init__(self, **kwargs):
Element.__init__(self)
+ _Connection.__init__(self, **kwargs)
# can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc)
self._bg_color = self._arrow_color = self._color = None
@@ -88,7 +92,7 @@ class Connection(Element):
if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \
else gtk.gdk.LINE_ON_OFF_DASH
get_domain_color = lambda d: Colors.get_color((
- self.get_parent().get_parent().get_domain(d) or {}
+ self.get_parent().get_parent().domains.get(d, {})
).get('color') or Colors.DEFAULT_DOMAIN_COLOR_CODE)
self._color = get_domain_color(source_domain)
self._bg_color = get_domain_color(sink_domain)
diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py
index 741c6fda95..022564cd77 100644
--- a/grc/gui/Constants.py
+++ b/grc/gui/Constants.py
@@ -17,18 +17,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import os
-import sys
-
-import pygtk
-pygtk.require('2.0')
import gtk
-from gnuradio import gr
+from ..core.Constants import *
-prefs = gr.prefs()
-GR_PREFIX = gr.prefix()
-EDITOR = prefs.get_string('grc', 'editor', '')
# default path for the open/save dialogs
DEFAULT_FILE_PATH = os.getcwd()
@@ -48,30 +40,14 @@ MIN_DIALOG_WIDTH = 500
MIN_DIALOG_HEIGHT = 500
# default sizes
DEFAULT_BLOCKS_WINDOW_WIDTH = 100
-DEFAULT_REPORTS_WINDOW_WIDTH = 100
-
-try: # ugly, but matches current code style
- raw = prefs.get_string('grc', 'canvas_default_size', '1280, 1024')
- DEFAULT_CANVAS_SIZE = tuple(int(x.strip('() ')) for x in raw.split(','))
- if len(DEFAULT_CANVAS_SIZE) != 2 or not all(300 < x < 4096 for x in DEFAULT_CANVAS_SIZE):
- raise Exception()
-except:
- DEFAULT_CANVAS_SIZE = 1280, 1024
- print >> sys.stderr, "Error: invalid 'canvas_default_size' setting."
-
-# flow-graph canvas fonts
-try: # ugly, but matches current code style
- FONT_SIZE = prefs.get_long('grc', 'canvas_font_size', 8)
- if FONT_SIZE <= 0:
- raise Exception()
-except:
- FONT_SIZE = 8
- print >> sys.stderr, "Error: invalid 'canvas_font_size' setting."
-FONT_FAMILY = "Sans"
-BLOCK_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE)
-PORT_FONT = BLOCK_FONT
-PARAM_FONT = "%s %f" % (FONT_FAMILY, FONT_SIZE - 0.5)
+DEFAULT_CONSOLE_WINDOW_WIDTH = 100
+DEFAULT_CANVAS_SIZE_DEFAULT = 1280, 1024
+
+FONT_SIZE = DEFAULT_FONT_SIZE = 8
+FONT_FAMILY = "Sans"
+BLOCK_FONT = PORT_FONT = "Sans 8"
+PARAM_FONT = "Sans 7.5"
# size of the state saving cache in the flow graph (undo/redo functionality)
STATE_CACHE_SIZE = 42
@@ -90,8 +66,7 @@ CANVAS_GRID_SIZE = 8
# port constraint dimensions
PORT_BORDER_SEPARATION = 8
PORT_SPACING = 2 * PORT_BORDER_SEPARATION
-PORT_SEPARATION = PORT_SPACING + 2 * PORT_LABEL_PADDING + int(1.5 * FONT_SIZE)
-PORT_SEPARATION += -PORT_SEPARATION % (2 * CANVAS_GRID_SIZE) # even multiple
+PORT_SEPARATION = 32
PORT_MIN_WIDTH = 20
PORT_LABEL_HIDDEN_WIDTH = 10
@@ -120,3 +95,17 @@ SCROLL_DISTANCE = 15
# How close the mouse click can be to a line and register a connection select.
LINE_SELECT_SENSITIVITY = 5
+
+
+def update_font_size(font_size):
+ global PORT_SEPARATION, BLOCK_FONT, PORT_FONT, PARAM_FONT, FONT_SIZE
+
+ FONT_SIZE = font_size
+ BLOCK_FONT = "%s %f" % (FONT_FAMILY, font_size)
+ PORT_FONT = BLOCK_FONT
+ PARAM_FONT = "%s %f" % (FONT_FAMILY, font_size - 0.5)
+
+ PORT_SEPARATION = PORT_SPACING + 2 * PORT_LABEL_PADDING + int(1.5 * font_size)
+ PORT_SEPARATION += -PORT_SEPARATION % (2 * CANVAS_GRID_SIZE) # even multiple
+
+update_font_size(DEFAULT_FONT_SIZE)
diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py
index f2941250a8..1d114356c8 100644
--- a/grc/gui/Dialogs.py
+++ b/grc/gui/Dialogs.py
@@ -17,15 +17,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import pygtk
-pygtk.require('2.0')
import gtk
import sys
from distutils.spawn import find_executable
-
-from . import Utils, Actions, Constants, Messages
+from . import Utils, Actions
+from ..core import Messages
class SimpleTextDisplay(gtk.TextView):
@@ -94,21 +92,21 @@ class TextDisplay(SimpleTextDisplay):
buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
def save(self, file_path):
- report_file = open(file_path, 'w')
+ console_file = open(file_path, 'w')
buffer = self.get_buffer()
- report_file.write(buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), True))
- report_file.close()
+ console_file.write(buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), True))
+ console_file.close()
# Callback functions to handle the scrolling lock and clear context menus options
# Action functions are set by the ActionHandler's init function
def clear_cb(self, menu_item, web_view):
- Actions.CLEAR_REPORTS()
+ Actions.CLEAR_CONSOLE()
def scroll_back_cb(self, menu_item, web_view):
Actions.TOGGLE_SCROLL_LOCK()
def save_cb(self, menu_item, web_view):
- Actions.SAVE_REPORTS()
+ Actions.SAVE_CONSOLE()
def populate_popup(self, view, menu):
"""Create a popup menu for the scroll lock and clear functions"""
@@ -177,14 +175,14 @@ def ErrorsDialog(flowgraph): MessageDialogHelper(
class AboutDialog(gtk.AboutDialog):
"""A cute little about dialog."""
- def __init__(self, platform):
+ def __init__(self, config):
"""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.set_name(config.name)
+ self.set_version(config.version)
+ self.set_license(config.license)
+ self.set_copyright(config.license.splitlines()[0])
+ self.set_website(config.website)
self.run()
self.destroy()
@@ -240,7 +238,7 @@ def MissingXTermDialog(xterm):
)
-def ChooseEditorDialog():
+def ChooseEditorDialog(config):
# Give the option to either choose an editor or use the default
# Always return true/false so the caller knows it was successful
buttons = (
@@ -266,10 +264,7 @@ def ChooseEditorDialog():
file_dialog.set_current_folder('/usr/bin')
try:
if file_dialog.run() == gtk.RESPONSE_OK:
- file_path = file_dialog.get_filename()
- Constants.prefs.set_string('grc', 'editor', file_path)
- Constants.prefs.save()
- Constants.EDITOR = file_path
+ config.editor = file_path = file_dialog.get_filename()
file_dialog.destroy()
return file_path
finally:
@@ -287,16 +282,12 @@ def ChooseEditorDialog():
if process is None:
raise ValueError("Can't find default editor executable")
# Save
- Constants.prefs.set_string('grc', 'editor', process)
- Constants.prefs.save()
- Constants.EDITOR = process
+ config.editor = process
return process
except Exception:
Messages.send('>>> Unable to load the default editor. Please choose an editor.\n')
# Just reset of the constant and force the user to select an editor the next time
- Constants.prefs.set_string('grc', 'editor', '')
- Constants.prefs.save()
- Constants.EDITOR = ""
+ config.editor = ''
return
Messages.send('>>> No editor selected.\n')
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py
index 4412129809..6a1df27a8c 100644
--- a/grc/gui/DrawingArea.py
+++ b/grc/gui/DrawingArea.py
@@ -20,7 +20,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import pygtk
pygtk.require('2.0')
import gtk
+
from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS
+import Colors
+
class DrawingArea(gtk.DrawingArea):
"""
@@ -68,13 +71,21 @@ class DrawingArea(gtk.DrawingArea):
self.set_flags(gtk.CAN_FOCUS) # self.set_can_focus(True)
self.connect('focus-out-event', self._handle_focus_lost_event)
- 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)
+ def new_pixmap(self, width, height):
+ return gtk.gdk.Pixmap(self.window, width, height, -1)
+
+ def get_screenshot(self, transparent_bg=False):
+ pixmap = self._pixmap
+ W, H = pixmap.get_size()
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, W, H)
+ pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8)
+ pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1)
+ if transparent_bg:
+ bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR
+ pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue)
return pixbuf
+
##########################################################################
## Handlers
##########################################################################
@@ -149,6 +160,12 @@ class DrawingArea(gtk.DrawingArea):
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)
+ # draw a light grey line on the bottom and right end of the canvas.
+ # this is useful when the theme uses the same panel bg color as the canvas
+ W, H = self._pixmap.get_size()
+ gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR)
+ self.window.draw_line(gc, 0, H-1, W, H-1)
+ self.window.draw_line(gc, W-1, 0, W-1, H)
def _handle_focus_lost_event(self, widget, event):
# don't clear selection while context menu is active
diff --git a/grc/gui/Element.py b/grc/gui/Element.py
index 18fb321929..9385424772 100644
--- a/grc/gui/Element.py
+++ b/grc/gui/Element.py
@@ -132,14 +132,14 @@ class Element(object):
"""
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):
"""
diff --git a/grc/gui/Executor.py b/grc/gui/Executor.py
new file mode 100644
index 0000000000..bf9eecb9a8
--- /dev/null
+++ b/grc/gui/Executor.py
@@ -0,0 +1,121 @@
+# Copyright 2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import gobject
+import os
+import threading
+import shlex
+import subprocess
+import sys
+import re
+from distutils.spawn import find_executable
+
+from ..core import Messages
+
+
+class ExecFlowGraphThread(threading.Thread):
+ """Execute the flow graph as a new process and wait on it to finish."""
+
+ def __init__(self, flow_graph_page, xterm_executable, callback):
+ """
+ ExecFlowGraphThread constructor.
+
+ Args:
+ action_handler: an instance of an ActionHandler
+ """
+ threading.Thread.__init__(self)
+
+ self.page = flow_graph_page # store page and dont use main window calls in run
+ self.xterm_executable = xterm_executable
+ self.update_callback = callback
+
+ try:
+ self.process = self._popen()
+ self.page.set_proc(self.process)
+ self.update_callback()
+ self.start()
+ except Exception as e:
+ Messages.send_verbose_exec(str(e))
+ Messages.send_end_exec()
+
+ def _popen(self):
+ """
+ Execute this python flow graph.
+ """
+ run_command = self.page.get_flow_graph().get_option('run_command')
+ generator = self.page.get_generator()
+
+ try:
+ run_command = run_command.format(
+ python=shlex_quote(sys.executable),
+ filename=shlex_quote(generator.file_path))
+ run_command_args = shlex.split(run_command)
+ except Exception as e:
+ raise ValueError("Can't parse run command {!r}: {}".format(run_command, e))
+
+ # When in no gui mode on linux, use a graphical terminal (looks nice)
+ xterm_executable = find_executable(self.xterm_executable)
+ if generator.generate_options == 'no_gui' and xterm_executable:
+ run_command_args = [xterm_executable, '-e', run_command]
+
+ # this does not reproduce a shell executable command string, if a graphical
+ # terminal is used. Passing run_command though shlex_quote would do it but
+ # it looks really ugly and confusing in the console panel.
+ Messages.send_start_exec(' '.join(run_command_args))
+
+ return subprocess.Popen(
+ args=run_command_args,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
+ shell=False, universal_newlines=True
+ )
+
+ 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.process.stdout.fileno(), 1024)
+ self.process.poll()
+ gobject.idle_add(self.done)
+
+ def done(self):
+ """Perform end of execution tasks."""
+ Messages.send_end_exec(self.process.returncode)
+ self.page.set_proc(None)
+ self.update_callback()
+
+
+###########################################################
+# back-port from python3
+###########################################################
+_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
+
+
+def shlex_quote(s):
+ """Return a shell-escaped version of the string *s*."""
+ if not s:
+ return "''"
+ if _find_unsafe(s) is None:
+ return s
+
+ # use single quotes, and put single quotes into double quotes
+ # the string $'b is then quoted as '$'"'"'b'
+ return "'" + s.replace("'", "'\"'\"'") + "'"
diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py
index 730ac6fba0..e9430b1f88 100644
--- a/grc/gui/FileDialogs.py
+++ b/grc/gui/FileDialogs.py
@@ -33,7 +33,7 @@ import Utils
##################################################
OPEN_FLOW_GRAPH = 'open flow graph'
SAVE_FLOW_GRAPH = 'save flow graph'
-SAVE_REPORTS = 'save reports'
+SAVE_CONSOLE = 'save console'
SAVE_IMAGE = 'save image'
OPEN_QSS_THEME = 'open qss theme'
@@ -43,46 +43,45 @@ File <b>$encode($filename)</b> Exists!\nWould you like to overwrite the existing
FILE_DNE_MARKUP_TMPL="""\
File <b>$encode($filename)</b> Does not Exist!"""
-##################################################
+
+
# File Filters
-##################################################
-##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
+
def get_text_files_filter():
filter = gtk.FileFilter()
filter.set_name('Text Files')
filter.add_pattern('*'+TEXT_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
-##the filter for all files
+
def get_all_files_filter():
filter = gtk.FileFilter()
filter.set_name('All Files')
filter.add_pattern('*')
return filter
-##the filter for qss files
+
def get_qss_themes_filter():
filter = gtk.FileFilter()
filter.set_name('QSS Themes')
filter.add_pattern('*.qss')
return filter
-##################################################
+
# File Dialogs
-##################################################
class FileDialogHelper(gtk.FileChooserDialog):
"""
A wrapper class for the gtk file chooser dialog.
@@ -105,6 +104,7 @@ class FileDialogHelper(gtk.FileChooserDialog):
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."""
@@ -124,8 +124,8 @@ class FileDialog(FileDialogHelper):
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))
- elif self.type == SAVE_REPORTS:
- FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save Reports to a File...')
+ elif self.type == SAVE_CONSOLE:
+ FileDialogHelper.__init__(self, gtk.FILE_CHOOSER_ACTION_SAVE, 'Save Console to a File...')
self.add_and_set_filter(get_text_files_filter())
file_path = path.splitext(path.basename(current_file_path))[0]
self.set_current_name(file_path) #show the current filename
@@ -164,11 +164,11 @@ class FileDialog(FileDialogHelper):
#############################################
# Handle Save Dialogs
#############################################
- if self.type in (SAVE_FLOW_GRAPH, SAVE_REPORTS, SAVE_IMAGE):
+ if self.type in (SAVE_FLOW_GRAPH, SAVE_CONSOLE, SAVE_IMAGE):
filename = self.get_filename()
extension = {
SAVE_FLOW_GRAPH: Preferences.file_extension(),
- SAVE_REPORTS: TEXT_FILE_EXTENSION,
+ SAVE_CONSOLE: TEXT_FILE_EXTENSION,
SAVE_IMAGE: IMAGE_FILE_EXTENSION,
}[self.type]
#append the missing file extension if the filter matches
@@ -205,8 +205,37 @@ class FileDialog(FileDialogHelper):
self.destroy()
return filename
-class OpenFlowGraphFileDialog(FileDialog): type = OPEN_FLOW_GRAPH
-class SaveFlowGraphFileDialog(FileDialog): type = SAVE_FLOW_GRAPH
-class OpenQSSFileDialog(FileDialog): type = OPEN_QSS_THEME
-class SaveReportsFileDialog(FileDialog): type = SAVE_REPORTS
-class SaveImageFileDialog(FileDialog): type = SAVE_IMAGE
+
+class OpenFlowGraphFileDialog(FileDialog):
+ type = OPEN_FLOW_GRAPH
+
+
+class SaveFlowGraphFileDialog(FileDialog):
+ type = SAVE_FLOW_GRAPH
+
+
+class OpenQSSFileDialog(FileDialog):
+ type = OPEN_QSS_THEME
+
+
+class SaveConsoleFileDialog(FileDialog):
+ type = SAVE_CONSOLE
+
+
+class SaveImageFileDialog(FileDialog):
+ type = SAVE_IMAGE
+
+
+class SaveScreenShotDialog(SaveImageFileDialog):
+
+ def __init__(self, current_file_path=''):
+ SaveImageFileDialog.__init__(self, current_file_path)
+ self._button = button = gtk.CheckButton('_Background transparent')
+ self._button.set_active(Preferences.screen_shot_background_transparent())
+ self.set_extra_widget(button)
+
+ def run(self):
+ filename = SaveImageFileDialog.run(self)
+ bg_transparent = self._button.get_active()
+ Preferences.screen_shot_background_transparent(bg_transparent)
+ return filename, bg_transparent
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 2053e86454..6eb05f9ac9 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -17,39 +17,43 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-import random
import functools
-from itertools import chain
-from operator import methodcaller
+import random
from distutils.spawn import find_executable
+from itertools import chain, count
+from operator import methodcaller
import gobject
-from . import Actions, Colors, Constants, Utils, Messages, Bars, Dialogs
-from . Element import Element
-from . Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
-from . external_editor import ExternalEditor
+from . import Actions, Colors, Constants, Utils, Bars, Dialogs
+from .Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
+from .Element import Element
+from .external_editor import ExternalEditor
+
+from ..core.FlowGraph import FlowGraph as _Flowgraph
+from ..core import Messages
-class FlowGraph(Element):
+class FlowGraph(Element, _Flowgraph):
"""
FlowGraph is the data structure to store graphical signal blocks,
graphical inputs and outputs,
and the connections between inputs and outputs.
"""
- def __init__(self):
+ def __init__(self, **kwargs):
"""
FlowGraph constructor.
Create a list for signal blocks and connections. Connect mouse handlers.
"""
Element.__init__(self)
+ _Flowgraph.__init__(self, **kwargs)
#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._selected_elements = []
self.press_coor = (0, 0)
#selected ports
self._old_selected_port = None
@@ -62,14 +66,31 @@ class FlowGraph(Element):
self._external_updaters = {}
+ 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
+ """
+ for index in count():
+ block_id = '{}_{}'.format(base_id, index)
+ if block_id not in (b.get_id() for b in self.blocks):
+ break
+ return block_id
+
def install_external_editor(self, param):
target = (param.get_parent().get_id(), param.get_key())
if target in self._external_updaters:
editor = self._external_updaters[target]
else:
- editor = (find_executable(Constants.EDITOR) or
- Dialogs.ChooseEditorDialog())
+ config = self.get_parent().config
+ editor = (find_executable(config.editor) or
+ Dialogs.ChooseEditorDialog(config))
if not editor:
return
updater = functools.partial(
@@ -86,9 +107,7 @@ class FlowGraph(Element):
# Problem launching the editor. Need to select a new editor.
Messages.send('>>> Error opening an external editor. Please select a different editor.\n')
# Reset the editor to force the user to select a new one.
- Constants.prefs.set_string('grc', 'editor', '')
- Constants.prefs.save()
- Constants.EDITOR = ""
+ self.get_parent().config.editor = ''
def handle_external_editor_change(self, new_value, target):
try:
@@ -131,7 +150,7 @@ class FlowGraph(Element):
int(random.uniform(.25, .75)*v_adj.page_size + v_adj.get_value()),
)
#get the new block
- block = self.get_new_block(key)
+ block = self.new_block(key)
block.set_coordinate(coor)
block.set_rotation(0)
block.get_param('id').set_value(id)
@@ -160,7 +179,7 @@ class FlowGraph(Element):
#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(),
+ self.connections,
)
clipboard = (
(x_min, y_min),
@@ -190,7 +209,7 @@ class FlowGraph(Element):
for block_n in blocks_n:
block_key = block_n.find('key')
if block_key == 'options': continue
- block = self.get_new_block(block_key)
+ block = self.new_block(block_key)
if not block:
continue # unknown block was pasted (e.g. dummy block)
selected.add(block)
@@ -206,7 +225,7 @@ class FlowGraph(Element):
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 [blk.get_id() for blk in self.get_blocks()]:
+ if param_value in (blk.get_id() for blk in self.blocks):
param_value = self._get_unique_id(param_value)
#set value to key
block.get_param(param_key).set_value(param_value)
@@ -293,6 +312,47 @@ class FlowGraph(Element):
selected_block.move(delta_coordinate)
self.element_moved = True
+ def align_selected(self, calling_action=None):
+ """
+ Align the selected blocks.
+
+ Args:
+ calling_action: the action initiating the alignment
+
+ Returns:
+ True if changed, otherwise False
+ """
+ blocks = self.get_selected_blocks()
+ if calling_action is None or not blocks:
+ return False
+
+ # compute common boundary of selected objects
+ min_x, min_y = max_x, max_y = blocks[0].get_coordinate()
+ for selected_block in blocks:
+ x, y = selected_block.get_coordinate()
+ min_x, min_y = min(min_x, x), min(min_y, y)
+ x += selected_block.W
+ y += selected_block.H
+ max_x, max_y = max(max_x, x), max(max_y, y)
+ ctr_x, ctr_y = (max_x + min_x)/2, (max_y + min_y)/2
+
+ # align the blocks as requested
+ transform = {
+ Actions.BLOCK_VALIGN_TOP: lambda x, y, w, h: (x, min_y),
+ Actions.BLOCK_VALIGN_MIDDLE: lambda x, y, w, h: (x, ctr_y - h/2),
+ Actions.BLOCK_VALIGN_BOTTOM: lambda x, y, w, h: (x, max_y - h),
+ Actions.BLOCK_HALIGN_LEFT: lambda x, y, w, h: (min_x, y),
+ Actions.BLOCK_HALIGN_CENTER: lambda x, y, w, h: (ctr_x-w/2, y),
+ Actions.BLOCK_HALIGN_RIGHT: lambda x, y, w, h: (max_x - w, y),
+ }.get(calling_action, lambda *args: args)
+
+ for selected_block in blocks:
+ x, y = selected_block.get_coordinate()
+ w, h = selected_block.W, selected_block.H
+ selected_block.set_coordinate(transform(x, y, w, h))
+
+ return True
+
def rotate_selected(self, rotation):
"""
Rotate the selected blocks by multiples of 90 degrees.
@@ -303,7 +363,8 @@ class FlowGraph(Element):
Returns:
true if changed, otherwise false.
"""
- if not self.get_selected_blocks(): return 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()
@@ -344,13 +405,18 @@ class FlowGraph(Element):
"""
W,H = self.get_size()
+ hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active()
+ hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active()
+
#draw the background
gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR)
window.draw_rectangle(gc, True, 0, 0, W, H)
# draw comments first
if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active():
- for block in self.iter_blocks():
+ for block in self.blocks:
+ if hide_variables and (block.is_variable or block.is_import):
+ continue # skip hidden disabled blocks and connections
if block.get_enabled():
block.draw_comment(gc, window)
#draw multi select rectangle
@@ -367,11 +433,12 @@ class FlowGraph(Element):
gc.set_foreground(Colors.BORDER_COLOR)
window.draw_rectangle(gc, False, x, y, w, h)
#draw blocks on top of connections
- hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active()
- blocks = sorted(self.iter_blocks(), key=methodcaller('get_enabled'))
- for element in chain(self.iter_connections(), blocks):
+ blocks = sorted(self.blocks, key=methodcaller('get_enabled'))
+ for element in chain(self.connections, blocks):
if hide_disabled_blocks and not element.get_enabled():
continue # skip hidden disabled blocks and connections
+ if hide_variables and (element.is_variable or element.is_import):
+ continue # skip hidden disabled blocks and connections
element.draw(gc, window)
#draw selected blocks on top of selected connections
for selected_element in self.get_selected_connections() + self.get_selected_blocks():
@@ -432,6 +499,10 @@ class FlowGraph(Element):
"""
self._selected_elements = []
+ def select_all(self):
+ """Select all blocks in the flow graph"""
+ self._selected_elements = list(self.get_elements())
+
def what_is_selected(self, coor, coor_m=None):
"""
What is selected?
@@ -451,18 +522,18 @@ class FlowGraph(Element):
selected_port = None
selected = set()
#check the elements
+ hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active()
+ hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active()
for element in reversed(self.get_elements()):
+ if hide_disabled_blocks and not element.get_enabled():
+ continue # skip hidden disabled blocks and connections
+ if hide_variables and (element.is_variable or element.is_import):
+ continue # skip hidden disabled blocks and connections
selected_element = element.what_is_selected(coor, coor_m)
- if not selected_element: continue
- # hidden disabled connections, blocks and their ports can not be selected
- if Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() and (
- selected_element.is_block() and not selected_element.get_enabled() or
- selected_element.is_connection() and not selected_element.get_enabled() or
- selected_element.is_port() and not selected_element.get_parent().get_enabled()
- ):
+ if not selected_element:
continue
#update the selected port information
- if selected_element.is_port():
+ if selected_element.is_port:
if not coor_m: selected_port = selected_element
selected_element = selected_element.get_parent()
selected.add(selected_element)
@@ -486,7 +557,8 @@ class FlowGraph(Element):
"""
selected = set()
for selected_element in self.get_selected_elements():
- if selected_element.is_connection(): selected.add(selected_element)
+ if selected_element.is_connection:
+ selected.add(selected_element)
return list(selected)
def get_selected_blocks(self):
@@ -498,7 +570,8 @@ class FlowGraph(Element):
"""
selected = set()
for selected_element in self.get_selected_elements():
- if selected_element.is_block(): selected.add(selected_element)
+ if selected_element.is_block:
+ selected.add(selected_element)
return list(selected)
def get_selected_block(self):
@@ -508,7 +581,8 @@ class FlowGraph(Element):
Returns:
a block or None
"""
- return self.get_selected_blocks() and self.get_selected_blocks()[0] or None
+ selected_blocks = self.get_selected_blocks()
+ return selected_blocks[0] if selected_blocks else None
def get_selected_elements(self):
"""
@@ -526,7 +600,8 @@ class FlowGraph(Element):
Returns:
a block, port, or connection or None
"""
- return self.get_selected_elements() and self.get_selected_elements()[0] or None
+ selected_elements = self.get_selected_elements()
+ return selected_elements[0] if selected_elements else None
def update_selected_elements(self):
"""
@@ -673,7 +748,7 @@ class FlowGraph(Element):
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():
+ 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
if not self.get_ctrl_mask():
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index a340bcc817..1437391236 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -17,21 +17,20 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Constants import \
- NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH
-import Actions
-import pygtk
-pygtk.require('2.0')
-import gtk
-import Bars
-from BlockTreeWindow import BlockTreeWindow
-from Dialogs import TextDisplay, MessageDialogHelper
-from NotebookPage import NotebookPage
-import Preferences
-import Messages
-import Utils
import os
+import gtk
+
+from . import Bars, Actions, Preferences, Utils
+from .BlockTreeWindow import BlockTreeWindow
+from .VariableEditor import VariableEditor
+from .Constants import \
+ NEW_FLOGRAPH_TITLE, DEFAULT_CONSOLE_WINDOW_WIDTH
+from .Dialogs import TextDisplay, MessageDialogHelper
+from .NotebookPage import NotebookPage
+
+from ..core import Messages
+
MAIN_WINDOW_TITLE_TMPL = """\
#if not $saved
*#slurp
@@ -58,6 +57,7 @@ PAGE_TITLE_MARKUP_TMPL = """\
#end if
"""
+
############################################################
# Main window
############################################################
@@ -65,59 +65,98 @@ PAGE_TITLE_MARKUP_TMPL = """\
class MainWindow(gtk.Window):
"""The topmost window with menus, the tool bar, and other major windows."""
+ # Constants the action handler can use to indicate which panel visibility to change.
+ BLOCKS = 0
+ CONSOLE = 1
+ VARIABLES = 2
+
def __init__(self, platform, action_handler_callback):
"""
- MainWindow contructor
- Setup the menu, toolbar, flowgraph editor notebook, block selection window...
+ MainWindow constructor
+ Setup the menu, toolbar, flow graph editor notebook, block selection window...
"""
self._platform = platform
- gen_opts = platform.get_block('options').get_param('generate_options')
+
+ gen_opts = platform.blocks['options'].get_param('generate_options')
generate_mode_default = gen_opts.get_value()
generate_modes = [
(o.get_key(), o.get_name(), o.get_key() == generate_mode_default)
for o in gen_opts.get_options()]
- # load preferences
+
+ # Load preferences
Preferences.load(platform)
- #setup window
+
+ # 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
+
+ # Create the menu bar and toolbar
self.add_accel_group(Actions.get_accel_group())
self.menu_bar = Bars.MenuBar(generate_modes, action_handler_callback)
vbox.pack_start(self.menu_bar, False)
- self.tool_bar = Bars.Toolbar(generate_modes, action_handler_callback )
+ self.tool_bar = Bars.Toolbar(generate_modes, action_handler_callback)
vbox.pack_start(self.tool_bar, False)
- vbox.pack_start(self.hpaned)
- #create the notebook
+
+ # Main parent container for the different panels
+ self.container = gtk.HPaned()
+ vbox.pack_start(self.container)
+
+ # 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.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
+
+ # Create the console 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(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
+ self.console_window = gtk.ScrolledWindow()
+ self.console_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.console_window.add(self.text_display)
+ self.console_window.set_size_request(-1, DEFAULT_CONSOLE_WINDOW_WIDTH)
+
+ # Create the block tree and variable panels
+ self.btwin = BlockTreeWindow(platform, self.get_flow_graph)
+ self.vars = VariableEditor(platform, self.get_flow_graph)
+
+ # Figure out which place to put the variable editor
+ self.left = gtk.VPaned()
+ self.right = gtk.VPaned()
+ self.left_subpanel = gtk.HPaned()
+
+ self.variable_panel_sidebar = Preferences.variable_editor_sidebar()
+ if self.variable_panel_sidebar:
+ self.left.pack1(self.notebook)
+ self.left.pack2(self.console_window, False)
+ self.right.pack1(self.btwin)
+ self.right.pack2(self.vars, False)
+ else:
+ # Put the variable editor in a panel with the console
+ self.left.pack1(self.notebook)
+ self.left_subpanel.pack1(self.console_window, shrink=False)
+ self.left_subpanel.pack2(self.vars, resize=False, shrink=True)
+ self.left.pack2(self.left_subpanel, False)
+
+ # Create the right panel
+ self.right.pack1(self.btwin)
+
+ self.container.pack1(self.left)
+ self.container.pack2(self.right, False)
+
+ # load preferences and show the main window
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.container.set_position(Preferences.blocks_window_position())
+ self.left.set_position(Preferences.console_window_position())
+ if self.variable_panel_sidebar:
+ self.right.set_position(Preferences.variable_editor_position(sidebar=True))
+ else:
+ self.left_subpanel.set_position(Preferences.variable_editor_position())
+
self.show_all()
- self.reports_scrolled_window.hide()
+ self.console_window.hide()
+ self.vars.hide()
self.btwin.hide()
############################################################
@@ -148,14 +187,45 @@ class MainWindow(gtk.Window):
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 update_panel_visibility(self, panel, visibility=True):
+ """
+ Handles changing visibility of panels.
+ """
+ # Set the visibility for the requested panel, then update the containers if they need
+ # to be hidden as well.
+
+ if panel == self.BLOCKS:
+ self.btwin.set_visible(visibility)
+ elif panel == self.CONSOLE:
+ self.console_window.set_visible(visibility)
+ elif panel == self.VARIABLES:
+ self.vars.set_visible(visibility)
+ else:
+ return
+
+ if self.variable_panel_sidebar:
+ # If both the variable editor and block panels are hidden, hide the right container
+ if not self.btwin.get_visible() and not self.vars.get_visible():
+ self.right.hide()
+ else:
+ self.right.show()
+ else:
+ if not self.btwin.get_visible():
+ self.right.hide()
+ else:
+ self.right.show()
+ if not self.vars.get_visible() and not self.console_window.get_visible():
+ self.left_subpanel.hide()
+ else:
+ self.left_subpanel.show()
+
############################################################
- # Report Window
+ # Console Window
############################################################
- def add_report_line(self, line):
+ def add_console_line(self, line):
"""
Place line at the end of the text buffer, then scroll its window all the way down.
@@ -227,8 +297,12 @@ class MainWindow(gtk.Window):
Preferences.set_open_files(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.console_window_position(self.left.get_position())
+ Preferences.blocks_window_position(self.container.get_position())
+ if self.variable_panel_sidebar:
+ Preferences.variable_editor_position(self.right.get_position(), sidebar=True)
+ else:
+ Preferences.variable_editor_position(self.left_subpanel.get_position())
Preferences.save()
return True
@@ -272,7 +346,7 @@ class MainWindow(gtk.Window):
"""
Set the title of the main window.
Set the titles on the page tabs.
- Show/hide the reports window.
+ Show/hide the console window.
Args:
title: the window title
@@ -283,7 +357,7 @@ class MainWindow(gtk.Window):
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(),
+ platform_name=self._platform.config.name,
)
)
#set tab titles
@@ -298,6 +372,9 @@ class MainWindow(gtk.Window):
#show/hide notebook tabs
self.notebook.set_show_tabs(len(self.get_pages()) > 1)
+ # Need to update the variable window when changing
+ self.vars.update_gui()
+
def update_pages(self):
"""
Forces a reload of all the pages in this notebook.
diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py
index 4c112154af..c9e8d0f186 100644
--- a/grc/gui/NotebookPage.py
+++ b/grc/gui/NotebookPage.py
@@ -39,13 +39,13 @@ class NotebookPage(gtk.HBox):
file_path: path to a flow graph file
"""
self._flow_graph = flow_graph
- self.set_proc(None)
+ self.process = None
#import the file
self.main_window = main_window
- self.set_file_path(file_path)
+ self.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)
+ self.saved = True
#import the data to the flow graph
self.get_flow_graph().import_data(initial_state)
#initialize page gui
@@ -102,10 +102,8 @@ class NotebookPage(gtk.HBox):
Returns:
generator
"""
- return self.get_flow_graph().get_parent().get_generator()(
- self.get_flow_graph(),
- self.get_file_path(),
- )
+ platform = self.get_flow_graph().get_parent()
+ return platform.Generator(self.get_flow_graph(), self.get_file_path())
def _handle_button(self, button):
"""
@@ -191,8 +189,7 @@ class NotebookPage(gtk.HBox):
Args:
file_path: file path string
"""
- if file_path: self.file_path = os.path.abspath(file_path)
- else: self.file_path = ''
+ self.file_path = os.path.abspath(file_path) if file_path else ''
def get_saved(self):
"""
diff --git a/grc/gui/Param.py b/grc/gui/Param.py
index 6884d6530a..4b5a3c294a 100644
--- a/grc/gui/Param.py
+++ b/grc/gui/Param.py
@@ -23,8 +23,10 @@ import pygtk
pygtk.require('2.0')
import gtk
-from . import Colors, Utils, Constants, Dialogs
-from . Element import Element
+from . import Colors, Utils, Constants
+from .Element import Element
+
+from ..core.Param import Param as _Param
class InputParam(gtk.HBox):
@@ -82,7 +84,7 @@ class InputParam(gtk.HBox):
self._have_pending_changes = True
self._update_gui()
if self._editing_callback:
- self._editing_callback()
+ self._editing_callback(self, None)
def _apply_change(self, *args):
"""
@@ -93,7 +95,7 @@ class InputParam(gtk.HBox):
self.param.set_value(self.get_text())
#call the callback
if self._changed_callback:
- self._changed_callback(*args)
+ self._changed_callback(self, None)
else:
self.param.validate()
#gui update
@@ -127,8 +129,19 @@ class EntryParam(InputParam):
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)
+ need_status_color = self.label not in self.get_children()
+ text_color = (
+ Colors.PARAM_ENTRY_TEXT_COLOR if not need_status_color else
+ gtk.gdk.color_parse('blue') if self._have_pending_changes else
+ gtk.gdk.color_parse('red') if not self.param.is_valid() else
+ Colors.PARAM_ENTRY_TEXT_COLOR)
+ base_color = (
+ Colors.BLOCK_DISABLED_COLOR
+ if need_status_color and not self.param.get_parent().get_enabled()
+ else gtk.gdk.color_parse(color)
+ )
+ self._input.modify_base(gtk.STATE_NORMAL, base_color)
+ self._input.modify_text(gtk.STATE_NORMAL, text_color)
def set_tooltip_text(self, text):
try:
@@ -317,7 +330,9 @@ class FileParam(EntryParam):
if self.param.get_key() == 'qt_qss_theme':
dirname = os.path.dirname(dirname) # trim filename
if not os.path.exists(dirname):
- dirname = os.path.join(Constants.GR_PREFIX, '/share/gnuradio/themes')
+ platform = self.param.get_parent().get_parent().get_parent()
+ dirname = os.path.join(platform.config.install_prefix,
+ '/share/gnuradio/themes')
if not os.path.exists(dirname):
dirname = os.getcwd() # fix bad paths
@@ -378,11 +393,12 @@ Error:
#end if"""
-class Param(Element):
+class Param(Element, _Param):
"""The graphical parameter."""
- def __init__(self):
+ def __init__(self, **kwargs):
Element.__init__(self)
+ _Param.__init__(self, **kwargs)
def get_input(self, *args, **kwargs):
"""
diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py
index eda28a0e94..500df1cce4 100644
--- a/grc/gui/Platform.py
+++ b/grc/gui/Platform.py
@@ -17,12 +17,55 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Element import Element
+import os
+import sys
-class Platform(Element):
- def __init__(self, prefs_file):
+from ..core.Platform import Platform as _Platform
+
+from .Config import Config as _Config
+from .Block import Block as _Block
+from .Connection import Connection as _Connection
+from .Element import Element
+from .FlowGraph import FlowGraph as _FlowGraph
+from .Param import Param as _Param
+from .Port import Port as _Port
+
+
+class Platform(Element, _Platform):
+
+ def __init__(self, *args, **kwargs):
Element.__init__(self)
+ _Platform.__init__(self, *args, **kwargs)
+
+ # Ensure conf directories
+ gui_prefs_file = self.config.gui_prefs_file
+ if not os.path.exists(os.path.dirname(gui_prefs_file)):
+ os.mkdir(os.path.dirname(gui_prefs_file))
+
+ self._move_old_pref_file()
+
+ def get_prefs_file(self):
+ return self.config.gui_prefs_file
- self._prefs_file = prefs_file
+ def _move_old_pref_file(self):
+ gui_prefs_file = self.config.gui_prefs_file
+ old_gui_prefs_file = os.environ.get(
+ 'GRC_PREFS_PATH', os.path.expanduser('~/.grc'))
+ if gui_prefs_file == old_gui_prefs_file:
+ return # prefs file overridden with env var
+ if os.path.exists(old_gui_prefs_file) and not os.path.exists(gui_prefs_file):
+ try:
+ import shutil
+ shutil.move(old_gui_prefs_file, gui_prefs_file)
+ except Exception as e:
+ print >> sys.stderr, e
- def get_prefs_file(self): return self._prefs_file
+ ##############################################
+ # Constructors
+ ##############################################
+ FlowGraph = _FlowGraph
+ Connection = _Connection
+ Block = _Block
+ Port = _Port
+ Param = _Param
+ Config = _Config
diff --git a/grc/gui/Port.py b/grc/gui/Port.py
index ae1a1d223f..6314b7ede8 100644
--- a/grc/gui/Port.py
+++ b/grc/gui/Port.py
@@ -17,32 +17,33 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from Element import Element
-from Constants import (
- PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL,
- CONNECTOR_EXTENSION_INCREMENT, CANVAS_GRID_SIZE,
- PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT
-)
-from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
-import Utils
-import Actions
-import Colors
import pygtk
pygtk.require('2.0')
import gtk
+from . import Actions, Colors, Utils
+from .Constants import (
+ PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL,
+ CONNECTOR_EXTENSION_INCREMENT, PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT
+)
+from .Element import Element
+from ..core.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
+
+from ..core.Port import Port as _Port
+
PORT_MARKUP_TMPL="""\
<span foreground="black" font_desc="$font">$encode($port.get_name())</span>"""
-class Port(Element):
+class Port(_Port, Element):
"""The graphical port."""
- def __init__(self):
+ def __init__(self, block, n, dir):
"""
Port contructor.
Create list of connector coordinates.
"""
+ _Port.__init__(self, block, n, dir)
Element.__init__(self)
self.W = self.H = self.w = self.h = 0
self._connector_coordinate = (0, 0)
@@ -63,7 +64,7 @@ class Port(Element):
rotation = self.get_rotation()
#get all sibling ports
ports = self.get_parent().get_sources_gui() \
- if self.is_source() else self.get_parent().get_sinks_gui()
+ if self.is_source else self.get_parent().get_sinks_gui()
ports = filter(lambda p: not p.get_hide(), ports)
#get the max width
self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH])
@@ -81,27 +82,27 @@ class Port(Element):
index = length-index-1
port_separation = PORT_SEPARATION \
- if not self.get_parent().has_busses[self.is_source()] \
+ if not self.get_parent().has_busses[self.is_source] \
else max([port.H for port in ports]) + PORT_SPACING
offset = (self.get_parent().H - (length-1)*port_separation - self.H)/2
#create areas and connector coordinates
- if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180):
+ if (self.is_sink and rotation == 0) or (self.is_source and rotation == 180):
x = -W
y = port_separation*index+offset
self.add_area((x, y), (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):
+ elif (self.is_source and rotation == 0) or (self.is_sink and rotation == 180):
x = self.get_parent().W
y = port_separation*index+offset
self.add_area((x, y), (W, self.H))
self._connector_coordinate = (x+1+W, y+self.H/2)
- elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270):
+ elif (self.is_source and rotation == 90) or (self.is_sink and rotation == 270):
y = -W
x = port_separation*index+offset
self.add_area((x, y), (self.H, W))
self._connector_coordinate = (x+self.H/2, y-1)
- elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270):
+ elif (self.is_sink and rotation == 90) or (self.is_source and rotation == 270):
y = self.get_parent().W
x = port_separation*index+offset
self.add_area((x, y), (self.H, W))
@@ -144,7 +145,7 @@ class Port(Element):
Element.draw(
self, gc, window, bg_color=self._bg_color,
border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or
- self.get_parent().is_dummy_block() and Colors.MISSING_BLOCK_BORDER_COLOR or
+ self.get_parent().is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or
Colors.BORDER_COLOR,
)
if not self._areas_list or self._label_hidden():
@@ -176,8 +177,8 @@ class Port(Element):
Returns:
the direction in degrees
"""
- if self.is_source(): return self.get_rotation()
- elif self.is_sink(): return (self.get_rotation() + 180)%360
+ if self.is_source: return self.get_rotation()
+ elif self.is_sink: return (self.get_rotation() + 180)%360
def get_connector_length(self):
"""
diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py
index 3ebee24345..5fbdfe927a 100644
--- a/grc/gui/Preferences.py
+++ b/grc/gui/Preferences.py
@@ -35,7 +35,7 @@ _config_parser = ConfigParser.SafeConfigParser()
def file_extension():
- return '.'+_platform.get_key()
+ return '.grc'
def load(platform):
@@ -140,13 +140,34 @@ def add_recent_file(file_name):
set_recent_files(recent_files[:10]) # Keep up to 10 files
-def reports_window_position(pos=None):
- return entry('reports_window_position', pos, default=-1) or 1
+def console_window_position(pos=None):
+ return entry('console_window_position', pos, default=-1) or 1
def blocks_window_position(pos=None):
return entry('blocks_window_position', pos, default=-1) or 1
+def variable_editor_position(pos=None, sidebar=False):
+ # Figure out default
+ if sidebar:
+ w, h = main_window_size()
+ return entry('variable_editor_sidebar_position', pos, default=int(h*0.7))
+ else:
+ return entry('variable_editor_position', pos, default=int(blocks_window_position()*0.5))
+
+
+def variable_editor_sidebar(pos=None):
+ return entry('variable_editor_sidebar', pos, default=False)
+
+
+def variable_editor_confirm_delete(pos=None):
+ return entry('variable_editor_confirm_delete', pos, default=True)
+
+
def xterm_missing(cmd=None):
return entry('xterm_missing', cmd, default='INVALID_XTERM_SETTING')
+
+
+def screen_shot_background_transparent(transparent=None):
+ return entry('screen_shot_background_transparent', transparent, default=False)
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index bf7d31d391..7c66a77a54 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -97,7 +97,8 @@ class PropsDialog(gtk.Dialog):
self._params_boxes.append((tab, label, vbox))
# Docs for the block
- self._docs_text_display = SimpleTextDisplay()
+ self._docs_text_display = doc_view = SimpleTextDisplay()
+ doc_view.get_buffer().create_tag('b', weight=pango.WEIGHT_BOLD)
self._docs_box = gtk.ScrolledWindow()
self._docs_box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self._docs_box.add_with_viewport(self._docs_text_display)
@@ -200,10 +201,43 @@ class PropsDialog(gtk.Dialog):
messages = '\n\n'.join(self._block.get_error_messages())
self._error_messages_text_display.set_text(messages)
# update the docs box
- self._docs_text_display.set_text(self._block.get_doc())
+ self._update_docs_page()
# update the generated code
self._update_generated_code_page()
+ def _update_docs_page(self):
+ """Show documentation from XML and try to display best matching docstring"""
+ buffer = self._docs_text_display.get_buffer()
+ buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
+ pos = buffer.get_end_iter()
+
+ docstrings = self._block.get_doc()
+ if not docstrings:
+ return
+
+ # show documentation string from block xml
+ from_xml = docstrings.pop('', '')
+ for line in from_xml.splitlines():
+ if line.lstrip() == line and line.endswith(':'):
+ buffer.insert_with_tags_by_name(pos, line + '\n', 'b')
+ else:
+ buffer.insert(pos, line + '\n')
+ if from_xml:
+ buffer.insert(pos, '\n')
+
+ # if given the current parameters an exact match can be made
+ block_constructor = self._block.get_make().rsplit('.', 2)[-1]
+ block_class = block_constructor.partition('(')[0].strip()
+ if block_class in docstrings:
+ docstrings = {block_class: docstrings[block_class]}
+
+ # show docstring(s) extracted from python sources
+ for cls_name, docstring in docstrings.iteritems():
+ buffer.insert_with_tags_by_name(pos, cls_name + '\n', 'b')
+ buffer.insert(pos, docstring + '\n\n')
+ pos.backward_chars(2)
+ buffer.delete(pos, buffer.get_end_iter())
+
def _update_generated_code_page(self):
if not self._code_text_display:
return # user disabled code preview
diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py
index f20e3c0fa6..51b9b19e9f 100644
--- a/grc/gui/Utils.py
+++ b/grc/gui/Utils.py
@@ -123,10 +123,11 @@ class TemplateParser(object):
parse_template = TemplateParser()
-def align_to_grid(coor):
- _align = lambda: int(round(x / (1.0 * CANVAS_GRID_SIZE)) * CANVAS_GRID_SIZE)
+def align_to_grid(coor, mode=round):
+ def align(value):
+ return int(mode(value / (1.0 * CANVAS_GRID_SIZE)) * CANVAS_GRID_SIZE)
try:
- return [_align() for x in coor]
+ return map(align, coor)
except TypeError:
x = coor
- return _align()
+ return align(coor)
diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py
new file mode 100644
index 0000000000..7721f3bda6
--- /dev/null
+++ b/grc/gui/VariableEditor.py
@@ -0,0 +1,354 @@
+"""
+Copyright 2015 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+from operator import attrgetter
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+
+from . import Actions
+from . import Preferences
+from .Constants import DEFAULT_BLOCKS_WINDOW_WIDTH
+
+BLOCK_INDEX = 0
+ID_INDEX = 1
+
+
+class VariableEditorContextMenu(gtk.Menu):
+ """ A simple context menu for our variable editor """
+ def __init__(self, var_edit):
+ gtk.Menu.__init__(self)
+
+ self.imports = gtk.MenuItem("Add _Import")
+ self.imports.connect('activate', var_edit.handle_action, var_edit.ADD_IMPORT)
+ self.add(self.imports)
+
+ self.variables = gtk.MenuItem("Add _Variable")
+ self.variables.connect('activate', var_edit.handle_action, var_edit.ADD_VARIABLE)
+ self.add(self.variables)
+ self.add(gtk.SeparatorMenuItem())
+
+ self.enable = gtk.MenuItem("_Enable")
+ self.enable.connect('activate', var_edit.handle_action, var_edit.ENABLE_BLOCK)
+ self.disable = gtk.MenuItem("_Disable")
+ self.disable.connect('activate', var_edit.handle_action, var_edit.DISABLE_BLOCK)
+ self.add(self.enable)
+ self.add(self.disable)
+ self.add(gtk.SeparatorMenuItem())
+
+ self.delete = gtk.MenuItem("_Delete")
+ self.delete.connect('activate', var_edit.handle_action, var_edit.DELETE_BLOCK)
+ self.add(self.delete)
+ self.add(gtk.SeparatorMenuItem())
+
+ self.properties = gtk.MenuItem("_Properties...")
+ self.properties.connect('activate', var_edit.handle_action, var_edit.OPEN_PROPERTIES)
+ self.add(self.properties)
+ self.show_all()
+
+ def update_sensitive(self, selected, enabled=False):
+ self.delete.set_sensitive(selected)
+ self.properties.set_sensitive(selected)
+ self.enable.set_sensitive(selected and not enabled)
+ self.disable.set_sensitive(selected and enabled)
+
+
+class VariableEditor(gtk.VBox):
+
+ # Actions that are handled by the editor
+ ADD_IMPORT = 0
+ ADD_VARIABLE = 1
+ OPEN_PROPERTIES = 2
+ DELETE_BLOCK = 3
+ DELETE_CONFIRM = 4
+ ENABLE_BLOCK = 5
+ DISABLE_BLOCK = 6
+
+ def __init__(self, platform, get_flow_graph):
+ gtk.VBox.__init__(self)
+ self.platform = platform
+ self.get_flow_graph = get_flow_graph
+ self._block = None
+ self._mouse_button_pressed = False
+
+ # Only use the model to store the block reference and name.
+ # Generate everything else dynamically
+ self.treestore = gtk.TreeStore(gobject.TYPE_PYOBJECT, # Block reference
+ gobject.TYPE_STRING) # Category and block name
+ self.treeview = gtk.TreeView(self.treestore)
+ self.treeview.set_enable_search(False)
+ self.treeview.set_search_column(-1)
+ #self.treeview.set_enable_search(True)
+ #self.treeview.set_search_column(ID_INDEX)
+ self.treeview.get_selection().set_mode('single')
+ self.treeview.set_headers_visible(True)
+ self.treeview.connect('button-press-event', self._handle_mouse_button_press)
+ self.treeview.connect('button-release-event', self._handle_mouse_button_release)
+ self.treeview.connect('motion-notify-event', self._handle_motion_notify)
+ self.treeview.connect('key-press-event', self._handle_key_button_press)
+
+ # Block Name or Category
+ self.id_cell = gtk.CellRendererText()
+ self.id_cell.connect('edited', self._handle_name_edited_cb)
+ id_column = gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX)
+ id_column.set_name("id")
+ id_column.set_resizable(True)
+ id_column.set_max_width(300)
+ id_column.set_min_width(80)
+ id_column.set_fixed_width(100)
+ id_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ id_column.set_cell_data_func(self.id_cell, self.set_properties)
+ self.id_column = id_column
+ self.treeview.append_column(id_column)
+ self.treestore.set_sort_column_id(ID_INDEX, gtk.SORT_ASCENDING)
+ # For forcing resize
+ self._col_width = 0
+
+ # Block Value
+ self.value_cell = gtk.CellRendererText()
+ self.value_cell.connect('edited', self._handle_value_edited_cb)
+ value_column = gtk.TreeViewColumn("Value", self.value_cell)
+ value_column.set_name("value")
+ value_column.set_resizable(False)
+ value_column.set_expand(True)
+ value_column.set_min_width(100)
+ value_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
+ value_column.set_cell_data_func(self.value_cell, self.set_value)
+ self.value_column = value_column
+ self.treeview.append_column(value_column)
+
+ # Block Actions (Add, Remove)
+ self.action_cell = gtk.CellRendererPixbuf()
+ value_column.pack_start(self.action_cell, False)
+ value_column.set_cell_data_func(self.action_cell, self.set_icon)
+
+ # 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)
+
+ # Context menus
+ self._context_menu = VariableEditorContextMenu(self)
+ self._confirm_delete = Preferences.variable_editor_confirm_delete()
+
+ # Sets cell contents
+ def set_icon(self, col, cell, model, iter):
+ block = model.get_value(iter, BLOCK_INDEX)
+ if block:
+ pb = self.treeview.render_icon(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU, None)
+ else:
+ pb = self.treeview.render_icon(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU, None)
+ cell.set_property('pixbuf', pb)
+
+ def set_value(self, col, cell, model, iter):
+ sp = cell.set_property
+ block = model.get_value(iter, BLOCK_INDEX)
+
+ # Set the default properties for this column first.
+ # Some set in set_properties() may be overridden (editable for advanced variable blocks)
+ self.set_properties(col, cell, model, iter)
+
+ # Set defaults
+ value = None
+ self.set_tooltip_text(None)
+
+ # Block specific values
+ if block:
+ if block.get_key() == 'import':
+ value = block.get_param('import').get_value()
+ elif block.get_key() != "variable":
+ value = "<Open Properties>"
+ sp('editable', False)
+ sp('foreground', '#0D47A1')
+ else:
+ value = block.get_param('value').get_value()
+
+ # Check if there are errors in the blocks.
+ # Show the block error as a tooltip
+ error_message = block.get_error_messages()
+ if len(error_message) > 0:
+ # Set the error message to the last error in the list.
+ # This should be the first message generated
+ self.set_tooltip_text(error_message[-1])
+ else:
+ # Evaluate and show the value (if it is a variable)
+ if block.get_key() == "variable":
+ evaluated = str(block.get_param('value').evaluate())
+ self.set_tooltip_text(evaluated)
+ # Always set the text value.
+ sp('text', value)
+
+ def set_properties(self, col, cell, model, iter):
+ sp = cell.set_property
+ block = model.get_value(iter, BLOCK_INDEX)
+ # Set defaults
+ sp('sensitive', True)
+ sp('editable', False)
+ sp('foreground', None)
+
+ # Block specific changes
+ if block:
+ if not block.get_enabled():
+ # Disabled block. But, this should still be editable
+ sp('editable', True)
+ sp('foreground', 'gray')
+ else:
+ sp('editable', True)
+ if block.get_error_messages():
+ sp('foreground', 'red')
+
+ def update_gui(self):
+ if not self.get_flow_graph():
+ return
+ self._update_blocks()
+ self._rebuild()
+ self.treeview.expand_all()
+
+ def _update_blocks(self):
+ self._imports = filter(attrgetter('is_import'),
+ self.get_flow_graph().blocks)
+ self._variables = filter(attrgetter('is_variable'),
+ self.get_flow_graph().blocks)
+
+ def _rebuild(self, *args):
+ self.treestore.clear()
+ imports = self.treestore.append(None, [None, 'Imports'])
+ variables = self.treestore.append(None, [None, 'Variables'])
+ for block in self._imports:
+ self.treestore.append(imports, [block, block.get_param('id').get_value()])
+ for block in sorted(self._variables, key=lambda v: v.get_id()):
+ self.treestore.append(variables, [block, block.get_param('id').get_value()])
+
+ def _handle_name_edited_cb(self, cell, path, new_text):
+ block = self.treestore[path][BLOCK_INDEX]
+ block.get_param('id').set_value(new_text)
+ Actions.VARIABLE_EDITOR_UPDATE()
+
+ def _handle_value_edited_cb(self, cell, path, new_text):
+ block = self.treestore[path][BLOCK_INDEX]
+ if block.is_import:
+ block.get_param('import').set_value(new_text)
+ else:
+ block.get_param('value').set_value(new_text)
+ Actions.VARIABLE_EDITOR_UPDATE()
+
+ def handle_action(self, item, key, event=None):
+ """
+ Single handler for the different actions that can be triggered by the context menu,
+ key presses or mouse clicks. Also triggers an update of the flow graph and editor.
+ """
+ if key == self.ADD_IMPORT:
+ self.get_flow_graph().add_new_block('import')
+ elif key == self.ADD_VARIABLE:
+ self.get_flow_graph().add_new_block('variable')
+ elif key == self.OPEN_PROPERTIES:
+ Actions.BLOCK_PARAM_MODIFY(self._block)
+ elif key == self.DELETE_BLOCK:
+ self.get_flow_graph().remove_element(self._block)
+ elif key == self.DELETE_CONFIRM:
+ if self._confirm_delete:
+ # Create a context menu to confirm the delete operation
+ confirmation_menu = gtk.Menu()
+ block_id = self._block.get_param('id').get_value().replace("_", "__")
+ confirm = gtk.MenuItem("Delete {}".format(block_id))
+ confirm.connect('activate', self.handle_action, self.DELETE_BLOCK)
+ confirmation_menu.add(confirm)
+ confirmation_menu.show_all()
+ confirmation_menu.popup(None, None, None, event.button, event.time)
+ else:
+ self.handle_action(None, self.DELETE_BLOCK, None)
+ elif key == self.ENABLE_BLOCK:
+ self._block.set_enabled(True)
+ elif key == self.DISABLE_BLOCK:
+ self._block.set_enabled(False)
+ Actions.VARIABLE_EDITOR_UPDATE()
+
+ def _handle_mouse_button_press(self, widget, event):
+ """
+ Handles mouse button for several different events:
+ - Double Click to open properties for advanced blocks
+ - Click to add/remove blocks
+ """
+ # Save the column width to see if it changes on button_release
+ self._mouse_button_pressed = True
+ self._col_width = self.id_column.get_width()
+
+ path = widget.get_path_at_pos(int(event.x), int(event.y))
+ if path:
+ # If there is a valid path, then get the row, column and block selected.
+ row = self.treestore[path[0]]
+ col = path[1]
+ self._block = row[BLOCK_INDEX]
+
+ if event.button == 1 and col.get_name() == "value":
+ # Make sure this has a block (not the import/variable rows)
+ if self._block and event.type == gtk.gdk._2BUTTON_PRESS:
+ # Open the advanced dialog if it is a gui variable
+ if self._block.get_key() not in ("variable", "import"):
+ self.handle_action(None, self.OPEN_PROPERTIES, event=event)
+ return True
+ if event.type == gtk.gdk.BUTTON_PRESS:
+ # User is adding/removing blocks
+ # Make sure this is the action cell (Add/Remove Icons)
+ if path[2] > col.cell_get_position(self.action_cell)[0]:
+ if row[1] == "Imports":
+ # Add a new import block.
+ self.handle_action(None, self.ADD_IMPORT, event=event)
+ elif row[1] == "Variables":
+ # Add a new variable block
+ self.handle_action(None, self.ADD_VARIABLE, event=event)
+ else:
+ self.handle_action(None, self.DELETE_CONFIRM, event=event)
+ return True
+ elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS:
+ if self._block:
+ self._context_menu.update_sensitive(True, enabled=self._block.get_enabled())
+ else:
+ self._context_menu.update_sensitive(False)
+ self._context_menu.popup(None, None, None, event.button, event.time)
+
+ # Null handler. Stops the treeview from handling double click events.
+ if event.type == gtk.gdk._2BUTTON_PRESS:
+ return True
+ return False
+
+ def _handle_mouse_button_release(self, widget, event):
+ self._mouse_button_pressed = False
+ return False
+
+ def _handle_motion_notify(self, widget, event):
+ # Check to see if the column size has changed
+ if self._mouse_button_pressed and self.id_column.get_width() != self._col_width:
+ self.value_column.queue_resize()
+ return False
+
+ def _handle_key_button_press(self, widget, event):
+ model, path = self.treeview.get_selection().get_selected_rows()
+ if path and self._block:
+ if self._block.get_enabled() and event.string == "d":
+ self.handle_action(None, self.DISABLE_BLOCK, None)
+ return True
+ elif not self._block.get_enabled() and event.string == "e":
+ self.handle_action(None, self.ENABLE_BLOCK, None)
+ return True
+ return False
diff --git a/grc/main.py b/grc/main.py
new file mode 100755
index 0000000000..ae7a0ce115
--- /dev/null
+++ b/grc/main.py
@@ -0,0 +1,55 @@
+# Copyright 2009-2016 Free Software Foundation, Inc.
+# This file is part of GNU Radio
+#
+# GNU Radio Companion 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
+# of the License, or (at your option) any later version.
+#
+# GNU Radio Companion 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+import optparse
+
+import gtk
+from gnuradio import gr
+
+from .gui.Platform import Platform
+from .gui.ActionHandler import ActionHandler
+
+
+VERSION_AND_DISCLAIMER_TEMPLATE = """\
+GNU Radio Companion %s
+
+This program is part of GNU Radio
+GRC comes with ABSOLUTELY NO WARRANTY.
+This is free software, and you are welcome to redistribute it.
+"""
+
+
+def main():
+ parser = optparse.OptionParser(
+ usage='usage: %prog [options] [saved flow graphs]',
+ version=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
+ options, args = parser.parse_args()
+
+ try:
+ gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0))
+ except:
+ pass
+
+ platform = Platform(
+ prefs_file=gr.prefs(),
+ version=gr.version(),
+ version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()),
+ install_prefix=gr.prefix()
+ )
+ ActionHandler(args, platform)
+ gtk.main()
+
diff --git a/grc/python/Block.py b/grc/python/Block.py
deleted file mode 100644
index 782893fd8f..0000000000
--- a/grc/python/Block.py
+++ /dev/null
@@ -1,323 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import itertools
-import collections
-
-from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI
-from .. base.odict import odict
-
-from .. base.Block import Block as _Block
-from .. gui.Block import Block as _GUIBlock
-
-from . FlowGraph import _variable_matcher
-from . import epy_block_io
-
-
-class Block(_Block, _GUIBlock):
-
- 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 '').strip('\n').replace('\\\n', '')
- 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._bus_structure_source = n.find('bus_structure_source') or ''
- self._bus_structure_sink = n.find('bus_structure_sink') or ''
- self.port_counters = [itertools.count(), itertools.count()]
- #build the block
- _Block.__init__(
- self,
- flow_graph=flow_graph,
- n=n,
- )
- _GUIBlock.__init__(self)
-
- self._epy_source_hash = -1 # for epy blocks
- self._epy_reload_error = None
-
- 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 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)
- # for variables check the value (only if var_value is used
- if _variable_matcher.match(self.get_key()) and self._var_value != '$value':
- value = self._var_value
- try:
- value = self.get_var_value()
- self.get_parent().evaluate(value)
- except Exception as err:
- self.add_error_message('Value "%s" cannot be evaluated:\n%s' % (value, err))
-
- # check if this is a GUI block and matches the selected generate option
- current_generate_option = self.get_parent().get_option('generate_options')
-
- def check_generate_mode(label, flag, valid_options):
- block_requires_mode = (
- flag in self.get_flags() or
- self.get_name().upper().startswith(label)
- )
- if block_requires_mode and current_generate_option not in valid_options:
- self.add_error_message("Can't generate this block in mode " +
- repr(current_generate_option))
-
- check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',))
- check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui'))
- if self._epy_reload_error:
- self.get_param('_source_code').add_error_message(str(self._epy_reload_error))
-
- def rewrite(self):
- """
- Add and remove ports to adjust for the nports.
- """
- _Block.rewrite(self)
- # Check and run any custom rewrite function for this block
- getattr(self, 'rewrite_' + self._key, lambda: None)()
-
- # adjust nports, disconnect hidden ports
- for ports in (self.get_sources(), self.get_sinks()):
- for i, master_port in enumerate(ports):
- nports = master_port.get_nports() or 1
- num_ports = 1 + len(master_port.get_clones())
- if master_port.get_hide():
- for connection in master_port.get_connections():
- self.get_parent().remove_element(connection)
- if not nports and num_ports == 1: # not a master port and no left-over clones
- continue
- # remove excess cloned ports
- for port in master_port.get_clones()[nports-1:]:
- # remove excess connections
- for connection in port.get_connections():
- self.get_parent().remove_element(connection)
- master_port.remove_clone(port)
- ports.remove(port)
- # add more cloned ports
- for j in range(num_ports, nports):
- port = master_port.add_clone()
- ports.insert(ports.index(master_port) + j, port)
-
- self.back_ofthe_bus(ports)
- # renumber non-message/-msg ports
- domain_specific_port_index = collections.defaultdict(int)
- for port in filter(lambda p: p.get_key().isdigit(), ports):
- domain = port.get_domain()
- port._key = str(domain_specific_port_index[domain])
- domain_specific_port_index[domain] += 1
-
- 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):
- platform = self.get_parent().get_parent()
- extracted_docs = platform.block_docstrings.get(self._key, '')
- return (self._doc + '\n\n' + extracted_docs).strip()
-
- def get_category(self):
- return _Block.get_category(self)
-
- def get_imports(self, raw=False):
- """
- 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
- """
- if raw:
- return self._imports
- return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), []))
-
- def get_make(self, raw=False):
- if raw:
- return self._make
- return self.resolve_dependencies(self._make)
-
- def get_var_make(self):
- return self.resolve_dependencies(self._var_make)
-
- def get_var_value(self):
- return self.resolve_dependencies(self._var_value)
-
- 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'
-
- ###########################################################################
- # Custom rewrite functions
- ###########################################################################
-
- def rewrite_epy_block(self):
- flowgraph = self.get_parent()
- platform = flowgraph.get_parent()
- param_blk = self.get_param('_io_cache')
- param_src = self.get_param('_source_code')
- doc_end_tag = 'Block Documentation:'
-
- src = param_src.get_value()
- src_hash = hash((self.get_id(), src))
- if src_hash == self._epy_source_hash:
- return
-
- try:
- blk_io = epy_block_io.extract(src)
-
- except Exception as e:
- self._epy_reload_error = ValueError(str(e))
- try: # load last working block io
- blk_io = epy_block_io.BlockIO(*eval(param_blk.get_value()))
- except:
- return
- else:
- self._epy_reload_error = None # clear previous errors
- param_blk.set_value(repr(tuple(blk_io)))
-
- # print "Rewriting embedded python block {!r}".format(self.get_id())
- self._epy_source_hash = src_hash
- self._name = blk_io.name or blk_io.cls
- self._doc = self._doc.split(doc_end_tag)[0] + doc_end_tag + '\n' + blk_io.doc
- self._imports[0] = 'import ' + self.get_id()
- self._make = '{0}.{1}({2})'.format(self.get_id(), blk_io.cls, ', '.join(
- '{0}=${0}'.format(key) for key, _ in blk_io.params))
-
- params = {}
- for param in list(self._params):
- if hasattr(param, '__epy_param__'):
- params[param.get_key()] = param
- self._params.remove(param)
-
- for key, value in blk_io.params:
- try:
- param = params[key]
- param.set_default(value)
- except KeyError: # need to make a new param
- name = key.replace('_', ' ').title()
- n = odict(dict(name=name, key=key, type='raw', value=value))
- param = platform.Param(block=self, n=n)
- setattr(param, '__epy_param__', True)
- self._params.append(param)
-
- def update_ports(label, ports, port_specs, direction):
- ports_to_remove = list(ports)
- iter_ports = iter(ports)
- ports_new = []
- port_current = next(iter_ports, None)
- for key, port_type in port_specs:
- reuse_port = (
- port_current is not None and
- port_current.get_type() == port_type and
- (key.isdigit() or port_current.get_key() == key)
- )
- if reuse_port:
- ports_to_remove.remove(port_current)
- port, port_current = port_current, next(iter_ports, None)
- else:
- n = odict(dict(name=label + str(key), type=port_type, key=key))
- if port_type == 'message':
- n['name'] = key
- n['optional'] = '1'
- port = platform.Port(block=self, n=n, dir=direction)
- ports_new.append(port)
- # replace old port list with new one
- del ports[:]
- ports.extend(ports_new)
- # remove excess port connections
- for port in ports_to_remove:
- for connection in port.get_connections():
- flowgraph.remove_element(connection)
-
- update_ports('in', self.get_sinks(), blk_io.sinks, 'sink')
- update_ports('out', self.get_sources(), blk_io.sources, 'source')
- _Block.rewrite(self)
diff --git a/grc/python/Connection.py b/grc/python/Connection.py
deleted file mode 100644
index 822876a0ae..0000000000
--- a/grc/python/Connection.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import Constants
-from .. base.Connection import Connection as _Connection
-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_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.
- """
- _Connection.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/FlowGraph.py b/grc/python/FlowGraph.py
deleted file mode 100644
index b2a1d27859..0000000000
--- a/grc/python/FlowGraph.py
+++ /dev/null
@@ -1,338 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-import re
-import imp
-from operator import methodcaller
-
-from . import expr_utils
-from .. base.FlowGraph import FlowGraph as _FlowGraph
-from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
-
-_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):
- self.grc_file_path = ''
- _FlowGraph.__init__(self, **kwargs)
- _GUIFlowGraph.__init__(self)
- self.n = {}
- self.n_hash = -1
- self._renew_eval_ns = True
- self._eval_cache = {}
-
- 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_hier_block_stream_io(self, direction):
- """
- Get a list of stream io signatures for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- return filter(lambda p: p['type'] != "message",
- self.get_hier_block_io(direction))
-
- def get_hier_block_message_io(self, direction):
- """
- Get a list of message io signatures for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- return filter(lambda p: p['type'] == "message",
- self.get_hier_block_io(direction))
-
- def get_hier_block_io(self, direction):
- """
- Get a list of io ports for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- pads = self.get_pad_sources() if direction in ('sink', 'in') else \
- self.get_pad_sinks() if direction in ('source', 'out') else []
- ports = []
- for pad in pads:
- master = {
- 'label': str(pad.get_param('label').get_evaluated()),
- 'type': str(pad.get_param('type').get_evaluated()),
- 'vlen': str(pad.get_param('vlen').get_value()),
- 'size': pad.get_param('type').get_opt('size'),
- 'optional': bool(pad.get_param('optional').get_evaluated()),
- }
- num_ports = pad.get_param('num_streams').get_evaluated()
- if num_ports > 1:
- for i in xrange(num_ports):
- clone = master.copy()
- clone['label'] += str(i)
- ports.append(clone)
- else:
- ports.append(master)
- return ports
-
- 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_pad_port_global_key(self, port):
- """
- Get the key for a port of a pad source/sink to use in connect()
- This takes into account that pad blocks may have multiple ports
-
- Returns:
- the key (str)
- """
- key_offset = 0
- pads = self.get_pad_sources() if port.is_source() else self.get_pad_sinks()
- for pad in pads:
- # using the block param 'type' instead of the port domain here
- # to emphasize that hier block generation is domain agnostic
- is_message_pad = pad.get_param('type').get_evaluated() == "message"
- if port.get_parent() == pad:
- if is_message_pad:
- key = pad.get_param('label').get_value()
- else:
- key = str(key_offset + int(port.get_key()))
- return key
- else:
- # assuming we have either only sources or sinks
- if not is_message_pad:
- key_offset += len(pad.get_ports())
- return -1
-
- 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.iter_enabled_blocks())
- return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('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.iter_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.iter_enabled_blocks())
- return monitors
-
- def get_python_modules(self):
- """Iterate over custom code block ID and Source"""
- for block in self.iter_enabled_blocks():
- if block.get_key() == 'epy_module':
- yield block.get_id(), block.get_param('source_code').get_value()
-
- def get_bussink(self):
- bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks())
-
- 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
-
- 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())
-
- return bussrc
-
- 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 code in self.get_imports():
- try: exec code in n
- except: pass
-
- for id, code in self.get_python_modules():
- try:
- module = imp.new_module(id)
- exec code in module.__dict__
- n[id] = module
- 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_var_value(), 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 get_new_block(self, key):
- """Try to auto-generate the block from file if missing"""
- block = _FlowGraph.get_new_block(self, key)
- if not block:
- platform = self.get_parent()
- # we're before the initial fg rewrite(), so no evaluated values!
- # --> use raw value instead
- path_param = self._options_block.get_param('hier_block_src_path')
- file_path = platform.find_file_in_paths(
- filename=key + '.' + platform.get_key(),
- paths=path_param.get_value(),
- cwd=self.grc_file_path
- )
- if file_path: # grc file found. load and get block
- platform.load_and_generate_flow_graph(file_path)
- block = _FlowGraph.get_new_block(self, key) # can be None
- return block
diff --git a/grc/python/Param.py b/grc/python/Param.py
deleted file mode 100644
index e60f613f00..0000000000
--- a/grc/python/Param.py
+++ /dev/null
@@ -1,433 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import ast
-import re
-
-from gnuradio import gr
-
-from .. base.Param import Param as _Param
-from .. gui.Param import Param as _GUIParam
-
-import Constants
-from Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES
-
-from gnuradio import eng_notation
-
-_check_id_matcher = re.compile('^[a-z|A-Z]\w*$')
-_show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook|epy_module)$')
-
-
-#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__)
-
-
-def num_to_str(num):
- """ Display logic for numbers """
- 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)
-
-
-class Param(_Param, _GUIParam):
-
- 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', '_multiline', '_multiline_python_external',
- '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()
-
- ##################################################
- # 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_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)
-
- 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 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()
- 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', '_multiline', '_multiline_python_external'):
- #do not check if file/directory exists, that is a runtime issue
- try:
- e = self.get_parent().get_parent().evaluate(v)
- if not isinstance(e, str):
- raise Exception()
- except:
- self._stringify_flag = True
- e = str(v)
- if t == '_multiline_python_external':
- ast.parse(e) # raises SyntaxError
- return 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 = '?'
-
- 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}
-
- # FIXME: Move replace(...) into the make template of the qtgui blocks and return a string here
- class GuiHint(object):
- def __init__(self, ws):
- self._ws = ws
-
- def __call__(self, w):
- return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w
-
- def __str__(self):
- return self._ws
- return GuiHint(widget_str)
- #########################
- # 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', '_multiline', '_multiline_python_external'): # 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()], [])
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
deleted file mode 100644
index 351f04cb95..0000000000
--- a/grc/python/Platform.py
+++ /dev/null
@@ -1,176 +0,0 @@
-"""
-Copyright 2008-2016 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import os
-import sys
-
-from gnuradio import gr
-
-from .. base.Platform import Platform as _Platform
-from .. gui.Platform import Platform as _GUIPlatform
-from .. gui import Messages
-
-from . import extract_docs
-from .FlowGraph import FlowGraph as _FlowGraph
-from .Connection import Connection as _Connection
-from .Block import Block as _Block
-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,
- PREFS_FILE, PREFS_FILE_OLD, CORE_TYPES
-)
-
-COLORS = [(name, color) for name, key, sizeof, color in CORE_TYPES]
-
-
-class Platform(_Platform, _GUIPlatform):
- def __init__(self):
- """
- Make a platform for gnuradio.
- """
- # ensure hier and conf directories
- if not os.path.exists(HIER_BLOCKS_LIB_DIR):
- os.mkdir(HIER_BLOCKS_LIB_DIR)
- if not os.path.exists(os.path.dirname(PREFS_FILE)):
- os.mkdir(os.path.dirname(PREFS_FILE))
-
- self.block_docstrings = block_docstrings = dict()
- self.block_docstrings_loaded_callback = lambda: None
-
- def setter(key, docs):
- block_docstrings[key] = '\n\n'.join(
- '--- {0} ---\n{1}\n'.format(b, d.replace('\n\n', '\n'))
- for b, d in docs.iteritems() if d is not None
- )
-
- self._docstring_extractor = extract_docs.SubprocessLoader(
- callback_query_result=setter,
- callback_finished=lambda: self.block_docstrings_loaded_callback()
- )
-
- # init
- _Platform.__init__(
- self,
- name='GNU Radio Companion',
- version=(gr.version(), gr.major_version(), gr.api_version(), gr.minor_version()),
- key='grc',
- license=__doc__.strip(),
- website='http://gnuradio.org/',
- block_paths=BLOCKS_DIRS,
- block_dtd=BLOCK_DTD,
- default_flow_graph=DEFAULT_FLOW_GRAPH,
- generator=Generator,
- colors=COLORS,
- )
- self._move_old_pref_file()
- _GUIPlatform.__init__(
- self,
- prefs_file=PREFS_FILE
- )
- self._auto_hier_block_generate_chain = set()
-
- @staticmethod
- def _move_old_pref_file():
- if PREFS_FILE == PREFS_FILE_OLD:
- return # prefs file overridden with env var
- if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE):
- try:
- import shutil
- shutil.move(PREFS_FILE_OLD, PREFS_FILE)
- except Exception as e:
- print >> sys.stderr, e
-
- def load_blocks(self):
- self._docstring_extractor.start()
- _Platform.load_blocks(self)
- self._docstring_extractor.finish()
- # self._docstring_extractor.wait()
-
- def load_block_xml(self, xml_file):
- block = _Platform.load_block_xml(self, xml_file)
- self._docstring_extractor.query(
- block.get_key(),
- block.get_imports(raw=True),
- block.get_make(raw=True)
- )
- return block
-
- @staticmethod
- def find_file_in_paths(filename, paths, cwd):
- """Checks the provided paths relative to cwd for a certain filename"""
- if not os.path.isdir(cwd):
- cwd = os.path.dirname(cwd)
- if isinstance(paths, str):
- paths = (p for p in paths.split(':') if p)
-
- for path in paths:
- path = os.path.expanduser(path)
- if not os.path.isabs(path):
- path = os.path.normpath(os.path.join(cwd, path))
- file_path = os.path.join(path, filename)
- if os.path.exists(os.path.normpath(file_path)):
- return file_path
-
- def load_and_generate_flow_graph(self, file_path):
- """Loads a flowgraph from file and generates it"""
- Messages.set_indent(len(self._auto_hier_block_generate_chain))
- Messages.send('>>> Loading: %r\n' % file_path)
- if file_path in self._auto_hier_block_generate_chain:
- Messages.send(' >>> Warning: cyclic hier_block dependency\n')
- return False
- self._auto_hier_block_generate_chain.add(file_path)
- try:
- flow_graph = self.get_new_flow_graph()
- flow_graph.grc_file_path = file_path
- # other, nested higiter_blocks might be auto-loaded here
- flow_graph.import_data(self.parse_flow_graph(file_path))
- flow_graph.rewrite()
- flow_graph.validate()
- if not flow_graph.is_valid():
- raise Exception('Flowgraph invalid')
- if not flow_graph.get_option('generate_options').startswith('hb'):
- raise Exception('Not a hier block')
- except Exception as e:
- Messages.send('>>> Load Error: %r: %s\n' % (file_path, str(e)))
- return False
- finally:
- self._auto_hier_block_generate_chain.discard(file_path)
- Messages.set_indent(len(self._auto_hier_block_generate_chain))
-
- try:
- Messages.send('>>> Generating: %r\n' % file_path)
- generator = self.get_generator()(flow_graph, file_path)
- generator.write()
- except Exception as e:
- Messages.send('>>> Generate Error: %r: %s\n' % (file_path, str(e)))
- return False
-
- self.load_block_xml(generator.get_file_path_xml())
- return True
-
- ##############################################
- # Constructors
- ##############################################
- FlowGraph = _FlowGraph
- Connection = _Connection
- Block = _Block
- Port = _Port
- Param = _Param
diff --git a/grc/python/Port.py b/grc/python/Port.py
deleted file mode 100644
index 249d7aed71..0000000000
--- a/grc/python/Port.py
+++ /dev/null
@@ -1,268 +0,0 @@
-"""
-Copyright 2008-2012 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion 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
-of the License, or (at your option) any later version.
-
-GNU Radio Companion 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 this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-from .. base.Port import Port as _Port
-from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
-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
-
-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
-
-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
-
-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
-
-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'] == 'message':
- n['domain'] = GR_MESSAGE_DOMAIN
- if 'domain' not in n:
- n['domain'] = DEFAULT_DOMAIN
- elif n['domain'] == GR_MESSAGE_DOMAIN:
- n['key'] = n['name']
- n['type'] = 'message' # for port color
- if n['type'] == 'msg':
- n['key'] = 'msg'
- if not n.find('key'):
- n['key'] = str(next(block.port_counters[dir == 'source']))
- # 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'))
- self._clones = [] # references to cloned ports (for nports > 1)
-
- 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.')
- #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.
- """
- 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 = ''
- _Port.rewrite(self)
-
- 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 a positive integer, return 1.
-
- Returns:
- the number of ports or 1
- """
- if self._nports == '': return ''
-
- nports = self.get_parent().resolve_dependencies(self._nports)
- try:
- return max(1, int(self.get_parent().get_parent().evaluate(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 get_clones(self):
- """
- Get the clones of this master port (nports > 1)
-
- Returns:
- a list of ports
- """
- return self._clones
-
- def add_clone(self):
- """
- Create a clone of this (master) port and store a reference in self._clones.
-
- The new port name (and key for message ports) will have index 1... appended.
- If this is the first clone, this (master) port will get a 0 appended to its name (and key)
-
- Returns:
- the cloned port
- """
- # add index to master port name if there are no clones yet
- if not self._clones:
- self._name = self._n['name'] + '0'
- if not self._key.isdigit(): # also update key for none stream ports
- self._key = self._name
-
- # Prepare a copy of the odict for the clone
- n = self._n.copy()
- if 'nports' in n: n.pop('nports') # remove nports from the key so the copy cannot be a duplicator
- n['name'] = self._n['name'] + str(len(self._clones) + 1)
- n['key'] = '99999' if self._key.isdigit() else n['name'] # dummy value 99999 will be fixed later
-
- port = self.__class__(self.get_parent(), n, self._dir) # clone
- self._clones.append(port)
- return port
-
- def remove_clone(self, port):
- """
- Remove a cloned port (from the list of clones only)
- Remove the index 0 of the master port name (and key9 if there are no more clones left
- """
- self._clones.remove(port)
- # remove index from master port name if there are no more clones
- if not self._clones:
- self._name = self._n['name']
- if not self._key.isdigit(): # also update key for none stream ports
- self._key = self._name
diff --git a/grc/scripts/CMakeLists.txt b/grc/scripts/CMakeLists.txt
index e905892308..6cc78c3cf3 100644
--- a/grc/scripts/CMakeLists.txt
+++ b/grc/scripts/CMakeLists.txt
@@ -23,3 +23,5 @@ GR_PYTHON_INSTALL(
DESTINATION ${GR_RUNTIME_DIR}
COMPONENT "grc"
)
+
+add_subdirectory(freedesktop)
diff --git a/grc/freedesktop/CMakeLists.txt b/grc/scripts/freedesktop/CMakeLists.txt
index 47e836f697..47e836f697 100644
--- a/grc/freedesktop/CMakeLists.txt
+++ b/grc/scripts/freedesktop/CMakeLists.txt
diff --git a/grc/freedesktop/README b/grc/scripts/freedesktop/README
index 0857ecc224..0857ecc224 100644
--- a/grc/freedesktop/README
+++ b/grc/scripts/freedesktop/README
diff --git a/grc/freedesktop/convert.sh b/grc/scripts/freedesktop/convert.sh
index e2cba264a6..e2cba264a6 100755
--- a/grc/freedesktop/convert.sh
+++ b/grc/scripts/freedesktop/convert.sh
diff --git a/grc/freedesktop/gnuradio-grc.desktop b/grc/scripts/freedesktop/gnuradio-grc.desktop
index 39beeca1b8..39beeca1b8 100644
--- a/grc/freedesktop/gnuradio-grc.desktop
+++ b/grc/scripts/freedesktop/gnuradio-grc.desktop
diff --git a/grc/freedesktop/gnuradio-grc.xml b/grc/scripts/freedesktop/gnuradio-grc.xml
index a5cb95d9fd..a5cb95d9fd 100644
--- a/grc/freedesktop/gnuradio-grc.xml
+++ b/grc/scripts/freedesktop/gnuradio-grc.xml
diff --git a/grc/freedesktop/gnuradio_logo_icon-square.svg b/grc/scripts/freedesktop/gnuradio_logo_icon-square.svg
index 3b54bf4001..3b54bf4001 100644
--- a/grc/freedesktop/gnuradio_logo_icon-square.svg
+++ b/grc/scripts/freedesktop/gnuradio_logo_icon-square.svg
diff --git a/grc/freedesktop/grc-icon-128.png b/grc/scripts/freedesktop/grc-icon-128.png
index 13efe806ba..13efe806ba 100644
--- a/grc/freedesktop/grc-icon-128.png
+++ b/grc/scripts/freedesktop/grc-icon-128.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-16.png b/grc/scripts/freedesktop/grc-icon-16.png
index bdd1823b3d..bdd1823b3d 100644
--- a/grc/freedesktop/grc-icon-16.png
+++ b/grc/scripts/freedesktop/grc-icon-16.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-24.png b/grc/scripts/freedesktop/grc-icon-24.png
index a124768125..a124768125 100644
--- a/grc/freedesktop/grc-icon-24.png
+++ b/grc/scripts/freedesktop/grc-icon-24.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-256.png b/grc/scripts/freedesktop/grc-icon-256.png
index 077688eac5..077688eac5 100644
--- a/grc/freedesktop/grc-icon-256.png
+++ b/grc/scripts/freedesktop/grc-icon-256.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-32.png b/grc/scripts/freedesktop/grc-icon-32.png
index a345aace3c..a345aace3c 100644
--- a/grc/freedesktop/grc-icon-32.png
+++ b/grc/scripts/freedesktop/grc-icon-32.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-48.png b/grc/scripts/freedesktop/grc-icon-48.png
index c522a5d0ec..c522a5d0ec 100644
--- a/grc/freedesktop/grc-icon-48.png
+++ b/grc/scripts/freedesktop/grc-icon-48.png
Binary files differ
diff --git a/grc/freedesktop/grc-icon-64.png b/grc/scripts/freedesktop/grc-icon-64.png
index df4f6dc07b..df4f6dc07b 100644
--- a/grc/freedesktop/grc-icon-64.png
+++ b/grc/scripts/freedesktop/grc-icon-64.png
Binary files differ
diff --git a/grc/freedesktop/grc_setup_freedesktop.in b/grc/scripts/freedesktop/grc_setup_freedesktop.in
index 87a388e2ec..87a388e2ec 100644
--- a/grc/freedesktop/grc_setup_freedesktop.in
+++ b/grc/scripts/freedesktop/grc_setup_freedesktop.in
diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion
index 203a8c773d..04a1cb44e7 100755
--- a/grc/scripts/gnuradio-companion
+++ b/grc/scripts/gnuradio-companion
@@ -1,6 +1,6 @@
#!/usr/bin/env python
"""
-Copyright 2009-2015 Free Software Foundation, Inc.
+Copyright 2016 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -20,111 +20,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import os
import sys
-import optparse
-import warnings
-
-GR_IMPORT_ERROR_MESSAGE = """\
-Cannot import gnuradio.
-
-Is the python path environment variable set correctly?
- All OS: PYTHONPATH
-
-Is the library path environment variable set correctly?
- Linux: LD_LIBRARY_PATH
- Windows: PATH
- MacOSX: DYLD_LIBRARY_PATH
-"""
-
-VERSION_AND_DISCLAIMER_TEMPLATE = """\
-GNU Radio Companion %s
-
-This program is part of GNU Radio
-GRC comes with ABSOLUTELY NO WARRANTY.
-This is free software, and you are welcome to redistribute it.
-"""
-
-
-def die(error, message):
- msg = "{0}\n\n({1})".format(message, error)
- try:
- import gtk
- d = gtk.MessageDialog(
- type=gtk.MESSAGE_ERROR,
- buttons=gtk.BUTTONS_CLOSE,
- message_format=msg,
- )
- d.set_title(type(error).__name__)
- d.run()
- exit(1)
- except ImportError:
- exit(type(error).__name__ + '\n\n' + msg)
-
-
-def check_gtk():
- try:
- warnings.filterwarnings("error")
- import pygtk
- pygtk.require('2.0')
- import gtk
- gtk.init_check()
- warnings.filterwarnings("always")
- except Exception as err:
- die(err, "Failed to initialize GTK. If you are running over ssh, "
- "did you enable X forwarding and start ssh with -X?")
-
-
-def check_gnuradio_import():
- try:
- from gnuradio import gr
- except ImportError as err:
- die(err, GR_IMPORT_ERROR_MESSAGE)
-
-
-def check_blocks_path():
- if 'GR_DONT_LOAD_PREFS' in os.environ and not os.environ.get('GRC_BLOCKS_PATH', ''):
- die(EnvironmentError("No block definitions available"),
- "Can't find block definitions. Use config.conf or GRC_BLOCKS_PATH.")
-
-
-def get_source_tree_root():
- source_tree_subpath = "/grc/scripts"
- script_path = os.path.dirname(os.path.abspath(__file__))
- if script_path.endswith(source_tree_subpath):
- return script_path[:-len(source_tree_subpath)]
-
-
-def main():
- check_gnuradio_import()
-
- from gnuradio import gr
- parser = optparse.OptionParser(
- usage='usage: %prog [options] [saved flow graphs]',
- version=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
- options, args = parser.parse_args()
-
- check_gtk()
- check_blocks_path()
- source_tree_root = get_source_tree_root()
- if not source_tree_root:
- # run the installed version
- from gnuradio.grc.python.Platform import Platform
- from gnuradio.grc.gui.ActionHandler import ActionHandler
-
- else:
- print("Running from source tree")
- sys.path.insert(1, source_tree_root)
- from grc.python.Platform import Platform
- from grc.gui.ActionHandler import ActionHandler
-
- try:
- import gtk
- gtk.window_set_default_icon(gtk.IconTheme().load_icon('gnuradio-grc', 256, 0))
- except:
- pass
-
- ActionHandler(args, Platform())
-
-
-if __name__ == '__main__':
- main()
+script_path = os.path.dirname(os.path.abspath(__file__))
+source_tree_subpath = "/grc/scripts"
+
+if not script_path.endswith(source_tree_subpath):
+ # run the installed version
+ from gnuradio.grc.main import main
+ from gnuradio.grc import checks
+else:
+ print("Running from source tree")
+ sys.path.insert(1, script_path[:-len(source_tree_subpath)])
+ from grc.main import main
+ from grc import checks
+
+checks.do_all()
+exit(main())
diff --git a/grc/todo.txt b/grc/todo.txt
deleted file mode 100644
index cedea72aa3..0000000000
--- a/grc/todo.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-##################################################
-# Examples
-##################################################
-* Push-to-Talk example
-* Start/Stop the flow graph
-
-##################################################
-# Blocks
-##################################################
-* probe: also non-float outputs
-* log slider gui control
-* packet mod: whitening offset
-* wx min window size in options block
-* gr_adaptive_fir_ccf
-* size params for the graphical sinks
-* callbacks for set average on fft, waterfall, number sinks
-* add units to params: Sps, Hz, dB...
-* add bool type to command line option store_true or store_false
-* messages for packet blocks and probe blocks
-
-##################################################
-# Features
-##################################################
-* extract category from doxygen
- * fix up block tree to mirror current doxygen group
- * remove blocks in block tree covered by doxygen
-* param editor, expand entry boxes in focus
-* change param dialog to panel within main window
-* gui grid editor for configuring grid params/placing wxgui plots and controls
-* drag from one port to another to connect
-* per parameter docs
- * extract individual param docs from doxygen
- * doc tag in param for handwritten notes
-* separate generated code into top block and gui class
- * use gui.py in gr-wxgui and remove custom top_block_gui
-* configuration option for adding block paths
-* orientations for ports (top, right, bottom, left)
- * source defaults to right, sink defaults to left
-* separation of variables and gui controls
-* speedup w/ background layer and animation layer
-* multiple doxygen directories (doc_dir becomes doc_path)
-* use pango markup in tooltips for params
-* use get_var_make to determine if it is a variable, not regexp
-* concept of a project, or project flow graph
- * collection of blocks, hier and top
- * system-wide, default/work, and user created
-* use templates/macros to generate the repetative stuff in the xml
-
-##################################################
-# Problems
-##################################################
-* msg ports dont work with virtual connections
- * dont fix this until pmts are used?
-* hier block generation
- * auto generate hier library on changes
- * auto clean hier library when block removed
- * add hier blocks to tree without restart
-* dont generate py files in saved flowgraph dir
-* save/restore cwd
-* threads dont die on exit in probe and variable sink
-* align param titles in properties dialog
-* weird grid params misbehaving
-* gr hier blocks have more diverse IO capabilities than we allow for
-
-##################################################
-# Future
-##################################################
-* require pygtk 2.12 for treeview tooltips
- * remove try/except in BlockTreeWindow.py
diff --git a/volk b/volk
-Subproject 78c8bc4a0e49487e1f787f0fe77d8c3dace7c7f
+Subproject b930d7ffb9561be5d333301dea852fdbe104d36