diff options
135 files changed, 9625 insertions, 2697 deletions
diff --git a/.gitignore b/.gitignore index 6a6326509..b333709ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,30 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +.* +*.o +*.a +*.ko +*.so +*.la +*.lo +*.py[oc] +*.gz +*.patch +*~ +\#*# +.deps +.libs +TAGS +*-stamp +!.gitignore +make.log /configure /Makefile.in /config.log @@ -17,5 +44,3 @@ /compile /build /run_tests.sh -/*-stamp -*~ diff --git a/config/Makefile.am b/config/Makefile.am index d6a3ad393..3aead353a 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -61,6 +61,7 @@ m4macros = \ grc_gr_gcell.m4 \ grc_gr_gpio.m4 \ grc_gr_gsm_fr_vocoder.m4 \ + grc_gr_noaa.m4 \ grc_gr_radar_mono.m4 \ grc_gr_radio_astronomy.m4 \ grc_gr_sounder.m4 \ diff --git a/config/grc_gr_noaa.m4 b/config/grc_gr_noaa.m4 new file mode 100644 index 000000000..b00579ff5 --- /dev/null +++ b/config/grc_gr_noaa.m4 @@ -0,0 +1,41 @@ +dnl Copyright 2009 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_GR_NOAA],[ + GRC_ENABLE(gr-noaa) + + dnl Don't do gr-noaa if gnuradio-core skipped + GRC_CHECK_DEPENDENCY(gr-noaa, gnuradio-core) + GRC_CHECK_DEPENDENCY(gr-noaa, gr-wxgui) + GRC_CHECK_DEPENDENCY(gr-noaa, grc) + + AC_CONFIG_FILES([\ + gr-noaa/Makefile \ + gr-noaa/apps/Makefile \ + gr-noaa/grc/Makefile \ + gr-noaa/lib/Makefile \ + gr-noaa/python/Makefile \ + gr-noaa/swig/Makefile \ + ]) + + GRC_BUILD_CONDITIONAL(gr-noaa,[ + dnl run_tests is created from run_tests.in. Make it executable. + #AC_CONFIG_COMMANDS([run_tests_noaa], [chmod +x gr-pager/lib/run_tests]) + ]) +]) diff --git a/config/grc_grc.m4 b/config/grc_grc.m4 index ce23e3c25..7ee009fae 100644 --- a/config/grc_grc.m4 +++ b/config/grc_grc.m4 @@ -31,7 +31,7 @@ AC_DEFUN([GRC_GRC],[ if test $passed = yes; then PYTHON_CHECK_MODULE([sys],[Python >= 2.5],[],[passed=no],[sys.version.split()[[0]] >= "2.5"]) PYTHON_CHECK_MODULE([Cheetah],[Python Cheetah templates >= 2.0.0],[],[passed=no],[Cheetah.Version >= "2.0.0"]) - PYTHON_CHECK_MODULE([lxml.etree],[Python lxml wrappers >= 2.0.0],[],[passed=no],[lxml.etree.LXML_VERSION >= (2, 0, 0, 0)]) + PYTHON_CHECK_MODULE([lxml.etree],[Python lxml wrappers >= 1.3.6],[],[passed=no],[lxml.etree.LXML_VERSION >= (1, 3, 6, 0)]) PYTHON_CHECK_MODULE([gtk],[Python gtk wrappers >= 2.10.0],[],[passed=no],[gtk.pygtk_version >= (2, 10, 0)]) fi diff --git a/configure.ac b/configure.ac index 2bb37935e..b6b596bef 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,7 @@ AC_CANONICAL_HOST AC_CANONICAL_TARGET -VERSION=3.3svn +VERSION=3.3git AC_SUBST(VERSION) AM_INIT_AUTOMAKE(gnuradio,$VERSION) @@ -352,6 +352,7 @@ GRC_GR_COMEDI GRC_GR_CVSD_VOCODER GRC_GR_GPIO GRC_GR_GSM_FR_VOCODER +GRC_GR_NOAA GRC_GR_PAGER GRC_GR_RADAR_MONO GRC_GR_RADIO_ASTRONOMY diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc index bfc4c0467..8971d3d39 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc @@ -28,6 +28,7 @@ #include <gr_fir_ccf.h> #include <gr_fir_util.h> #include <gr_io_signature.h> +#include <cstdio> gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate, const std::vector<float> &taps, diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h index b79a89fe9..d4c886ec3 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h @@ -91,8 +91,8 @@ class gr_fir_ccf; * The theory behind this block can be found in Chapter 7.5 of * the following book. * - * <B><EM>f. harris, Multirate Signal Processing for Communication - * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> + * <B><EM>f. harris, "Multirate Signal Processing for Communication + * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> */ class gr_pfb_arb_resampler_ccf : public gr_block diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc index 7be611e23..a7e8de62a 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc @@ -29,6 +29,7 @@ #include <gr_fir_util.h> #include <gri_fft.h> #include <gr_io_signature.h> +#include <cstdio> gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, const std::vector<float> &taps) diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h index 7d0a31c59..b2e67e817 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h @@ -91,8 +91,8 @@ class gri_fft_complex; * The theory behind this block can be found in Chapter 6 of * the following book. * - * <B><EM>f. harris, Multirate Signal Processing for Communication - * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004. + * <B><EM>f. harris, "Multirate Signal Processing for Communication + * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> * */ diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc index b334f5878..e05e18ff2 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc @@ -30,6 +30,7 @@ #include <gri_fft.h> #include <gr_io_signature.h> #include <gr_expj.h> +#include <cstdio> gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim, const std::vector<float> &taps, diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h index 83997c0c9..200adee3d 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h @@ -88,7 +88,7 @@ class gri_fft_complex; * The theory behind this block can be found in Chapter 6 of * the following book. * - * <B><EM>f. harris, Multirate Signal Processing for Communication + * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B> */ diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc index d5eba885c..6a9598f34 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc @@ -28,6 +28,7 @@ #include <gr_fir_ccf.h> #include <gr_fir_util.h> #include <gr_io_signature.h> +#include <cstdio> gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp, const std::vector<float> &taps) diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h index 50849d510..d2efc591a 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h @@ -74,7 +74,7 @@ class gr_fir_ccf; * The theory behind this block can be found in Chapter 7.1 of the * following book. * - * <B><EM>f. harris, <EM>Multirate Signal Processing for Communication + * <B><EM>f. harris, "Multirate Signal Processing for Communication * Systems</EM>," Upper Saddle River, NJ: Prentice Hall, * Inc. 2004.</EM></B> */ diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am index ed36bbae7..dcc0017b3 100644 --- a/gnuradio-core/src/python/gnuradio/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/Makefile.am @@ -34,5 +34,6 @@ grpython_PYTHON = \ packet_utils.py \ gr_unittest.py \ optfir.py \ + usrp_options.py \ window.py endif diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am index 17be09cc7..f0825b151 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am @@ -36,6 +36,7 @@ grblkspython_PYTHON = \ filterbank.py \ fm_demod.py \ fm_emph.py \ + generic_usrp.py \ gmsk.py \ cpm.py \ logpwrfft.py \ diff --git a/gnuradio-examples/python/digital/generic_usrp.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py index c7ccbe53c..5abbaf9eb 100644 --- a/gnuradio-examples/python/digital/generic_usrp.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py @@ -33,7 +33,7 @@ class _dummy_freq_result(object): self.baseband_freq = target_freq self.dxc_freq = 0 self.residual_freq = 0 -from gnuradio import gr, usrp, usrp2 +from gnuradio import gr ######################################################################## # generic usrp common stuff @@ -167,6 +167,7 @@ class generic_usrp_source_c(_generic_usrp_base, gr.hier_block2): # setup usrp methods #################################################################### def _setup_usrp1(self): + from gnuradio import usrp self._u = usrp.source_c (self._which, fusb_block_size=self._fusb_block_size, fusb_nblocks=self._fusb_nblocks) @@ -178,6 +179,7 @@ class generic_usrp_source_c(_generic_usrp_base, gr.hier_block2): self._dxc = 0 def _setup_usrp2(self): + from gnuradio import usrp2 self._u = usrp2.source_32fc(self._interface, self._mac_addr) def _setup_dummy(self): self._u = gr.null_source(gr.sizeof_gr_complex) @@ -224,6 +226,7 @@ class generic_usrp_sink_c(_generic_usrp_base, gr.hier_block2): # setup usrp methods #################################################################### def _setup_usrp1(self): + from gnuradio import usrp self._u = usrp.sink_c (self._which, fusb_block_size=self._fusb_block_size, fusb_nblocks=self._fusb_nblocks) @@ -234,6 +237,8 @@ class generic_usrp_sink_c(_generic_usrp_base, gr.hier_block2): self._u.set_mux(usrp.determine_tx_mux_value(self._u, self._subdev_spec)) self._dxc = self._subdev.which() - def _setup_usrp2(self): self._u = usrp2.sink_32fc(self._interface, self._mac_addr) + def _setup_usrp2(self): + from gnuradio import usrp2 + self._u = usrp2.sink_32fc(self._interface, self._mac_addr) def _setup_dummy(self): self._u = gr.null_sink(gr.sizeof_gr_complex) diff --git a/gnuradio-core/src/python/gnuradio/eng_option.py b/gnuradio-core/src/python/gnuradio/eng_option.py index 09c3e1d87..e10235f14 100644 --- a/gnuradio-core/src/python/gnuradio/eng_option.py +++ b/gnuradio-core/src/python/gnuradio/eng_option.py @@ -23,29 +23,11 @@ from copy import copy from optparse import Option, OptionValueError - -scale_factor = {} -scale_factor['E'] = 1e18 -scale_factor['P'] = 1e15 -scale_factor['T'] = 1e12 -scale_factor['G'] = 1e9 -scale_factor['M'] = 1e6 -scale_factor['k'] = 1e3 -scale_factor['m'] = 1e-3 -scale_factor['u'] = 1e-6 -scale_factor['n'] = 1e-9 -scale_factor['p'] = 1e-12 -scale_factor['f'] = 1e-15 -scale_factor['a'] = 1e-18 - +import eng_notation def check_eng_float (option, opt, value): try: - scale = 1.0 - suffix = value[-1] - if scale_factor.has_key (suffix): - return float (value[0:-1]) * scale_factor[suffix] - return float (value) + return eng_notation.str_to_num(value) except: raise OptionValueError ( "option %s: invalid engineering notation value: %r" % (opt, value)) diff --git a/gnuradio-examples/python/digital/usrp_options.py b/gnuradio-core/src/python/gnuradio/usrp_options.py index 380ef60f4..86dba2f9a 100644 --- a/gnuradio-examples/python/digital/usrp_options.py +++ b/gnuradio-core/src/python/gnuradio/usrp_options.py @@ -27,7 +27,7 @@ class _parser_groups(object): self.usrp1exp_grp = parser.add_option_group("USRP1 Expert Options") self.usrp2_grp = parser.add_option_group("USRP2 Specific Options") -import generic_usrp +from gnuradio import blks2 def _add_options(parser): """ @@ -76,7 +76,7 @@ def add_rx_options(parser): help="set fpga decimation rate to DECIM [default=%default]") def create_usrp_source(options): - u = generic_usrp.generic_usrp_source_c( + u = blks2.generic_usrp_source_c( usrpx=options.usrpx, which=options.which, subdev_spec=options.rx_subdev_spec, @@ -107,7 +107,7 @@ def add_tx_options(parser): help="set fpga interpolation rate to INTERP [default=%default]") def create_usrp_sink(options): - u = generic_usrp.generic_usrp_sink_c( + u = blks2.generic_usrp_sink_c( usrpx=options.usrpx, which=options.which, subdev_spec=options.tx_subdev_spec, diff --git a/gnuradio-examples/python/digital/Makefile.am b/gnuradio-examples/python/digital/Makefile.am index 64ce4ec46..e32180cd4 100644 --- a/gnuradio-examples/python/digital/Makefile.am +++ b/gnuradio-examples/python/digital/Makefile.am @@ -25,7 +25,6 @@ ourdatadir = $(exampledir)/digital dist_ourdata_DATA = \ README \ - generic_usrp.py \ pick_bitrate.py \ qt_digital_window.ui \ qt_digital_window.py \ @@ -33,7 +32,6 @@ dist_ourdata_DATA = \ qt_rx_window.py \ receive_path.py \ transmit_path.py \ - usrp_options.py \ usrp_receive_path.py \ usrp_transmit_path.py diff --git a/gnuradio-examples/python/digital/benchmark_qt_rx.py b/gnuradio-examples/python/digital/benchmark_qt_rx.py index 33cf94a5c..0cbb68d23 100755 --- a/gnuradio-examples/python/digital/benchmark_qt_rx.py +++ b/gnuradio-examples/python/digital/benchmark_qt_rx.py @@ -25,6 +25,7 @@ from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser +from gnuradio import usrp_options import random import struct @@ -33,7 +34,6 @@ import sys # from current dir from receive_path import receive_path from pick_bitrate import pick_rx_bitrate -import usrp_options try: from gnuradio.qtgui import qtgui diff --git a/gnuradio-examples/python/digital/usrp_receive_path.py b/gnuradio-examples/python/digital/usrp_receive_path.py index fd47c2725..e28eb0a8c 100644 --- a/gnuradio-examples/python/digital/usrp_receive_path.py +++ b/gnuradio-examples/python/digital/usrp_receive_path.py @@ -20,7 +20,7 @@ # from gnuradio import gr -import usrp_options +from gnuradio import usrp_options import receive_path from pick_bitrate import pick_rx_bitrate from gnuradio import eng_notation diff --git a/gnuradio-examples/python/digital/usrp_transmit_path.py b/gnuradio-examples/python/digital/usrp_transmit_path.py index ed2603fa3..ad9f741a6 100644 --- a/gnuradio-examples/python/digital/usrp_transmit_path.py +++ b/gnuradio-examples/python/digital/usrp_transmit_path.py @@ -20,7 +20,7 @@ # from gnuradio import gr -import usrp_options +from gnuradio import usrp_options import transmit_path from pick_bitrate import pick_tx_bitrate from gnuradio import eng_notation diff --git a/gr-noaa/.gitignore b/gr-noaa/.gitignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/gr-noaa/.gitignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/gr-noaa/Makefile.am b/gr-noaa/Makefile.am new file mode 100644 index 000000000..f3f4f6a38 --- /dev/null +++ b/gr-noaa/Makefile.am @@ -0,0 +1,29 @@ +# +# Copyright 2009 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 $(top_srcdir)/Makefile.common + +SUBDIRS = lib grc + +if PYTHON +SUBDIRS += swig python apps +endif + diff --git a/gr-noaa/README b/gr-noaa/README new file mode 100644 index 000000000..d99c0d90a --- /dev/null +++ b/gr-noaa/README @@ -0,0 +1,53 @@ +This component implements an NOAA POES HRPT receiver. After installation, +the scripts described below will be install in the users PATH. + +As the scripts are generated using GRC, GRC must be installed at runtime +in order for them to operate. + + +HRPT Operation +-------------- + +usrp_rx_hrpt.py + +This GUI script will receive HRPT RF, demodulate, synchronize, and deframe +HRPT minor frames into a file. The file stores a series of 11090 word, +16-bits per word corresponding to the HRPT minor frame format (only the +lower 10-bits per word are significant.) + +The script file by default uses USRP side A, 1698 MHz, at decimation 16. A +configuration file 'usrp_rx_hrpt.cfg' in the current working directory will +allow changing this, as well as implementing persistent storage of GUI +entered parameters from invocation to invocation. + +The present HRPT demodulator is only tested at decimation 16. The only other +valid decimation rates are 24 and 32, which may word but with more bit +errors. No other decimation rates will work. + + +demod_hrpt_file.py + +This command-line only script will operate on a file generated with +usrp_rx_cfile.py and output frames in the same format as above. It does +*not* use the configuration file above. + +Usage: demod_hrpt_file.py: [options] + +Options: + -h, --help show this help message and exit + -d DECIM, --decim=DECIM + Set Decimation [default=16] + -p PLL_ALPHA, --pll-alpha=PLL_ALPHA + Set pll_alpha [default=50m] + -s SYNC_ALPHA, --sync-alpha=SYNC_ALPHA + Set sync_alpha [default=50m] + -F FILENAME, --filename=FILENAME + Set Filename [default=usrp.dat] + -o OUTPUT, --output=OUTPUT + Set Output [default=frames.dat] + + +LRIT Operation +-------------- + +The work-in-progress LRIT GRC script is not currently in a usable state. diff --git a/gr-noaa/apps/.gitignore b/gr-noaa/apps/.gitignore new file mode 100644 index 000000000..773a6df9b --- /dev/null +++ b/gr-noaa/apps/.gitignore @@ -0,0 +1 @@ +*.dat diff --git a/gr-noaa/apps/Makefile.am b/gr-noaa/apps/Makefile.am new file mode 100644 index 000000000..906638ff1 --- /dev/null +++ b/gr-noaa/apps/Makefile.am @@ -0,0 +1,35 @@ +# +# Copyright 2009 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 $(top_srcdir)/Makefile.common + +if PYTHON + +dist_bin_SCRIPTS = \ + demod_hrpt_file.py \ + usrp_rx_hrpt.py \ + usrp_rx_lrit.py + +EXTRA_DIST = \ + demod_hrpt_file.grc \ + usrp_rx_hrpt.grc \ + usrp_rx_lrit.grc +endif diff --git a/gr-noaa/apps/demod_hrpt_file.grc b/gr-noaa/apps/demod_hrpt_file.grc new file mode 100644 index 000000000..4a5e87170 --- /dev/null +++ b/gr-noaa/apps/demod_hrpt_file.grc @@ -0,0 +1,781 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Wed Sep 23 11:37:25 2009</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>demod_hrpt_file</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>USRP HRPT Receiver</value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>4096,4096</value> + </param> + <param> + <key>generate_options</key> + <value>no_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>max_sync_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.01</value> + </param> + <param> + <key>_coordinate</key> + <value>(705, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>max_carrier_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>2*math.pi*100e3/sample_rate</value> + </param> + <param> + <key>_coordinate</key> + <value>(575, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>hs</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>int(sps/2.0)</value> + </param> + <param> + <key>_coordinate</key> + <value>(499, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>sample_rate/sym_rate</value> + </param> + <param> + <key>_coordinate</key> + <value>(397, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sym_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>600*1109</value> + </param> + <param> + <key>_coordinate</key> + <value>(301, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sample_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>64e6/decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(198, 17)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>decim</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Decimation</value> + </param> + <param> + <key>value</key> + <value>16</value> + </param> + <param> + <key>type</key> + <value>intx</value> + </param> + <param> + <key>short_id</key> + <value>d</value> + </param> + <param> + <key>_coordinate</key> + <value>(404, 102)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>pll_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0.05</value> + </param> + <param> + <key>type</key> + <value>eng_float</value> + </param> + <param> + <key>short_id</key> + <value>p</value> + </param> + <param> + <key>_coordinate</key> + <value>(516, 102)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>sync_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0.05</value> + </param> + <param> + <key>type</key> + <value>eng_float</value> + </param> + <param> + <key>short_id</key> + <value>s</value> + </param> + <param> + <key>_coordinate</key> + <value>(601, 103)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import math</value> + </param> + <param> + <key>_coordinate</key> + <value>(9, 92)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>filename</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Filename</value> + </param> + <param> + <key>value</key> + <value>usrp.dat</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>short_id</key> + <value>F</value> + </param> + <param> + <key>_coordinate</key> + <value>(200, 101)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_file_source</key> + <param> + <key>id</key> + <value>file_source</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>filename</value> + </param> + <param> + <key>type</key> + <value>short</value> + </param> + <param> + <key>repeat</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(102, 368)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_short_to_float</key> + <param> + <key>id</key> + <value>s2f</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(305, 380)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_deinterleave</key> + <param> + <key>id</key> + <value>deinterleave</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>num_streams</key> + <value>2</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(526, 363)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_float_to_complex</key> + <param> + <key>id</key> + <value>f2c</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(730, 363)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>virtual_sink</key> + <param> + <key>id</key> + <value>samples_sink</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>stream_id</key> + <value>samples</value> + </param> + <param> + <key>_coordinate</key> + <value>(968, 376)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>virtual_source</key> + <param> + <key>id</key> + <value>samples_source</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>stream_id</key> + <value>samples</value> + </param> + <param> + <key>_coordinate</key> + <value>(104, 479)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_moving_average_xx</key> + <param> + <key>id</key> + <value>matched_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>length</key> + <value>hs</value> + </param> + <param> + <key>scale</key> + <value>1.0/hs</value> + </param> + <param> + <key>max_iter</key> + <value>4000</value> + </param> + <param> + <key>_coordinate</key> + <value>(302, 463)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_pll_cf</key> + <param> + <key>id</key> + <value>pll</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alpha</key> + <value>pll_alpha</value> + </param> + <param> + <key>beta</key> + <value>pll_alpha**2/4.0</value> + </param> + <param> + <key>max_offset</key> + <value>max_carrier_offset</value> + </param> + <param> + <key>_coordinate</key> + <value>(504, 463)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_sync_fb</key> + <param> + <key>id</key> + <value>sync</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alpha</key> + <value>sync_alpha</value> + </param> + <param> + <key>beta</key> + <value>sync_alpha**2/4.0</value> + </param> + <param> + <key>sps</key> + <value>sps</value> + </param> + <param> + <key>max_offset</key> + <value>max_sync_offset</value> + </param> + <param> + <key>_coordinate</key> + <value>(711, 455)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_deframer</key> + <param> + <key>id</key> + <value>deframer</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(935, 483)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_file_sink</key> + <param> + <key>id</key> + <value>file_sink</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>output</value> + </param> + <param> + <key>type</key> + <value>short</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1136, 479)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_decoder</key> + <param> + <key>id</key> + <value>decoder</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1135, 542)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>output</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Output</value> + </param> + <param> + <key>value</key> + <value>frames.dat</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>short_id</key> + <value>o</value> + </param> + <param> + <key>_coordinate</key> + <value>(302, 101)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>deframer</source_block_id> + <sink_block_id>file_sink</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>sync</source_block_id> + <sink_block_id>deframer</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>pll</source_block_id> + <sink_block_id>sync</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>matched_filter</source_block_id> + <sink_block_id>pll</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>s2f</source_block_id> + <sink_block_id>deinterleave</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>deinterleave</source_block_id> + <sink_block_id>f2c</sink_block_id> + <source_key>1</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>deinterleave</source_block_id> + <sink_block_id>f2c</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>file_source</source_block_id> + <sink_block_id>s2f</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>deframer</source_block_id> + <sink_block_id>decoder</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>f2c</source_block_id> + <sink_block_id>samples_sink</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>samples_source</source_block_id> + <sink_block_id>matched_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-noaa/apps/demod_hrpt_file.py b/gr-noaa/apps/demod_hrpt_file.py new file mode 100755 index 000000000..a1469e9e0 --- /dev/null +++ b/gr-noaa/apps/demod_hrpt_file.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +################################################## +# Gnuradio Python Flow Graph +# Title: USRP HRPT Receiver +# Generated: Wed Sep 23 11:37:25 2009 +################################################## + +from gnuradio import eng_notation +from gnuradio import gr +from gnuradio import noaa +from gnuradio.eng_option import eng_option +from gnuradio.gr import firdes +from optparse import OptionParser +import math + +class demod_hrpt_file(gr.top_block): + + def __init__(self, decim=16, pll_alpha=0.05, sync_alpha=0.05, filename="usrp.dat", output="frames.dat"): + gr.top_block.__init__(self, "USRP HRPT Receiver") + + ################################################## + # Parameters + ################################################## + self.decim = decim + self.pll_alpha = pll_alpha + self.sync_alpha = sync_alpha + self.filename = filename + self.output = output + + ################################################## + # Variables + ################################################## + self.sym_rate = sym_rate = 600*1109 + self.sample_rate = sample_rate = 64e6/decim + self.sps = sps = sample_rate/sym_rate + self.max_sync_offset = max_sync_offset = 0.01 + self.max_carrier_offset = max_carrier_offset = 2*math.pi*100e3/sample_rate + self.hs = hs = int(sps/2.0) + + ################################################## + # Blocks + ################################################## + self.decoder = noaa.hrpt_decoder() + self.deframer = noaa.hrpt_deframer() + self.deinterleave = gr.deinterleave(gr.sizeof_float*1) + self.f2c = gr.float_to_complex(1) + self.file_sink = gr.file_sink(gr.sizeof_short*1, output) + self.file_source = gr.file_source(gr.sizeof_short*1, filename, False) + self.matched_filter = gr.moving_average_cc(hs, 1.0/hs, 4000) + self.pll = noaa.hrpt_pll_cf(pll_alpha, pll_alpha**2/4.0, max_carrier_offset) + self.s2f = gr.short_to_float() + self.sync = noaa.hrpt_sync_fb(sync_alpha, sync_alpha**2/4.0, sps, max_sync_offset) + + ################################################## + # Connections + ################################################## + self.connect((self.deframer, 0), (self.file_sink, 0)) + self.connect((self.sync, 0), (self.deframer, 0)) + self.connect((self.pll, 0), (self.sync, 0)) + self.connect((self.matched_filter, 0), (self.pll, 0)) + self.connect((self.s2f, 0), (self.deinterleave, 0)) + self.connect((self.deinterleave, 1), (self.f2c, 1)) + self.connect((self.deinterleave, 0), (self.f2c, 0)) + self.connect((self.file_source, 0), (self.s2f, 0)) + self.connect((self.deframer, 0), (self.decoder, 0)) + self.connect((self.f2c, 0), (self.matched_filter, 0)) + + def set_decim(self, decim): + self.decim = decim + self.set_sample_rate(64e6/self.decim) + + def set_pll_alpha(self, pll_alpha): + self.pll_alpha = pll_alpha + self.pll.set_alpha(self.pll_alpha) + self.pll.set_beta(self.pll_alpha**2/4.0) + + def set_sync_alpha(self, sync_alpha): + self.sync_alpha = sync_alpha + self.sync.set_alpha(self.sync_alpha) + self.sync.set_beta(self.sync_alpha**2/4.0) + + def set_filename(self, filename): + self.filename = filename + + def set_output(self, output): + self.output = output + + def set_sym_rate(self, sym_rate): + self.sym_rate = sym_rate + self.set_sps(self.sample_rate/self.sym_rate) + + def set_sample_rate(self, sample_rate): + self.sample_rate = sample_rate + self.set_max_carrier_offset(2*math.pi*100e3/self.sample_rate) + self.set_sps(self.sample_rate/self.sym_rate) + + def set_sps(self, sps): + self.sps = sps + self.set_hs(int(self.sps/2.0)) + + def set_max_sync_offset(self, max_sync_offset): + self.max_sync_offset = max_sync_offset + self.sync.set_max_offset(self.max_sync_offset) + + def set_max_carrier_offset(self, max_carrier_offset): + self.max_carrier_offset = max_carrier_offset + self.pll.set_max_offset(self.max_carrier_offset) + + def set_hs(self, hs): + self.hs = hs + self.matched_filter.set_length_and_scale(self.hs, 1.0/self.hs) + +if __name__ == '__main__': + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + parser.add_option("-d", "--decim", dest="decim", type="intx", default=16, + help="Set Decimation [default=%default]") + parser.add_option("-p", "--pll-alpha", dest="pll_alpha", type="eng_float", default=eng_notation.num_to_str(0.05), + help="Set pll_alpha [default=%default]") + parser.add_option("-s", "--sync-alpha", dest="sync_alpha", type="eng_float", default=eng_notation.num_to_str(0.05), + help="Set sync_alpha [default=%default]") + parser.add_option("-F", "--filename", dest="filename", type="string", default="usrp.dat", + help="Set Filename [default=%default]") + parser.add_option("-o", "--output", dest="output", type="string", default="frames.dat", + help="Set Output [default=%default]") + (options, args) = parser.parse_args() + tb = demod_hrpt_file(decim=options.decim, pll_alpha=options.pll_alpha, sync_alpha=options.sync_alpha, filename=options.filename, output=options.output) + tb.start() + raw_input('Press Enter to quit: ') + tb.stop() + diff --git a/gr-noaa/apps/usrp_rx_hrpt.cfg b/gr-noaa/apps/usrp_rx_hrpt.cfg new file mode 100644 index 000000000..69f3c0bf0 --- /dev/null +++ b/gr-noaa/apps/usrp_rx_hrpt.cfg @@ -0,0 +1,13 @@ +[output] +filename = frames.dat + +[demod] +pll_alpha = 0.05 +sync_alpha = 0.05 + +[usrp] +freq = 1698000000.0 +decim = 16 +side = A +gain = 35.0 + diff --git a/gr-noaa/apps/usrp_rx_hrpt.grc b/gr-noaa/apps/usrp_rx_hrpt.grc new file mode 100644 index 000000000..90d868769 --- /dev/null +++ b/gr-noaa/apps/usrp_rx_hrpt.grc @@ -0,0 +1,1394 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Wed Sep 23 11:32:00 2009</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>usrp_rx_hrpt</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>USRP HRPT Receiver</value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>4096,4096</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>max_carrier_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>2*math.pi*100e3/sample_rate</value> + </param> + <param> + <key>_coordinate</key> + <value>(575, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_moving_average_xx</key> + <param> + <key>id</key> + <value>matched_filter</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>length</key> + <value>hs</value> + </param> + <param> + <key>scale</key> + <value>1.0/hs</value> + </param> + <param> + <key>max_iter</key> + <value>4000</value> + </param> + <param> + <key>_coordinate</key> + <value>(441, 723)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import math</value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 76)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>config_filename</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>'usrp_rx_hrpt.cfg'</value> + </param> + <param> + <key>_coordinate</key> + <value>(12, 129)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sym_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>600*1109</value> + </param> + <param> + <key>_coordinate</key> + <value>(301, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>sample_rate/sym_rate</value> + </param> + <param> + <key>_coordinate</key> + <value>(397, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>hs</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>int(sps/2.0)</value> + </param> + <param> + <key>_coordinate</key> + <value>(499, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sample_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>64e6/decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(198, 17)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>gain</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>RX Gain</value> + </param> + <param> + <key>value</key> + <value>saved_gain</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>100</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 1, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(340, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_text_box</key> + <param> + <key>id</key> + <value>freq</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Frequency</value> + </param> + <param> + <key>value</key> + <value>saved_freq</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(199, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>pll_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>PLL Alpha</value> + </param> + <param> + <key>value</key> + <value>saved_pll_alpha</value> + </param> + <param> + <key>min</key> + <value>0.0</value> + </param> + <param> + <key>max</key> + <value>0.5</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 2, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(479, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>sync_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>SYNC Alpha</value> + </param> + <param> + <key>value</key> + <value>saved_sync_alpha</value> + </param> + <param> + <key>min</key> + <value>0.0</value> + </param> + <param> + <key>max</key> + <value>0.5</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 3, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(618, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_static_text</key> + <param> + <key>id</key> + <value>side_text</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>USRP Side</value> + </param> + <param> + <key>value</key> + <value>side</value> + </param> + <param> + <key>converver</key> + <value>str_converter</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(828, 20)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>side</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>'A'</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'usrp'</value> + </param> + <param> + <key>option</key> + <value>'side'</value> + </param> + <param> + <key>writeback</key> + <value>side</value> + </param> + <param> + <key>_coordinate</key> + <value>(194, 253)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>decim</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>16</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'usrp'</value> + </param> + <param> + <key>option</key> + <value>'decim'</value> + </param> + <param> + <key>writeback</key> + <value>decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(351, 255)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_freq</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>1698e6</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'usrp'</value> + </param> + <param> + <key>option</key> + <value>'freq'</value> + </param> + <param> + <key>writeback</key> + <value>freq</value> + </param> + <param> + <key>_coordinate</key> + <value>(507, 258)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_gain</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>35</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'usrp'</value> + </param> + <param> + <key>option</key> + <value>'gain'</value> + </param> + <param> + <key>writeback</key> + <value>gain</value> + </param> + <param> + <key>_coordinate</key> + <value>(664, 259)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_pll_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.05</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'demod'</value> + </param> + <param> + <key>option</key> + <value>'pll_alpha'</value> + </param> + <param> + <key>writeback</key> + <value>pll_alpha</value> + </param> + <param> + <key>_coordinate</key> + <value>(823, 258)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_sync_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.05</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'demod'</value> + </param> + <param> + <key>option</key> + <value>'sync_alpha'</value> + </param> + <param> + <key>writeback</key> + <value>sync_alpha</value> + </param> + <param> + <key>_coordinate</key> + <value>(981, 258)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>output_filename</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>'frames.dat'</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>'output'</value> + </param> + <param> + <key>option</key> + <value>'filename'</value> + </param> + <param> + <key>writeback</key> + <value>output_filename</value> + </param> + <param> + <key>_coordinate</key> + <value>(1139, 259)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_static_text</key> + <param> + <key>id</key> + <value>decim_text</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Decimation</value> + </param> + <param> + <key>value</key> + <value>decim</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 1, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(973, 20)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>max_sync_offset</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.01</value> + </param> + <param> + <key>_coordinate</key> + <value>(705, 19)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>usrp_simple_source_x</key> + <param> + <key>id</key> + <value>usrp_source</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>format</key> + <value></value> + </param> + <param> + <key>which</key> + <value>0</value> + </param> + <param> + <key>decimation</key> + <value>decim</value> + </param> + <param> + <key>frequency</key> + <value>freq</value> + </param> + <param> + <key>lo_offset</key> + <value>float('inf')</value> + </param> + <param> + <key>gain</key> + <value>gain</value> + </param> + <param> + <key>side</key> + <value>side</value> + </param> + <param> + <key>rx_ant</key> + <value>RXA</value> + </param> + <param> + <key>hb_filters</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(56, 699)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_agc_xx</key> + <param> + <key>id</key> + <value>agc</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>rate</key> + <value>1e-6</value> + </param> + <param> + <key>reference</key> + <value>1.0</value> + </param> + <param> + <key>gain</key> + <value>1.0</value> + </param> + <param> + <key>max_gain</key> + <value>1.0</value> + </param> + <param> + <key>_coordinate</key> + <value>(273, 715)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>rx_scope</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>RX Waveform</value> + </param> + <param> + <key>samp_rate</key> + <value>sample_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0</value> + </param> + <param> + <key>t_scale</key> + <value>20.0/sample_rate</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>False</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(439, 829)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>rx_fft</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>RX Spectrum</value> + </param> + <param> + <key>samp_rate</key> + <value>sample_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>freq</value> + </param> + <param> + <key>y_per_div</key> + <value>5</value> + </param> + <param> + <key>y_divs</key> + <value>8</value> + </param> + <param> + <key>ref_level</key> + <value>-5</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>True</value> + </param> + <param> + <key>avg_alpha</key> + <value>0.1</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(439, 465)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>pll_scope</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Post-PLL</value> + </param> + <param> + <key>samp_rate</key> + <value>sample_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0.5</value> + </param> + <param> + <key>t_scale</key> + <value>20.0/sample_rate</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>False</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(605, 552)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>notebook</key> + <param> + <key>id</key> + <value>displays</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>style</key> + <value>wx.NB_TOP</value> + </param> + <param> + <key>labels</key> + <value>['RX','Demod']</value> + </param> + <param> + <key>grid_pos</key> + <value>2, 0, 1, 4</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(15, 237)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_pll_cf</key> + <param> + <key>id</key> + <value>pll</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alpha</key> + <value>pll_alpha</value> + </param> + <param> + <key>beta</key> + <value>pll_alpha**2/4.0</value> + </param> + <param> + <key>max_offset</key> + <value>max_carrier_offset</value> + </param> + <param> + <key>_coordinate</key> + <value>(632, 723)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_sync_fb</key> + <param> + <key>id</key> + <value>sync</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>alpha</key> + <value>sync_alpha</value> + </param> + <param> + <key>beta</key> + <value>sync_alpha**2/4.0</value> + </param> + <param> + <key>sps</key> + <value>sps</value> + </param> + <param> + <key>max_offset</key> + <value>max_sync_offset</value> + </param> + <param> + <key>_coordinate</key> + <value>(840, 715)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_deframer</key> + <param> + <key>id</key> + <value>deframer</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1071, 743)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>noaa_hrpt_decoder</key> + <param> + <key>id</key> + <value>decoder</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1274, 743)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_file_sink</key> + <param> + <key>id</key> + <value>frame_sink</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>output_filename</value> + </param> + <param> + <key>type</key> + <value>short</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1273, 851)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>deframer</source_block_id> + <sink_block_id>frame_sink</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>sync</source_block_id> + <sink_block_id>deframer</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>pll</source_block_id> + <sink_block_id>sync</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>pll</source_block_id> + <sink_block_id>pll_scope</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>agc</source_block_id> + <sink_block_id>rx_scope</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>agc</source_block_id> + <sink_block_id>rx_fft</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>agc</source_block_id> + <sink_block_id>matched_filter</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>matched_filter</source_block_id> + <sink_block_id>pll</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>deframer</source_block_id> + <sink_block_id>decoder</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>usrp_source</source_block_id> + <sink_block_id>agc</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-noaa/apps/usrp_rx_hrpt.py b/gr-noaa/apps/usrp_rx_hrpt.py new file mode 100755 index 000000000..7efbecd3a --- /dev/null +++ b/gr-noaa/apps/usrp_rx_hrpt.py @@ -0,0 +1,435 @@ +#!/usr/bin/env python +################################################## +# Gnuradio Python Flow Graph +# Title: USRP HRPT Receiver +# Generated: Wed Sep 23 11:32:04 2009 +################################################## + +from gnuradio import eng_notation +from gnuradio import gr +from gnuradio import noaa +from gnuradio.eng_option import eng_option +from gnuradio.gr import firdes +from gnuradio.wxgui import fftsink2 +from gnuradio.wxgui import forms +from gnuradio.wxgui import scopesink2 +from grc_gnuradio import usrp as grc_usrp +from grc_gnuradio import wxgui as grc_wxgui +from optparse import OptionParser +import ConfigParser +import math +import wx + +class usrp_rx_hrpt(grc_wxgui.top_block_gui): + + def __init__(self): + grc_wxgui.top_block_gui.__init__(self, title="USRP HRPT Receiver") + + ################################################## + # Variables + ################################################## + self.config_filename = config_filename = 'usrp_rx_hrpt.cfg' + self._decim_config = ConfigParser.ConfigParser() + self._decim_config.read(config_filename) + try: decim = self._decim_config.getfloat('usrp', 'decim') + except: decim = 16 + self.decim = decim + self.sym_rate = sym_rate = 600*1109 + self.sample_rate = sample_rate = 64e6/decim + self.sps = sps = sample_rate/sym_rate + self._side_config = ConfigParser.ConfigParser() + self._side_config.read(config_filename) + try: side = self._side_config.get('usrp', 'side') + except: side = 'A' + self.side = side + self._saved_sync_alpha_config = ConfigParser.ConfigParser() + self._saved_sync_alpha_config.read(config_filename) + try: saved_sync_alpha = self._saved_sync_alpha_config.getfloat('demod', 'sync_alpha') + except: saved_sync_alpha = 0.05 + self.saved_sync_alpha = saved_sync_alpha + self._saved_pll_alpha_config = ConfigParser.ConfigParser() + self._saved_pll_alpha_config.read(config_filename) + try: saved_pll_alpha = self._saved_pll_alpha_config.getfloat('demod', 'pll_alpha') + except: saved_pll_alpha = 0.05 + self.saved_pll_alpha = saved_pll_alpha + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(config_filename) + try: saved_gain = self._saved_gain_config.getfloat('usrp', 'gain') + except: saved_gain = 35 + self.saved_gain = saved_gain + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(config_filename) + try: saved_freq = self._saved_freq_config.getfloat('usrp', 'freq') + except: saved_freq = 1698e6 + self.saved_freq = saved_freq + self.sync_alpha = sync_alpha = saved_sync_alpha + self.side_text = side_text = side + self.pll_alpha = pll_alpha = saved_pll_alpha + self._output_filename_config = ConfigParser.ConfigParser() + self._output_filename_config.read(config_filename) + try: output_filename = self._output_filename_config.get('output', 'filename') + except: output_filename = 'frames.dat' + self.output_filename = output_filename + self.max_sync_offset = max_sync_offset = 0.01 + self.max_carrier_offset = max_carrier_offset = 2*math.pi*100e3/sample_rate + self.hs = hs = int(sps/2.0) + self.gain = gain = saved_gain + self.freq = freq = saved_freq + self.decim_text = decim_text = decim + + ################################################## + # Notebooks + ################################################## + self.displays = wx.Notebook(self.GetWin(), style=wx.NB_TOP) + self.displays.AddPage(grc_wxgui.Panel(self.displays), "RX") + self.displays.AddPage(grc_wxgui.Panel(self.displays), "Demod") + self.GridAdd(self.displays, 2, 0, 1, 4) + + ################################################## + # Controls + ################################################## + _sync_alpha_sizer = wx.BoxSizer(wx.VERTICAL) + self._sync_alpha_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_sync_alpha_sizer, + value=self.sync_alpha, + callback=self.set_sync_alpha, + label="SYNC Alpha", + converter=forms.float_converter(), + proportion=0, + ) + self._sync_alpha_slider = forms.slider( + parent=self.GetWin(), + sizer=_sync_alpha_sizer, + value=self.sync_alpha, + callback=self.set_sync_alpha, + minimum=0.0, + maximum=0.5, + num_steps=100, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_sync_alpha_sizer, 0, 3, 1, 1) + self._side_text_static_text = forms.static_text( + parent=self.GetWin(), + value=self.side_text, + callback=self.set_side_text, + label="USRP Side", + converter=forms.str_converter(), + ) + self.GridAdd(self._side_text_static_text, 1, 0, 1, 1) + _pll_alpha_sizer = wx.BoxSizer(wx.VERTICAL) + self._pll_alpha_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_pll_alpha_sizer, + value=self.pll_alpha, + callback=self.set_pll_alpha, + label="PLL Alpha", + converter=forms.float_converter(), + proportion=0, + ) + self._pll_alpha_slider = forms.slider( + parent=self.GetWin(), + sizer=_pll_alpha_sizer, + value=self.pll_alpha, + callback=self.set_pll_alpha, + minimum=0.0, + maximum=0.5, + num_steps=100, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_pll_alpha_sizer, 0, 2, 1, 1) + _gain_sizer = wx.BoxSizer(wx.VERTICAL) + self._gain_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_gain_sizer, + value=self.gain, + callback=self.set_gain, + label="RX Gain", + converter=forms.float_converter(), + proportion=0, + ) + self._gain_slider = forms.slider( + parent=self.GetWin(), + sizer=_gain_sizer, + value=self.gain, + callback=self.set_gain, + minimum=0, + maximum=100, + num_steps=100, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_gain_sizer, 0, 1, 1, 1) + self._freq_text_box = forms.text_box( + parent=self.GetWin(), + value=self.freq, + callback=self.set_freq, + label="Frequency", + converter=forms.float_converter(), + ) + self.GridAdd(self._freq_text_box, 0, 0, 1, 1) + self._decim_text_static_text = forms.static_text( + parent=self.GetWin(), + value=self.decim_text, + callback=self.set_decim_text, + label="Decimation", + converter=forms.float_converter(), + ) + self.GridAdd(self._decim_text_static_text, 1, 1, 1, 1) + + ################################################## + # Blocks + ################################################## + self.agc = gr.agc_cc(1e-6, 1.0, 1.0, 1.0) + self.decoder = noaa.hrpt_decoder() + self.deframer = noaa.hrpt_deframer() + self.frame_sink = gr.file_sink(gr.sizeof_short*1, output_filename) + self.matched_filter = gr.moving_average_cc(hs, 1.0/hs, 4000) + self.pll = noaa.hrpt_pll_cf(pll_alpha, pll_alpha**2/4.0, max_carrier_offset) + self.pll_scope = scopesink2.scope_sink_f( + self.displays.GetPage(1).GetWin(), + title="Post-PLL", + sample_rate=sample_rate, + v_scale=0.5, + t_scale=20.0/sample_rate, + ac_couple=False, + xy_mode=False, + num_inputs=1, + ) + self.displays.GetPage(1).GridAdd(self.pll_scope.win, 0, 0, 1, 1) + self.rx_fft = fftsink2.fft_sink_c( + self.displays.GetPage(0).GetWin(), + baseband_freq=freq, + y_per_div=5, + y_divs=8, + ref_level=-5, + ref_scale=2.0, + sample_rate=sample_rate, + fft_size=1024, + fft_rate=30, + average=True, + avg_alpha=0.1, + title="RX Spectrum", + peak_hold=False, + ) + self.displays.GetPage(0).GridAdd(self.rx_fft.win, 0, 0, 1, 1) + self.rx_scope = scopesink2.scope_sink_c( + self.displays.GetPage(0).GetWin(), + title="RX Waveform", + sample_rate=sample_rate, + v_scale=0, + t_scale=20.0/sample_rate, + ac_couple=False, + xy_mode=False, + num_inputs=1, + ) + self.displays.GetPage(0).GridAdd(self.rx_scope.win, 1, 0, 1, 1) + self.sync = noaa.hrpt_sync_fb(sync_alpha, sync_alpha**2/4.0, sps, max_sync_offset) + self.usrp_source = grc_usrp.simple_source_c(which=0, side=side, rx_ant="RXA") + self.usrp_source.set_decim_rate(decim) + self.usrp_source.set_frequency(freq, verbose=True) + self.usrp_source.set_gain(gain) + + ################################################## + # Connections + ################################################## + self.connect((self.deframer, 0), (self.frame_sink, 0)) + self.connect((self.sync, 0), (self.deframer, 0)) + self.connect((self.pll, 0), (self.sync, 0)) + self.connect((self.pll, 0), (self.pll_scope, 0)) + self.connect((self.agc, 0), (self.rx_scope, 0)) + self.connect((self.agc, 0), (self.rx_fft, 0)) + self.connect((self.agc, 0), (self.matched_filter, 0)) + self.connect((self.matched_filter, 0), (self.pll, 0)) + self.connect((self.deframer, 0), (self.decoder, 0)) + self.connect((self.usrp_source, 0), (self.agc, 0)) + + def set_config_filename(self, config_filename): + self.config_filename = config_filename + self._side_config = ConfigParser.ConfigParser() + self._side_config.read(self.config_filename) + if not self._side_config.has_section('usrp'): + self._side_config.add_section('usrp') + self._side_config.set('usrp', 'side', str(self.side)) + self._side_config.write(open(self.config_filename, 'w')) + self._decim_config = ConfigParser.ConfigParser() + self._decim_config.read(self.config_filename) + if not self._decim_config.has_section('usrp'): + self._decim_config.add_section('usrp') + self._decim_config.set('usrp', 'decim', str(self.decim)) + self._decim_config.write(open(self.config_filename, 'w')) + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(self.config_filename) + if not self._saved_freq_config.has_section('usrp'): + self._saved_freq_config.add_section('usrp') + self._saved_freq_config.set('usrp', 'freq', str(self.freq)) + self._saved_freq_config.write(open(self.config_filename, 'w')) + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(self.config_filename) + if not self._saved_gain_config.has_section('usrp'): + self._saved_gain_config.add_section('usrp') + self._saved_gain_config.set('usrp', 'gain', str(self.gain)) + self._saved_gain_config.write(open(self.config_filename, 'w')) + self._saved_pll_alpha_config = ConfigParser.ConfigParser() + self._saved_pll_alpha_config.read(self.config_filename) + if not self._saved_pll_alpha_config.has_section('demod'): + self._saved_pll_alpha_config.add_section('demod') + self._saved_pll_alpha_config.set('demod', 'pll_alpha', str(self.pll_alpha)) + self._saved_pll_alpha_config.write(open(self.config_filename, 'w')) + self._saved_sync_alpha_config = ConfigParser.ConfigParser() + self._saved_sync_alpha_config.read(self.config_filename) + if not self._saved_sync_alpha_config.has_section('demod'): + self._saved_sync_alpha_config.add_section('demod') + self._saved_sync_alpha_config.set('demod', 'sync_alpha', str(self.sync_alpha)) + self._saved_sync_alpha_config.write(open(self.config_filename, 'w')) + self._output_filename_config = ConfigParser.ConfigParser() + self._output_filename_config.read(self.config_filename) + if not self._output_filename_config.has_section('output'): + self._output_filename_config.add_section('output') + self._output_filename_config.set('output', 'filename', str(self.output_filename)) + self._output_filename_config.write(open(self.config_filename, 'w')) + + def set_decim(self, decim): + self.decim = decim + self.set_sample_rate(64e6/self.decim) + self._decim_config = ConfigParser.ConfigParser() + self._decim_config.read(self.config_filename) + if not self._decim_config.has_section('usrp'): + self._decim_config.add_section('usrp') + self._decim_config.set('usrp', 'decim', str(self.decim)) + self._decim_config.write(open(self.config_filename, 'w')) + self.set_decim_text(self.decim) + self.usrp_source.set_decim_rate(self.decim) + + def set_sym_rate(self, sym_rate): + self.sym_rate = sym_rate + self.set_sps(self.sample_rate/self.sym_rate) + + def set_sample_rate(self, sample_rate): + self.sample_rate = sample_rate + self.set_max_carrier_offset(2*math.pi*100e3/self.sample_rate) + self.set_sps(self.sample_rate/self.sym_rate) + self.rx_scope.set_sample_rate(self.sample_rate) + self.rx_fft.set_sample_rate(self.sample_rate) + self.pll_scope.set_sample_rate(self.sample_rate) + + def set_sps(self, sps): + self.sps = sps + self.set_hs(int(self.sps/2.0)) + + def set_side(self, side): + self.side = side + self.set_side_text(self.side) + self._side_config = ConfigParser.ConfigParser() + self._side_config.read(self.config_filename) + if not self._side_config.has_section('usrp'): + self._side_config.add_section('usrp') + self._side_config.set('usrp', 'side', str(self.side)) + self._side_config.write(open(self.config_filename, 'w')) + + def set_saved_sync_alpha(self, saved_sync_alpha): + self.saved_sync_alpha = saved_sync_alpha + self.set_sync_alpha(self.saved_sync_alpha) + + def set_saved_pll_alpha(self, saved_pll_alpha): + self.saved_pll_alpha = saved_pll_alpha + self.set_pll_alpha(self.saved_pll_alpha) + + def set_saved_gain(self, saved_gain): + self.saved_gain = saved_gain + self.set_gain(self.saved_gain) + + def set_saved_freq(self, saved_freq): + self.saved_freq = saved_freq + self.set_freq(self.saved_freq) + + def set_sync_alpha(self, sync_alpha): + self.sync_alpha = sync_alpha + self._sync_alpha_slider.set_value(self.sync_alpha) + self._sync_alpha_text_box.set_value(self.sync_alpha) + self._saved_sync_alpha_config = ConfigParser.ConfigParser() + self._saved_sync_alpha_config.read(self.config_filename) + if not self._saved_sync_alpha_config.has_section('demod'): + self._saved_sync_alpha_config.add_section('demod') + self._saved_sync_alpha_config.set('demod', 'sync_alpha', str(self.sync_alpha)) + self._saved_sync_alpha_config.write(open(self.config_filename, 'w')) + self.sync.set_alpha(self.sync_alpha) + self.sync.set_beta(self.sync_alpha**2/4.0) + + def set_side_text(self, side_text): + self.side_text = side_text + self._side_text_static_text.set_value(self.side_text) + + def set_pll_alpha(self, pll_alpha): + self.pll_alpha = pll_alpha + self._pll_alpha_slider.set_value(self.pll_alpha) + self._pll_alpha_text_box.set_value(self.pll_alpha) + self._saved_pll_alpha_config = ConfigParser.ConfigParser() + self._saved_pll_alpha_config.read(self.config_filename) + if not self._saved_pll_alpha_config.has_section('demod'): + self._saved_pll_alpha_config.add_section('demod') + self._saved_pll_alpha_config.set('demod', 'pll_alpha', str(self.pll_alpha)) + self._saved_pll_alpha_config.write(open(self.config_filename, 'w')) + self.pll.set_alpha(self.pll_alpha) + self.pll.set_beta(self.pll_alpha**2/4.0) + + def set_output_filename(self, output_filename): + self.output_filename = output_filename + self._output_filename_config = ConfigParser.ConfigParser() + self._output_filename_config.read(self.config_filename) + if not self._output_filename_config.has_section('output'): + self._output_filename_config.add_section('output') + self._output_filename_config.set('output', 'filename', str(self.output_filename)) + self._output_filename_config.write(open(self.config_filename, 'w')) + + def set_max_sync_offset(self, max_sync_offset): + self.max_sync_offset = max_sync_offset + self.sync.set_max_offset(self.max_sync_offset) + + def set_max_carrier_offset(self, max_carrier_offset): + self.max_carrier_offset = max_carrier_offset + self.pll.set_max_offset(self.max_carrier_offset) + + def set_hs(self, hs): + self.hs = hs + self.matched_filter.set_length_and_scale(self.hs, 1.0/self.hs) + + def set_gain(self, gain): + self.gain = gain + self._gain_slider.set_value(self.gain) + self._gain_text_box.set_value(self.gain) + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(self.config_filename) + if not self._saved_gain_config.has_section('usrp'): + self._saved_gain_config.add_section('usrp') + self._saved_gain_config.set('usrp', 'gain', str(self.gain)) + self._saved_gain_config.write(open(self.config_filename, 'w')) + self.usrp_source.set_gain(self.gain) + + def set_freq(self, freq): + self.freq = freq + self._freq_text_box.set_value(self.freq) + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(self.config_filename) + if not self._saved_freq_config.has_section('usrp'): + self._saved_freq_config.add_section('usrp') + self._saved_freq_config.set('usrp', 'freq', str(self.freq)) + self._saved_freq_config.write(open(self.config_filename, 'w')) + self.usrp_source.set_frequency(self.freq) + self.rx_fft.set_baseband_freq(self.freq) + + def set_decim_text(self, decim_text): + self.decim_text = decim_text + self._decim_text_static_text.set_value(self.decim_text) + +if __name__ == '__main__': + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + (options, args) = parser.parse_args() + tb = usrp_rx_hrpt() + tb.Run(True) + diff --git a/gr-noaa/apps/usrp_rx_lrit.grc b/gr-noaa/apps/usrp_rx_lrit.grc new file mode 100644 index 000000000..55fe39787 --- /dev/null +++ b/gr-noaa/apps/usrp_rx_lrit.grc @@ -0,0 +1,1477 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Sat Aug 29 11:26:03 2009</timestamp> + <block> + <key>options</key> + <param> + <key>id</key> + <value>usrp_rx_lrit</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>USRP LRIT Receiver</value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>4095, 4095</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>64e6/decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 81)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>symbol_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>293e3</value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 148)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>sps</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>samp_rate/symbol_rate</value> + </param> + <param> + <key>_coordinate</key> + <value>(12, 214)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_text_box</key> + <param> + <key>id</key> + <value>decim</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Decim</value> + </param> + <param> + <key>value</key> + <value>saved_decim</value> + </param> + <param> + <key>converver</key> + <value>int_converter</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(243, 13)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>wxgui_scopesink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>Waveform</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0.5</value> + </param> + <param> + <key>t_scale</key> + <value>20.0/samp_rate</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>True</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(434, 551)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_agc_xx</key> + <param> + <key>id</key> + <value>gr_agc_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>rate</key> + <value>1e-6</value> + </param> + <param> + <key>reference</key> + <value>1.0</value> + </param> + <param> + <key>gain</key> + <value>1.0/32767.0</value> + </param> + <param> + <key>max_gain</key> + <value>1.0</value> + </param> + <param> + <key>_coordinate</key> + <value>(261, 493)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>root_raised_cosine_filter</key> + <param> + <key>id</key> + <value>root_raised_cosine_filter_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>fir_filter_ccf</value> + </param> + <param> + <key>decim</key> + <value>1</value> + </param> + <param> + <key>interp</key> + <value>1</value> + </param> + <param> + <key>gain</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>sym_rate</key> + <value>symbol_rate</value> + </param> + <param> + <key>alpha</key> + <value>0.5</value> + </param> + <param> + <key>ntaps</key> + <value>50</value> + </param> + <param> + <key>_coordinate</key> + <value>(618, 373)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>usrp_simple_source_x</key> + <param> + <key>id</key> + <value>usrp_simple_source_x_0</value> + </param> + <param> + <key>_enabled</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>format</key> + <value></value> + </param> + <param> + <key>which</key> + <value>0</value> + </param> + <param> + <key>decimation</key> + <value>decim</value> + </param> + <param> + <key>frequency</key> + <value>freq</value> + </param> + <param> + <key>lo_offset</key> + <value>float('inf')</value> + </param> + <param> + <key>gain</key> + <value>gain</value> + </param> + <param> + <key>side</key> + <value>B</value> + </param> + <param> + <key>rx_ant</key> + <value>RXA</value> + </param> + <param> + <key>hb_filters</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 477)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>wxgui_fftsink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>Spectrum</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>freq</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> + <value>50</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(434, 337)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_throttle</key> + <param> + <key>id</key> + <value>gr_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>_coordinate</key> + <value>(181, 663)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>wxgui_scopesink2_1</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>title</key> + <value>Scope Plot</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0.4</value> + </param> + <param> + <key>t_scale</key> + <value>20.0/samp_rate</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>True</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1126, 251)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_probe_mpsk_snr_c</key> + <param> + <key>id</key> + <value>gr_probe_mpsk_snr_c_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>snr</value> + </param> + <param> + <key>alpha</key> + <value>0.0001</value> + </param> + <param> + <key>probe_rate</key> + <value>10</value> + </param> + <param> + <key>_coordinate</key> + <value>(1126, 723)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_numbersink2</key> + <param> + <key>id</key> + <value>wxgui_numbersink2_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>SNR</value> + </param> + <param> + <key>units</key> + <value>dB</value> + </param> + <param> + <key>samp_rate</key> + <value>10</value> + </param> + <param> + <key>min_value</key> + <value>0</value> + </param> + <param> + <key>max_value</key> + <value>30</value> + </param> + <param> + <key>factor</key> + <value>1.0</value> + </param> + <param> + <key>decimal_places</key> + <value>1</value> + </param> + <param> + <key>ref_level</key> + <value>0</value> + </param> + <param> + <key>number_rate</key> + <value>10</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>show_gauge</key> + <value>True</value> + </param> + <param> + <key>grid_pos</key> + <value>2, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1335, 651)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_mpsk_receiver_cc</key> + <param> + <key>id</key> + <value>gr_mpsk_receiver_cc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>M</key> + <value>2</value> + </param> + <param> + <key>theta</key> + <value>0</value> + </param> + <param> + <key>alpha</key> + <value>costas_alpha</value> + </param> + <param> + <key>beta</key> + <value>costas_alpha*costas_alpha/4.0</value> + </param> + <param> + <key>fmin</key> + <value>-0.05</value> + </param> + <param> + <key>fmax</key> + <value>0.05</value> + </param> + <param> + <key>mu</key> + <value>0.5</value> + </param> + <param> + <key>gain_mu</key> + <value>gain_mu</value> + </param> + <param> + <key>omega</key> + <value>sps</value> + </param> + <param> + <key>gain_omega</key> + <value>gain_mu*gain_mu/4.0</value> + </param> + <param> + <key>omega_relative_limit</key> + <value>0.05</value> + </param> + <param> + <key>_coordinate</key> + <value>(881, 437)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_complex_to_real</key> + <param> + <key>id</key> + <value>gr_complex_to_real_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1133, 521)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_char_to_float</key> + <param> + <key>id</key> + <value>gr_char_to_float_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1523, 521)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_binary_slicer_fb</key> + <param> + <key>id</key> + <value>gr_binary_slicer_fb_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1343, 521)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_add_const_vxx</key> + <param> + <key>id</key> + <value>gr_add_const_vxx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>const</key> + <value>48.0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1707, 517)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_float_to_char</key> + <param> + <key>id</key> + <value>gr_float_to_char_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(1878, 521)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_file_sink</key> + <param> + <key>id</key> + <value>gr_file_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>bits.dat</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(2059, 517)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_file_source</key> + <param> + <key>id</key> + <value>gr_file_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>file</key> + <value>lrit.dat</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>repeat</key> + <value>False</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 655)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>notebook</key> + <param> + <key>id</key> + <value>displays</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>style</key> + <value>wx.NB_TOP</value> + </param> + <param> + <key>labels</key> + <value>['USRP RX', 'Costas Output']</value> + </param> + <param> + <key>grid_pos</key> + <value>2, 0, 1, 3</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(14, 351)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_decim</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>160</value> + </param> + <param> + <key>type</key> + <value>int</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>main</value> + </param> + <param> + <key>option</key> + <value>decim</value> + </param> + <param> + <key>writeback</key> + <value>decim</value> + </param> + <param> + <key>_coordinate</key> + <value>(246, 172)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>gain</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Gain</value> + </param> + <param> + <key>value</key> + <value>saved_gain</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>115</value> + </param> + <param> + <key>num_steps</key> + <value>115</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 1, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(411, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_gain</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>33</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>main</value> + </param> + <param> + <key>option</key> + <value>gain</value> + </param> + <param> + <key>writeback</key> + <value>gain</value> + </param> + <param> + <key>_coordinate</key> + <value>(412, 172)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>freq</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Frequency</value> + </param> + <param> + <key>value</key> + <value>saved_freq</value> + </param> + <param> + <key>min</key> + <value>135e6</value> + </param> + <param> + <key>max</key> + <value>139e6</value> + </param> + <param> + <key>num_steps</key> + <value>400</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 2, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(574, 12)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_freq</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>137e6</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</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>_coordinate</key> + <value>(576, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>costas_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Costas Alpha</value> + </param> + <param> + <key>value</key> + <value>saved_costas_alpha</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>0.5</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(738, 13)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_costas_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.005</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>main</value> + </param> + <param> + <key>option</key> + <value>costas_alpha</value> + </param> + <param> + <key>writeback</key> + <value>costas_alpha</value> + </param> + <param> + <key>_coordinate</key> + <value>(739, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_config</key> + <param> + <key>id</key> + <value>saved_gain_mu</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.005</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + <param> + <key>config_file</key> + <value>config_filename</value> + </param> + <param> + <key>section</key> + <value>main</value> + </param> + <param> + <key>option</key> + <value>gain_mu</value> + </param> + <param> + <key>writeback</key> + <value>gain_mu</value> + </param> + <param> + <key>_coordinate</key> + <value>(900, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>gain_mu</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Gain Mu</value> + </param> + <param> + <key>value</key> + <value>saved_gain_mu</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>0.5</value> + </param> + <param> + <key>num_steps</key> + <value>100</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 1, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(902, 13)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>config_filename</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>"usrp_rx_lrit.cfg"</value> + </param> + <param> + <key>_coordinate</key> + <value>(13, 283)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>usrp_simple_source_x_0</source_block_id> + <sink_block_id>gr_agc_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_agc_xx_0</source_block_id> + <sink_block_id>wxgui_scopesink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_file_source_0</source_block_id> + <sink_block_id>gr_throttle_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_throttle_0</source_block_id> + <sink_block_id>gr_agc_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_probe_mpsk_snr_c_0</source_block_id> + <sink_block_id>wxgui_numbersink2_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_mpsk_receiver_cc_0</source_block_id> + <sink_block_id>gr_probe_mpsk_snr_c_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_agc_xx_0</source_block_id> + <sink_block_id>gr_mpsk_receiver_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_mpsk_receiver_cc_0</source_block_id> + <sink_block_id>wxgui_scopesink2_1</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_agc_xx_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>gr_mpsk_receiver_cc_0</source_block_id> + <sink_block_id>gr_complex_to_real_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_complex_to_real_0</source_block_id> + <sink_block_id>gr_binary_slicer_fb_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_binary_slicer_fb_0</source_block_id> + <sink_block_id>gr_char_to_float_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_char_to_float_0</source_block_id> + <sink_block_id>gr_add_const_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_add_const_vxx_0</source_block_id> + <sink_block_id>gr_float_to_char_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gr_float_to_char_0</source_block_id> + <sink_block_id>gr_file_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/gr-noaa/apps/usrp_rx_lrit.py b/gr-noaa/apps/usrp_rx_lrit.py new file mode 100755 index 000000000..bc313e3af --- /dev/null +++ b/gr-noaa/apps/usrp_rx_lrit.py @@ -0,0 +1,399 @@ +#!/usr/bin/env python +################################################## +# Gnuradio Python Flow Graph +# Title: USRP LRIT Receiver +# Generated: Sat Aug 29 11:26:03 2009 +################################################## + +from gnuradio import gr +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import fftsink2 +from gnuradio.wxgui import forms +from gnuradio.wxgui import numbersink2 +from gnuradio.wxgui import scopesink2 +from grc_gnuradio import blks2 as grc_blks2 +from grc_gnuradio import wxgui as grc_wxgui +from optparse import OptionParser +import ConfigParser +import wx + +class usrp_rx_lrit(grc_wxgui.top_block_gui): + + def __init__(self): + grc_wxgui.top_block_gui.__init__(self, title="USRP LRIT Receiver") + + ################################################## + # Variables + ################################################## + self.config_filename = config_filename = "usrp_rx_lrit.cfg" + self._saved_decim_config = ConfigParser.ConfigParser() + self._saved_decim_config.read(config_filename) + try: saved_decim = self._saved_decim_config.getint("main", "decim") + except: saved_decim = 160 + self.saved_decim = saved_decim + self.decim = decim = saved_decim + self.symbol_rate = symbol_rate = 293e3 + self._saved_gain_mu_config = ConfigParser.ConfigParser() + self._saved_gain_mu_config.read(config_filename) + try: saved_gain_mu = self._saved_gain_mu_config.getfloat("main", "gain_mu") + except: saved_gain_mu = 0.005 + self.saved_gain_mu = saved_gain_mu + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(config_filename) + try: saved_gain = self._saved_gain_config.getfloat("main", "gain") + except: saved_gain = 33 + self.saved_gain = saved_gain + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(config_filename) + try: saved_freq = self._saved_freq_config.getfloat("main", "freq") + except: saved_freq = 137e6 + self.saved_freq = saved_freq + self._saved_costas_alpha_config = ConfigParser.ConfigParser() + self._saved_costas_alpha_config.read(config_filename) + try: saved_costas_alpha = self._saved_costas_alpha_config.getfloat("main", "costas_alpha") + except: saved_costas_alpha = 0.005 + self.saved_costas_alpha = saved_costas_alpha + self.samp_rate = samp_rate = 64e6/decim + self.sps = sps = samp_rate/symbol_rate + self.gain_mu = gain_mu = saved_gain_mu + self.gain = gain = saved_gain + self.freq = freq = saved_freq + self.costas_alpha = costas_alpha = saved_costas_alpha + + ################################################## + # Notebooks + ################################################## + self.displays = wx.Notebook(self.GetWin(), style=wx.NB_TOP) + self.displays.AddPage(grc_wxgui.Panel(self.displays), "USRP RX") + self.displays.AddPage(grc_wxgui.Panel(self.displays), "Costas Output") + self.GridAdd(self.displays, 2, 0, 1, 3) + + ################################################## + # Controls + ################################################## + self._decim_text_box = forms.text_box( + parent=self.GetWin(), + value=self.decim, + callback=self.set_decim, + label="Decim", + converter=forms.int_converter(), + ) + self.GridAdd(self._decim_text_box, 0, 0, 1, 1) + _gain_mu_sizer = wx.BoxSizer(wx.VERTICAL) + self._gain_mu_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_gain_mu_sizer, + value=self.gain_mu, + callback=self.set_gain_mu, + label="Gain Mu", + converter=forms.float_converter(), + proportion=0, + ) + self._gain_mu_slider = forms.slider( + parent=self.GetWin(), + sizer=_gain_mu_sizer, + value=self.gain_mu, + callback=self.set_gain_mu, + minimum=0, + maximum=0.5, + num_steps=100, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_gain_mu_sizer, 1, 1, 1, 1) + _gain_sizer = wx.BoxSizer(wx.VERTICAL) + self._gain_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_gain_sizer, + value=self.gain, + callback=self.set_gain, + label="Gain", + converter=forms.float_converter(), + proportion=0, + ) + self._gain_slider = forms.slider( + parent=self.GetWin(), + sizer=_gain_sizer, + value=self.gain, + callback=self.set_gain, + minimum=0, + maximum=115, + num_steps=115, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_gain_sizer, 0, 1, 1, 1) + _freq_sizer = wx.BoxSizer(wx.VERTICAL) + self._freq_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_freq_sizer, + value=self.freq, + callback=self.set_freq, + label="Frequency", + converter=forms.float_converter(), + proportion=0, + ) + self._freq_slider = forms.slider( + parent=self.GetWin(), + sizer=_freq_sizer, + value=self.freq, + callback=self.set_freq, + minimum=135e6, + maximum=139e6, + num_steps=400, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_freq_sizer, 0, 2, 1, 1) + _costas_alpha_sizer = wx.BoxSizer(wx.VERTICAL) + self._costas_alpha_text_box = forms.text_box( + parent=self.GetWin(), + sizer=_costas_alpha_sizer, + value=self.costas_alpha, + callback=self.set_costas_alpha, + label="Costas Alpha", + converter=forms.float_converter(), + proportion=0, + ) + self._costas_alpha_slider = forms.slider( + parent=self.GetWin(), + sizer=_costas_alpha_sizer, + value=self.costas_alpha, + callback=self.set_costas_alpha, + minimum=0, + maximum=0.5, + num_steps=100, + style=wx.SL_HORIZONTAL, + cast=float, + proportion=1, + ) + self.GridAdd(_costas_alpha_sizer, 1, 0, 1, 1) + + ################################################## + # Blocks + ################################################## + self.gr_add_const_vxx_0 = gr.add_const_vff((48.0, )) + self.gr_agc_xx_0 = gr.agc_cc(1e-6, 1.0, 1.0/32767.0, 1.0) + self.gr_binary_slicer_fb_0 = gr.binary_slicer_fb() + self.gr_char_to_float_0 = gr.char_to_float() + self.gr_complex_to_real_0 = gr.complex_to_real(1) + self.gr_file_sink_0 = gr.file_sink(gr.sizeof_char*1, "bits.dat") + self.gr_file_source_0 = gr.file_source(gr.sizeof_gr_complex*1, "lrit.dat", False) + self.gr_float_to_char_0 = gr.float_to_char() + self.gr_mpsk_receiver_cc_0 = gr.mpsk_receiver_cc(2, 0, costas_alpha, costas_alpha*costas_alpha/4.0, -0.05, 0.05, 0.5, gain_mu, sps, gain_mu*gain_mu/4.0, 0.05) + self.gr_probe_mpsk_snr_c_0 = grc_blks2.probe_mpsk_snr_c( + type='snr', + alpha=0.0001, + probe_rate=10, + ) + self.gr_throttle_0 = gr.throttle(gr.sizeof_gr_complex*1, samp_rate) + self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( + self.displays.GetPage(0).GetWin(), + baseband_freq=freq, + y_per_div=10, + y_divs=10, + ref_level=50, + sample_rate=samp_rate, + fft_size=1024, + fft_rate=30, + average=False, + avg_alpha=None, + title="Spectrum", + peak_hold=False, + ) + self.displays.GetPage(0).GridAdd(self.wxgui_fftsink2_0.win, 0, 0, 1, 1) + self.wxgui_numbersink2_0 = numbersink2.number_sink_f( + self.displays.GetPage(1).GetWin(), + unit="dB", + minval=0, + maxval=30, + factor=1.0, + decimal_places=1, + ref_level=0, + sample_rate=10, + number_rate=10, + average=False, + avg_alpha=None, + label="SNR", + peak_hold=False, + show_gauge=True, + ) + self.displays.GetPage(1).GridAdd(self.wxgui_numbersink2_0.win, 2, 0, 1, 1) + self.wxgui_scopesink2_0 = scopesink2.scope_sink_c( + self.displays.GetPage(0).GetWin(), + title="Waveform", + sample_rate=samp_rate, + v_scale=0.5, + t_scale=20.0/samp_rate, + ac_couple=False, + xy_mode=True, + num_inputs=1, + ) + self.displays.GetPage(0).GridAdd(self.wxgui_scopesink2_0.win, 1, 0, 1, 1) + self.wxgui_scopesink2_1 = scopesink2.scope_sink_c( + self.displays.GetPage(1).GetWin(), + title="Scope Plot", + sample_rate=samp_rate, + v_scale=0.4, + t_scale=20.0/samp_rate, + ac_couple=False, + xy_mode=True, + num_inputs=1, + ) + self.displays.GetPage(1).GridAdd(self.wxgui_scopesink2_1.win, 0, 0, 1, 1) + + ################################################## + # Connections + ################################################## + self.connect((self.gr_agc_xx_0, 0), (self.wxgui_scopesink2_0, 0)) + self.connect((self.gr_file_source_0, 0), (self.gr_throttle_0, 0)) + self.connect((self.gr_throttle_0, 0), (self.gr_agc_xx_0, 0)) + self.connect((self.gr_probe_mpsk_snr_c_0, 0), (self.wxgui_numbersink2_0, 0)) + self.connect((self.gr_mpsk_receiver_cc_0, 0), (self.gr_probe_mpsk_snr_c_0, 0)) + self.connect((self.gr_agc_xx_0, 0), (self.gr_mpsk_receiver_cc_0, 0)) + self.connect((self.gr_mpsk_receiver_cc_0, 0), (self.wxgui_scopesink2_1, 0)) + self.connect((self.gr_agc_xx_0, 0), (self.wxgui_fftsink2_0, 0)) + self.connect((self.gr_mpsk_receiver_cc_0, 0), (self.gr_complex_to_real_0, 0)) + self.connect((self.gr_complex_to_real_0, 0), (self.gr_binary_slicer_fb_0, 0)) + self.connect((self.gr_binary_slicer_fb_0, 0), (self.gr_char_to_float_0, 0)) + self.connect((self.gr_char_to_float_0, 0), (self.gr_add_const_vxx_0, 0)) + self.connect((self.gr_add_const_vxx_0, 0), (self.gr_float_to_char_0, 0)) + self.connect((self.gr_float_to_char_0, 0), (self.gr_file_sink_0, 0)) + + def set_config_filename(self, config_filename): + self.config_filename = config_filename + self._saved_decim_config = ConfigParser.ConfigParser() + self._saved_decim_config.read(self.config_filename) + if not self._saved_decim_config.has_section("main"): + self._saved_decim_config.add_section("main") + self._saved_decim_config.set("main", "decim", str(self.decim)) + self._saved_decim_config.write(open(self.config_filename, 'w')) + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(self.config_filename) + if not self._saved_gain_config.has_section("main"): + self._saved_gain_config.add_section("main") + self._saved_gain_config.set("main", "gain", str(self.gain)) + self._saved_gain_config.write(open(self.config_filename, 'w')) + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(self.config_filename) + if not self._saved_freq_config.has_section("main"): + self._saved_freq_config.add_section("main") + self._saved_freq_config.set("main", "freq", str(self.freq)) + self._saved_freq_config.write(open(self.config_filename, 'w')) + self._saved_costas_alpha_config = ConfigParser.ConfigParser() + self._saved_costas_alpha_config.read(self.config_filename) + if not self._saved_costas_alpha_config.has_section("main"): + self._saved_costas_alpha_config.add_section("main") + self._saved_costas_alpha_config.set("main", "costas_alpha", str(self.costas_alpha)) + self._saved_costas_alpha_config.write(open(self.config_filename, 'w')) + self._saved_gain_mu_config = ConfigParser.ConfigParser() + self._saved_gain_mu_config.read(self.config_filename) + if not self._saved_gain_mu_config.has_section("main"): + self._saved_gain_mu_config.add_section("main") + self._saved_gain_mu_config.set("main", "gain_mu", str(self.gain_mu)) + self._saved_gain_mu_config.write(open(self.config_filename, 'w')) + + def set_saved_decim(self, saved_decim): + self.saved_decim = saved_decim + self.set_decim(self.saved_decim) + + def set_decim(self, decim): + self.decim = decim + self.set_samp_rate(64e6/self.decim) + self._decim_text_box.set_value(self.decim) + self._saved_decim_config = ConfigParser.ConfigParser() + self._saved_decim_config.read(self.config_filename) + if not self._saved_decim_config.has_section("main"): + self._saved_decim_config.add_section("main") + self._saved_decim_config.set("main", "decim", str(self.decim)) + self._saved_decim_config.write(open(self.config_filename, 'w')) + + def set_symbol_rate(self, symbol_rate): + self.symbol_rate = symbol_rate + self.set_sps(self.samp_rate/self.symbol_rate) + + def set_saved_gain_mu(self, saved_gain_mu): + self.saved_gain_mu = saved_gain_mu + self.set_gain_mu(self.saved_gain_mu) + + def set_saved_gain(self, saved_gain): + self.saved_gain = saved_gain + self.set_gain(self.saved_gain) + + def set_saved_freq(self, saved_freq): + self.saved_freq = saved_freq + self.set_freq(self.saved_freq) + + def set_saved_costas_alpha(self, saved_costas_alpha): + self.saved_costas_alpha = saved_costas_alpha + self.set_costas_alpha(self.saved_costas_alpha) + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + self.set_sps(self.samp_rate/self.symbol_rate) + self.wxgui_scopesink2_0.set_sample_rate(self.samp_rate) + self.wxgui_fftsink2_0.set_sample_rate(self.samp_rate) + self.wxgui_scopesink2_1.set_sample_rate(self.samp_rate) + + def set_sps(self, sps): + self.sps = sps + self.gr_mpsk_receiver_cc_0.set_omega(self.sps) + + def set_gain_mu(self, gain_mu): + self.gain_mu = gain_mu + self.gr_mpsk_receiver_cc_0.set_gain_mu(self.gain_mu) + self.gr_mpsk_receiver_cc_0.set_gain_omega(self.gain_mu*self.gain_mu/4.0) + self._saved_gain_mu_config = ConfigParser.ConfigParser() + self._saved_gain_mu_config.read(self.config_filename) + if not self._saved_gain_mu_config.has_section("main"): + self._saved_gain_mu_config.add_section("main") + self._saved_gain_mu_config.set("main", "gain_mu", str(self.gain_mu)) + self._saved_gain_mu_config.write(open(self.config_filename, 'w')) + self._gain_mu_slider.set_value(self.gain_mu) + self._gain_mu_text_box.set_value(self.gain_mu) + + def set_gain(self, gain): + self.gain = gain + self._gain_slider.set_value(self.gain) + self._gain_text_box.set_value(self.gain) + self._saved_gain_config = ConfigParser.ConfigParser() + self._saved_gain_config.read(self.config_filename) + if not self._saved_gain_config.has_section("main"): + self._saved_gain_config.add_section("main") + self._saved_gain_config.set("main", "gain", str(self.gain)) + self._saved_gain_config.write(open(self.config_filename, 'w')) + + def set_freq(self, freq): + self.freq = freq + self.wxgui_fftsink2_0.set_baseband_freq(self.freq) + self._freq_slider.set_value(self.freq) + self._freq_text_box.set_value(self.freq) + self._saved_freq_config = ConfigParser.ConfigParser() + self._saved_freq_config.read(self.config_filename) + if not self._saved_freq_config.has_section("main"): + self._saved_freq_config.add_section("main") + self._saved_freq_config.set("main", "freq", str(self.freq)) + self._saved_freq_config.write(open(self.config_filename, 'w')) + + def set_costas_alpha(self, costas_alpha): + self.costas_alpha = costas_alpha + self.gr_mpsk_receiver_cc_0.set_alpha(self.costas_alpha) + self.gr_mpsk_receiver_cc_0.set_beta(self.costas_alpha*self.costas_alpha/4.0) + self._costas_alpha_slider.set_value(self.costas_alpha) + self._costas_alpha_text_box.set_value(self.costas_alpha) + self._saved_costas_alpha_config = ConfigParser.ConfigParser() + self._saved_costas_alpha_config.read(self.config_filename) + if not self._saved_costas_alpha_config.has_section("main"): + self._saved_costas_alpha_config.add_section("main") + self._saved_costas_alpha_config.set("main", "costas_alpha", str(self.costas_alpha)) + self._saved_costas_alpha_config.write(open(self.config_filename, 'w')) + +if __name__ == '__main__': + parser = OptionParser(option_class=eng_option, usage="%prog: [options]") + (options, args) = parser.parse_args() + tb = usrp_rx_lrit() + tb.Run(True) + diff --git a/gr-noaa/grc/.gitignore b/gr-noaa/grc/.gitignore new file mode 100644 index 000000000..70845e08e --- /dev/null +++ b/gr-noaa/grc/.gitignore @@ -0,0 +1 @@ +Makefile.in diff --git a/gr-noaa/grc/Makefile.am b/gr-noaa/grc/Makefile.am new file mode 100644 index 000000000..1f056473c --- /dev/null +++ b/gr-noaa/grc/Makefile.am @@ -0,0 +1,31 @@ +# +# Copyright 2009 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 $(top_srcdir)/Makefile.common + +grcblocksdir = $(prefix)/share/gnuradio/grc/blocks + +dist_grcblocks_DATA = \ + noaa_hrpt_decoder.xml \ + noaa_hrpt_deframer.xml \ + noaa_hrpt_pll_cf.xml \ + noaa_hrpt_sync_fb.xml + diff --git a/gr-noaa/grc/noaa_hrpt_decoder.xml b/gr-noaa/grc/noaa_hrpt_decoder.xml new file mode 100644 index 000000000..183d72aba --- /dev/null +++ b/gr-noaa/grc/noaa_hrpt_decoder.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<block> + <name>HRPT Decoder</name> + <key>noaa_hrpt_decoder</key> + <category>NOAA</category> + <import>from gnuradio import noaa</import> + <make>noaa.hrpt_decoder()</make> + <sink> + <name>in</name> + <type>short</type> + </sink> +</block> diff --git a/gr-noaa/grc/noaa_hrpt_deframer.xml b/gr-noaa/grc/noaa_hrpt_deframer.xml new file mode 100644 index 000000000..af36abf2a --- /dev/null +++ b/gr-noaa/grc/noaa_hrpt_deframer.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<block> + <name>HRPT Deframer</name> + <key>noaa_hrpt_deframer</key> + <category>NOAA</category> + <import>from gnuradio import noaa</import> + <make>noaa.hrpt_deframer()</make> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>short</type> + </source> +</block> diff --git a/gr-noaa/grc/noaa_hrpt_pll_cf.xml b/gr-noaa/grc/noaa_hrpt_pll_cf.xml new file mode 100644 index 000000000..bbe15e8c3 --- /dev/null +++ b/gr-noaa/grc/noaa_hrpt_pll_cf.xml @@ -0,0 +1,34 @@ +<?xml version="1.0"?> +<block> + <name>HRPT PLL</name> + <key>noaa_hrpt_pll_cf</key> + <category>NOAA</category> + <import>from gnuradio import noaa</import> + <make>noaa.hrpt_pll_cf($alpha, $beta, $max_offset)</make> + <callback>set_alpha($alpha)</callback> + <callback>set_beta($beta)</callback> + <callback>set_max_offset($max_offset)</callback> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <type>real</type> + </param> + <param> + <name>Max Offset</name> + <key>max_offset</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/gr-noaa/grc/noaa_hrpt_sync_fb.xml b/gr-noaa/grc/noaa_hrpt_sync_fb.xml new file mode 100644 index 000000000..e066e3489 --- /dev/null +++ b/gr-noaa/grc/noaa_hrpt_sync_fb.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<block> + <name>HRPT SYNC</name> + <key>noaa_hrpt_sync_fb</key> + <category>NOAA</category> + <import>from gnuradio import noaa</import> + <make>noaa.hrpt_sync_fb($alpha, $beta, $sps, $max_offset)</make> + <callback>set_alpha($alpha)</callback> + <callback>set_beta($beta)</callback> + <callback>set_max_offset($max_offset)</callback> + <param> + <name>Alpha</name> + <key>alpha</key> + <type>real</type> + </param> + <param> + <name>Beta</name> + <key>beta</key> + <type>real</type> + </param> + <param> + <name>Samples/Symbol</name> + <key>sps</key> + <type>real</type> + </param> + <param> + <name>Max Offset</name> + <key>max_offset</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/gr-noaa/lib/.gitignore b/gr-noaa/lib/.gitignore new file mode 100644 index 000000000..02b052397 --- /dev/null +++ b/gr-noaa/lib/.gitignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +.deps +.libs diff --git a/gr-noaa/lib/Makefile.am b/gr-noaa/lib/Makefile.am new file mode 100644 index 000000000..6435d192e --- /dev/null +++ b/gr-noaa/lib/Makefile.am @@ -0,0 +1,46 @@ +# +# Copyright 2009 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 $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = \ + $(STD_DEFINES_AND_INCLUDES) \ + $(WITH_INCLUDES) + +lib_LTLIBRARIES = \ + libgnuradio-noaa.la + +libgnuradio_noaa_la_SOURCES = \ + noaa_hrpt_decoder.cc \ + noaa_hrpt_deframer.cc \ + noaa_hrpt_pll_cf.cc \ + noaa_hrpt_sync_fb.cc + +libgnuradio_noaa_la_LIBADD = \ + $(GNURADIO_CORE_LA) + +libgnuradio_noaa_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 + +grinclude_HEADERS = \ + noaa_hrpt_decoder.h \ + noaa_hrpt_deframer.h \ + noaa_hrpt_pll_cf.h \ + noaa_hrpt_sync_fb.h diff --git a/gr-noaa/lib/noaa_hrpt_decoder.cc b/gr-noaa/lib/noaa_hrpt_decoder.cc new file mode 100644 index 000000000..8cfaa913c --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_decoder.cc @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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 <noaa_hrpt_decoder.h> +#include <gr_io_signature.h> + +#define SYNC1 0x0284 +#define SYNC2 0x016F +#define SYNC3 0x035C +#define SYNC4 0x019D +#define SYNC5 0x020F +#define SYNC6 0x0095 + +noaa_hrpt_decoder_sptr +noaa_make_hrpt_decoder() +{ + return gnuradio::get_initial_sptr(new noaa_hrpt_decoder()); +} + +noaa_hrpt_decoder::noaa_hrpt_decoder() + : gr_sync_block("noaa_hrpt_decoder", + gr_make_io_signature(1, 1, sizeof(short)), + gr_make_io_signature(0, 0, 0)) +{ + d_word_count = 0; +} + +int +noaa_hrpt_decoder::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const unsigned short *in = (const unsigned short*)input_items[0]; + + int i = 0; + while (i < noutput_items) { + unsigned short word = in[i++]; + d_word_count++; + //fprintf(stderr, "%5u: ", d_word_count); + for (int pos = 0; pos < 10; pos++) { + char ch = (word & (1 << 9)) ? '1' : '0'; + word = word << 1; + //fprintf(stderr, "%c ", ch); + } + //fprintf(stderr, "\n"); + + if (d_word_count == 11090) { + d_word_count = 0; + //fprintf(stderr, "\n"); + } + } + + return i; +} diff --git a/gr-noaa/lib/noaa_hrpt_decoder.h b/gr-noaa/lib/noaa_hrpt_decoder.h new file mode 100644 index 000000000..305243b09 --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_decoder.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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_NOAA_HRPT_DECODER_H +#define INCLUDED_NOAA_HRPT_DECODER_H + +#include <gr_sync_block.h> + +class noaa_hrpt_decoder; +typedef boost::shared_ptr<noaa_hrpt_decoder> noaa_hrpt_decoder_sptr; + +noaa_hrpt_decoder_sptr +noaa_make_hrpt_decoder(); + +class noaa_hrpt_decoder : public gr_sync_block +{ + friend noaa_hrpt_decoder_sptr noaa_make_hrpt_decoder(); + noaa_hrpt_decoder(); + + unsigned int d_word_count; + +public: + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_NOAA_HRPT_DECODER_H */ diff --git a/gr-noaa/lib/noaa_hrpt_deframer.cc b/gr-noaa/lib/noaa_hrpt_deframer.cc new file mode 100644 index 000000000..89486aa19 --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_deframer.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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 <noaa_hrpt_deframer.h> +#include <gr_io_signature.h> +#include <cstring> + +#define ST_IDLE 0 +#define ST_SYNCED 1 + +#define SYNC1 0x0284 +#define SYNC2 0x016F +#define SYNC3 0x035C +#define SYNC4 0x019D +#define SYNC5 0x020F +#define SYNC6 0x0095 + +#define HRPT_MINOR_FRAME_SYNC 0x0A116FD719D83C95LL + +static int frames_seen = 0; + +noaa_hrpt_deframer_sptr +noaa_make_hrpt_deframer() +{ + return gnuradio::get_initial_sptr(new noaa_hrpt_deframer()); +} + +noaa_hrpt_deframer::noaa_hrpt_deframer() + : gr_block("noaa_hrpt_deframer", + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature(1, 1, sizeof(short))) +{ + set_output_multiple(6); // room for writing full sync when received + enter_idle(); +} + +void +noaa_hrpt_deframer::enter_idle() +{ + d_state = ST_IDLE; +} + +void +noaa_hrpt_deframer::enter_synced() +{ + d_state = ST_SYNCED; + d_bit_count = HRPT_BITS_PER_WORD; + d_word_count = HRPT_MINOR_FRAME_WORDS-HRPT_SYNC_WORDS; + d_word = 0; +} + +int +noaa_hrpt_deframer::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int ninputs = ninput_items[0]; + const char *in = (const char *)input_items[0]; + unsigned short *out = (unsigned short *)output_items[0]; + + int i = 0, j = 0; + while (i < ninputs && j < noutput_items) { + char bit = in[i++]; + + switch (d_state) { + case ST_IDLE: + d_shifter = (d_shifter << 1) | bit; // MSB transmitted first + + if ((d_shifter & 0x0FFFFFFFFFFFFFFFLL) == HRPT_MINOR_FRAME_SYNC) { + fprintf(stderr, "SYNC #%i", frames_seen++); + out[j++] = SYNC1; + out[j++] = SYNC2; + out[j++] = SYNC3; + out[j++] = SYNC4; + out[j++] = SYNC5; + out[j++] = SYNC6; + enter_synced(); + } + break; + + case ST_SYNCED: + d_word = (d_word << 1) | bit; // MSB transmitted first + if (--d_bit_count == 0) { + out[j++] = d_word; + d_word = 0; + d_bit_count = HRPT_BITS_PER_WORD; + if (--d_word_count == 0) { + fprintf(stderr, "...done\n"); + enter_idle(); + } + } + break; + + default: + throw std::runtime_error("noaa_hrpt_deframer: bad state\n"); + } + } + + consume_each(i); + return j; +} diff --git a/gr-noaa/lib/noaa_hrpt_deframer.h b/gr-noaa/lib/noaa_hrpt_deframer.h new file mode 100644 index 000000000..0aeb16a2d --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_deframer.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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_NOAA_HRPT_DEFRAMER_H +#define INCLUDED_NOAA_HRPT_DEFRAMER_H + +#define HRPT_SYNC_WORDS 6 +#define HRPT_MINOR_FRAME_WORDS 11090 +#define HRPT_BITS_PER_WORD 10 + +#include <gr_block.h> + +class noaa_hrpt_deframer; +typedef boost::shared_ptr<noaa_hrpt_deframer> noaa_hrpt_deframer_sptr; + +noaa_hrpt_deframer_sptr +noaa_make_hrpt_deframer(); + +class noaa_hrpt_deframer : public gr_block +{ + friend noaa_hrpt_deframer_sptr noaa_make_hrpt_deframer(); + noaa_hrpt_deframer(); + + unsigned int d_state; + unsigned int d_bit_count; + unsigned int d_word_count; + unsigned long long d_shifter; // 60 bit sync word + unsigned short d_word; // 10 bit HRPT word + + void enter_idle(); + void enter_synced(); + +public: + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_NOAA_HRPT_DEFRAMER_H */ diff --git a/gr-noaa/lib/noaa_hrpt_pll_cf.cc b/gr-noaa/lib/noaa_hrpt_pll_cf.cc new file mode 100644 index 000000000..08ab1d15f --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_pll_cf.cc @@ -0,0 +1,82 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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 <noaa_hrpt_pll_cf.h> +#include <gr_io_signature.h> +#include <gr_math.h> +#include <gr_sincos.h> + +#define M_TWOPI (2*M_PI) + +noaa_hrpt_pll_cf_sptr +noaa_make_hrpt_pll_cf(float alpha, float beta, float max_offset) +{ + return gnuradio::get_initial_sptr(new noaa_hrpt_pll_cf(alpha, beta, max_offset)); +} + +noaa_hrpt_pll_cf::noaa_hrpt_pll_cf(float alpha, float beta, float max_offset) + : gr_sync_block("noaa_hrpt_pll_cf", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(float))), + d_alpha(alpha), d_beta(beta), d_max_offset(max_offset), + d_phase(0.0), d_freq(0.0) +{ +} + +float +phase_wrap(float phase) +{ + while (phase < -M_PI) + phase += M_TWOPI; + while (phase > M_PI) + phase -= M_TWOPI; + + return phase; +} + +int +noaa_hrpt_pll_cf::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + float *out = (float *) output_items[0]; + + for (int i = 0; i < noutput_items; i++) { + + // Adjust PLL phase/frequency + float error = phase_wrap(gr_fast_atan2f(in[i].imag(), in[i].real()) - d_phase); + d_freq = gr_branchless_clip(d_freq + error*d_beta, d_max_offset); + d_phase = phase_wrap(d_phase + error*d_alpha + d_freq); + + // Generate and mix out carrier + float re, im; + gr_sincosf(d_phase, &im, &re); + out[i] = (in[i]*gr_complex(re, -im)).imag(); + } + + return noutput_items; +} diff --git a/gr-noaa/lib/noaa_hrpt_pll_cf.h b/gr-noaa/lib/noaa_hrpt_pll_cf.h new file mode 100644 index 000000000..507d47fe7 --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_pll_cf.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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_NOAA_HRPT_PLL_CF_H +#define INCLUDED_NOAA_HRPT_PLL_CF_H + +#include <gr_sync_block.h> + +class noaa_hrpt_pll_cf; +typedef boost::shared_ptr<noaa_hrpt_pll_cf> noaa_hrpt_pll_cf_sptr; + +noaa_hrpt_pll_cf_sptr +noaa_make_hrpt_pll_cf(float alpha, float beta, float max_offset); + +class noaa_hrpt_pll_cf : public gr_sync_block +{ + friend noaa_hrpt_pll_cf_sptr noaa_make_hrpt_pll_cf(float alpha, float beta, float max_offset); + noaa_hrpt_pll_cf(float alpha, float beta, float max_offset); + + float d_alpha; // 1st order loop constant + float d_beta; // 2nd order loop constant + float d_max_offset; // Maximum frequency offset, radians/sample + float d_phase; // Instantaneous carrier phase + float d_freq; // Instantaneous carrier frequency, radians/sample + + public: + virtual int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + void set_alpha(float alpha) { d_alpha = alpha; } + void set_beta(float beta) { d_beta = beta; } + void set_max_offset(float max_offset) { d_max_offset = max_offset; } +}; + +#endif /* INCLUDED_NOAA_HRPT_PLL_CF_H */ diff --git a/gr-noaa/lib/noaa_hrpt_sync_fb.cc b/gr-noaa/lib/noaa_hrpt_sync_fb.cc new file mode 100644 index 000000000..f99947f82 --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_sync_fb.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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 <noaa_hrpt_sync_fb.h> +#include <gr_io_signature.h> + +inline int signum(float f) +{ + return f >= 0.0 ? 1 : -1; +} + +noaa_hrpt_sync_fb_sptr +noaa_make_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset) +{ + return gnuradio::get_initial_sptr(new noaa_hrpt_sync_fb(alpha, beta, sps, max_offset)); +} + +noaa_hrpt_sync_fb::noaa_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset) + : gr_block("noaa_hrpt_sync_fb", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(char))), + d_alpha(alpha), d_beta(beta), + d_sps(sps), d_max_offset(max_offset), + d_phase(0.0), d_freq(1.0/sps), + d_last_sign(1) +{ +} + +int +noaa_hrpt_sync_fb::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + int ninputs = ninput_items[0]; + const float *in = (const float *)input_items[0]; + char *out = (char *)output_items[0]; + + int i = 0, j = 0; + while (i < ninputs && j < noutput_items) { + float sample = in[i++]; + int sign = signum(sample); + d_phase += d_freq; + + // Train on zero crossings in center region of symbol + if (sign != d_last_sign) { + if (d_phase > 0.25 && d_phase < 0.75) { + float phase_err = d_phase-0.5; + d_phase -= phase_err*d_alpha; // 1st order phase adjustment + d_freq -= phase_err*d_beta; // 2nd order frequency adjustment + } + + d_last_sign = sign; + } + + if (d_phase > 1.0) { + if (sample < 0.0) + out[j++] = 1; + else + out[j++] = 0; + d_phase -= 1.0; + } + } + + consume_each(i); + return j; +} diff --git a/gr-noaa/lib/noaa_hrpt_sync_fb.h b/gr-noaa/lib/noaa_hrpt_sync_fb.h new file mode 100644 index 000000000..a9416b9ea --- /dev/null +++ b/gr-noaa/lib/noaa_hrpt_sync_fb.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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_NOAA_HRPT_SYNC_FB_H +#define INCLUDED_NOAA_HRPT_SYNC_FB_H + +#include <gr_block.h> + +class noaa_hrpt_sync_fb; +typedef boost::shared_ptr<noaa_hrpt_sync_fb> noaa_hrpt_sync_fb_sptr; + +noaa_hrpt_sync_fb_sptr +noaa_make_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset); + +class noaa_hrpt_sync_fb : public gr_block +{ + friend noaa_hrpt_sync_fb_sptr noaa_make_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset); + noaa_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset); + + float d_alpha; // 1st order loop constant + float d_beta; // 2nd order loop constant + float d_sps; // samples per symbol + float d_max_offset; // Maximum frequency offset for d_sps, samples/symbol + float d_phase; // Instantaneous symbol phase + float d_freq; // Instantaneous symbol frequency, samples/symbol + int d_last_sign; // Tracks zero crossings + + public: + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + void set_alpha(float alpha) { d_alpha = alpha; } + void set_beta(float beta) { d_beta = beta; } + void set_max_offset(float max_offset) { d_max_offset = max_offset; } +}; + +#endif /* INCLUDED_NOAA_HRPT_SYNC_FB_H */ diff --git a/gr-noaa/python/Makefile.am b/gr-noaa/python/Makefile.am new file mode 100644 index 000000000..869c5f353 --- /dev/null +++ b/gr-noaa/python/Makefile.am @@ -0,0 +1,27 @@ +# +# Copyright 2009 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 $(top_srcdir)/Makefile.common + +if PYTHON + +endif + diff --git a/gr-noaa/swig/.gitignore b/gr-noaa/swig/.gitignore new file mode 100644 index 000000000..d18a966df --- /dev/null +++ b/gr-noaa/swig/.gitignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +.deps +.libs +noaa_swig.cc +noaa_swig.py diff --git a/gr-noaa/swig/Makefile.am b/gr-noaa/swig/Makefile.am new file mode 100644 index 000000000..cd7686e21 --- /dev/null +++ b/gr-noaa/swig/Makefile.am @@ -0,0 +1,68 @@ +# +# Copyright 2004,2005,2006,2008,2009 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 $(top_srcdir)/Makefile.common + +AM_CPPFLAGS = \ + $(STD_DEFINES_AND_INCLUDES) \ + $(PYTHON_CPPFLAGS) \ + $(WITH_INCLUDES) \ + -I$(top_srcdir)/gr-noaa/lib + +if PYTHON +# ---------------------------------------------------------------- +# The SWIG library +# TESTS = run_tests + +TOP_SWIG_IFILES = \ + noaa_swig.i + +# Install so that they end up available as: +# import gnuradio.noaa +# This ends up at: +# ${prefix}/lib/python${python_version}/site-packages/gnuradio/noaa +noaa_swig_pythondir_category = \ + gnuradio/noaa + +# additional libraries for linking with the SWIG-generated library +noaa_swig_la_swig_libadd = \ + $(top_builddir)/gr-noaa/lib/libgnuradio-noaa.la + +# additional Python files to be installed along with the SWIG-generated one +noaa_swig_python = \ + __init__.py + +# additional SWIG files to be installed +noaa_swig_swiginclude_headers = \ + noaa_swig.i \ + noaa_hrpt_decoder.i \ + noaa_hrpt_deframer.i \ + noaa_hrpt_pll_cf.i \ + noaa_hrpt_sync_fb.i + +include $(top_srcdir)/Makefile.swig + +# add some of the variables generated inside the Makefile.swig.gen +BUILT_SOURCES = $(swig_built_sources) + +# Do not distribute the output of SWIG +no_dist_files = $(swig_built_sources) +endif diff --git a/gr-noaa/swig/Makefile.swig.gen b/gr-noaa/swig/Makefile.swig.gen new file mode 100644 index 000000000..3d7102fe3 --- /dev/null +++ b/gr-noaa/swig/Makefile.swig.gen @@ -0,0 +1,259 @@ +# -*- Makefile -*- +# +# Copyright 2009 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. +# + +# Makefile.swig.gen for noaa_swig.i + +## Default install locations for these files: +## +## Default location for the Python directory is: +## ${prefix}/lib/python${python_version}/site-packages/[category]/noaa_swig +## Default location for the Python exec directory is: +## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/noaa_swig +## +## The following can be overloaded to change the install location, but +## this has to be done in the including Makefile.am -before- +## Makefile.swig is included. + +noaa_swig_pythondir_category ?= gnuradio/noaa_swig +noaa_swig_pylibdir_category ?= $(noaa_swig_pythondir_category) +noaa_swig_pythondir = $(pythondir)/$(noaa_swig_pythondir_category) +noaa_swig_pylibdir = $(pyexecdir)/$(noaa_swig_pylibdir_category) + +## SWIG headers are always installed into the same directory. + +noaa_swig_swigincludedir = $(swigincludedir) + +## This is a template file for a "generated" Makefile addition (in +## this case, "Makefile.swig.gen"). By including the top-level +## Makefile.swig, this file will be used to generate the SWIG +## dependencies. Assign the variable TOP_SWIG_FILES to be the list of +## SWIG .i files to generated wrappings for; there can be more than 1 +## so long as the names are unique (no sorting is done on the +## TOP_SWIG_FILES list). This file explicitly assumes that a SWIG .i +## file will generate .cc, .py, and possibly .h files -- meaning that +## all of these files will have the same base name (that provided for +## the SWIG .i file). +## +## This code is setup to ensure parallel MAKE ("-j" or "-jN") does the +## right thing. For more info, see < +## http://sources.redhat.com/automake/automake.html#Multiple-Outputs > + +## Stamps used to ensure parallel make does the right thing. These +## are removed by "make clean", but otherwise unused except during the +## parallel built. These will not be included in a tarball, because +## the SWIG-generated files will be removed from the distribution. + +STAMPS += $(DEPDIR)/noaa_swig-generate-* + +## Other cleaned files: dependency files generated by SWIG or this Makefile + +MOSTLYCLEANFILES += $(DEPDIR)/*.S* + +## Add the .py and .cc files to the list of SWIG built sources. The +## .h file is sometimes built, but not always ... so that one has to +## be added manually by the including Makefile.am . + +swig_built_sources += noaa_swig.py noaa_swig.cc + +## Various SWIG variables. These can be overloaded in the including +## Makefile.am by setting the variable value there, then including +## Makefile.swig . + +noaa_swig_swiginclude_HEADERS = \ + noaa_swig.i \ + $(noaa_swig_swiginclude_headers) + +noaa_swig_pylib_LTLIBRARIES = \ + _noaa_swig.la + +_noaa_swig_la_SOURCES = \ + noaa_swig.cc \ + $(noaa_swig_la_swig_sources) + +_noaa_swig_la_LIBADD = \ + $(STD_SWIG_LA_LIB_ADD) \ + $(noaa_swig_la_swig_libadd) + +_noaa_swig_la_LDFLAGS = \ + $(STD_SWIG_LA_LD_FLAGS) \ + $(noaa_swig_la_swig_ldflags) + +_noaa_swig_la_CXXFLAGS = \ + $(STD_SWIG_CXX_FLAGS) \ + $(noaa_swig_la_swig_cxxflags) + +noaa_swig_python_PYTHON = \ + noaa_swig.py \ + $(noaa_swig_python) + +## Entry rule for running SWIG + +noaa_swig.h noaa_swig.py noaa_swig.cc: noaa_swig.i +## This rule will get called only when MAKE decides that one of the +## targets needs to be created or re-created, because: +## +## * The .i file is newer than any or all of the generated files; +## +## * Any or all of the .cc, .h, or .py files does not exist and is +## needed (in the case this file is not needed, the rule for it is +## ignored); or +## +## * Some SWIG-based dependecy of the .cc file isn't met and hence the +## .cc file needs be be regenerated. Explanation: Because MAKE +## knows how to handle dependencies for .cc files (regardless of +## their name or extension), then the .cc file is used as a target +## instead of the .i file -- but with the dependencies of the .i +## file. It is this last reason why the line: +## +## if test -f $@; then :; else +## +## cannot be used in this case: If a .i file dependecy is not met, +## then the .cc file needs to be rebuilt. But if the stamp is newer +## than the .cc file, and the .cc file exists, then in the original +## version (with the 'test' above) the internal MAKE call will not +## be issued and hence the .cc file will not be rebuilt. +## +## Once execution gets to here, it should always proceed no matter the +## state of a stamp (as discussed in link above). The +## $(DEPDIR)/noaa_swig-generate stuff is used to allow for parallel +## builds to "do the right thing". The stamp has no relationship with +## either the target files or dependency file; it is used solely for +## the protection of multiple builds during a given call to MAKE. +## +## Catch signals SIGHUP (1), SIGINT (2), SIGPIPE (13), and SIGTERM +## (15). At a caught signal, the quoted command will be issued before +## exiting. In this case, remove any stamp, whether temporary of not. +## The trap is valid until the process exits; the process includes all +## commands appended via "\"s. +## + trap 'rm -rf $(DEPDIR)/noaa_swig-generate-*' 1 2 13 15; \ +## +## Create a temporary directory, which acts as a lock. The first +## process to create the directory will succeed and issue the MAKE +## command to do the actual work, while all subsequent processes will +## fail -- leading them to wait for the first process to finish. +## + if mkdir $(DEPDIR)/noaa_swig-generate-lock 2>/dev/null; then \ +## +## This code is being executed by the first process to succeed in +## creating the directory lock. +## +## Remove the stamp associated with this filename. +## + rm -f $(DEPDIR)/noaa_swig-generate-stamp; \ +## +## Tell MAKE to run the rule for creating this stamp. +## + $(MAKE) $(AM_MAKEFLAGS) $(DEPDIR)/noaa_swig-generate-stamp WHAT=$<; \ +## +## Now that the .cc, .h, and .py files have been (re)created from the +## .i file, future checking of this rule during the same MAKE +## execution will come back that the rule doesn't need to be executed +## because none of the conditions mentioned at the start of this rule +## will be positive. Remove the the directory lock, which frees up +## any waiting process(es) to continue. +## + rmdir $(DEPDIR)/noaa_swig-generate-lock; \ + else \ +## +## This code is being executed by any follower processes while the +## directory lock is in place. +## +## Wait until the first process is done, testing once per second. +## + while test -d $(DEPDIR)/noaa_swig-generate-lock; do \ + sleep 1; \ + done; \ +## +## Succeed if and only if the first process succeeded; exit this +## process returning the status of the generated stamp. +## + test -f $(DEPDIR)/noaa_swig-generate-stamp; \ + exit $$?; \ + fi; + +$(DEPDIR)/noaa_swig-generate-stamp: +## This rule will be called only by the first process issuing the +## above rule to succeed in creating the lock directory, after +## removing the actual stamp file in order to guarantee that MAKE will +## execute this rule. +## +## Call SWIG to generate the various output files; special +## post-processing on 'mingw32' host OS for the dependency file. +## + if $(SWIG) $(STD_SWIG_PYTHON_ARGS) $(noaa_swig_swig_args) \ + -MD -MF $(DEPDIR)/noaa_swig.Std \ + -module noaa_swig -o noaa_swig.cc $(WHAT); then \ + if test $(host_os) = mingw32; then \ + $(RM) $(DEPDIR)/noaa_swig.Sd; \ + $(SED) 's,\\\\,/,g' < $(DEPDIR)/noaa_swig.Std \ + > $(DEPDIR)/noaa_swig.Sd; \ + $(RM) $(DEPDIR)/noaa_swig.Std; \ + $(MV) $(DEPDIR)/noaa_swig.Sd $(DEPDIR)/noaa_swig.Std; \ + fi; \ + else \ + $(RM) $(DEPDIR)/noaa_swig.S*; exit 1; \ + fi; +## +## Mess with the SWIG output .Std dependency file, to create a +## dependecy file valid for the input .i file: Basically, simulate the +## dependency file created for libraries by GNU's libtool for C++, +## where all of the dependencies for the target are first listed, then +## each individual dependency is listed as a target with no further +## dependencies. +## +## (1) remove the current dependency file +## + $(RM) $(DEPDIR)/noaa_swig.d +## +## (2) Copy the whole SWIG file: +## + cp $(DEPDIR)/noaa_swig.Std $(DEPDIR)/noaa_swig.d +## +## (3) all a carriage return to the end of the dependency file. +## + echo "" >> $(DEPDIR)/noaa_swig.d +## +## (4) from the SWIG file, remove the first line (the target); remove +## trailing " \" and " " from each line. Append ":" to each line, +## followed by 2 carriage returns, then append this to the end of +## the dependency file. +## + $(SED) -e '1d;s, \\,,g;s, ,,g' < $(DEPDIR)/noaa_swig.Std | \ + awk '{ printf "%s:\n\n", $$0 }' >> $(DEPDIR)/noaa_swig.d +## +## (5) remove the SWIG-generated file +## + $(RM) $(DEPDIR)/noaa_swig.Std +## +## Create the stamp for this filename generation, to signal success in +## executing this rule; allows other threads waiting on this process +## to continue. +## + touch $(DEPDIR)/noaa_swig-generate-stamp + +# KLUDGE: Force runtime include of a SWIG dependency file. This is +# not guaranteed to be portable, but will probably work. If it works, +# we have accurate dependencies for our swig stuff, which is good. + +@am__include@ @am__quote@./$(DEPDIR)/noaa_swig.d@am__quote@ + diff --git a/gr-noaa/swig/__init__.py b/gr-noaa/swig/__init__.py new file mode 100644 index 000000000..d8d337e65 --- /dev/null +++ b/gr-noaa/swig/__init__.py @@ -0,0 +1,28 @@ +# +# Copyright 2009 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. +# + +# The presence of this file turns this directory into a Python package + +# Add SWIG generated code to this namespace +from noaa_swig import * + +# Add other content from pure-Python modules here + diff --git a/gr-noaa/swig/noaa_hrpt_decoder.i b/gr-noaa/swig/noaa_hrpt_decoder.i new file mode 100644 index 000000000..ddf181c28 --- /dev/null +++ b/gr-noaa/swig/noaa_hrpt_decoder.i @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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. + */ + +GR_SWIG_BLOCK_MAGIC(noaa,hrpt_decoder) + +noaa_hrpt_decoder_sptr +noaa_make_hrpt_decoder(); + +class noaa_hrpt_decoder : public gr_sync_block +{ +private: + noaa_hrpt_decoder(); +}; diff --git a/gr-noaa/swig/noaa_hrpt_deframer.i b/gr-noaa/swig/noaa_hrpt_deframer.i new file mode 100644 index 000000000..6914b93e6 --- /dev/null +++ b/gr-noaa/swig/noaa_hrpt_deframer.i @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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. + */ + +GR_SWIG_BLOCK_MAGIC(noaa,hrpt_deframer) + +noaa_hrpt_deframer_sptr +noaa_make_hrpt_deframer(); + +class noaa_hrpt_deframer : public gr_block +{ +private: + noaa_hrpt_deframer(); +}; diff --git a/gr-noaa/swig/noaa_hrpt_pll_cf.i b/gr-noaa/swig/noaa_hrpt_pll_cf.i new file mode 100644 index 000000000..859548a2d --- /dev/null +++ b/gr-noaa/swig/noaa_hrpt_pll_cf.i @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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. + */ + +GR_SWIG_BLOCK_MAGIC(noaa,hrpt_pll_cf) + +noaa_hrpt_pll_cf_sptr +noaa_make_hrpt_pll_cf(float alpha, float beta, float max_offset); + +class noaa_hrpt_pll_cf : public gr_sync_block +{ +private: + noaa_hrpt_pll_cf(); + +public: + void set_alpha(float alpha); + void set_beta(float beta); + void set_max_offset(float min_freq); +}; diff --git a/gr-noaa/swig/noaa_hrpt_sync_fb.i b/gr-noaa/swig/noaa_hrpt_sync_fb.i new file mode 100644 index 000000000..a8e5b21dd --- /dev/null +++ b/gr-noaa/swig/noaa_hrpt_sync_fb.i @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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. + */ + +GR_SWIG_BLOCK_MAGIC(noaa,hrpt_sync_fb) + +noaa_hrpt_sync_fb_sptr +noaa_make_hrpt_sync_fb(float alpha, float beta, float sps, float max_offset); + +class noaa_hrpt_sync_fb : public gr_sync_block +{ +private: + noaa_hrpt_sync_fb(); + +public: + void set_alpha(float alpha); + void set_beta(float beta); + void set_max_offset(float min_freq); +}; diff --git a/gr-noaa/swig/noaa_swig.i b/gr-noaa/swig/noaa_swig.i new file mode 100644 index 000000000..e6497bc46 --- /dev/null +++ b/gr-noaa/swig/noaa_swig.i @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 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 "gnuradio.i" + +%{ +#include <noaa_hrpt_decoder.h> +#include <noaa_hrpt_deframer.h> +#include <noaa_hrpt_pll_cf.h> +#include <noaa_hrpt_sync_fb.h> +%} + +%include "noaa_hrpt_decoder.i" +%include "noaa_hrpt_deframer.i" +%include "noaa_hrpt_pll_cf.i" +%include "noaa_hrpt_sync_fb.i" diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 59ca215a7..fb21e4f44 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -50,17 +50,15 @@ bin_SCRIPTS = \ gr_plot_qt.py \ gr_filter_design.py \ lsusrp \ - qr_fft.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ usrp_rx_cfile.py \ usrp_rx_nogui.py \ usrp_siggen.py \ + usrp_siggen_gui.py \ usrp_test_counting.py \ usrp_test_loopback.py \ usrp2_fft.py \ - usrp2_rx_cfile.py \ - usrp2_siggen.py \ - usrp2_siggen_gui.py + usrp2_rx_cfile.py diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index a5e3463c8..f3dc472f5 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -7,14 +7,36 @@ except ImportError: print "Please install SciPy to run this script (http://www.scipy.org/)" raise SystemExit, 1 +try: + from matplotlib import mlab +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net)" + raise SystemExit, 1 + +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + # FIXME: reenable this before committing + #from gnuradio.pyqt_plot import Ui_MainWindow + from pyqt_plot import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_plot. Please build with \"pyuic4 pyqt_plot.ui -o pyqt_plot.py\"" + raise SystemExit, 1 + import sys, os -from PyQt4 import Qt, QtCore, QtGui -import PyQt4.Qwt5 as Qwt -from matplotlib import mlab from optparse import OptionParser from gnuradio import eng_notation -from pyqt_plot import Ui_MainWindow class SpectrogramData(Qwt.QwtRasterData): @@ -42,9 +64,12 @@ class SpectrogramData(Qwt.QwtRasterData): return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) def value(self, x, y): - f = int(self.freq.searchsorted(x)) - t = int(self.time.searchsorted(y)) - return self.sp[f][t-1] + try: + f = int(self.freq.searchsorted(x)) + t = int(self.time.searchsorted(y)) + return self.sp[f][t-1] + except AttributeError: # if no file loaded yet + return 0 class gr_plot_qt(QtGui.QMainWindow): @@ -53,6 +78,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui = Ui_MainWindow() self.gui.setupUi(self) + self.filename = None self.block_length = options.block_length self.start = options.start self.sample_rate = options.sample_rate @@ -61,6 +87,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.winfunc = scipy.blackman self.sizeof_data = 8 self.datatype = scipy.complex64 + self.pen_width = 1 self.iq = list() self.time = list() @@ -102,6 +129,18 @@ class gr_plot_qt(QtGui.QMainWindow): self.colorComboBoxEdit) + # Set up line style combo box + self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, + "Circle" : Qwt.QwtSymbol.Ellipse, + "Diamond" : Qwt.QwtSymbol.Rect, + "Triangle" : Qwt.QwtSymbol.Triangle} + self.gui.lineStyleComboBox.addItems(self.line_styles.keys()) + pos = self.gui.lineStyleComboBox.findText("None") + self.gui.lineStyleComboBox.setCurrentIndex(pos) + self.connect(self.gui.lineStyleComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.lineStyleComboBoxEdit) + # Create zoom functionality for the plots self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, self.gui.timePlot.yLeft, @@ -121,16 +160,6 @@ class gr_plot_qt(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.specPlot.canvas()) - self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, - self.gui.timePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPlotPicker.CrossRubberBand, - Qwt.QwtPicker.AlwaysOn, - self.gui.timePlot.canvas()) - self.picker.connect(self.picker, - Qt.SIGNAL('selected(const QwtDoublePoint&)'), - self.clickMe) - # Set up action when tab is changed self.connect(self.gui.tabGroup, Qt.SIGNAL("currentChanged (int)"), @@ -153,7 +182,14 @@ class gr_plot_qt(QtGui.QMainWindow): self.connect(self.gui.action_open, Qt.SIGNAL("activated()"), self.open_file) - + + # Connect Reload action to reload the file + self.connect(self.gui.action_reload, + Qt.SIGNAL("activated()"), + self.reload_file) + self.gui.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", + None, QtGui.QApplication.UnicodeUTF8)) + # Set up file position boxes to update current figure self.connect(self.gui.filePosStartLineEdit, Qt.SIGNAL("editingFinished()"), @@ -175,8 +211,20 @@ class gr_plot_qt(QtGui.QMainWindow): Qt.SIGNAL("editingFinished()"), self.file_time_length_changed) + stylestr = str(self.gui.lineStyleComboBox.currentText().toAscii()) + style = self.line_styles[stylestr] + self.rcurve = Qwt.QwtPlotCurve("Real") self.icurve = Qwt.QwtPlotCurve("Imaginary") + self.rsym = Qwt.QwtSymbol() + self.rsym.setStyle(style) + self.rsym.setSize(10) + self.isym = Qwt.QwtSymbol() + self.isym.setStyle(style) + self.isym.setSize(10) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.icurve.attach(self.gui.timePlot) self.rcurve.attach(self.gui.timePlot) @@ -208,6 +256,20 @@ class gr_plot_qt(QtGui.QMainWindow): # Set up initial color scheme self.color_modes["Blue on Black"]() + # When line width spin box changes, update the pen size + self.connect(self.gui.lineWidthSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_pen_width) + self.gui.lineWidthSpinBox.setRange(1, 10) + + # When style size spin box changes, update the pen size + self.connect(self.gui.styleSizeSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_style_size) + self.gui.styleSizeSpinBox.setRange(1, 20) + self.gui.styleSizeSpinBox.setValue(5) + + # Connect a signal for when the sample rate changes self.set_sample_rate(self.sample_rate) self.connect(self.gui.sampleRateLineEdit, @@ -222,10 +284,15 @@ class gr_plot_qt(QtGui.QMainWindow): def open_file(self): filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") if(filename != ""): - print filename + #print filename self.initialize(filename) + def reload_file(self): + if(self.filename): + self.initialize(self.filename) + def initialize(self, filename): + self.filename = filename self.hfile = open(filename, "r") self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) @@ -243,7 +310,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_psd() self.get_specgram() self.gui.plotHBar.setSliderPosition(0) - self.gui.plotHBar.setMaximum(self.signal_size) + self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) self.update_time_curves() @@ -253,7 +320,7 @@ class gr_plot_qt(QtGui.QMainWindow): def init_data_input(self): self.hfile.seek(0, os.SEEK_END) self.signal_size = self.hfile.tell()/self.sizeof_data - print "Sizeof File: ", self.signal_size + #print "Sizeof File: ", self.signal_size self.hfile.seek(0, os.SEEK_SET) def get_data(self, start, end): @@ -265,10 +332,8 @@ class gr_plot_qt(QtGui.QMainWindow): count=end-start) if(len(iq) < (end-start)): - end = len(iq) - self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end)) - self.gui.plotHBar.setMaximum(end) - self.gui.plotHBar.setSingleStep(end) + end = start + len(iq) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq))) self.file_length_changed() tstep = 1.0 / self.sample_rate @@ -305,9 +370,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.spec_f = f self.spec_t = t - def clickMe(self, qPoint): - print qPoint.x() - def psdFFTComboBoxEdit(self, fftSize): self.psdfftsize = fftSize.toInt()[0] self.get_psd() @@ -323,6 +385,14 @@ class gr_plot_qt(QtGui.QMainWindow): color_func = self.color_modes[colorstr] color_func() + def lineStyleComboBoxEdit(self, styleSelection): + stylestr = str(styleSelection.toAscii()) + self.rsym.setStyle(self.line_styles[stylestr]) + self.isym.setStyle(self.line_styles[stylestr]) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def sliderMoved(self, value): pos_start = value pos_end = value + self.gui.plotHBar.pageStep() @@ -382,7 +452,11 @@ class gr_plot_qt(QtGui.QMainWindow): # If there's a non-digit character, reset box else: - self.set_file_pos_box(self.cur_start, self.cur_stop) + try: + self.set_file_pos_box(self.cur_start, self.cur_stop) + except AttributeError: + pass + def file_time_changed(self): tstart = self.gui.fileTimeStartLineEdit.text().toDouble() @@ -517,25 +591,40 @@ class gr_plot_qt(QtGui.QMainWindow): def tabChanged(self, index): self.gui.timePlot.replot() self.gui.freqPlot.replot() + self.gui.specPlot.replot() + + def change_pen_width(self, width): + self.pen_width = width + colormode = str(self.gui.colorComboBox.currentText().toAscii()) + color_func = self.color_modes[colormode]() + def change_style_size(self, size): + self.rsym.setSize(size) + self.isym.setSize(size) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def color_black_on_white(self): blue = QtGui.qRgb(0x00, 0x00, 0xFF) red = QtGui.qRgb(0xFF, 0x00, 0x00) - blackBrush = Qt.QBrush(Qt.QColor("black")) - blueBrush = Qt.QBrush(Qt.QColor(blue)) - redBrush = Qt.QBrush(Qt.QColor(red)) + blackPen = Qt.QPen(Qt.QBrush(Qt.QColor("black")), self.pen_width) + bluePen = Qt.QPen(Qt.QBrush(Qt.QColor(blue)), self.pen_width) + redPen = Qt.QPen(Qt.QBrush(Qt.QColor(red)), self.pen_width) self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(blackPen) + self.timeZoomer.setRubberBandPen(blackPen) + self.freqZoomer.setTrackerPen(blackPen) + self.freqZoomer.setRubberBandPen(blackPen) + self.psdcurve.setPen(bluePen) + self.rcurve.setPen(bluePen) + self.icurve.setPen(redPen) + + self.rsym.setPen(bluePen) + self.isym.setPen(redPen) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -550,14 +639,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(whiteBrush, 1)) - self.rcurve.setPen(Qt.QPen(whiteBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -573,14 +661,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(greenBrush, 1)) - self.rcurve.setPen(Qt.QPen(greenBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -595,14 +682,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 74c43c3eb..98977da97 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Aug 25 18:18:14 2009 +# Created: Tue Sep 1 23:02:36 2009 # by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -12,7 +12,7 @@ from PyQt4 import QtCore, QtGui class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(927, 696) + MainWindow.resize(927, 718) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtGui.QGridLayout(self.centralwidget) @@ -20,8 +20,123 @@ class Ui_MainWindow(object): self.plotHBar = QtGui.QScrollBar(self.centralwidget) self.plotHBar.setOrientation(QtCore.Qt.Horizontal) self.plotHBar.setObjectName("plotHBar") - self.gridLayout.addWidget(self.plotHBar, 2, 0, 1, 2) - self.tabGroup = QtGui.QTabWidget(self.centralwidget) + self.gridLayout.addWidget(self.plotHBar, 1, 0, 1, 3) + self.filePosBox = QtGui.QGroupBox(self.centralwidget) + self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) + self.filePosBox.setObjectName("filePosBox") + self.gridLayout_4 = QtGui.QGridLayout(self.filePosBox) + self.gridLayout_4.setObjectName("gridLayout_4") + self.filePosLayout = QtGui.QFormLayout() + self.filePosLayout.setObjectName("filePosLayout") + self.filePosStartLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosStartLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosStartLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosStartLineEdit.setObjectName("filePosStartLineEdit") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit) + self.filePosStopLabel = QtGui.QLabel(self.filePosBox) + self.filePosStopLabel.setObjectName("filePosStopLabel") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel) + self.filePosStopLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosStopLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosStopLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosStopLineEdit.setObjectName("filePosStopLineEdit") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit) + self.filePosLengthLabel = QtGui.QLabel(self.filePosBox) + self.filePosLengthLabel.setObjectName("filePosLengthLabel") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel) + self.filePosLengthLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosLengthLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosLengthLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit) + self.filePosStartLabel = QtGui.QLabel(self.filePosBox) + self.filePosStartLabel.setObjectName("filePosStartLabel") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel) + self.gridLayout_4.addLayout(self.filePosLayout, 0, 0, 1, 1) + self.fileTimeLayout = QtGui.QFormLayout() + self.fileTimeLayout.setObjectName("fileTimeLayout") + self.fileTimeStartLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeStartLabel.setObjectName("fileTimeStartLabel") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel) + self.fileTimeStartLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeStartLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeStartLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit) + self.fileTimeStopLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeStopLabel.setObjectName("fileTimeStopLabel") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel) + self.fileTimeStopLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeStopLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeStopLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit) + self.fileTimeLengthLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel) + self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeLengthLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeLengthLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit) + self.gridLayout_4.addLayout(self.fileTimeLayout, 0, 1, 1, 1) + self.gridLayout.addWidget(self.filePosBox, 2, 0, 1, 1) + self.displayGroupBox = QtGui.QGroupBox(self.centralwidget) + self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) + self.displayGroupBox.setObjectName("displayGroupBox") + self.gridLayout_2 = QtGui.QGridLayout(self.displayGroupBox) + self.gridLayout_2.setObjectName("gridLayout_2") + self.colorComboBox = QtGui.QComboBox(self.displayGroupBox) + self.colorComboBox.setObjectName("colorComboBox") + self.gridLayout_2.addWidget(self.colorComboBox, 0, 0, 1, 2) + self.lineWidthSpinBox = QtGui.QSpinBox(self.displayGroupBox) + self.lineWidthSpinBox.setMinimumSize(QtCore.QSize(100, 0)) + self.lineWidthSpinBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.lineWidthSpinBox.setObjectName("lineWidthSpinBox") + self.gridLayout_2.addWidget(self.lineWidthSpinBox, 1, 1, 1, 1) + self.lineWidthLabel = QtGui.QLabel(self.displayGroupBox) + self.lineWidthLabel.setObjectName("lineWidthLabel") + self.gridLayout_2.addWidget(self.lineWidthLabel, 1, 0, 1, 1) + self.lineStyleLabel = QtGui.QLabel(self.displayGroupBox) + self.lineStyleLabel.setObjectName("lineStyleLabel") + self.gridLayout_2.addWidget(self.lineStyleLabel, 2, 0, 1, 1) + self.lineStyleComboBox = QtGui.QComboBox(self.displayGroupBox) + self.lineStyleComboBox.setMinimumSize(QtCore.QSize(100, 0)) + self.lineStyleComboBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.lineStyleComboBox.setObjectName("lineStyleComboBox") + self.gridLayout_2.addWidget(self.lineStyleComboBox, 2, 1, 1, 1) + self.styleSizeLabel = QtGui.QLabel(self.displayGroupBox) + self.styleSizeLabel.setObjectName("styleSizeLabel") + self.gridLayout_2.addWidget(self.styleSizeLabel, 3, 0, 1, 1) + self.styleSizeSpinBox = QtGui.QSpinBox(self.displayGroupBox) + self.styleSizeSpinBox.setMinimumSize(QtCore.QSize(100, 0)) + self.styleSizeSpinBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.styleSizeSpinBox.setObjectName("styleSizeSpinBox") + self.gridLayout_2.addWidget(self.styleSizeSpinBox, 3, 1, 1, 1) + self.gridLayout.addWidget(self.displayGroupBox, 2, 2, 1, 1) + self.sysGroupBox = QtGui.QGroupBox(self.centralwidget) + self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0)) + self.sysGroupBox.setObjectName("sysGroupBox") + self.formLayout = QtGui.QFormLayout(self.sysGroupBox) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.sampleRateLabel = QtGui.QLabel(self.sysGroupBox) + self.sampleRateLabel.setObjectName("sampleRateLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) + self.sampleRateLineEdit = QtGui.QLineEdit(self.sysGroupBox) + self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.sampleRateLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) + self.gridLayout.addWidget(self.sysGroupBox, 2, 1, 1, 1) + self.frame = QtGui.QFrame(self.centralwidget) + self.frame.setFrameShape(QtGui.QFrame.StyledPanel) + self.frame.setFrameShadow(QtGui.QFrame.Raised) + self.frame.setObjectName("frame") + self.gridLayout_3 = QtGui.QGridLayout(self.frame) + self.gridLayout_3.setObjectName("gridLayout_3") + self.tabGroup = QtGui.QTabWidget(self.frame) + self.tabGroup.setMinimumSize(QtCore.QSize(0, 0)) self.tabGroup.setObjectName("tabGroup") self.timeTab = QtGui.QWidget() self.timeTab.setObjectName("timeTab") @@ -41,14 +156,14 @@ class Ui_MainWindow(object): self.formLayout_4 = QtGui.QFormLayout(self.fftPropBox) self.formLayout_4.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_4.setObjectName("formLayout_4") + self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox) + self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel") + self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel) self.psdFFTComboBox = QtGui.QComboBox(self.fftPropBox) self.psdFFTComboBox.setMinimumSize(QtCore.QSize(96, 0)) self.psdFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215)) self.psdFFTComboBox.setObjectName("psdFFTComboBox") self.formLayout_4.setWidget(0, QtGui.QFormLayout.FieldRole, self.psdFFTComboBox) - self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox) - self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel") - self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel) self.horizontalLayout_2.addWidget(self.fftPropBox) self.freqPlot = Qwt5.QwtPlot(self.freqTab) self.freqPlot.setObjectName("freqPlot") @@ -75,87 +190,8 @@ class Ui_MainWindow(object): self.specPlot.setObjectName("specPlot") self.horizontalLayout_3.addWidget(self.specPlot) self.tabGroup.addTab(self.specTab, "") - self.gridLayout.addWidget(self.tabGroup, 1, 0, 1, 1) - self.filePosBox = QtGui.QGroupBox(self.centralwidget) - self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) - self.filePosBox.setObjectName("filePosBox") - self.formLayoutWidget_2 = QtGui.QWidget(self.filePosBox) - self.formLayoutWidget_2.setGeometry(QtCore.QRect(0, 20, 160, 92)) - self.formLayoutWidget_2.setObjectName("formLayoutWidget_2") - self.filePosLayout = QtGui.QFormLayout(self.formLayoutWidget_2) - self.filePosLayout.setObjectName("filePosLayout") - self.filePosStartLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosStartLabel.setObjectName("filePosStartLabel") - self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel) - self.filePosStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosStartLineEdit.setObjectName("filePosStartLineEdit") - self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit) - self.filePosStopLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosStopLabel.setObjectName("filePosStopLabel") - self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel) - self.filePosStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosStopLineEdit.setObjectName("filePosStopLineEdit") - self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit) - self.filePosLengthLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosLengthLabel.setObjectName("filePosLengthLabel") - self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel) - self.filePosLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit") - self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit) - self.formLayoutWidget_4 = QtGui.QWidget(self.filePosBox) - self.formLayoutWidget_4.setGeometry(QtCore.QRect(180, 20, 231, 92)) - self.formLayoutWidget_4.setObjectName("formLayoutWidget_4") - self.fileTimeLayout = QtGui.QFormLayout(self.formLayoutWidget_4) - self.fileTimeLayout.setObjectName("fileTimeLayout") - self.fileTimeStartLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeStartLabel.setObjectName("fileTimeStartLabel") - self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel) - self.fileTimeStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit") - self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit) - self.fileTimeStopLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeStopLabel.setObjectName("fileTimeStopLabel") - self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel) - self.fileTimeStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit") - self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit) - self.fileTimeLengthLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel") - self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel) - self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit") - self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit) - self.sysGroupBox = QtGui.QGroupBox(self.filePosBox) - self.sysGroupBox.setGeometry(QtCore.QRect(530, 0, 200, 120)) - self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0)) - self.sysGroupBox.setObjectName("sysGroupBox") - self.formLayoutWidget_3 = QtGui.QWidget(self.sysGroupBox) - self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 20, 191, 91)) - self.formLayoutWidget_3.setObjectName("formLayoutWidget_3") - self.formLayout_2 = QtGui.QFormLayout(self.formLayoutWidget_3) - self.formLayout_2.setObjectName("formLayout_2") - self.sampleRateLabel = QtGui.QLabel(self.formLayoutWidget_3) - self.sampleRateLabel.setObjectName("sampleRateLabel") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) - self.sampleRateLineEdit = QtGui.QLineEdit(self.formLayoutWidget_3) - self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(0, 0)) - self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) - self.displayGroupBox = QtGui.QGroupBox(self.filePosBox) - self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 120)) - self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) - self.displayGroupBox.setObjectName("displayGroupBox") - self.verticalLayoutWidget = QtGui.QWidget(self.displayGroupBox) - self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 20, 160, 91)) - self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget) - self.verticalLayout.setObjectName("verticalLayout") - self.colorComboBox = QtGui.QComboBox(self.verticalLayoutWidget) - self.colorComboBox.setObjectName("colorComboBox") - self.verticalLayout.addWidget(self.colorComboBox) - spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.verticalLayout.addItem(spacerItem) - self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) + self.gridLayout_3.addWidget(self.tabGroup, 0, 0, 1, 1) + self.gridLayout.addWidget(self.frame, 0, 0, 1, 3) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 24)) @@ -170,7 +206,10 @@ class Ui_MainWindow(object): self.action_open.setObjectName("action_open") self.action_exit = QtGui.QAction(MainWindow) self.action_exit.setObjectName("action_exit") + self.action_reload = QtGui.QAction(MainWindow) + self.action_reload.setObjectName("action_reload") self.menu_File.addAction(self.action_open) + self.menu_File.addAction(self.action_reload) self.menu_File.addAction(self.action_exit) self.menubar.addAction(self.menu_File.menuAction()) @@ -181,26 +220,30 @@ class Ui_MainWindow(object): def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) - self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) - self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8)) self.filePosBox.setTitle(QtGui.QApplication.translate("MainWindow", "File Position", None, QtGui.QApplication.UnicodeUTF8)) - self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) self.filePosStopLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop", None, QtGui.QApplication.UnicodeUTF8)) self.filePosLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "Length", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeStartLabel.setText(QtGui.QApplication.translate("MainWindow", "time start (sec)", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeStopLabel.setText(QtGui.QApplication.translate("MainWindow", "time stop (sec)", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "time length (sec)", None, QtGui.QApplication.UnicodeUTF8)) + self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.lineWidthLabel.setText(QtGui.QApplication.translate("MainWindow", "Line Width", None, QtGui.QApplication.UnicodeUTF8)) + self.lineStyleLabel.setText(QtGui.QApplication.translate("MainWindow", "Line Style", None, QtGui.QApplication.UnicodeUTF8)) + self.styleSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "Style Size", None, QtGui.QApplication.UnicodeUTF8)) self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8)) self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8)) - self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + self.action_reload.setText(QtGui.QApplication.translate("MainWindow", "&Reload", None, QtGui.QApplication.UnicodeUTF8)) from PyQt4 import Qwt5 diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index 19a62adf5..7244d24c9 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -6,7 +6,7 @@ <x>0</x> <y>0</y> <width>927</width> - <height>696</height> + <height>718</height> </rect> </property> <property name="windowTitle" > @@ -14,126 +14,14 @@ </property> <widget class="QWidget" name="centralwidget" > <layout class="QGridLayout" name="gridLayout" > - <item row="2" column="0" colspan="2" > + <item row="1" column="0" colspan="3" > <widget class="QScrollBar" name="plotHBar" > <property name="orientation" > <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QTabWidget" name="tabGroup" > - <property name="currentIndex" > - <number>0</number> - </property> - <widget class="QWidget" name="timeTab" > - <attribute name="title" > - <string>Time Domain</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout" > - <item> - <widget class="QwtPlot" name="timePlot" /> - </item> - </layout> - </widget> - <widget class="QWidget" name="freqTab" > - <attribute name="title" > - <string>Frequency Domain</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout_2" > - <item> - <widget class="QGroupBox" name="fftPropBox" > - <property name="minimumSize" > - <size> - <width>160</width> - <height>0</height> - </size> - </property> - <property name="title" > - <string>FFT Properties</string> - </property> - <layout class="QFormLayout" name="formLayout_4" > - <property name="fieldGrowthPolicy" > - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <item row="0" column="1" > - <widget class="QComboBox" name="psdFFTComboBox" > - <property name="minimumSize" > - <size> - <width>96</width> - <height>0</height> - </size> - </property> - <property name="maximumSize" > - <size> - <width>96</width> - <height>16777215</height> - </size> - </property> - </widget> - </item> - <item row="0" column="0" > - <widget class="QLabel" name="psdFFTSizeLabel" > - <property name="text" > - <string>FFT Size</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QwtPlot" name="freqPlot" /> - </item> - </layout> - </widget> - <widget class="QWidget" name="specTab" > - <attribute name="title" > - <string>Spectrogram</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout_3" > - <item> - <widget class="QGroupBox" name="groupBox" > - <property name="title" > - <string>Spectrogram Properties</string> - </property> - <layout class="QFormLayout" name="formLayout_3" > - <item row="1" column="0" > - <widget class="QLabel" name="specFFTLabel" > - <property name="text" > - <string>FFT Size</string> - </property> - </widget> - </item> - <item row="1" column="1" > - <widget class="QComboBox" name="specFFTComboBox" > - <property name="minimumSize" > - <size> - <width>96</width> - <height>0</height> - </size> - </property> - <property name="maximumSize" > - <size> - <width>96</width> - <height>16777215</height> - </size> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QwtPlot" name="specPlot" /> - </item> - </layout> - <zorder>specPlot</zorder> - <zorder>groupBox</zorder> - </widget> - </widget> - </item> - <item row="3" column="0" > + <item row="2" column="0" > <widget class="QGroupBox" name="filePosBox" > <property name="minimumSize" > <size> @@ -144,185 +32,416 @@ <property name="title" > <string>File Position</string> </property> - <widget class="QWidget" name="formLayoutWidget_2" > - <property name="geometry" > - <rect> - <x>0</x> - <y>20</y> - <width>160</width> - <height>92</height> - </rect> - </property> - <layout class="QFormLayout" name="filePosLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="filePosStartLabel" > - <property name="text" > - <string>Start</string> - </property> - </widget> - </item> - <item row="0" column="1" > - <widget class="QLineEdit" name="filePosStartLineEdit" /> - </item> - <item row="1" column="0" > - <widget class="QLabel" name="filePosStopLabel" > - <property name="text" > - <string>Stop</string> - </property> - </widget> - </item> - <item row="1" column="1" > - <widget class="QLineEdit" name="filePosStopLineEdit" /> - </item> - <item row="2" column="0" > - <widget class="QLabel" name="filePosLengthLabel" > - <property name="text" > - <string>Length</string> - </property> - </widget> - </item> - <item row="2" column="1" > - <widget class="QLineEdit" name="filePosLengthLineEdit" /> - </item> - </layout> - </widget> - <widget class="QWidget" name="formLayoutWidget_4" > - <property name="geometry" > - <rect> - <x>180</x> - <y>20</y> - <width>231</width> - <height>92</height> - </rect> - </property> - <layout class="QFormLayout" name="fileTimeLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="fileTimeStartLabel" > - <property name="text" > - <string>time start (sec)</string> - </property> - </widget> - </item> - <item row="0" column="1" > - <widget class="QLineEdit" name="fileTimeStartLineEdit" /> - </item> - <item row="1" column="0" > - <widget class="QLabel" name="fileTimeStopLabel" > - <property name="text" > - <string>time stop (sec)</string> - </property> - </widget> - </item> - <item row="1" column="1" > - <widget class="QLineEdit" name="fileTimeStopLineEdit" /> - </item> - <item row="2" column="0" > - <widget class="QLabel" name="fileTimeLengthLabel" > - <property name="text" > - <string>time length (sec)</string> - </property> - </widget> - </item> - <item row="2" column="1" > - <widget class="QLineEdit" name="fileTimeLengthLineEdit" /> - </item> - </layout> - </widget> - <widget class="QGroupBox" name="sysGroupBox" > - <property name="geometry" > - <rect> - <x>530</x> - <y>0</y> - <width>200</width> - <height>120</height> - </rect> - </property> - <property name="minimumSize" > - <size> - <width>200</width> - <height>0</height> - </size> - </property> - <property name="title" > - <string>System Properties</string> - </property> - <widget class="QWidget" name="formLayoutWidget_3" > - <property name="geometry" > - <rect> - <x>0</x> - <y>20</y> - <width>191</width> - <height>91</height> - </rect> - </property> - <layout class="QFormLayout" name="formLayout_2" > + <layout class="QGridLayout" name="gridLayout_4" > + <item row="0" column="0" > + <layout class="QFormLayout" name="filePosLayout" > + <item row="0" column="1" > + <widget class="QLineEdit" name="filePosStartLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="filePosStopLabel" > + <property name="text" > + <string>Stop</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="filePosStopLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="filePosLengthLabel" > + <property name="text" > + <string>Length</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="filePosLengthLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> <item row="0" column="0" > - <widget class="QLabel" name="sampleRateLabel" > + <widget class="QLabel" name="filePosStartLabel" > <property name="text" > - <string>Sample Rate</string> + <string>Start</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="1" > + <layout class="QFormLayout" name="fileTimeLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="fileTimeStartLabel" > + <property name="text" > + <string>time start (sec)</string> </property> </widget> </item> <item row="0" column="1" > - <widget class="QLineEdit" name="sampleRateLineEdit" > + <widget class="QLineEdit" name="fileTimeStartLineEdit" > <property name="minimumSize" > <size> - <width>0</width> + <width>50</width> <height>0</height> </size> </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> </widget> </item> - </layout> - </widget> - </widget> - <widget class="QGroupBox" name="displayGroupBox" > - <property name="geometry" > - <rect> - <x>730</x> - <y>0</y> - <width>170</width> - <height>120</height> - </rect> - </property> - <property name="minimumSize" > - <size> - <width>170</width> - <height>0</height> - </size> - </property> - <property name="title" > - <string>Display Properties</string> - </property> - <widget class="QWidget" name="verticalLayoutWidget" > - <property name="geometry" > - <rect> - <x>0</x> - <y>20</y> - <width>160</width> - <height>91</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout" > - <item> - <widget class="QComboBox" name="colorComboBox" /> + <item row="1" column="0" > + <widget class="QLabel" name="fileTimeStopLabel" > + <property name="text" > + <string>time stop (sec)</string> + </property> + </widget> </item> - <item> - <spacer name="verticalSpacer" > - <property name="orientation" > - <enum>Qt::Vertical</enum> + <item row="1" column="1" > + <widget class="QLineEdit" name="fileTimeStopLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="fileTimeLengthLabel" > + <property name="text" > + <string>time length (sec)</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="fileTimeLengthLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> </property> - <property name="sizeHint" stdset="0" > + <property name="maximumSize" > <size> - <width>20</width> - <height>40</height> + <width>100</width> + <height>16777215</height> </size> </property> - </spacer> + </widget> </item> </layout> - </widget> - </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="2" > + <widget class="QGroupBox" name="displayGroupBox" > + <property name="minimumSize" > + <size> + <width>170</width> + <height>0</height> + </size> + </property> + <property name="title" > + <string>Display Properties</string> + </property> + <layout class="QGridLayout" name="gridLayout_2" > + <item row="0" column="0" colspan="2" > + <widget class="QComboBox" name="colorComboBox" /> + </item> + <item row="1" column="1" > + <widget class="QSpinBox" name="lineWidthSpinBox" > + <property name="minimumSize" > + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="lineWidthLabel" > + <property name="text" > + <string>Line Width</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="lineStyleLabel" > + <property name="text" > + <string>Line Style</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QComboBox" name="lineStyleComboBox" > + <property name="minimumSize" > + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="styleSizeLabel" > + <property name="text" > + <string>Style Size</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QSpinBox" name="styleSizeSpinBox" > + <property name="minimumSize" > + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="1" > + <widget class="QGroupBox" name="sysGroupBox" > + <property name="minimumSize" > + <size> + <width>200</width> + <height>0</height> + </size> + </property> + <property name="title" > + <string>System Properties</string> + </property> + <layout class="QFormLayout" name="formLayout" > + <property name="fieldGrowthPolicy" > + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="sampleRateLabel" > + <property name="text" > + <string>Sample Rate</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="sampleRateLineEdit" > + <property name="minimumSize" > + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" colspan="3" > + <widget class="QFrame" name="frame" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_3" > + <item row="0" column="0" > + <widget class="QTabWidget" name="tabGroup" > + <property name="minimumSize" > + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="timeTab" > + <attribute name="title" > + <string>Time Domain</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="QwtPlot" name="timePlot" /> + </item> + </layout> + <zorder>timePlot</zorder> + </widget> + <widget class="QWidget" name="freqTab" > + <attribute name="title" > + <string>Frequency Domain</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_2" > + <item> + <widget class="QGroupBox" name="fftPropBox" > + <property name="minimumSize" > + <size> + <width>160</width> + <height>0</height> + </size> + </property> + <property name="title" > + <string>FFT Properties</string> + </property> + <layout class="QFormLayout" name="formLayout_4" > + <property name="fieldGrowthPolicy" > + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="psdFFTSizeLabel" > + <property name="text" > + <string>FFT Size</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QComboBox" name="psdFFTComboBox" > + <property name="minimumSize" > + <size> + <width>96</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>96</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + <zorder>psdFFTSizeLabel</zorder> + <zorder>psdFFTComboBox</zorder> + </widget> + </item> + <item> + <widget class="QwtPlot" name="freqPlot" /> + </item> + </layout> + </widget> + <widget class="QWidget" name="specTab" > + <attribute name="title" > + <string>Spectrogram</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_3" > + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Spectrogram Properties</string> + </property> + <layout class="QFormLayout" name="formLayout_3" > + <item row="1" column="0" > + <widget class="QLabel" name="specFFTLabel" > + <property name="text" > + <string>FFT Size</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="specFFTComboBox" > + <property name="minimumSize" > + <size> + <width>96</width> + <height>0</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>96</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QwtPlot" name="specPlot" /> + </item> + </layout> + <zorder>specPlot</zorder> + <zorder>groupBox</zorder> + </widget> + </widget> + </item> + </layout> + <zorder>tabGroup</zorder> </widget> </item> </layout> @@ -341,6 +460,7 @@ <string>&File</string> </property> <addaction name="action_open" /> + <addaction name="action_reload" /> <addaction name="action_exit" /> </widget> <addaction name="menu_File" /> @@ -359,6 +479,11 @@ <string>E&xit</string> </property> </action> + <action name="action_reload" > + <property name="text" > + <string>&Reload</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py deleted file mode 100755 index c2f06d715..000000000 --- a/gr-utils/src/python/qr_fft.py +++ /dev/null @@ -1,505 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2009 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.wxgui import forms -from gnuradio import gr, gru -from gnuradio import vrt -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider -from gnuradio.gr import pubsub -from optparse import OptionParser -import wx -import sys -import numpy -import time - -class app_top_block(stdgui2.std_top_block, pubsub.pubsub): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - pubsub.pubsub.__init__(self) - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - #parser.add_option("-e", "--interface", type="string", default="eth0", - # help="select Ethernet interface, default is eth0") - #parser.add_option("-m", "--mac-addr", type="string", default="", - # help="select USRP by MAC address, default is auto-select") - #parser.add_option("-A", "--antenna", default=None, - # help="select Rx Antenna (only on RFX-series boards)") - #parser.add_option("-d", "--decim", type="int", default=16, - # help="set fgpa decimation rate to DECIM [default=%default]") - #parser.add_option("-f", "--freq", type="eng_float", default=None, - # help="set frequency to FREQ", metavar="FREQ") - #parser.add_option("-g", "--gain", type="eng_float", default=None, - # help="set gain in dB (default is midpoint)") - parser.add_option("-W", "--waterfall", action="store_true", default=False, - help="Enable waterfall display") - parser.add_option("-S", "--oscilloscope", action="store_true", default=False, - help="Enable oscilloscope display") - parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, default=[%default]") - parser.add_option("", "--ref-scale", type="eng_float", default=1.0, - help="Set dBFS=0dB input value, default=[%default]") - parser.add_option("--fft-size", type="int", default=1024, - help="Set number of FFT bins [default=%default]") - parser.add_option("--samples-per-pkt", type="int", default=0, - help="Set number of SAMPLES-PER-PKT [default=%default]") - parser.add_option("", "--ip-addr", type="string", default="192.168.10.2", - help="IP address default=[%default]") - (options, args) = parser.parse_args() - if len(args) != 0: - parser.print_help() - sys.exit(1) - self.options = options - self.show_debug_info = True - - self.u = vrt.quadradio_source_32fc(options.ip_addr, - int(62.5e6), options.samples_per_pkt) - #self.u.set_decim(options.decim) - - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = int(120e6/4) - - if options.waterfall: - self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) - elif options.oscilloscope: - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) - else: - self.scope = fftsink2.fft_sink_c (panel, - fft_size=options.fft_size, - sample_rate=input_rate, - ref_scale=options.ref_scale, - ref_level=20.0, - y_divs = 12, - avg_alpha=options.avg_alpha) - - self.connect(self.u, self.scope) - - self._build_gui(vbox) - self._setup_events() - - # set initial values - - #if options.gain is None: - # # if no gain was specified, use the mid-point in dB - # g = self.u.gain_range() - # options.gain = float(g[0]+g[1])/2 - - #if options.freq is None: - # # if no freq was specified, use the mid-point - # r = self.u.freq_range() - # options.freq = float(r[0]+r[1])/2 - - #self.set_gain(options.gain) - - #if options.antenna is not None: - # print "Selecting antenna %s" % (options.antenna,) - # self.subdev.select_rx_antenna(options.antenna) - - if self.show_debug_info: - # self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - # self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - - #if not(self.set_freq(options.freq)): - # self._set_status_msg("Failed to set initial frequency") - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=hbox, label="Center freq", weight=1, - callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) - - hbox.Add((5,0), 0, 0) - #g = self.u.gain_range() - - # some configurations don't have gain control - if 0 and g[1] > g[0]: - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,0), 0, 0) - vbox.Add(hbox, 0, wx.EXPAND) - - self._build_subpanel(vbox) - - def _build_subpanel(self, vbox_arg): - # build a secondary information panel (sometimes hidden) - - # FIXME figure out how to have this be a subpanel that is always - # created, but has its visibility controlled by foo.Show(True/False) - - def _form_set_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@gbe'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@GbE") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - ##### db control stuff ##### - self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01)) - self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq - self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01)) - self.subscribe('db_ctrl_atten0', self.u.set_attenuation0) - self.subscribe('db_ctrl_atten1', self.u.set_attenuation1) - self.subscribe('sys_beaming', self.u.set_beamforming) - #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten) - self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain) - self.subscribe('db_ctrl_diggain', self.u.set_digital_gain) - self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp) - self.subscribe('db_ctrl_bandsel', self.u.set_band_select) - self.subscribe('db_ctrl_type', self.u.select_rx_antenna) - self.subscribe('db_test_signal', self.u.set_test_signal) - self['db_ctrl_bandsel'] = 'A' - self['cal_div_lo_freq'] = 2.1e9 - self['cal_div_cal_freq'] = 2.102e9 - self['db_ctrl_atten0'] = 0 - self['db_ctrl_atten1'] = 0 - #self['db_ctrl_10db'] = False - self['db_ctrl_adcgain'] = False - self['db_ctrl_dcoffset'] = False - self['db_ctrl_diggain'] = 0.0 - self['db_ctrl_type'] = 'rf' - self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL - self['sys_beaming'] = [16.7e6, 0, 0, 0] - #slider and box for freqs - for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')): - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - forms.text_box( - label=name, - ps=self, - key=key, - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key=key, - minimum=0, #TODO get bounds from cal_div, from vrt... - maximum=int(3.5e9), - step_size=int(5e6), - cast=float, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - ############################################ - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create slider for atten - atten0_txt_box = forms.static_text( - label='Attenuation (0)', - ps=self, - key='db_ctrl_atten0', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - atten0_slider = forms.slider( - ps=self, - key='db_ctrl_atten0', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - #create slider for atten - forms.static_text( - label='Attenuation (1)', - ps=self, - key='db_ctrl_atten1', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key='db_ctrl_atten1', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - def update_atten0(*args): - for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B') - update_atten0() - self.subscribe('db_ctrl_bandsel', update_atten0) - #create checkbox for 10dB att - #forms.check_box( - # label='10dB Attenuation', - # ps=self, - # key='db_ctrl_10db', - # sizer=hbox, - # parent=panel, - # proportion=1, - #) - #hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - hbox2 = wx.BoxSizer(wx.HORIZONTAL) - hbox2.AddSpacer(10) - forms.static_text( - label='ADC Controls', - ps=self, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox2.AddSpacer(20) - #create checkbox for ADC digital gain - forms.slider( - #label='ADC Digital Gain', - ps=self, - minimum=0, - maximum=6, - step_size=0.5, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - #create checkbox for 3.5dB ADC gain - forms.check_box( - label='3.5dB ADC Gain', - ps=self, - key='db_ctrl_adcgain', - sizer=hbox2, - parent=panel, - proportion=1, - ) - hbox2.AddSpacer(10) - #create checkbox for DC Offset Correction in ADC - forms.check_box( - label='DC Offset Correction', - ps=self, - key='db_ctrl_dcoffset', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - vbox.Add(hbox2, 0, wx.EXPAND) - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create radio buttons for band sel - forms.radio_buttons( - label='Band Select', - ps=self, - key='db_ctrl_bandsel', - choices=['A', 'B', 'C', 'D'], - labels=['A', 'B', 'C', 'D'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - forms.radio_buttons( - label='RF Input', - ps=self, - key='db_ctrl_type', - choices=['rf', 'cal'], - labels=['Main RF', 'Calibrator'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for band sel - types = sorted( - filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)), - lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)), - ) - forms.drop_down( - label='Test Signal', - ps=self, - key='db_test_signal', - choices=map(lambda a: getattr(vrt, a), types), - labels=types, - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for type - forms.drop_down( - label='Beamformer', - ps=self, - key='sys_beaming', - choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4], - labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - return True - - r = self.u.set_center_freq(target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.oscilloscope: - self.scope.win.set_baseband_freq(target_freq) - return True - - return False - - def set_gain(self, gain): - return True - - if self.myform.has_key('gain'): - self.myform['gain'].set_value(gain) # update displayed value - self.u.set_gain(gain) - - def set_decim(self, decim): - return True - - ok = self.u.set_decim(decim) - if not ok: - print "set_decim failed" - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = 120e6/4 - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - return ok - - def _setup_events(self): - if not self.options.waterfall and not self.options.oscilloscope: - self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) - - def evt_left_dclick(self, event): - (ux, uy) = self.scope.win.GetXY(event) - if event.CmdDown(): - # Re-center on maximum power - points = self.scope.win._points - if self.scope.win.peak_hold: - if self.scope.win.peak_vals is not None: - ind = numpy.argmax(self.scope.win.peak_vals) - else: - ind = int(points.shape()[0]/2) - else: - ind = numpy.argmax(points[:,1]) - (freq, pwr) = points[ind] - target_freq = freq/self.scope.win._scale_factor - print ind, freq, pwr - self.set_freq(target_freq) - else: - # Re-center on clicked frequency - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) - - -def main (): - app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py deleted file mode 100755 index 9ade933c7..000000000 --- a/gr-utils/src/python/usrp2_siggen.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2009 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, eng_notation, usrp2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys -import math - -n2s = eng_notation.num_to_str - -waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", - gr.GR_CONST_WAVE : "Constant", - gr.GR_GAUSSIAN : "Gaussian Noise", - gr.GR_UNIFORM : "Uniform Noise", - "2tone" : "Two Tone", - "sweep" : "Sweep" } - -# -# GUI-unaware GNU Radio flowgraph. This may be used either with command -# line applications or GUI applications. -# -class top_block(gr.top_block): - def __init__(self, options, args): - gr.top_block.__init__(self) - self._verbose = options.verbose - - self._interp = 0 - self._gain = 0 - self._freq = None # Indicates frequency hasn't been successfully set yet - self._bb_freq = 0 - self._ddc_freq = 0 - self._amplitude = 0 - self._type = None # Indicates waveform flowgraph not created yet - self._offset = options.offset - - self.set_usrp2(options.interface, options.mac_addr) - self.set_interp(options.interp) - self.set_gain(options.gain) - self.set_freq(options.tx_freq, options.lo_offset) - self.set_amplitude(options.amplitude) - - self.set_waveform_freq(options.waveform_freq) - self.set_waveform2_freq(options.waveform2_freq) - self.set_waveform(options.type) - - def set_usrp2(self, interface, mac_addr): - self._u = usrp2.sink_32fc(interface, mac_addr) - self._dac_rate = self._u.dac_rate() - if self._verbose: - print "Network interface:", interface - print "Network address:", self._u.mac_addr() - print "Daughterboard ID:", hex(self._u.daughterboard_id()) - - def set_interp(self, interp): - if interp < 4 or interp > 512: # FIXME get from flowgraph - if self._verbose: print "Interpolation rate out of range:", interp - return False - - if not self._u.set_interp(interp): - raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - - self._interp = interp - self._eth_rate = self._dac_rate/self._interp - if self._verbose: - print "USRP2 interpolation rate:", self._interp - print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),) - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE): - self._src.set_sampling_freq(self._eth_rate) - elif self._type == "2tone": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._eth_rate) - elif self._type == "sweep": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate) - else: - return True # Waveform not yet set - - if self._verbose: print "Set interpolation rate to:", interp - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - self._ddc_freq = tr.dxc_freq - self._bb_freq = tr.baseband_freq - if self._verbose: - print "Set center frequency to", fs - print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) - print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) - print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) - - return tr - - def set_waveform_freq(self, freq): - self._waveform_freq = freq - if self._type == gr.GR_SIN_WAVE: - self._src.set_frequency(freq) - elif self._type == "2tone" or self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform2_freq(self, freq): - self._waveform2_freq = freq - if self._type == "2tone": - self._src2.set_frequency(freq) - elif self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform(self, type): - self.lock() - self.disconnect_all() - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(self._eth_rate, # Sample rate - type, # Waveform type - self._waveform_freq, # Waveform frequency - self._amplitude, # Waveform amplitude - self._offset) # Waveform offset - elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(type, self._amplitude) - elif type == "2tone": - self._src1 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform_freq, - self._amplitude/2.0, - 0) - if(self._waveform2_freq is None): - self._waveform2_freq = -self._waveform_freq - - self._src2 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform2_freq, - self._amplitude/2.0, - 0) - self._src = gr.add_cc() - self.connect(self._src1,(self._src,0)) - self.connect(self._src2,(self._src,1)) - elif type == "sweep": - # rf freq is center frequency - # waveform_freq is total swept width - # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - if self._waveform2_freq is None: - self._waveform2_freq = 0.1 - - self._src1 = gr.sig_source_f(self._eth_rate, - gr.GR_TRI_WAVE, - self._waveform2_freq, - 1.0, - -0.5) - self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate) - self._src = gr.multiply_const_cc(self._amplitude) - self.connect(self._src1,self._src2,self._src) - else: - raise RuntimeError("Unknown waveform type") - - self.connect(self._src, self._u) - self._type = type - self.unlock() - - if self._verbose: - print "Set baseband modulation to:", waveforms[self._type] - if type == gr.GR_SIN_WAVE: - print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),) - print "Initial phase:", self._offset - elif type == "2tone": - print "Tone 1: %sHz" % (n2s(self._waveform_freq),) - print "Tone 2: %sHz" % (n2s(self._waveform2_freq),) - elif type == "sweep": - print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0)) - print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),) - print "TX amplitude:", self._amplitude - - - def set_amplitude(self, amplitude): - if amplitude < 0.0 or amplitude > 1.0: - if self._verbose: print "Amplitude out of range:", amplitude - return False - - self._amplitude = amplitude - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE or - self._type == gr.GR_GAUSSIAN or - self._type == gr.GR_UNIFORM): - self._src.set_amplitude(amplitude) - elif self._type == "2tone": - self._src1.set_amplitude(amplitude/2.0) - self._src2.set_amplitude(amplitude/2.0) - elif self._type == "sweep": - self._src.set_k(amplitude) - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - - # Property getters - - def mac_addr(self): - return self._u.mac_addr() - - def interface_name(self): - return self._u.interface_name() - - def daughterboard_id(self): - return self._u.daughterboard_id() - - def interp_rate(self): - return self._interp - - def eth_rate(self): - return self._eth_rate - - def freq(self): - return self._freq - - def freq_range(self): - return self._u.freq_range() - - def ddc_freq(self): - return self._ddc_freq - - def baseband_freq(self): - return self._bb_freq - - def amplitude(self): - return self._amplitude - - def waveform_type(self): - return self._type - - def waveform_freq(self): - return self._waveform_freq - - def waveform2_freq(self): - if self._waveform2_freq is None: - return -self._waveform_freq - else: - return self._waveform2_freq - -def get_options(): - usage="%prog: [options]" - - parser = OptionParser(option_class=eng_option, usage=usage) - - parser.add_option("-e", "--interface", type="string", default="eth0", - help="Use specified Ethernet interface [default=%default]") - parser.add_option("-m", "--mac-addr", type="string", default="", - help="Use USRP2 at specified MAC address [default=None]") - parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP", - help="Set FPGA interpolation rate of INTERP [default=%default]") - parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") - parser.add_option("--lo-offset", type="eng_float", default=None, - help="set daughterboard LO offset to OFFSET [default=hw default]") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="Set TX gain to GAIN [default=mid-point]") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, - help="Set baseband waveform frequency to FREQ [default=%default]") - parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, - help="Set 2nd waveform frequency to FREQ [default=%default]") - parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) - parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="Generate a constant carrier") - parser.add_option("--offset", type="eng_float", default=0, - help="Set waveform phase offset to OFFSET [default=%default]") - parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="Generate Gaussian random output") - parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="Generate Uniform random output") - parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - help="Generate Two Tone signal for IMD testing") - parser.add_option("--sweep", dest="type", action="store_const", const="sweep", - help="Generate a swept sine wave") - parser.add_option("-a", "--amplitude", type="eng_float", default=0.1, - help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="Use verbose console output [default=%default]") - - (options, args) = parser.parse_args() - - return (options, args) - -# If this script is executed, the following runs. If it is imported, the below does not run. -if __name__ == "__main__": - if gr.enable_realtime_scheduling() != gr.RT_OK: - print "Note: failed to enable realtime scheduling, continuing" - - # Grab command line options and create top block - try: - (options, args) = get_options() - tb = top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - - # Run it - try: - tb.run() - - except KeyboardInterrupt: - pass diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py deleted file mode 100755 index 89bc6e589..000000000 --- a/gr-utils/src/python/usrp2_siggen_gui.py +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import wx -from gnuradio.wxgui import form, slider, gui -import usrp2_siggen -import sys, math - -class app_gui(object): - def __init__(self, frame, panel, vbox, top_block, options, args): - self.frame = frame # Use for top-level application window frame - self.panel = panel # Use as parent class for created windows - self.vbox = vbox # Use as sizer for created windows - self.tb = top_block # GUI-unaware flowgraph class - self.options = options # Supplied command-line options - self.args = args # Supplied command-line arguments - - freq_range = self.tb.freq_range() - self.min_freq = freq_range[0] - self.max_freq = freq_range[1] - self.freq_step = (self.max_freq-self.min_freq)/100.0 - self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items()) - - self.build_gui() - - # TODO: turn these into listeners - self.myform['ifc'].set_value(self.tb.interface_name()) - self.myform['mac'].set_value(self.tb.mac_addr()) - dbid = self.tb.daughterboard_id() - self.myform['dbid'].set_value("%04x" % (dbid,)) - - w = usrp2_siggen.waveforms[self.tb.waveform_type()] - self.myform['type'].set_value(w) - self.myform['w1freq'].set_value(self.tb.waveform_freq()) - self.myform['w2freq'].set_value(self.tb.waveform2_freq()) - - freq = self.tb.freq() - if freq is None: - self.evt_set_status_msg("Failed to set initial frequency") - else: - self.myform['freq'].set_value(freq) - self.myform['freq_slider'].set_value(self.tb.freq()) - - amp = self.tb.amplitude() - if (amp > 0.0): - db = 20*math.log10(amp) - else: - db = -100.0 - self.myform['amp'].set_value(amp) - self.myform['amp_slider'].set_value(db) - self.myform['eth'].set_value(self.tb.eth_rate()) - self.myform['gbe'].set_value(self.tb.eth_rate()*32) - self.myform['interp'].set_value(self.tb.interp_rate()) - self.myform['DDC'].set_value(self.tb.ddc_freq()) - self.myform['analog'].set_value(self.tb.baseband_freq()) - - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) - - def evt_set_freq1(self, kv): - return self.tb.set_waveform_freq(kv['w1freq']) - - def evt_set_freq2(self, kv): - return self.tb.set_waveform2_freq(kv['w2freq']) - - def evt_set_freq(self, kv): - if type(kv) == type(0.0): # Set from slider - tr = self.tb.set_freq(kv) - if tr is not None: - self.myform['freq'].set_value(kv) - else: # Set from edit box - f = kv['freq'] - tr = self.tb.set_freq(f) - if tr is not None: - self.myform['freq_slider'].set_value(f) - - if tr is not None: - self.myform['DDC'].set_value(tr.dxc_freq) - self.myform['analog'].set_value(tr.baseband_freq) - - return (tr is not None) - - def evt_set_amplitude(self, kv): - if type(kv) == type(0.0): # Set from slider - amp = math.pow(10, kv/20.0) - self.myform['amp'].set_value(amp) - return self.tb.set_amplitude(amp) - else: # Set from edit box - amp = kv['amp'] - if amp < 0.0 or amp > 1.0: - return False - if amp == 0.0: - db = -100.0 - else: - db = 20*math.log10(amp) - self.myform['amp_slider'].set_value(db) - return self.tb.set_amplitude(amp) - - def evt_set_interp(self): - interp = self.myform['interp'].get_value() - if self.tb.set_interp(interp): - eth_rate = self.tb.eth_rate() - self.myform['eth'].set_value(eth_rate) - self.myform['gbe'].set_value(eth_rate*32) - return True - return False - - def evt_set_waveform_type(self, type): - # TODO: update frequency labels - return self.tb.set_waveform(self._types[type]) - - # GUI construction - def build_gui(self): - self.myform = myform = form.form() - - # Baseband controls - bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation") - bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit - - # First row of baseband controls (modulation type) - mod_hbox = wx.BoxSizer(wx.HORIZONTAL) - mod_hbox.Add((10,0), 0, 0) - myform['type'] = form.radiobox_field( - parent=self.panel, label="Type", sizer=mod_hbox, value=None, - callback=self.evt_set_waveform_type, weight=1, major_dimension=0, - choices=usrp2_siggen.waveforms.values() ) - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(mod_hbox, 0, wx.EXPAND) - - # Second row of baseband controls (frequencies) - bbf_hbox = wx.BoxSizer(wx.HORIZONTAL) - bbf_hbox.Add((10,0), 0, 0) - myform['w1freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - myform['w2freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(bbf_hbox, 0, wx.EXPAND) - - # Add baseband controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - - # Frequency controls - fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency") - fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit - - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - freq_hbox.Add((10,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=freq_hbox, label=None, weight=1, - callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) ) - freq_hbox.Add((10,0), 0, 0) - myform['freq_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4, - range = (self.min_freq, self.max_freq, self.freq_step), - callback=self.evt_set_freq) - freq_hbox.Add((10,0), 0, 0) - - fc_vbox.Add((10,0), 0, 0) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - tr_hbox.Add((10,0), 0, 0) - myform['analog'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - myform['DDC'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - - # Add frequency controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - - # Amplitude row - amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude") - amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL) - amp_hbox.Add((10,0), 0, 0) - myform['amp'] = form.float_field( - parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1, - callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) ) - amp_hbox.Add((10,0), 0, 0) - myform['amp_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4, - range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude) - amp_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - - # Sample rate row - sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate") - sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL) - sam_hbox.Add((10,0), 0, 0) - myform['interp'] = form.int_field( - parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1, - callback=self.evt_set_interp) - sam_hbox.Add((10,0), 0, 0) - myform['eth'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1) - sam_hbox.Add((10,0), 0, 0) - myform['gbe'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1) - sam_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - - # USRP2 row - u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware") - u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL) - u2_hbox.Add((10,0), 0, 0) - myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Interface", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="MAC Address", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Daughterboard ID", weight=1) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.Add((0,20), 0, 0) - -if __name__ == "__main__": - try: - # Get command line parameters - (options, args) = usrp2_siggen.get_options() - - # Create the top block using these - tb = usrp2_siggen.top_block(options, args) - - # Create the GUI application - app = gui.app(top_block=tb, # Constructed top block - gui=app_gui, # User interface class - options=options, # Command line options - args=args, # Command line args - title="USRP2 Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 8ae2fbfbf..8ee8cfd2a 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,200 +20,307 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru -from gnuradio import usrp +DESC_KEY = 'desc' +SAMP_RATE_KEY = 'samp_rate' +LINK_RATE_KEY = 'link_rate' +DAC_RATE_KEY = 'dac_rate' +INTERP_KEY = 'interp' +GAIN_KEY = 'gain' +TX_FREQ_KEY = 'tx_freq' +DDC_FREQ_KEY = 'ddc_freq' +BB_FREQ_KEY = 'bb_freq' +AMPLITUDE_KEY = 'amplitude' +AMPL_RANGE_KEY = 'ampl_range' +WAVEFORM_FREQ_KEY = 'waveform_freq' +WAVEFORM_OFFSET_KEY = 'waveform_offset' +WAVEFORM2_FREQ_KEY = 'waveform2_freq' +FREQ_RANGE_KEY = 'freq_range' +GAIN_RANGE_KEY = 'gain_range' +TYPE_KEY = 'type' + +def setter(ps, key, val): ps[key] = val + +from gnuradio import gr, eng_notation +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option -from gnuradio import eng_notation +from gnuradio import usrp_options from optparse import OptionParser import sys +import math +n2s = eng_notation.num_to_str -class my_top_block(gr.top_block): - def __init__ (self, nsamples): +waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", + gr.GR_CONST_WAVE : "Constant", + gr.GR_GAUSSIAN : "Gaussian Noise", + gr.GR_UNIFORM : "Uniform Noise", + "2tone" : "Two Tone", + "sweep" : "Sweep" } + +# +# GUI-unaware GNU Radio flowgraph. This may be used either with command +# line applications or GUI applications. +# +class top_block(gr.top_block, pubsub): + def __init__(self, options, args): gr.top_block.__init__(self) + pubsub.__init__(self) + self._verbose = options.verbose + #initialize values from options + self._setup_usrpx(options) + self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i)) + self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32)) + self[INTERP_KEY] = options.interp or 16 + self[TX_FREQ_KEY] = options.tx_freq + self[AMPLITUDE_KEY] = options.amplitude + self[WAVEFORM_FREQ_KEY] = options.waveform_freq + self[WAVEFORM_OFFSET_KEY] = options.offset + self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq + self[BB_FREQ_KEY] = 0 + self[DDC_FREQ_KEY] = 0 + #subscribe set methods + self.subscribe(INTERP_KEY, self.set_interp) + self.subscribe(GAIN_KEY, self.set_gain) + self.subscribe(TX_FREQ_KEY, self.set_freq) + self.subscribe(AMPLITUDE_KEY, self.set_amplitude) + self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) + self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) + self.subscribe(TYPE_KEY, self.set_waveform) + #force update on pubsub keys + for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY, + AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): + self[key] = self[key] + self[TYPE_KEY] = options.type #set type last + + def _setup_usrpx(self, options): + self._u = usrp_options.create_usrp_sink(options) + self.publish(DESC_KEY, lambda: str(self._u)) + self.publish(DAC_RATE_KEY, self._u.dac_rate) + self.publish(FREQ_RANGE_KEY, self._u.freq_range) + self.publish(GAIN_RANGE_KEY, self._u.gain_range) + self.publish(GAIN_KEY, self._u.gain) + if self._verbose: print str(self._u) + + def _set_tx_amplitude(self, ampl): + """ + Sets the transmit amplitude sent to the USRP + @param ampl the amplitude or None for automatic + """ + ampl_range = self[AMPL_RANGE_KEY] + if ampl is None: ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0] + self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) + + def set_interp(self, interp): + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) + + if self._verbose: + print "USRP interpolation rate:", interp + print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),) + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "2tone": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "sweep": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + else: + return True # Waveform not yet set - # controllable values - self.interp = 64 - self.waveform_type = gr.GR_SIN_WAVE - self.waveform_ampl = 16000 - self.waveform_freq = 100.12345e3 - self.waveform_offset = 0 - self.nsamples = nsamples - self._instantiate_blocks () - self.set_waveform_type (self.waveform_type) - - def usb_freq (self): - return self.u.dac_freq() / self.interp - - def usb_throughput (self): - return self.usb_freq () * 4 - - def set_waveform_type (self, type): - ''' - valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, - gr.GR_UNIFORM and gr.GR_GAUSSIAN - ''' - self._configure_graph (type) - self.waveform_type = type - - def set_waveform_ampl (self, ampl): - self.waveform_ampl = ampl - self.siggen.set_amplitude (ampl) - self.noisegen.set_amplitude (ampl) - - def set_waveform_freq (self, freq): - self.waveform_freq = freq - self.siggen.set_frequency (freq) - - def set_waveform_offset (self, offset): - self.waveform_offset = offset - self.siggen.set_offset (offset) - - def set_interpolator (self, interp): - self.interp = interp - self.siggen.set_sampling_freq (self.usb_freq ()) - self.u.set_interp_rate (interp) - - def _instantiate_blocks (self): - self.src = None - self.u = usrp.sink_c (0, self.interp) - - self.siggen = gr.sig_source_c (self.usb_freq (), - gr.GR_SIN_WAVE, - self.waveform_freq, - self.waveform_ampl, - self.waveform_offset) - - self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, - self.waveform_ampl) - - self.head = None - if self.nsamples > 0: - self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples)) - - # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") - - def _configure_graph (self, type): - try: - self.lock() - self.disconnect_all () - - if self.head: - self.connect(self.head, self.u) - tail = self.head - else: - tail = self.u - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, tail) - # self.connect (self.siggen, self.file_sink) - self.siggen.set_waveform (type) - self.src = self.siggen - elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, tail) - self.noisegen.set_type (type) - self.src = self.noisegen - else: - raise ValueError, type - finally: - self.unlock() + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: + g = self[GAIN_RANGE_KEY] + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self[GAIN_KEY] = gain + return + self._u.set_gain(gain) + if self._verbose: + print "Set TX gain to:", gain def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital up converter. - """ - r = self.u.tune(self.subdev.which(), self.subdev, target_freq) - if r: - #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) - #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) - #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) - #print "r.inverted =", r.inverted - return True - - return False - - - -def main (): - parser = OptionParser (option_class=eng_option) - parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0), - help="select USRP Tx side A or B") - parser.add_option ("-f", "--rf-freq", type="eng_float", default=None, - help="set RF center frequency to FREQ") - parser.add_option ("-i", "--interp", type="int", default=64, - help="set fgpa interpolation rate to INTERP [default=%default]") - - parser.add_option ("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) - parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") - parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") - parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") - - parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, - help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") - parser.add_option ("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") - parser.add_option ("-o", "--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") - parser.add_option ("-N", "--nsamples", type="eng_float", default=0, - help="set number of samples to transmit [default=+inf]") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - raise SystemExit - - if options.rf_freq is None: - sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n") - parser.print_help() - raise SystemExit - - tb = my_top_block(options.nsamples) - tb.set_interpolator (options.interp) - tb.set_waveform_type (options.type) - tb.set_waveform_freq (options.waveform_freq) - tb.set_waveform_ampl (options.amplitude) - tb.set_waveform_offset (options.offset) - - # determine the daughterboard subdevice we're using - if options.tx_subdev_spec is None: - options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u) - - m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec) - #print "mux = %#04x" % (m,) - tb.u.set_mux(m) - tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec) - print "Using TX d'board %s" % (tb.subdev.side_and_name(),) - - if options.gain is None: - tb.subdev.set_gain(tb.subdev.gain_range()[1]) # set max Tx gain - else: - tb.subdev.set_gain(options.gain) # set max Tx gain - - if not tb.set_freq(options.rf_freq): - sys.stderr.write('Failed to set RF frequency\n') - raise SystemExit + if target_freq is None: + f = self[FREQ_RANGE_KEY] + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + self[TX_FREQ_KEY] = target_freq + return + + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq + self[DDC_FREQ_KEY] = tr.dxc_freq + self[BB_FREQ_KEY] = tr.baseband_freq + if self._verbose: + print "Set center frequency to", fs + print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) + print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) + print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) + elif self._verbose: print "Failed to set freq." + return tr + + def set_waveform_freq(self, freq): + if self[TYPE_KEY] == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self[TYPE_KEY] == "2tone": + self._src1.set_frequency(freq) + elif self[TYPE_KEY] == 'sweep': + #there is no set sensitivity, redo fg + self[TYPE_KEY] = self[TYPE_KEY] + return True + + def set_waveform2_freq(self, freq): + if freq is None: + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + return + if self[TYPE_KEY] == "2tone": + self._src2.set_frequency(freq) + elif self[TYPE_KEY] == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform(self, type): + self.lock() + self.disconnect_all() + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate + type, # Waveform type + self[WAVEFORM_FREQ_KEY], # Waveform frequency + self[AMPLITUDE_KEY], # Waveform amplitude + self[WAVEFORM_OFFSET_KEY]) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) + elif type == "2tone": + self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + if(self[WAVEFORM2_FREQ_KEY] is None): + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + + self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM2_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + self._src = gr.add_cc() + self.connect(self._src1,(self._src,0)) + self.connect(self._src2,(self._src,1)) + elif type == "sweep": + # rf freq is center frequency + # waveform_freq is total swept width + # waveform2_freq is sweep rate + # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) + if self[WAVEFORM2_FREQ_KEY] is None: + self[WAVEFORM2_FREQ_KEY] = 0.1 + + self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], + gr.GR_TRI_WAVE, + self[WAVEFORM2_FREQ_KEY], + 1.0, + -0.5) + self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) + self.connect(self._src1,self._src2,self._src) + else: + raise RuntimeError("Unknown waveform type") + + self.connect(self._src, self._u) + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[type] + if type == gr.GR_SIN_WAVE: + print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Initial phase:", self[WAVEFORM_OFFSET_KEY] + elif type == "2tone": + print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + elif type == "sweep": + print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) + print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + print "TX amplitude:", self[AMPLITUDE_KEY] + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self[TYPE_KEY] == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self[TYPE_KEY] == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + +def get_options(): + usage="%prog: [options]" + + parser = OptionParser(option_class=eng_option, usage=usage) + usrp_options.add_tx_options(parser) + parser.add_option("-f", "--tx-freq", type="eng_float", default=None, + help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") + parser.add_option("-x", "--waveform-freq", type="eng_float", default=0, + help="Set baseband waveform frequency to FREQ [default=%default]") + parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None, + help="Set 2nd waveform frequency to FREQ [default=%default]") + parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, + help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) + parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, + help="Generate a constant carrier") + parser.add_option("--offset", type="eng_float", default=0, + help="Set waveform phase offset to OFFSET [default=%default]") + parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, + help="Generate Gaussian random output") + parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="Generate Uniform random output") + parser.add_option("--2tone", dest="type", action="store_const", const="2tone", + help="Generate Two Tone signal for IMD testing") + parser.add_option("--sweep", dest="type", action="store_const", const="sweep", + help="Generate a swept sine wave") + parser.add_option("-A", "--amplitude", type="eng_float", default=0.15, + help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Use verbose console output [default=%default]") + + (options, args) = parser.parse_args() + + return (options, args) + +# If this script is executed, the following runs. If it is imported, the below does not run. +if __name__ == "__main__": + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Note: failed to enable realtime scheduling, continuing" - tb.subdev.set_enable(True) # enable transmitter + # Grab command line options and create top block + try: + (options, args) = get_options() + tb = top_block(options, args) + except RuntimeError, e: + print e + sys.exit(1) + + # Run it try: tb.run() + except KeyboardInterrupt: pass - - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py new file mode 100755 index 000000000..40848fbee --- /dev/null +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from gnuradio import gr +from gnuradio.gr.pubsub import pubsub +from gnuradio.wxgui import gui, forms +import usrp_siggen +import sys, math + +class app_gui(pubsub): + def __init__(self, frame, panel, vbox, top_block, options, args): + pubsub.__init__(self) + self.frame = frame # Use for top-level application window frame + self.panel = panel # Use as parent class for created windows + self.vbox = vbox # Use as sizer for created windows + self.tb = top_block # GUI-unaware flowgraph class + self.options = options # Supplied command-line options + self.args = args # Supplied command-line arguments + self.build_gui() + + # Event response handlers + def evt_set_status_msg(self, msg): + self.frame.SetStatusText(msg, 0) + + # GUI construction + def build_gui(self): + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + ################################################## + # Baseband controls + ################################################## + bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True) + self.vbox.Add(bb_vbox, 0, wx.EXPAND) + sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + #callback to show/hide forms + def set_type(type): + sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE) + sweep_bb_hbox.ShowItems(type == 'sweep') + tone_bb_hbox.ShowItems(type == '2tone') + self.vbox.Layout() + self.tb.subscribe(usrp_siggen.TYPE_KEY, set_type) + #create sine forms + sine_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sine_bb_hbox, + label='Frequency (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sine_bb_hbox.AddStretchSpacer() + #create sweep forms + sweep_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Width (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Rate (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + #create 2tone forms + tone_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 1 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 2 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.radio_buttons( + parent=self.panel, sizer=bb_vbox, + choices=usrp_siggen.waveforms.keys(), + labels=usrp_siggen.waveforms.values(), + ps=self.tb, + key=usrp_siggen.TYPE_KEY, + style=wx.NO_BORDER | wx.RA_HORIZONTAL, + ) + bb_vbox.AddSpacer(10) + bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND) + set_type(self.tb[usrp_siggen.TYPE_KEY]) + ################################################## + # Frequency controls + ################################################## + fc_vbox = forms.static_box_sizer(parent=self.panel, label="Center Frequency", orient=wx.VERTICAL, bold=True) + fc_vbox.AddSpacer(5) + # First row of frequency controls (center frequency) + freq_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(freq_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(10) + # Second row of frequency controls (results) + tr_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(tr_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(5) + # Add frequency controls to top window sizer + self.vbox.Add(fc_vbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + freq_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=freq_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + ) + freq_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=freq_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1], + num_steps=100, + ) + freq_hbox.AddSpacer(5) + tr_hbox.AddSpacer(5) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='Daughterboard (Hz)', + ps=self.tb, + key=usrp_siggen.BB_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='USRP DDC (Hz)', + ps=self.tb, + key=usrp_siggen.DDC_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(5) + ################################################## + # Amplitude controls + ################################################## + amp_hbox = forms.static_box_sizer(parent=self.panel, label="Amplitude", orient=wx.VERTICAL, bold=True) + amp_hbox.AddSpacer(5) + # First row of amp controls (ampl) + lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(lvl_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(10) + # Second row of amp controls (tx gain) + gain_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(gain_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(5) + self.vbox.Add(amp_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + lvl_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=lvl_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + label="Level (0.0-1.0)", + ) + lvl_hbox.AddSpacer(10) + forms.log_slider( + parent=self.panel, sizer=lvl_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + min_exp=-6, + max_exp=0, + base=10, + num_steps=100, + ) + lvl_hbox.AddSpacer(5) + if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: + gain_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=gain_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + label="TX Gain (dB)", + ) + gain_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=gain_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1], + step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2], + ) + gain_hbox.AddSpacer(5) + ################################################## + # Sample Rate controls + ################################################## + sam_hbox = forms.static_box_sizer(parent=self.panel, label="Sample Rate", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(sam_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + sam_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=sam_hbox, + converter=forms.int_converter(), + ps=self.tb, + key=usrp_siggen.INTERP_KEY, + label="Interpolation", + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Sample Rate (sps)', + ps=self.tb, + key=usrp_siggen.SAMP_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Link Rate (bits/sec)', + ps=self.tb, + key=usrp_siggen.LINK_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddSpacer(5) + ################################################## + # USRP status + ################################################## + u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(u2_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + u2_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=u2_hbox, + ps=self.tb, + key=usrp_siggen.DESC_KEY, + converter=forms.str_converter(), + ) + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + +if __name__ == "__main__": + try: + # Get command line parameters + (options, args) = usrp_siggen.get_options() + + # Create the top block using these + tb = usrp_siggen.top_block(options, args) + + # Create the GUI application + app = gui.app(top_block=tb, # Constructed top block + gui=app_gui, # User interface class + options=options, # Command line options + args=args, # Command line args + title="USRP Signal Generator", # Top window title + nstatus=1, # Number of status lines + start=True, # Whether to start flowgraph + realtime=True) # Whether to set realtime priority + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) diff --git a/gr-wxgui/src/python/fft_window.py b/gr-wxgui/src/python/fft_window.py index 237c8940c..e025c28dd 100644 --- a/gr-wxgui/src/python/fft_window.py +++ b/gr-wxgui/src/python/fft_window.py @@ -1,5 +1,5 @@ # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2008, 2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -156,9 +156,9 @@ class control_panel(wx.Panel): def _on_decr_ref_level(self, event): self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] - self.parent[Y_PER_DIV_KEY] def _on_incr_db_div(self, event): - self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, self.parent[Y_PER_DIV_KEY]*2) + self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, common.get_clean_incr(self.parent[Y_PER_DIV_KEY])) def _on_decr_db_div(self, event): - self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, self.parent[Y_PER_DIV_KEY]/2) + self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, common.get_clean_decr(self.parent[Y_PER_DIV_KEY])) ################################################## # FFT window with plotter and control panel diff --git a/gr-wxgui/src/python/forms/converters.py b/gr-wxgui/src/python/forms/converters.py index 9f757aa84..db14d2752 100644 --- a/gr-wxgui/src/python/forms/converters.py +++ b/gr-wxgui/src/python/forms/converters.py @@ -72,12 +72,14 @@ class bool_converter(abstract_converter): self._true = true self._false = false def external_to_internal(self, v): - return bool(v) + if v == self._true: return True + if v == self._false: return False + raise Exception, 'Value "%s" is not a possible option.'%v def internal_to_external(self, v): if v: return self._true else: return self._false def help(self): - return "Value must be cast-able to type bool." + return "Value must be in (%s, %s)."%(self._true, self._false) class eval_converter(abstract_converter): """ @@ -134,8 +136,7 @@ class slider_converter(abstract_converter): self._scaler = float(maximum - minimum)/num_steps self._cast = cast def external_to_internal(self, v): - #slider's internal representation is an integer - return int(round((v - self._offset)/self._scaler)) + return (v - self._offset)/self._scaler def internal_to_external(self, v): return self._cast(v*self._scaler + self._offset) def help(self): diff --git a/gr-wxgui/src/python/forms/forms.py b/gr-wxgui/src/python/forms/forms.py index c69315b03..8dc58367d 100644 --- a/gr-wxgui/src/python/forms/forms.py +++ b/gr-wxgui/src/python/forms/forms.py @@ -176,7 +176,7 @@ class _slider_base(_form_base): self._add_widget(self._slider, label, flag=wx.EXPAND) def _handle(self, event): self[INT_KEY] = self._slider.GetValue() - def _update(self, value): self._slider.SetValue(value) + def _update(self, value): self._slider.SetValue(int(round(value))) ######################################################################## # Static Text Form @@ -224,11 +224,18 @@ class text_box(_form_base): def __init__(self, label='', width=-1, converter=converters.eval_converter(), **kwargs): _form_base.__init__(self, converter=converter, **kwargs) self._text_box = wx.TextCtrl(self._parent, size=wx.Size(width, -1), style=wx.TE_PROCESS_ENTER) + self._default_bg_colour = self._text_box.GetBackgroundColour() self._text_box.Bind(wx.EVT_TEXT_ENTER, self._handle) + self._text_box.Bind(wx.EVT_TEXT, self._update_color) self._add_widget(self._text_box, label) + def _update_color(self, *args): + if self._text_box.GetValue() == self[INT_KEY]: + self._text_box.SetBackgroundColour(self._default_bg_colour) + else: self._text_box.SetBackgroundColour('#EEDDDD') + def _handle(self, event): self[INT_KEY] = self._text_box.GetValue() - def _update(self, value): self._text_box.SetValue(value) + def _update(self, value): self._text_box.SetValue(value); self._update_color() ######################################################################## # Slider Form diff --git a/grc/Makefile.inc b/grc/Makefile.inc index 96ee11b67..c45d1ce1f 100644 --- a/grc/Makefile.inc +++ b/grc/Makefile.inc @@ -1,5 +1,5 @@ # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2008, 2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,5 +20,5 @@ # include $(top_srcdir)/Makefile.common -grc_src_prefix = $(pythondir)/gnuradio/grc +grc_src_prefix = $(pkgpythondir)/grc grc_blocksdir = $(pkgdatadir)/grc/blocks diff --git a/grc/base/Block.py b/grc/base/Block.py index d5e104785..203e878e4 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -47,7 +47,9 @@ class TemplateArg(UserDict): return self._param.get_evaluated() def _get_keys(lst): return [elem.get_key() for elem in lst] -def _get_elem(lst, key): return lst[_get_keys(lst).index(key)] +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): @@ -72,16 +74,16 @@ class Block(Element): self._params = list() #add the id param self.get_params().append(self.get_parent().get_parent().Param( - self, - odict({ + block=self, + n=odict({ 'name': 'ID', 'key': 'id', 'type': 'id', }) )) self.get_params().append(self.get_parent().get_parent().Param( - self, - odict({ + block=self, + n=odict({ 'name': 'Enabled', 'key': '_enabled', 'type': 'raw', @@ -89,7 +91,7 @@ class Block(Element): 'hide': 'all', }) )) - for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params): + for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params): key = param.get_key() #test against repeated keys try: assert key not in self.get_param_keys() @@ -98,7 +100,7 @@ class Block(Element): self.get_params().append(param) #create the source objects self._sources = list() - for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources): + 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 try: assert key not in self.get_source_keys() @@ -107,21 +109,13 @@ class Block(Element): self.get_sources().append(source) #create the sink objects self._sinks = list() - for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks): + 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 try: assert key not in self.get_sink_keys() except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key #store the port self.get_sinks().append(sink) - #begin the testing - self.test() - - def test(self): - """ - Call test on all children. - """ - map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources()) def get_enabled(self): """ @@ -138,21 +132,6 @@ class Block(Element): """ self.get_param('_enabled').set_value(str(enabled)) - def validate(self): - """ - Validate the block. - All ports and params must be valid. - All checks must evaluate to true. - """ - Element.validate(self) - for c in self.get_params() + self.get_ports() + self.get_connections(): - try: - c.validate() - assert c.is_valid() - except AssertionError: - for msg in c.get_error_messages(): - self.add_error_message('>>> %s:\n\t%s'%(c, msg)) - 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() @@ -162,6 +141,7 @@ class Block(Element): def get_category(self): return self._category def get_doc(self): return '' def get_ports(self): return self.get_sources() + self.get_sinks() + def get_children(self): return self.get_ports() + self.get_params() def get_block_wrapper_path(self): return self._block_wrapper_path ############################################## @@ -253,12 +233,22 @@ class Block(Element): """ 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. @param n the nested data odict """ - 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) + get_hash = lambda: reduce(lambda x, y: x ^ y, [hash(param) for param in self.get_params()], 0) + 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() diff --git a/grc/base/Element.py b/grc/base/Element.py index 16000c46c..a57090f3b 100644 --- a/grc/base/Element.py +++ b/grc/base/Element.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +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 @@ -21,37 +21,59 @@ class Element(object): def __init__(self, parent=None): self._parent = parent - self.flag() - - def test(self): - """ - Test the element against failures. - Overload this method in sub-classes. - """ - pass ################################################## # Element Validation API ################################################## - def validate(self): self._error_messages = list() - def is_valid(self): return not self.get_error_messages() or not self.get_enabled() - def add_error_message(self, msg): self._error_messages.append(msg) - def get_error_messages(self): return self._error_messages + def validate(self): + """ + Validate this element and call validate on all children. + Call this base method before adding error messages in the subclass. + """ + self._error_messages = list() + for child in self.get_children(): child.validate() - def get_enabled(self): return True + def is_valid(self): + """ + Is this element valid? + @return true when the element is enabled and has no error messages + """ + return not self.get_error_messages() or not self.get_enabled() - def get_parent(self): return self._parent + def add_error_message(self, msg): + """ + Add an error message to the list of errors. + @param msg the error message string + """ + self._error_messages.append(msg) + + def get_error_messages(self): + """ + Get the list of error messages from this element and all of its children. + Do not include the error messages from disabled children. + Cleverly indent the children error messages for printing purposes. + @return a list of error message strings + """ + error_messages = list(self._error_messages) #make a copy + for child in filter(lambda c: c.get_enabled(), self.get_children()): + for msg in child.get_error_messages(): + error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t"))) + return error_messages + + def rewrite(self): + """ + Rewrite this element and call rewrite on all children. + Call this base method before rewriting the element. + """ + for child in self.get_children(): child.rewrite() + + def get_enabled(self): return True ############################################## - ## Update flagging + ## Tree-like API ############################################## - def is_flagged(self): return self._flag - def flag(self): - self._flag = True - if self.get_parent(): self.get_parent().flag() - def deflag(self): - self._flag = False - if self.get_parent(): self.get_parent().deflag() + def get_parent(self): return self._parent + def get_children(self): return list() ############################################## ## Type testing methods diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py index ea489e948..7c51ef42a 100644 --- a/grc/base/FlowGraph.py +++ b/grc/base/FlowGraph.py @@ -68,6 +68,7 @@ class FlowGraph(Element): def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0] def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements()) def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements()) + def get_children(self): return self.get_elements() def get_elements(self): """ Get a list of all the elements. @@ -102,7 +103,6 @@ class FlowGraph(Element): @param key the block key @return the new block or None if not found """ - self.flag() 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) @@ -116,8 +116,7 @@ class FlowGraph(Element): @throw Exception bad connection @return the new connection """ - self.flag() - connection = self.get_parent().Connection(self, porta, portb) + connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb) self.get_elements().append(connection) return connection @@ -128,7 +127,6 @@ class FlowGraph(Element): If the element is a block, remove its connections. If the element is a connection, just remove the connection. """ - self.flag() if element not in self.get_elements(): return #found a port, set to parent signal block if element.is_port(): @@ -147,18 +145,6 @@ class FlowGraph(Element): """ raise NotImplementedError - def validate(self): - """ - Validate the flow graph. - All connections and blocks must be valid. - """ - Element.validate(self) - for c in self.get_elements(): - try: - c.validate() - assert c.is_valid() - except AssertionError: self.add_error_message('Element "%s" is not valid.'%c) - ############################################## ## Import/Export Methods ############################################## @@ -198,7 +184,6 @@ class FlowGraph(Element): #only load the block when the block key was valid if block: block.import_data(block_n) else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent())) - self.validate() #validate all blocks before connections are made (in case of nports) #build the connections for connection_n in connections_n: #try to make the connection @@ -225,3 +210,4 @@ class FlowGraph(Element): #build the connection self.connect(source, sink) except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key)) + self.rewrite() #global rewrite diff --git a/grc/base/Param.py b/grc/base/Param.py index 93c1c52bd..e56eac36e 100644 --- a/grc/base/Param.py +++ b/grc/base/Param.py @@ -19,74 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from . import odict from Element import Element -import pygtk -pygtk.require('2.0') -import gtk -class InputParam(gtk.HBox): - """The base class for an input parameter inside the input parameters dialog.""" - - def __init__(self, param, _handle_changed): - gtk.HBox.__init__(self) - self.param = param - self._handle_changed = _handle_changed - self.label = gtk.Label('') #no label, markup is added by set_markup - self.label.set_size_request(150, -1) - self.pack_start(self.label, False) - self.set_markup = lambda m: self.label.set_markup(m) - self.tp = None - def set_color(self, color): pass - -class EntryParam(InputParam): - """Provide an entry box for strings and numbers.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self.entry = input = gtk.Entry() - input.set_text(self.param.get_value()) - input.connect('changed', self._handle_changed) - self.pack_start(input, True) - self.get_text = input.get_text - #tool tip - self.tp = gtk.Tooltips() - self.tp.set_tip(self.entry, '') - self.tp.enable() - def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) - -class EnumParam(InputParam): - """Provide an entry box for Enum types with a drop down menu.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self._input = gtk.combo_box_new_text() - for option in self.param.get_options(): self._input.append_text(option.get_name()) - self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - self._input.connect('changed', self._handle_changed) - self.pack_start(self._input, False) - def get_text(self): return self.param.get_option_keys()[self._input.get_active()] - -class EnumEntryParam(InputParam): - """Provide an entry box and drop down menu for Raw Enum types.""" - - def __init__(self, *args, **kwargs): - InputParam.__init__(self, *args, **kwargs) - self._input = gtk.combo_box_entry_new_text() - for option in self.param.get_options(): self._input.append_text(option.get_name()) - try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) - except: - self._input.set_active(-1) - self._input.get_child().set_text(self.param.get_value()) - self._input.connect('changed', self._handle_changed) - self._input.get_child().connect('changed', self._handle_changed) - self.pack_start(self._input, False) - def get_text(self): - if self._input.get_active() == -1: return self._input.get_child().get_text() - return self.param.get_option_keys()[self._input.get_active()] - def set_color(self, color): - if self._input.get_active() == -1: #custom entry, use color - self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) - else: #from enum, make white background - self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) +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): @@ -123,15 +60,11 @@ class Option(Element): class Param(Element): - ##possible param types - TYPES = ['enum', 'raw'] - def __init__(self, block, n): """ Make a new param from nested data. @param block the parent element @param n the nested odict - @return a new param """ #grab the data self._name = n.find('name') @@ -142,22 +75,22 @@ class Param(Element): #build the param Element.__init__(self, block) #create the Option objects from the n data - self._options = odict() - for option in map(lambda o: Option(self, o), n.findall('option')): + 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 try: assert key not in self.get_option_keys() except AssertionError: raise Exception, 'Key "%s" already exists in options'%key #store the option - self._options[key] = option + self.get_options().append(option) #test the enum options if self.is_enum(): #test against options with identical keys - try: assert len(set(self.get_option_keys())) == len(self._options) + try: assert len(set(self.get_option_keys())) == len(self.get_options()) except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys() #test against inconsistent keys in options - opt_keys = self._options.values()[0].get_opt_keys() - for option in self._options.values(): + opt_keys = self.get_options()[0].get_opt_keys() + for option in self.get_options(): try: assert set(opt_keys) == set(option.get_opt_keys()) except AssertionError: 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 @@ -165,14 +98,6 @@ class Param(Element): try: assert self.get_value() in self.get_option_keys() except AssertionError: 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 '' - #begin the testing - self.test() - - def test(self): - """ - call test on all children - """ - map(lambda c: c.test(), self.get_options()) def validate(self): """ @@ -180,7 +105,7 @@ class Param(Element): The value must be evaluated and type must a possible type. """ Element.validate(self) - try: assert self.get_type() in self.TYPES + try: assert self.get_type() in self.get_types() except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) def get_evaluated(self): raise NotImplementedError @@ -192,12 +117,19 @@ class Param(Element): """ raise NotImplementedError + def get_types(self): + """ + Get a list of all possible param types. + @throw NotImplementedError + """ + raise NotImplementedError + def get_color(self): return '#FFFFFF' def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key()) def is_param(self): return True def get_name(self): return self._name def get_key(self): return self._key - def get_hide(self): return self.get_parent().resolve_dependencies(self._hide) + def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip() def get_value(self): value = self._value @@ -206,9 +138,7 @@ class Param(Element): self.set_value(value) return value - def set_value(self, value): - self.flag() - self._value = str(value) #must be a string + def set_value(self, value): self._value = str(value) #must be a string def get_type(self): return self.get_parent().resolve_dependencies(self._type) def is_enum(self): return self._type == 'enum' @@ -223,31 +153,19 @@ class Param(Element): if self.is_enum(): return self.get_option(self.get_value()).get_name() return self.get_value() - def get_input_class(self): - """ - Get the graphical gtk class to represent this parameter. - An enum requires and combo parameter. - A non-enum with options gets a combined entry/combo parameter. - All others get a standard entry parameter. - @return gtk input class - """ - if self.is_enum(): return EnumParam - if self.get_options(): return EnumEntryParam - return EntryParam - ############################################## # Access Options ############################################## - def get_option_keys(self): return self._options.keys() - def get_option(self, key): return self._options[key] - def get_options(self): return self._options.values() + 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._options[self.get_value()].get_opt_keys() - def get_opt(self, key): return self._options[self.get_value()].get_opt(key) - def get_opts(self): return self._options[self.get_value()].get_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 diff --git a/grc/base/Platform.py b/grc/base/Platform.py index 02d6d2319..51a3b2f87 100644 --- a/grc/base/Platform.py +++ b/grc/base/Platform.py @@ -146,7 +146,7 @@ class Platform(_Element): def is_platform(self): return True - def get_new_flow_graph(self): return self.FlowGraph(self) + def get_new_flow_graph(self): return self.FlowGraph(platform=self) def get_generator(self): return self._generator @@ -171,6 +171,5 @@ class Platform(_Element): FlowGraph = _FlowGraph Connection = _Connection Block = _Block - Source = _Port - Sink = _Port + Port = _Port Param = _Param diff --git a/grc/base/Port.py b/grc/base/Port.py index f4e8e5e1f..494ea894f 100644 --- a/grc/base/Port.py +++ b/grc/base/Port.py @@ -21,25 +21,20 @@ from Element import Element class Port(Element): - ##possible port types - TYPES = [] - - def __init__(self, block, n): + def __init__(self, block, n, dir): """ Make a new port from nested data. @param block the parent element @param n the nested odict - @return a new port + @param dir the direction source or sink """ - #grab the data - name = n['name'] - key = n['key'] - type = n['type'] #build the port Element.__init__(self, block) - self._name = name - self._key = key - self._type = type + #grab the data + self._name = n['name'] + self._key = n['key'] + self._type = n['type'] + self._dir = dir def validate(self): """ @@ -47,7 +42,7 @@ class Port(Element): The port must be non-empty and type must a possible type. """ Element.validate(self) - try: assert self.get_type() in self.TYPES + try: assert self.get_type() in self.get_types() except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type()) def __str__(self): @@ -56,12 +51,19 @@ class Port(Element): 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): return self._name def get_key(self): return self._key - def is_sink(self): return self in self.get_parent().get_sinks() - def is_source(self): return self in self.get_parent().get_sources() + 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_connections(self): diff --git a/grc/blocks/Makefile.am b/grc/blocks/Makefile.am index caae6ce75..617a3bf60 100644 --- a/grc/blocks/Makefile.am +++ b/grc/blocks/Makefile.am @@ -30,6 +30,8 @@ dist_ourdata_DATA = \ band_reject_filter.xml \ blks2_am_demod_cf.xml \ blks2_analysis_filterbank.xml \ + blks2_cvsd_encode.xml \ + blks2_cvsd_decode.xml \ blks2_dxpsk_demod.xml \ blks2_dxpsk_mod.xml \ blks2_error_rate.xml \ @@ -218,6 +220,8 @@ dist_ourdata_DATA = \ variable_slider.xml \ variable_static_text.xml \ variable_text_box.xml \ + virtual_sink.xml \ + virtual_source.xml \ wxgui_constellationsink2.xml \ wxgui_fftsink2.xml \ wxgui_histosink2.xml \ diff --git a/grc/blocks/band_pass_filter.xml b/grc/blocks/band_pass_filter.xml index e2e9acf4e..af083473d 100644 --- a/grc/blocks/band_pass_filter.xml +++ b/grc/blocks/band_pass_filter.xml @@ -10,8 +10,8 @@ <import>from gnuradio import gr</import> <import>from gnuradio.gr import firdes</import> <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.$(type.fcn)( - $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make> - <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback> + $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback> <param> <name>FIR Type</name> <key>type</key> @@ -118,27 +118,28 @@ </param> <param> <name>Window</name> - <key>window</key> - <type>enum</type> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> <option> <name>Hamming</name> - <key>WIN_HAMMING</key> + <key>firdes.WIN_HAMMING</key> </option> <option> <name>Hann</name> - <key>WIN_HANN</key> + <key>firdes.WIN_HANN</key> </option> <option> <name>Blackman</name> - <key>WIN_BLACKMAN</key> + <key>firdes.WIN_BLACKMAN</key> </option> <option> <name>Rectangular</name> - <key>WIN_RECTANGULAR</key> + <key>firdes.WIN_RECTANGULAR</key> </option> <option> <name>Kaiser</name> - <key>WIN_KAISER</key> + <key>firdes.WIN_KAISER</key> </option> </param> <param> diff --git a/grc/blocks/band_reject_filter.xml b/grc/blocks/band_reject_filter.xml index 3b58f0b51..dd5e7a9d7 100644 --- a/grc/blocks/band_reject_filter.xml +++ b/grc/blocks/band_reject_filter.xml @@ -10,8 +10,8 @@ <import>from gnuradio import gr</import> <import>from gnuradio.gr import firdes</import> <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.band_reject( - $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make> - <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback> + $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback> <param> <name>FIR Type</name> <key>type</key> @@ -84,27 +84,28 @@ </param> <param> <name>Window</name> - <key>window</key> - <type>enum</type> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> <option> <name>Hamming</name> - <key>WIN_HAMMING</key> + <key>firdes.WIN_HAMMING</key> </option> <option> <name>Hann</name> - <key>WIN_HANN</key> + <key>firdes.WIN_HANN</key> </option> <option> <name>Blackman</name> - <key>WIN_BLACKMAN</key> + <key>firdes.WIN_BLACKMAN</key> </option> <option> <name>Rectangular</name> - <key>WIN_RECTANGULAR</key> + <key>firdes.WIN_RECTANGULAR</key> </option> <option> <name>Kaiser</name> - <key>WIN_KAISER</key> + <key>firdes.WIN_KAISER</key> </option> </param> <param> diff --git a/grc/blocks/blks2_cvsd_decode.xml b/grc/blocks/blks2_cvsd_decode.xml new file mode 100644 index 000000000..6be7daa22 --- /dev/null +++ b/grc/blocks/blks2_cvsd_decode.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +## CVSD Encoder +################################################### + --> +<block> + <name>CVSD Decoder</name> + <key>blks2_cvsd_decode</key> + <import>from gnuradio import blks2</import> + <make>blks2.cvsd_decode($resample,$bw)</make> + <param> + <name>Resample</name> + <key>resample</key> + <value>8</value> + <type>int</type> + </param> + <param> + <name>Frac. Bandwidth</name> + <key>bw</key> + <value>0.5</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>byte</type> + </sink> + <source> + <name>out</name> + <type>float</type> + </source> +</block> diff --git a/grc/blocks/blks2_cvsd_encode.xml b/grc/blocks/blks2_cvsd_encode.xml new file mode 100644 index 000000000..3123b1aa9 --- /dev/null +++ b/grc/blocks/blks2_cvsd_encode.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +################################################### +## CVSD Encoder +################################################### + --> +<block> + <name>CVSD Encoder</name> + <key>blks2_cvsd_encode</key> + <import>from gnuradio import blks2</import> + <make>blks2.cvsd_encode($resample,$bw)</make> + <param> + <name>Resample</name> + <key>resample</key> + <value>8</value> + <type>int</type> + </param> + <param> + <name>Frac. Bandwidth</name> + <key>bw</key> + <value>0.5</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>byte</type> + </source> +</block> diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml index 5b45466f5..296f0ee91 100644 --- a/grc/blocks/block_tree.xml +++ b/grc/blocks/block_tree.xml @@ -22,6 +22,7 @@ <block>gr_wavfile_source</block> <block>gr_message_source</block> <block>pad_source</block> + <block>virtual_source</block> </cat> <cat> <name>Sinks</name> @@ -35,6 +36,7 @@ <block>gr_wavfile_sink</block> <block>gr_message_sink</block> <block>pad_sink</block> + <block>virtual_sink</block> </cat> <cat> <name>Graphical Sinks</name> @@ -250,6 +252,11 @@ <block>gr_descrambler_bb</block> </cat> <cat> + <name>Vocoders</name> + <block>blks2_cvsd_encode</block> + <block>blks2_cvsd_decode</block> + </cat> + <cat> <name>Probes</name> <block>gr_probe_avg_mag_sqrd_x</block> <block>gr_probe_density_b</block> diff --git a/grc/blocks/gr_noise_source_x.xml b/grc/blocks/gr_noise_source_x.xml index 4fcef5148..4789b4400 100644 --- a/grc/blocks/gr_noise_source_x.xml +++ b/grc/blocks/gr_noise_source_x.xml @@ -40,7 +40,7 @@ <name>Noise Type</name> <key>noise_type</key> <value>gr.GR_GAUSSIAN</value> - <type>raw</type> + <type>int</type> <option> <name>Uniform</name> <key>gr.GR_UNIFORM</key> diff --git a/grc/blocks/gr_sig_source_x.xml b/grc/blocks/gr_sig_source_x.xml index c329dba67..644cf52d0 100644 --- a/grc/blocks/gr_sig_source_x.xml +++ b/grc/blocks/gr_sig_source_x.xml @@ -53,7 +53,7 @@ <name>Waveform</name> <key>waveform</key> <value>gr.GR_COS_WAVE</value> - <type>raw</type> + <type>int</type> <option> <name>Constant</name> <key>gr.GR_CONST_WAVE</key> diff --git a/grc/blocks/high_pass_filter.xml b/grc/blocks/high_pass_filter.xml index 5be916fa9..0e29cbb36 100644 --- a/grc/blocks/high_pass_filter.xml +++ b/grc/blocks/high_pass_filter.xml @@ -10,8 +10,8 @@ <import>from gnuradio import gr</import> <import>from gnuradio.gr import firdes</import> <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.high_pass( - $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make> - <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback> + $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback> <param> <name>FIR Type</name> <key>type</key> @@ -79,27 +79,28 @@ </param> <param> <name>Window</name> - <key>window</key> - <type>enum</type> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> <option> <name>Hamming</name> - <key>WIN_HAMMING</key> + <key>firdes.WIN_HAMMING</key> </option> <option> <name>Hann</name> - <key>WIN_HANN</key> + <key>firdes.WIN_HANN</key> </option> <option> <name>Blackman</name> - <key>WIN_BLACKMAN</key> + <key>firdes.WIN_BLACKMAN</key> </option> <option> <name>Rectangular</name> - <key>WIN_RECTANGULAR</key> + <key>firdes.WIN_RECTANGULAR</key> </option> <option> <name>Kaiser</name> - <key>WIN_KAISER</key> + <key>firdes.WIN_KAISER</key> </option> </param> <param> diff --git a/grc/blocks/low_pass_filter.xml b/grc/blocks/low_pass_filter.xml index 27120c047..26435fd4d 100644 --- a/grc/blocks/low_pass_filter.xml +++ b/grc/blocks/low_pass_filter.xml @@ -10,8 +10,8 @@ <import>from gnuradio import gr</import> <import>from gnuradio.gr import firdes</import> <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.low_pass( - $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make> - <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback> + $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make> + <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback> <param> <name>FIR Type</name> <key>type</key> @@ -79,27 +79,28 @@ </param> <param> <name>Window</name> - <key>window</key> - <type>enum</type> + <key>win</key> + <value>firdes.WIN_HAMMING</value> + <type>int</type> <option> <name>Hamming</name> - <key>WIN_HAMMING</key> + <key>firdes.WIN_HAMMING</key> </option> <option> <name>Hann</name> - <key>WIN_HANN</key> + <key>firdes.WIN_HANN</key> </option> <option> <name>Blackman</name> - <key>WIN_BLACKMAN</key> + <key>firdes.WIN_BLACKMAN</key> </option> <option> <name>Rectangular</name> - <key>WIN_RECTANGULAR</key> + <key>firdes.WIN_RECTANGULAR</key> </option> <option> <name>Kaiser</name> - <key>WIN_KAISER</key> + <key>firdes.WIN_KAISER</key> </option> </param> <param> diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml index 18d6e2f0c..1798a69f8 100644 --- a/grc/blocks/options.xml +++ b/grc/blocks/options.xml @@ -9,16 +9,17 @@ <block> <name>Options</name> <key>options</key> - <import>from gnuradio import gr -#if $generate_options() == 'wx_gui' + <import>from gnuradio import gr</import> + <import>from gnuradio.gr import firdes</import> + <import>#if $generate_options() == 'wx_gui' from grc_gnuradio import wxgui as grc_wxgui import wx #end if #if $generate_options() != 'hb' from optparse import OptionParser from gnuradio.eng_option import eng_option -#end if -</import> +from gnuradio import eng_notation +#end if</import> <make></make> <callback>if $run: self.start() else: self.stop(); self.wait()</callback> diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml index 477f2ad13..734526793 100644 --- a/grc/blocks/pad_sink.xml +++ b/grc/blocks/pad_sink.xml @@ -59,10 +59,7 @@ <nports>$nports</nports> </sink> <doc> -This is a sink pad block for creating hierarchical flow graphs. \ The inputs of this block will become the outputs to this flow graph when it is instantiated as a hierarchical block. \ Limit one sink pad block per flow graph. - -Remember to set the generate options to hier block. </doc> </block> diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml index b6ef2c55d..f44d96238 100644 --- a/grc/blocks/pad_source.xml +++ b/grc/blocks/pad_source.xml @@ -59,10 +59,8 @@ <nports>$nports</nports> </source> <doc> -This is a source pad block for creating hierarchical flow graphs. \ The outputs of this block will become the inputs to this flow graph when it is instantiated as a hierarchical block. \ -Limit one source pad block per flow graph. - -Remember to set the generate options to hier block. +Limit one source pad block per flow graph. \ +The "pad sink id" will be ignored in this mode. </doc> </block> diff --git a/grc/blocks/parameter.xml b/grc/blocks/parameter.xml index 5d08c4b39..e35b8f4d1 100644 --- a/grc/blocks/parameter.xml +++ b/grc/blocks/parameter.xml @@ -45,7 +45,7 @@ </option> <option> <name>Int</name> - <key>int</key> + <key>intx</key> <opt>type:int</opt> </option> <option> @@ -58,6 +58,13 @@ <key>string</key> <opt>type:string</opt> </option> + <!-- not supported yet in tmpl + <option> + <name>Boolean</name> + <key>bool</key> + <opt>type:bool</opt> + </option> + --> </param> <param> <name>Short ID</name> diff --git a/grc/blocks/virtual_sink.xml b/grc/blocks/virtual_sink.xml new file mode 100644 index 000000000..35fb27e67 --- /dev/null +++ b/grc/blocks/virtual_sink.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Virtual Sink +################################################### + --> +<block> + <name>Virtual Sink</name> + <key>virtual_sink</key> + <make></make> + <param> + <name>Stream ID</name> + <key>stream_id</key> + <value></value> + <type>stream_id</type> + </param> + <sink> + <name>in</name> + <type></type> + </sink> +</block> diff --git a/grc/blocks/virtual_source.xml b/grc/blocks/virtual_source.xml new file mode 100644 index 000000000..e0c775449 --- /dev/null +++ b/grc/blocks/virtual_source.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Virtual Source +################################################### + --> +<block> + <name>Virtual Source</name> + <key>virtual_source</key> + <make></make> + <param> + <name>Stream ID</name> + <key>stream_id</key> + <value></value> + <type>stream_id</type> + </param> + <source> + <name>out</name> + <type></type> + </source> +</block> diff --git a/grc/blocks/wxgui_fftsink2.xml b/grc/blocks/wxgui_fftsink2.xml index faeca37e3..6f19f1aa4 100644 --- a/grc/blocks/wxgui_fftsink2.xml +++ b/grc/blocks/wxgui_fftsink2.xml @@ -15,6 +15,7 @@ fftsink2.$(type.fcn)( y_per_div=$y_per_div, y_divs=$y_divs, ref_level=$ref_level, + ref_scale=$ref_scale, sample_rate=$samp_rate, fft_size=$fft_size, fft_rate=$fft_rate, @@ -103,6 +104,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos())))) <type>real</type> </param> <param> + <name>Ref Scale (p2p)</name> + <key>ref_scale</key> + <value>2.0</value> + <type>real</type> + </param> + <param> <name>FFT Size</name> <key>fft_size</key> <value>1024</value> diff --git a/grc/blocks/wxgui_waterfallsink2.xml b/grc/blocks/wxgui_waterfallsink2.xml index 79ca356f7..35790f820 100644 --- a/grc/blocks/wxgui_waterfallsink2.xml +++ b/grc/blocks/wxgui_waterfallsink2.xml @@ -14,6 +14,7 @@ waterfallsink2.$(type.fcn)( baseband_freq=$baseband_freq, dynamic_range=$dynamic_range, ref_level=$ref_level, + ref_scale=$ref_scale, sample_rate=$samp_rate, fft_size=$fft_size, fft_rate=$fft_rate, @@ -75,6 +76,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos())))) <type>real</type> </param> <param> + <name>Ref Scale (p2p)</name> + <key>ref_scale</key> + <value>2.0</value> + <type>real</type> + </param> + <param> <name>FFT Size</name> <key>fft_size</key> <value>512</value> diff --git a/grc/examples/Makefile.am b/grc/examples/Makefile.am index 969485c0d..78321ce0a 100644 --- a/grc/examples/Makefile.am +++ b/grc/examples/Makefile.am @@ -25,7 +25,8 @@ grc_examples_prefix = $(exampledir)/grc audiodatadir = $(grc_examples_prefix)/audio dist_audiodata_DATA = \ - audio/dial_tone.grc + audio/dial_tone.grc \ + audio/cvsd_sweep.grc simpledatadir = $(grc_examples_prefix)/simple dist_simpledata_DATA = \ diff --git a/grc/examples/audio/cvsd_sweep.grc b/grc/examples/audio/cvsd_sweep.grc new file mode 100644 index 000000000..8d0b385ce --- /dev/null +++ b/grc/examples/audio/cvsd_sweep.grc @@ -0,0 +1,918 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Sat Sep 19 20:30:08 2009</timestamp> + <block> + <key>import</key> + <param> + <key>id</key> + <value>import_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>import</key> + <value>import math</value> + </param> + <param> + <key>_coordinate</key> + <value>(157, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blks2_cvsd_decode</key> + <param> + <key>id</key> + <value>blks2_cvsd_decode_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>resample</key> + <value>resample</value> + </param> + <param> + <key>bw</key> + <value>bw</value> + </param> + <param> + <key>_coordinate</key> + <value>(887, 340)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_sig_source_x</key> + <param> + <key>id</key> + <value>tri_source</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>waveform</key> + <value>gr.GR_TRI_WAVE</value> + </param> + <param> + <key>freq</key> + <value>0.05</value> + </param> + <param> + <key>amp</key> + <value>0.5</value> + </param> + <param> + <key>offset</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(44, 316)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_throttle</key> + <param> + <key>id</key> + <value>throttle</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>samples_per_second</key> + <value>audio_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(238, 348)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_vco_f</key> + <param> + <key>id</key> + <value>vco</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>sensitivity</key> + <value>audio_rate*2*math.pi</value> + </param> + <param> + <key>amplitude</key> + <value>0.9</value> + </param> + <param> + <key>_coordinate</key> + <value>(427, 332)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blks2_cvsd_encode</key> + <param> + <key>id</key> + <value>enc</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>resample</key> + <value>resample</value> + </param> + <param> + <key>bw</key> + <value>bw</value> + </param> + <param> + <key>_coordinate</key> + <value>(655, 340)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gr_packed_to_unpacked_xx</key> + <param> + <key>id</key> + <value>p2u</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>bits_per_chunk</key> + <value>1</value> + </param> + <param> + <key>endianness</key> + <value>gr.GR_MSB_FIRST</value> + </param> + <param> + <key>_coordinate</key> + <value>(648, 415)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>gr_char_to_float</key> + <param> + <key>id</key> + <value>c2f</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(676, 483)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>audio_sink</key> + <param> + <key>id</key> + <value>audio_sink</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>device_name</key> + <value>plughw:0,0</value> + </param> + <param> + <key>ok_to_block</key> + <value>True</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1127, 340)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>audio_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>8000</value> + </param> + <param> + <key>_coordinate</key> + <value>(251, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>resample</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>8</value> + </param> + <param> + <key>_coordinate</key> + <value>(344, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>bw</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>0.5</value> + </param> + <param> + <key>_coordinate</key> + <value>(431, 11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>notebook</key> + <param> + <key>id</key> + <value>displays</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>style</key> + <value>wx.NB_TOP</value> + </param> + <param> + <key>labels</key> + <value>['Original','Encoded','Decoded']</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(12, 106)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>orig_fft</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Original Spectrum</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>0</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> + <value>0</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(415, 97)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>orig_scope</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Original Waveform</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0</value> + </param> + <param> + <key>t_scale</key> + <value>0</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>False</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 0</value> + </param> + <param> + <key>_coordinate</key> + <value>(414, 425)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>enc_fft</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Encoded Spectrum</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate*resample</value> + </param> + <param> + <key>baseband_freq</key> + <value>0</value> + </param> + <param> + <key>y_per_div</key> + <value>10</value> + </param> + <param> + <key>y_divs</key> + <value>8</value> + </param> + <param> + <key>ref_level</key> + <value>10</value> + </param> + <param> + <key>ref_scale</key> + <value>2.0</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(610, 551)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>enc_scope</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Encoded Waveform</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate*resample</value> + </param> + <param> + <key>v_scale</key> + <value>0.5</value> + </param> + <param> + <key>t_scale</key> + <value>20.0/(audio_rate*resample)</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>False</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 1</value> + </param> + <param> + <key>_coordinate</key> + <value>(858, 591)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>wxgui_fftsink2</key> + <param> + <key>id</key> + <value>dec_fft</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Decoded Spectrum</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>baseband_freq</key> + <value>0</value> + </param> + <param> + <key>y_per_div</key> + <value>5</value> + </param> + <param> + <key>y_divs</key> + <value>10</value> + </param> + <param> + <key>ref_level</key> + <value>10</value> + </param> + <param> + <key>ref_scale</key> + <value>0.1</value> + </param> + <param> + <key>fft_size</key> + <value>1024</value> + </param> + <param> + <key>fft_rate</key> + <value>30</value> + </param> + <param> + <key>peak_hold</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>False</value> + </param> + <param> + <key>avg_alpha</key> + <value>0</value> + </param> + <param> + <key>grid_pos</key> + <value>0, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 2</value> + </param> + <param> + <key>_coordinate</key> + <value>(891, 98)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>wxgui_scopesink2</key> + <param> + <key>id</key> + <value>dec_scope</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>title</key> + <value>Decoded Waveform</value> + </param> + <param> + <key>samp_rate</key> + <value>audio_rate</value> + </param> + <param> + <key>v_scale</key> + <value>0</value> + </param> + <param> + <key>t_scale</key> + <value>0</value> + </param> + <param> + <key>ac_couple</key> + <value>False</value> + </param> + <param> + <key>xy_mode</key> + <value>False</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>grid_pos</key> + <value>1, 0, 1, 1</value> + </param> + <param> + <key>notebook</key> + <value>displays, 2</value> + </param> + <param> + <key>_coordinate</key> + <value>(889, 422)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>cvsd_sweep</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>CVSD Vocoder Test</value> + </param> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>wx_gui</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>vco</source_block_id> + <sink_block_id>orig_fft</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>tri_source</source_block_id> + <sink_block_id>throttle</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>throttle</source_block_id> + <sink_block_id>vco</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>vco</source_block_id> + <sink_block_id>enc</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>enc</source_block_id> + <sink_block_id>blks2_cvsd_decode_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>vco</source_block_id> + <sink_block_id>orig_scope</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blks2_cvsd_decode_0</source_block_id> + <sink_block_id>dec_fft</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blks2_cvsd_decode_0</source_block_id> + <sink_block_id>dec_scope</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blks2_cvsd_decode_0</source_block_id> + <sink_block_id>audio_sink</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>enc</source_block_id> + <sink_block_id>p2u</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>p2u</source_block_id> + <sink_block_id>c2f</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>c2f</source_block_id> + <sink_block_id>enc_fft</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>c2f</source_block_id> + <sink_block_id>enc_scope</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index ff137f669..ee3e19a6c 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -30,9 +30,8 @@ from threading import Thread import Messages from .. base import ParseXML import random -from Platform import Platform from MainWindow import MainWindow -from ParamsDialog import ParamsDialog +from PropsDialog import PropsDialog import Dialogs from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog @@ -53,11 +52,10 @@ class ActionHandler: @param platform platform module """ self.clipboard = None - platform = Platform(platform) - for action in Actions.get_all_actions(): action.connect('activate', self._handle_actions) + for action in Actions.get_all_actions(): action.connect('activate', self._handle_action) #setup the main window - self.main_window = MainWindow(self.handle_states, platform) - self.main_window.connect('delete_event', self._quit) + self.main_window = MainWindow(platform) + self.main_window.connect('delete-event', self._quit) self.main_window.connect('key-press-event', self._handle_key_press) self.get_page = self.main_window.get_page self.get_flow_graph = self.main_window.get_flow_graph @@ -67,7 +65,7 @@ class ActionHandler: Messages.send_init(platform) #initialize self.init_file_paths = file_paths - self.handle_states(Actions.APPLICATION_INITIALIZE) + Actions.APPLICATION_INITIALIZE() #enter the mainloop gtk.main() @@ -81,17 +79,9 @@ class ActionHandler: When not in focus, gtk and the accelerators handle the the key press. @return false to let gtk handle the key action """ - #dont allow key presses to queue up - if gtk.events_pending(): return True - #extract action name from this key press - key_name = gtk.gdk.keyval_name(event.keyval) - mod_mask = event.state - action_name = Actions.get_action_name_from_key_name(key_name, mod_mask) - #handle the action if flow graph is in focus - if action_name and self.get_focus_flag(): - self.handle_states(action_name) - return True #handled by this method - return False #let gtk handle the key press + try: assert self.get_focus_flag() + except AssertionError: return False + return Actions.handle_key_press(event) def _quit(self, window, event): """ @@ -100,41 +90,24 @@ class ActionHandler: This method in turns calls the state handler to quit. @return true """ - self.handle_states(Actions.APPLICATION_QUIT) + Actions.APPLICATION_QUIT() return True - def _handle_actions(self, event): - """ - Handle all of the activate signals from the gtk actions. - The action signals derive from clicking on a toolbar or menu bar button. - Forward the action to the state handler. - """ - self.handle_states(event.get_name()) - - def handle_states(self, state=''): - """ - Handle the state changes in the GUI. - Handle all of the state changes that arise from the action handler or other gui and - inputs in the application. The state passed to the handle_states method is a string descriping - the change. A series of if/elif statements handle the state by greying out action buttons, causing - changes in the flow graph, saving/opening files... The handle_states method is passed to the - contructors of many of the classes used in this application enabling them to report any state change. - @param state a string describing the state change - """ - #print state + def _handle_action(self, action): + #print action ################################################## # Initalize/Quit ################################################## - if state == Actions.APPLICATION_INITIALIZE: + if action == Actions.APPLICATION_INITIALIZE: for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled - # enable a select few actions + #enable a select few actions for action in ( Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW, Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY, Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY, - Actions.COLORS_WINDOW_DISPLAY, - ): Actions.get_action_from_name(action).set_sensitive(True) + Actions.TYPES_WINDOW_DISPLAY, + ): action.set_sensitive(True) if not self.init_file_paths: self.init_file_paths = Preferences.files_open() if not self.init_file_paths: self.init_file_paths = [''] @@ -143,26 +116,26 @@ class ActionHandler: if Preferences.file_open() in self.init_file_paths: self.main_window.new_page(Preferences.file_open(), show=True) if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists - elif state == Actions.APPLICATION_QUIT: + elif action == Actions.APPLICATION_QUIT: if self.main_window.close_pages(): gtk.main_quit() exit(0) ################################################## # Selections ################################################## - elif state == Actions.ELEMENT_SELECT: + elif action == Actions.ELEMENT_SELECT: pass #do nothing, update routines below - elif state == Actions.NOTHING_SELECT: + elif action == Actions.NOTHING_SELECT: self.get_flow_graph().unselect() ################################################## # Enable/Disable ################################################## - elif state == Actions.BLOCK_ENABLE: + elif action == Actions.BLOCK_ENABLE: if self.get_flow_graph().enable_selected(True): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_DISABLE: + 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()) @@ -170,12 +143,12 @@ class ActionHandler: ################################################## # Cut/Copy/Paste ################################################## - elif state == Actions.BLOCK_CUT: - self.handle_states(Actions.BLOCK_COPY) - self.handle_states(Actions.ELEMENT_DELETE) - elif state == Actions.BLOCK_COPY: + elif action == Actions.BLOCK_CUT: + Actions.BLOCK_COPY() + Actions.ELEMENT_DELETE() + elif action == Actions.BLOCK_COPY: self.clipboard = self.get_flow_graph().copy_to_clipboard() - elif state == Actions.BLOCK_PASTE: + elif action == Actions.BLOCK_PASTE: if self.clipboard: self.get_flow_graph().paste_from_clipboard(self.clipboard) self.get_flow_graph().update() @@ -184,81 +157,88 @@ class ActionHandler: ################################################## # Move/Rotate/Delete/Create ################################################## - elif state == Actions.BLOCK_MOVE: + elif action == Actions.BLOCK_MOVE: self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_CCW: + elif action == Actions.BLOCK_ROTATE_CCW: if self.get_flow_graph().rotate_selected(90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_CW: + elif action == Actions.BLOCK_ROTATE_CW: if self.get_flow_graph().rotate_selected(-90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.ELEMENT_DELETE: + 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()) - self.handle_states(Actions.NOTHING_SELECT) + Actions.NOTHING_SELECT() self.get_page().set_saved(False) - elif state == Actions.ELEMENT_CREATE: + 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()) - self.handle_states(Actions.NOTHING_SELECT) + Actions.NOTHING_SELECT() self.get_page().set_saved(False) - elif state == Actions.BLOCK_INC_TYPE: + elif action == Actions.BLOCK_INC_TYPE: if self.get_flow_graph().type_controller_modify_selected(1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_DEC_TYPE: + elif action == Actions.BLOCK_DEC_TYPE: if self.get_flow_graph().type_controller_modify_selected(-1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.PORT_CONTROLLER_INC: + elif action == Actions.PORT_CONTROLLER_INC: if self.get_flow_graph().port_controller_modify_selected(1): self.get_flow_graph().update() - self.get_flow_graph().update() #2 times self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.PORT_CONTROLLER_DEC: + elif action == Actions.PORT_CONTROLLER_DEC: if self.get_flow_graph().port_controller_modify_selected(-1): self.get_flow_graph().update() - self.get_flow_graph().update() #2 times self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) ################################################## # Window stuff ################################################## - elif state == Actions.ABOUT_WINDOW_DISPLAY: + elif action == Actions.ABOUT_WINDOW_DISPLAY: Dialogs.AboutDialog(self.get_flow_graph().get_parent()) - elif state == Actions.HELP_WINDOW_DISPLAY: + elif action == Actions.HELP_WINDOW_DISPLAY: Dialogs.HelpDialog() - elif state == Actions.COLORS_WINDOW_DISPLAY: - Dialogs.ColorsDialog(self.get_flow_graph().get_parent()) + elif action == Actions.TYPES_WINDOW_DISPLAY: + Dialogs.TypesDialog(self.get_flow_graph().get_parent()) + elif action == Actions.ERRORS_WINDOW_DISPLAY: + Dialogs.ErrorsDialog(self.get_flow_graph()) ################################################## # Param Modifications ################################################## - elif state == Actions.BLOCK_PARAM_MODIFY: + elif action == Actions.BLOCK_PARAM_MODIFY: selected_block = self.get_flow_graph().get_selected_block() - if selected_block and ParamsDialog(selected_block).run(): - 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 selected_block: + if PropsDialog(selected_block).run(): + #save the new state + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + else: + #restore the current state + n = self.get_page().get_state_cache().get_current_state() + self.get_flow_graph().import_data(n) + self.get_flow_graph().update() ################################################## # Undo/Redo ################################################## - elif state == Actions.FLOW_GRAPH_UNDO: + elif action == Actions.FLOW_GRAPH_UNDO: n = self.get_page().get_state_cache().get_prev_state() if n: self.get_flow_graph().unselect() self.get_flow_graph().import_data(n) self.get_flow_graph().update() self.get_page().set_saved(False) - elif state == Actions.FLOW_GRAPH_REDO: + elif action == Actions.FLOW_GRAPH_REDO: n = self.get_page().get_state_cache().get_next_state() if n: self.get_flow_graph().unselect() @@ -268,19 +248,19 @@ class ActionHandler: ################################################## # New/Open/Save/Close ################################################## - elif state == Actions.FLOW_GRAPH_NEW: + elif action == Actions.FLOW_GRAPH_NEW: self.main_window.new_page() - elif state == Actions.FLOW_GRAPH_OPEN: + elif action == Actions.FLOW_GRAPH_OPEN: file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run() if file_paths: #open a new page for each file, show only the first for i,file_path in enumerate(file_paths): self.main_window.new_page(file_path, show=(i==0)) - elif state == Actions.FLOW_GRAPH_CLOSE: + elif action == Actions.FLOW_GRAPH_CLOSE: self.main_window.close_page() - elif state == Actions.FLOW_GRAPH_SAVE: + 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(): - self.handle_states(Actions.FLOW_GRAPH_SAVE_AS) + Actions.FLOW_GRAPH_SAVE_AS() #otherwise try to save else: try: @@ -289,12 +269,12 @@ class ActionHandler: except IOError: Messages.send_fail_save(self.get_page().get_file_path()) self.get_page().set_saved(False) - elif state == Actions.FLOW_GRAPH_SAVE_AS: + elif action == Actions.FLOW_GRAPH_SAVE_AS: file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run() if file_path is not None: self.get_page().set_file_path(file_path) - self.handle_states(Actions.FLOW_GRAPH_SAVE) - elif state == Actions.FLOW_GRAPH_SCREEN_CAPTURE: + Actions.FLOW_GRAPH_SAVE() + elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE: file_path = SaveImageFileDialog(self.get_page().get_file_path()).run() if file_path is not None: pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf() @@ -302,10 +282,10 @@ class ActionHandler: ################################################## # Gen/Exec/Stop ################################################## - elif state == Actions.FLOW_GRAPH_GEN: + elif action == Actions.FLOW_GRAPH_GEN: if not self.get_page().get_pid(): if not self.get_page().get_saved() or not self.get_page().get_file_path(): - self.handle_states(Actions.FLOW_GRAPH_SAVE) #only save if file path missing or not saved + Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved if self.get_page().get_saved() and self.get_page().get_file_path(): generator = self.get_page().get_generator() try: @@ -313,37 +293,38 @@ class ActionHandler: generator.write() except Exception,e: Messages.send_fail_gen(e) else: self.generator = None - elif state == Actions.FLOW_GRAPH_EXEC: + elif action == Actions.FLOW_GRAPH_EXEC: if not self.get_page().get_pid(): - self.handle_states(Actions.FLOW_GRAPH_GEN) + Actions.FLOW_GRAPH_GEN() if self.get_page().get_saved() and self.get_page().get_file_path(): ExecFlowGraphThread(self) - elif state == Actions.FLOW_GRAPH_KILL: + elif action == Actions.FLOW_GRAPH_KILL: if self.get_page().get_pid(): try: os.kill(self.get_page().get_pid(), signal.SIGKILL) except: print "could not kill pid: %s"%self.get_page().get_pid() - elif state == '': #pass and run the global actions + elif action == Actions.PAGE_CHANGE: #pass and run the global actions pass - else: print '!!! State "%s" not handled !!!'%state + else: print '!!! Action "%s" not handled !!!'%action ################################################## # Global Actions for all States ################################################## #update general buttons - Actions.get_action_from_name(Actions.ELEMENT_DELETE).set_sensitive(bool(self.get_flow_graph().get_selected_elements())) - Actions.get_action_from_name(Actions.BLOCK_PARAM_MODIFY).set_sensitive(bool(self.get_flow_graph().get_selected_block())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_CCW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_CW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid()) + Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements())) + Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block())) + Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) #update cut/copy/paste - Actions.get_action_from_name(Actions.BLOCK_CUT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_COPY).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_PASTE).set_sensitive(bool(self.clipboard)) + Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard)) #update enable/disable - Actions.get_action_from_name(Actions.BLOCK_ENABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_DISABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) #set the exec and stop buttons self.update_exec_stop() #saved status - Actions.get_action_from_name(Actions.FLOW_GRAPH_SAVE).set_sensitive(not self.get_page().get_saved()) + Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved()) self.main_window.update() try: #set the size of the flow graph area (if changed) new_size = self.get_flow_graph().get_option('window_size') @@ -353,6 +334,7 @@ class ActionHandler: #draw the flow graph self.get_flow_graph().update_selected() self.get_flow_graph().queue_draw() + return True #action was handled def update_exec_stop(self): """ @@ -360,9 +342,9 @@ class ActionHandler: 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_pid() - Actions.get_action_from_name(Actions.FLOW_GRAPH_GEN).set_sensitive(sensitive) - Actions.get_action_from_name(Actions.FLOW_GRAPH_EXEC).set_sensitive(sensitive) - Actions.get_action_from_name(Actions.FLOW_GRAPH_KILL).set_sensitive(self.get_page().get_pid() != None) + Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive) + Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive) + Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_pid() != None) class ExecFlowGraphThread(Thread): """Execute the flow graph as a new process and wait on it to finish.""" diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 3695e09ef..f374efde1 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -21,149 +21,254 @@ import pygtk pygtk.require('2.0') import gtk -###################################################################################################### -# Action Names -###################################################################################################### -APPLICATION_INITIALIZE = 'app init' -APPLICATION_QUIT = 'app quit' -PARAM_MODIFY = 'param modify' -BLOCK_MOVE = 'block move' -BLOCK_ROTATE_CCW = 'block rotate ccw' -BLOCK_ROTATE_CW = 'block rotate cw' -BLOCK_PARAM_MODIFY = 'block param modify' -BLOCK_INC_TYPE = 'block increment type' -BLOCK_DEC_TYPE = 'block decrement type' -BLOCK_ENABLE = 'block enable' -BLOCK_DISABLE = 'block disable' -BLOCK_CUT = 'block cut' -BLOCK_COPY = 'block copy' -BLOCK_PASTE = 'block paste' -PORT_CONTROLLER_INC = 'port controller increment' -PORT_CONTROLLER_DEC = 'port controller decrement' -ELEMENT_CREATE = 'element create' -ELEMENT_DELETE = 'element delete' -ELEMENT_SELECT = 'element select' -NOTHING_SELECT = 'nothing select' -FLOW_GRAPH_OPEN = 'flow graph open' -FLOW_GRAPH_UNDO = 'flow graph undo' -FLOW_GRAPH_REDO = 'flow graph redo' -FLOW_GRAPH_SAVE = 'flow graph save' -FLOW_GRAPH_SAVE_AS = 'flow graph save as' -FLOW_GRAPH_CLOSE = 'flow graph close' -FLOW_GRAPH_NEW = 'flow graph new' -FLOW_GRAPH_GEN = 'flow graph gen' -FLOW_GRAPH_EXEC = 'flow graph exec' -FLOW_GRAPH_KILL = 'flow graph kill' -FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture' -ABOUT_WINDOW_DISPLAY = 'about window display' -HELP_WINDOW_DISPLAY = 'help window display' -COLORS_WINDOW_DISPLAY = 'colors window display' +NO_MODS_MASK = 0 -###################################################################################################### -# Action Key Map -###################################################################################################### -_actions_key_list = ( - #action name, key name, mod mask - (FLOW_GRAPH_NEW, 'n', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_OPEN, 'o', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE, 's', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE_AS, 's', gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), - (FLOW_GRAPH_CLOSE, 'w', gtk.gdk.CONTROL_MASK), - (APPLICATION_QUIT, 'q', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_UNDO, 'z', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_REDO, 'y', gtk.gdk.CONTROL_MASK), - (ELEMENT_DELETE, 'Delete', 0), - (BLOCK_ROTATE_CCW, 'Left', 0), - (BLOCK_ROTATE_CW, 'Right', 0), - (BLOCK_DEC_TYPE, 'Up', 0), - (BLOCK_INC_TYPE, 'Down', 0), - (BLOCK_PARAM_MODIFY, 'Return', 0), - (BLOCK_ENABLE, 'e', 0), - (BLOCK_DISABLE, 'd', 0), - (BLOCK_CUT, 'x', gtk.gdk.CONTROL_MASK), - (BLOCK_COPY, 'c', gtk.gdk.CONTROL_MASK), - (BLOCK_PASTE, 'v', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_GEN, 'F5', 0), - (FLOW_GRAPH_EXEC, 'F6', 0), - (FLOW_GRAPH_KILL, 'F7', 0), - (FLOW_GRAPH_SCREEN_CAPTURE, 'Print', 0), - (HELP_WINDOW_DISPLAY, 'F1', 0), - #the following have no associated gtk.Action - (PORT_CONTROLLER_INC, 'equal', 0), - (PORT_CONTROLLER_INC, 'plus', 0), - (PORT_CONTROLLER_INC, 'KP_Add', 0), - (PORT_CONTROLLER_DEC, 'minus', 0), - (PORT_CONTROLLER_DEC, 'KP_Subtract', 0), -) - -_actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list) -def get_action_name_from_key_name(key_name, mod_mask=0): +######################################################################## +# Actions API +######################################################################## +_actions_keypress_dict = dict() +_keymap = gtk.gdk.keymap_get_default() +_used_mods_mask = NO_MODS_MASK +def handle_key_press(event): """ - Get the action name associated with the key name and mask. - Both keyname and mask have to match. - @param key_name the name of the key - @param mod_mask the key press mask (shift, ctrl) 0 for none - @return the action name or blank string + Call the action associated with the key press event. + Both the key value and the mask must have a match. + @param event a gtk key press event + @return true if handled """ - key_name_mod_mask = (key_name, mod_mask) - if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask] - return '' + _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) + #extract the key value and the consumed modifiers + keyval, egroup, level, consumed = _keymap.translate_keyboard_state( + event.hardware_keycode, event.state, event.group) + #get the modifier mask and ignore irrelevant modifiers + mod_mask = event.state & ~consumed & _used_mods_mask + #look up the keypress and call the action + try: _actions_keypress_dict[(keyval, mod_mask)]() + except KeyError: return False #not handled + return True #handled here -###################################################################################################### -# Actions -###################################################################################################### -_actions_list = ( - gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', gtk.STOCK_NEW), - gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', gtk.STOCK_OPEN), - gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', gtk.STOCK_SAVE), - gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', gtk.STOCK_SAVE_AS), - gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', gtk.STOCK_CLOSE), - gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', gtk.STOCK_QUIT), - gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', gtk.STOCK_UNDO), - gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', gtk.STOCK_REDO), - gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', gtk.STOCK_DELETE), - gtk.Action(BLOCK_ROTATE_CCW, 'Rotate Counterclockwise', 'Rotate the selected blocks 90 degrees to the left', gtk.STOCK_GO_BACK), - gtk.Action(BLOCK_ROTATE_CW, 'Rotate Clockwise', 'Rotate the selected blocks 90 degrees to the right', gtk.STOCK_GO_FORWARD), - gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', gtk.STOCK_PROPERTIES), - gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', gtk.STOCK_CONNECT), - gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', gtk.STOCK_DISCONNECT), - gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', gtk.STOCK_CUT), - gtk.Action(BLOCK_COPY, '_Copy', 'Copy', gtk.STOCK_COPY), - gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE), - gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT), - gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP), - gtk.Action(COLORS_WINDOW_DISPLAY, '_Colors', 'Color Mapping', gtk.STOCK_DIALOG_INFO), - gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT), - gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE), - gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP), - gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', gtk.STOCK_PRINT), -) -def get_all_actions(): return _actions_list +_all_actions_list = list() +def get_all_actions(): return _all_actions_list + +_accel_group = gtk.AccelGroup() +def get_accel_group(): return _accel_group -_actions_dict = dict((action.get_name(), action) for action in _actions_list) -def get_action_from_name(action_name): +class Action(gtk.Action): """ - Retrieve the action from the action list. - Search the list and find an action with said name. - @param action_name the action name(string) - @throw KeyError bad action name - @return a gtk action object + A custom Action class based on gtk.Action. + Pass additional arguments such as keypresses. + Register actions and keypresses with this module. """ - if action_name in _actions_dict: return _actions_dict[action_name] - raise KeyError('Action Name: "%s" does not exist'%action_name) -###################################################################################################### -# Accelerators -###################################################################################################### -_accel_group = gtk.AccelGroup() -def get_accel_group(): return _accel_group + def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None): + """ + Create a new Action instance. + @param key_presses a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...) + @param the regular gtk.Action parameters (defaults to None) + """ + if name is None: name = label + gtk.Action.__init__(self, + name=name, label=label, + tooltip=tooltip, stock_id=stock_id, + ) + #register this action + _all_actions_list.append(self) + for i in range(len(keypresses)/2): + keyval, mod_mask = keypresses[i*2:(i+1)*2] + #register this keypress + assert not _actions_keypress_dict.has_key((keyval, mod_mask)) + _actions_keypress_dict[(keyval, mod_mask)] = self + #set the accelerator group, and accelerator path + #register the key name and mod mask with the accelerator path + if label is None: continue #dont register accel + accel_path = '<main>/'+self.get_name() + self.set_accel_group(get_accel_group()) + self.set_accel_path(accel_path) + gtk.accel_map_add_entry(accel_path, keyval, mod_mask) + + def __str__(self): + """ + The string representation should be the name of the action id. + Try to find the action id for this action by searching this module. + """ + try: + import Actions + return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0] + except: return self.get_name() + + def __repr__(self): return str(self) + + def __call__(self): + """ + Emit the activate signal when called with (). + """ + self.emit('activate') -#set the accelerator group, and accelerator path -#register the key name and mod mask with the accelerator path -for action_name, key_name, mod_mask in _actions_key_list: - try: - accel_path = '<main>/'+action_name - get_action_from_name(action_name).set_accel_group(get_accel_group()) - get_action_from_name(action_name).set_accel_path(accel_path) - gtk.accel_map_add_entry(accel_path, gtk.gdk.keyval_from_name(key_name), mod_mask) - except KeyError: pass #no action was created for this action name +######################################################################## +# Actions +######################################################################## +PAGE_CHANGE = Action() +FLOW_GRAPH_NEW = Action( + label='_New', + tooltip='Create a new flow graph', + stock_id=gtk.STOCK_NEW, + keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_OPEN = Action( + label='_Open', + tooltip='Open an existing flow graph', + stock_id=gtk.STOCK_OPEN, + keypresses=(gtk.keysyms.o, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE = Action( + label='_Save', + tooltip='Save the current flow graph', + stock_id=gtk.STOCK_SAVE, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE_AS = Action( + label='Save _As', + tooltip='Save the current flow graph as...', + stock_id=gtk.STOCK_SAVE_AS, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), +) +FLOW_GRAPH_CLOSE = Action( + label='_Close', + tooltip='Close the current flow graph', + stock_id=gtk.STOCK_CLOSE, + keypresses=(gtk.keysyms.w, gtk.gdk.CONTROL_MASK), +) +APPLICATION_INITIALIZE = Action() +APPLICATION_QUIT = Action( + label='_Quit', + tooltip='Quit program', + stock_id=gtk.STOCK_QUIT, + keypresses=(gtk.keysyms.q, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_UNDO = Action( + label='_Undo', + tooltip='Undo a change to the flow graph', + stock_id=gtk.STOCK_UNDO, + keypresses=(gtk.keysyms.z, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_REDO = Action( + label='_Redo', + tooltip='Redo a change to the flow graph', + stock_id=gtk.STOCK_REDO, + keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK), +) +NOTHING_SELECT = Action() +ELEMENT_SELECT = Action() +ELEMENT_CREATE = Action() +ELEMENT_DELETE = Action( + label='_Delete', + tooltip='Delete the selected blocks', + stock_id=gtk.STOCK_DELETE, + keypresses=(gtk.keysyms.Delete, NO_MODS_MASK), +) +BLOCK_MOVE = Action() +BLOCK_ROTATE_CCW = Action( + label='Rotate Counterclockwise', + tooltip='Rotate the selected blocks 90 degrees to the left', + stock_id=gtk.STOCK_GO_BACK, + keypresses=(gtk.keysyms.Left, NO_MODS_MASK), +) +BLOCK_ROTATE_CW = Action( + label='Rotate Clockwise', + tooltip='Rotate the selected blocks 90 degrees to the right', + stock_id=gtk.STOCK_GO_FORWARD, + keypresses=(gtk.keysyms.Right, NO_MODS_MASK), +) +BLOCK_PARAM_MODIFY = Action( + label='_Properties', + tooltip='Modify params for the selected block', + stock_id=gtk.STOCK_PROPERTIES, + keypresses=(gtk.keysyms.Return, NO_MODS_MASK), +) +BLOCK_ENABLE = Action( + label='E_nable', + tooltip='Enable the selected blocks', + stock_id=gtk.STOCK_CONNECT, + keypresses=(gtk.keysyms.e, NO_MODS_MASK), +) +BLOCK_DISABLE = Action( + label='D_isable', + tooltip='Disable the selected blocks', + stock_id=gtk.STOCK_DISCONNECT, + keypresses=(gtk.keysyms.d, NO_MODS_MASK), +) +BLOCK_CUT = Action( + label='Cu_t', + tooltip='Cut', + stock_id=gtk.STOCK_CUT, + keypresses=(gtk.keysyms.x, gtk.gdk.CONTROL_MASK), +) +BLOCK_COPY = Action( + label='_Copy', + tooltip='Copy', + stock_id=gtk.STOCK_COPY, + keypresses=(gtk.keysyms.c, gtk.gdk.CONTROL_MASK), +) +BLOCK_PASTE = Action( + label='_Paste', + tooltip='Paste', + stock_id=gtk.STOCK_PASTE, + keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK), +) +ERRORS_WINDOW_DISPLAY = Action( + label='_Errors', + tooltip='View flow graph errors', + stock_id=gtk.STOCK_DIALOG_ERROR, +) +ABOUT_WINDOW_DISPLAY = Action( + label='_About', + tooltip='About this program', + stock_id=gtk.STOCK_ABOUT, +) +HELP_WINDOW_DISPLAY = Action( + label='_Help', + tooltip='Usage tips', + stock_id=gtk.STOCK_HELP, + keypresses=(gtk.keysyms.F1, NO_MODS_MASK), +) +TYPES_WINDOW_DISPLAY = Action( + label='_Types', + tooltip='Types color mapping', + stock_id=gtk.STOCK_DIALOG_INFO, +) +FLOW_GRAPH_GEN = Action( + label='_Generate', + tooltip='Generate the flow graph', + stock_id=gtk.STOCK_CONVERT, + keypresses=(gtk.keysyms.F5, NO_MODS_MASK), +) +FLOW_GRAPH_EXEC = Action( + label='_Execute', + tooltip='Execute the flow graph', + stock_id=gtk.STOCK_EXECUTE, + keypresses=(gtk.keysyms.F6, NO_MODS_MASK), +) +FLOW_GRAPH_KILL = Action( + label='_Kill', + tooltip='Kill the flow graph', + stock_id=gtk.STOCK_STOP, + keypresses=(gtk.keysyms.F7, NO_MODS_MASK), +) +FLOW_GRAPH_SCREEN_CAPTURE = Action( + label='S_creen Capture', + tooltip='Create a screen capture of the flow graph', + stock_id=gtk.STOCK_PRINT, + keypresses=(gtk.keysyms.Print, NO_MODS_MASK), +) +PORT_CONTROLLER_DEC = Action( + keypresses=(gtk.keysyms.minus, NO_MODS_MASK, gtk.keysyms.KP_Subtract, NO_MODS_MASK), +) +PORT_CONTROLLER_INC = Action( + keypresses=(gtk.keysyms.plus, NO_MODS_MASK, gtk.keysyms.KP_Add, NO_MODS_MASK), +) +BLOCK_INC_TYPE = Action( + keypresses=(gtk.keysyms.Down, NO_MODS_MASK), +) +BLOCK_DEC_TYPE = Action( + keypresses=(gtk.keysyms.Up, NO_MODS_MASK), +) diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index e0c547eba..8fd167869 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -39,6 +39,7 @@ TOOLBAR_LIST = ( Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO, None, + Actions.ERRORS_WINDOW_DISPLAY, Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL, @@ -81,6 +82,9 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_PARAM_MODIFY, ]), + (gtk.Action('View', '_View', None, None), [ + Actions.ERRORS_WINDOW_DISPLAY, + ]), (gtk.Action('Build', '_Build', None, None), [ Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, @@ -88,7 +92,7 @@ MENU_BAR_LIST = ( ]), (gtk.Action('Help', '_Help', None, None), [ Actions.HELP_WINDOW_DISPLAY, - Actions.COLORS_WINDOW_DISPLAY, + Actions.TYPES_WINDOW_DISPLAY, None, Actions.ABOUT_WINDOW_DISPLAY, ]), @@ -104,9 +108,8 @@ class Toolbar(gtk.Toolbar): """ gtk.Toolbar.__init__(self) self.set_style(gtk.TOOLBAR_ICONS) - for action_name in TOOLBAR_LIST: - if action_name: #add a tool item - action = Actions.get_action_from_name(action_name) + for action in TOOLBAR_LIST: + if action: #add a tool item self.add(action.create_tool_item()) #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show action.set_property('tooltip', action.get_property('tooltip')) @@ -123,16 +126,15 @@ class MenuBar(gtk.MenuBar): Add the submenu to the menu bar. """ gtk.MenuBar.__init__(self) - for main_action,action_names in MENU_BAR_LIST: + for main_action, actions in MENU_BAR_LIST: #create the main menu item main_menu_item = main_action.create_menu_item() self.append(main_menu_item) #create the menu main_menu = gtk.Menu() main_menu_item.set_submenu(main_menu) - for action_name in action_names: - if action_name: #append a menu item - action = Actions.get_action_from_name(action_name) + for action in actions: + if action: #append a menu item main_menu.append(action.create_menu_item()) else: main_menu.append(gtk.SeparatorMenuItem()) main_menu.show_all() #this show all is required for the separators to show diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 4add3aa19..8c65bf06f 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -37,15 +37,15 @@ BLOCK_MARKUP_TMPL="""\ class Block(Element): """The graphical signal block.""" - def __init__(self, *args, **kwargs): + def __init__(self): """ Block contructor. Add graphics related params to the block. """ #add the position param self.get_params().append(self.get_parent().get_parent().Param( - self, - odict({ + block=self, + n=odict({ 'name': 'GUI Coordinate', 'key': '_coordinate', 'type': 'raw', @@ -54,8 +54,8 @@ class Block(Element): }) )) self.get_params().append(self.get_parent().get_parent().Param( - self, - odict({ + block=self, + n=odict({ 'name': 'GUI Rotation', 'key': '_rotation', 'type': 'raw', @@ -113,23 +113,16 @@ class Block(Element): """ self.get_param('_rotation').set_value(str(rot)) - def update(self): + def create_shapes(self): """Update the block, parameters, and ports when a change occurs.""" - self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR - self.clear() - self._create_labels() - self.W = self.label_width + 2*BLOCK_LABEL_PADDING - self.H = max(*( - [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ - sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION - for ports in (self.get_sources(), self.get_sinks())] - )) + Element.create_shapes(self) if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H)) elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W)) - map(lambda p: p.update(), self.get_ports()) - def _create_labels(self): + def create_labels(self): """Create the labels for the signal block.""" + Element.create_labels(self) + self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR layouts = list() #create the main layout layout = gtk.DrawingArea().create_pango_layout('') @@ -142,7 +135,7 @@ class Block(Element): layouts.append(layout) w,h = layout.get_pixel_size() self.label_width = max(w, self.label_width) - self.label_height = self.label_height + h + LABEL_SEPARATION + self.label_height += h + LABEL_SEPARATION width = self.label_width height = self.label_height #setup the pixmap @@ -164,7 +157,13 @@ class Block(Element): self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width) for i in range(width): for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j)) - map(lambda p: p._create_labels(), self.get_ports()) + #calculate width and height needed + self.W = self.label_width + 2*BLOCK_LABEL_PADDING + self.H = max(*( + [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ + sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION + for ports in (self.get_sources(), self.get_sinks())] + )) def draw(self, gc, window): """ diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 379c4a6a2..07b8ea7e0 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -28,6 +28,15 @@ NAME_INDEX = 0 KEY_INDEX = 1 DOC_INDEX = 2 +DOC_MARKUP_TMPL="""\ +#if $doc +$encode($doc)#slurp +#else +undocumented#slurp +#end if""" + +CAT_MARKUP_TMPL="""Category: $cat""" + class BlockTreeWindow(gtk.VBox): """The block selection panel.""" @@ -48,7 +57,7 @@ class BlockTreeWindow(gtk.VBox): self.treeview = gtk.TreeView(self.treestore) self.treeview.set_enable_search(False) #disable pop up search box self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self.treeview.connect('button_press_event', self._handle_mouse_button_press) + self.treeview.connect('button-press-event', self._handle_mouse_button_press) selection = self.treeview.get_selection() selection.set_mode('single') selection.connect('changed', self._handle_selection_change) @@ -97,14 +106,14 @@ class BlockTreeWindow(gtk.VBox): iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None) self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name) self.treestore.set_value(iter, KEY_INDEX, '') - self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode('Category: %s'%cat_name)) + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) self._categories[sub_category] = iter #add block if block is None: return iter = self.treestore.insert_before(self._categories[category], None) self.treestore.set_value(iter, NAME_INDEX, block.get_name()) self.treestore.set_value(iter, KEY_INDEX, block.get_key()) - self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode(block.get_doc() or 'undocumented')) + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())) ############################################################ ## Helper Methods diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 013bcb00f..fabf34ee7 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008 Free Software Foundation, Inc. +Copyright 2007, 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 @@ -32,6 +32,8 @@ class Connection(Element): The arrow coloring exposes the enabled and valid states. """ + def __init__(self): Element.__init__(self) + def get_coordinate(self): """ Get the 0,0 coordinate. @@ -48,8 +50,9 @@ class Connection(Element): """ return 0 - def update(self): + def create_shapes(self): """Precalculate relative coordinates.""" + Element.create_shapes(self) self._sink_rot = None self._source_rot = None self._sink_coor = None @@ -72,7 +75,7 @@ class Connection(Element): def _update_after_move(self): """Calculate coordinates.""" - self.clear() + self.clear() #FIXME do i want this here? #source connector source = self.get_source() X, Y = source.get_connector_coordinate() @@ -123,7 +126,7 @@ class Connection(Element): sink = self.get_sink() source = self.get_source() #check for changes - if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.update() + if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes() elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move() #cache values self._sink_rot = sink.get_rotation() diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index 8d764e28e..af40f47c0 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -57,6 +57,20 @@ def MessageDialogHelper(type, buttons, title=None, markup=None): message_dialog.destroy() return response + +ERRORS_MARKUP_TMPL="""\ +#for $i, $err_msg in enumerate($errors) +<b>Error $i:</b> +$encode($err_msg.replace('\t', ' ')) + +#end for""" +def ErrorsDialog(flowgraph): MessageDialogHelper( + type=gtk.MESSAGE_ERROR, + buttons=gtk.BUTTONS_CLOSE, + title='Flow Graph Errors', + markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()), +) + class AboutDialog(gtk.AboutDialog): """A cute little about dialog.""" @@ -98,8 +112,8 @@ COLORS_DIALOG_MARKUP_TMPL = """\ #end if """ -def ColorsDialog(platform): MessageDialogHelper( +def TypesDialog(platform): MessageDialogHelper( type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE, - title='Colors', + title='Types', markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors())) diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 315191723..f0518ee12 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 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 @@ -17,11 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import Colors import pygtk pygtk.require('2.0') import gtk -import pango from Constants import LINE_SELECT_SENSITIVITY from Constants import POSSIBLE_ROTATIONS @@ -32,7 +30,7 @@ class Element(object): and methods to detect selection of those areas. """ - def __init__(self, *args, **kwargs): + def __init__(self): """ Make a new list of rectangular areas and lines, and set the coordinate and the rotation. """ @@ -61,6 +59,21 @@ class Element(object): rotation = rotation or self.get_rotation() return rotation in (90, 270) + def create_labels(self): + """ + Create labels (if applicable) and call on all children. + Call this base method before creating labels in the element. + """ + for child in self.get_children(): child.create_labels() + + def create_shapes(self): + """ + Create shapes (if applicable) and call on all children. + Call this base method before creating shapes in the element. + """ + self.clear() + for child in self.get_children(): child.create_shapes() + def draw(self, gc, window, border_color, bg_color): """ Draw in the given window. @@ -70,14 +83,14 @@ class Element(object): @param bg_color the color for the inside of the rectangle """ X,Y = self.get_coordinate() - for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]: + for (rX,rY),(W,H) in self._areas_list: aX = X + rX aY = Y + rY gc.set_foreground(bg_color) window.draw_rectangle(gc, True, aX, aY, W, H) gc.set_foreground(border_color) window.draw_rectangle(gc, False, aX, aY, W, H) - for (x1, y1),(x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1),(x2, y2) in self._lines_list: gc.set_foreground(border_color) window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) @@ -90,8 +103,8 @@ class Element(object): def clear(self): """Empty the lines and areas.""" - self.areas_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) - self.lines_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) + self._areas_list = list() + self._lines_list = list() def set_coordinate(self, coor): """ @@ -136,7 +149,7 @@ class Element(object): X, Y = self.get_coordinate() self.set_coordinate((X+deltaX, Y+deltaY)) - def add_area(self, rel_coor, area, rotation=None): + def add_area(self, rel_coor, area): """ Add an area to the area list. An area is actually a coordinate relative to the main coordinate @@ -144,25 +157,21 @@ class Element(object): A positive width is to the right of the coordinate. A positive height is above the coordinate. The area is associated with a rotation. - If rotation is not specified, the element's current rotation is used. @param rel_coor (x,y) offset from this element's coordinate @param area (width,height) tuple - @param rotation rotation in degrees """ - self.areas_dict[rotation or self.get_rotation()].append((rel_coor, area)) + self._areas_list.append((rel_coor, area)) - def add_line(self, rel_coor1, rel_coor2, rotation=None): + def add_line(self, rel_coor1, rel_coor2): """ Add a line to the line list. A line is defined by 2 relative coordinates. Lines must be horizontal or vertical. The line is associated with a rotation. - If rotation is not specified, the element's current rotation is used. @param rel_coor1 relative (x1,y1) tuple @param rel_coor2 relative (x2,y2) tuple - @param rotation rotation in degrees """ - self.lines_dict[rotation or self.get_rotation()].append((rel_coor1, rel_coor2)) + self._lines_list.append((rel_coor1, rel_coor2)) def what_is_selected(self, coor, coor_m=None): """ @@ -183,24 +192,24 @@ class Element(object): if coor_m: x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())] #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: + for (x1,y1), (w,h) in self._areas_list: if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \ in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \ in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m): return self #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1), (x2, y2) in self._lines_list: if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ in_between(x2, x, x_m) and in_between(y2, y, y_m): return self return None else: #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: + for (x1,y1), (w,h) in self._areas_list: if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1), (x2, y2) in self._lines_list: if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY if in_between(x, x1, x2) and in_between(y, y1, y2): return self @@ -220,7 +229,3 @@ class Element(object): if rotation not in POSSIBLE_ROTATIONS: raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS)) self.rotation = rotation - - def update(self): - """Do nothing for the update. Dummy method.""" - pass diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index f8028f199..8feb171f1 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -18,10 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE -from Actions import \ - ELEMENT_CREATE, ELEMENT_SELECT, \ - BLOCK_PARAM_MODIFY, BLOCK_MOVE, \ - ELEMENT_DELETE +import Actions import Colors import Utils from Element import Element @@ -39,7 +36,7 @@ class FlowGraph(Element): and the connections between inputs and outputs. """ - def __init__(self, *args, **kwargs): + def __init__(self): """ FlowGraph contructor. Create a list for signal blocks and connections. Connect mouse handlers. @@ -86,7 +83,7 @@ class FlowGraph(Element): block.set_coordinate(coor) block.set_rotation(0) block.get_param('id').set_value(id) - self.handle_states(ELEMENT_CREATE) + Actions.ELEMENT_CREATE() ########################################################################### # Copy Paste @@ -291,10 +288,13 @@ class FlowGraph(Element): def update(self): """ - Call update on all elements. + Call the top level rewrite and validate. + Call the top level create labels and shapes. """ + self.rewrite() self.validate() - for element in self.get_elements(): element.update() + self.create_labels() + self.create_shapes() ########################################################################## ## Get Selected @@ -406,7 +406,7 @@ class FlowGraph(Element): self._old_selected_port is not self._new_selected_port: try: self.connect(self._old_selected_port, self._new_selected_port) - self.handle_states(ELEMENT_CREATE) + Actions.ELEMENT_CREATE() except: Messages.send_fail_connection() self._old_selected_port = None self._new_selected_port = None @@ -421,7 +421,7 @@ class FlowGraph(Element): self._selected_elements = list( set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements) ) - self.handle_states(ELEMENT_SELECT) + Actions.ELEMENT_SELECT() ########################################################################## ## Event Handlers @@ -443,7 +443,7 @@ class FlowGraph(Element): #double click detected, bring up params dialog if possible if double_click and self.get_selected_block(): self.mouse_pressed = False - self.handle_states(BLOCK_PARAM_MODIFY) + Actions.BLOCK_PARAM_MODIFY() def handle_mouse_button_release(self, left_click, coordinate): """ @@ -454,7 +454,7 @@ class FlowGraph(Element): self.time = 0 self.mouse_pressed = False if self.element_moved: - self.handle_states(BLOCK_MOVE) + Actions.BLOCK_MOVE() self.element_moved = False self.update_selected_elements() @@ -484,7 +484,7 @@ class FlowGraph(Element): 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(): - self.handle_states(ELEMENT_DELETE) + Actions.ELEMENT_DELETE() #move the selected elements and record the new coordinate X, Y = self.get_coordinate() if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 6d36f4cf7..9fcbe2a6c 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +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 @@ -19,9 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Constants import \ NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH -from Actions import \ - APPLICATION_QUIT, FLOW_GRAPH_KILL, \ - FLOW_GRAPH_SAVE, get_accel_group +import Actions import pygtk pygtk.require('2.0') import gtk @@ -67,20 +65,19 @@ PAGE_TITLE_MARKUP_TMPL = """\ class MainWindow(gtk.Window): """The topmost window with menus, the tool bar, and other major windows.""" - def __init__(self, handle_states, platform): + def __init__(self, platform): """ - MainWindow contructor. - @param handle_states the callback function + MainWindow contructor + Setup the menu, toolbar, flowgraph editor notebook, block selection window... """ self._platform = platform #setup window - self.handle_states = handle_states gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) vbox = gtk.VBox() self.hpaned = gtk.HPaned() self.add(vbox) #create the menu bar and toolbar - self.add_accel_group(get_accel_group()) + self.add_accel_group(Actions.get_accel_group()) vbox.pack_start(Bars.MenuBar(), False) vbox.pack_start(Bars.Toolbar(), False) vbox.pack_start(self.hpaned) @@ -123,7 +120,7 @@ class MainWindow(gtk.Window): This method in turns calls the state handler to quit. @return true """ - self.handle_states(APPLICATION_QUIT) + Actions.APPLICATION_QUIT() return True def _handle_page_change(self, notebook, page, page_num): @@ -137,7 +134,7 @@ class MainWindow(gtk.Window): """ self.current_page = self.notebook.get_nth_page(page_num) Messages.send_page_switch(self.current_page.get_file_path()) - self.handle_states() + Actions.PAGE_CHANGE() ############################################################ # Report Window @@ -223,12 +220,12 @@ class MainWindow(gtk.Window): self._set_page(self.page_to_be_closed) #unsaved? ask the user if not self.page_to_be_closed.get_saved() and self._save_changes(): - self.handle_states(FLOW_GRAPH_SAVE) #try to save + Actions.FLOW_GRAPH_SAVE() #try to save if not self.page_to_be_closed.get_saved(): #still unsaved? self.page_to_be_closed = None #set the page to be closed back to None return #stop the flow graph if executing - if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL) + if self.page_to_be_closed.get_pid(): Actions.FLOW_GRAPH_KILL() #remove the page self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed)) if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one diff --git a/grc/gui/Makefile.am b/grc/gui/Makefile.am index cb45d5359..b14817d04 100644 --- a/grc/gui/Makefile.am +++ b/grc/gui/Makefile.am @@ -43,7 +43,7 @@ ourpython_PYTHON = \ MainWindow.py \ Messages.py \ NotebookPage.py \ - ParamsDialog.py \ + PropsDialog.py \ Preferences.py \ StateCache.py \ __init__.py diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index cb6b7ed30..fddfeaf5f 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -17,10 +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 """ -from Actions import FLOW_GRAPH_CLOSE import pygtk pygtk.require('2.0') import gtk +import Actions from StateCache import StateCache from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT from DrawingArea import DrawingArea @@ -80,9 +80,8 @@ class NotebookPage(gtk.HBox): self.drawing_area = DrawingArea(self.get_flow_graph()) self.scrolled_window.add_with_viewport(self.get_drawing_area()) self.pack_start(self.scrolled_window) - #inject drawing area and handle states into flow graph + #inject drawing area into flow graph self.get_flow_graph().drawing_area = self.get_drawing_area() - self.get_flow_graph().handle_states = main_window.handle_states self.show_all() def get_drawing_area(self): return self.drawing_area @@ -104,7 +103,7 @@ class NotebookPage(gtk.HBox): @param the button """ self.main_window.page_to_be_closed = self - self.main_window.handle_states(FLOW_GRAPH_CLOSE) + Actions.FLOW_GRAPH_CLOSE() def set_markup(self, markup): """ diff --git a/grc/gui/Param.py b/grc/gui/Param.py index a11fd9065..4464a57ab 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -23,6 +23,106 @@ import pygtk pygtk.require('2.0') import gtk +class InputParam(gtk.HBox): + """The base class for an input parameter inside the input parameters dialog.""" + + def __init__(self, param, callback=None): + gtk.HBox.__init__(self) + self.param = param + self._callback = callback + self.label = gtk.Label() #no label, markup is added by set_markup + self.label.set_size_request(150, -1) + self.pack_start(self.label, False) + self.set_markup = lambda m: self.label.set_markup(m) + self.tp = None + #connect events + self.connect('show', self._update_gui) + def set_color(self, color): pass + + def _update_gui(self, *args): + """ + Set the markup, color, tooltip, show/hide. + """ + #set the markup + has_cb = \ + hasattr(self.param.get_parent(), 'get_callbacks') and \ + filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks) + self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb)) + #set the color + self.set_color(self.param.get_color()) + #set the tooltip + if self.tp: self.tp.set_tip( + self.entry, + Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(), + ) + #show/hide + if self.param.get_hide() == 'all': self.hide_all() + else: self.show_all() + + def _handle_changed(self, *args): + """ + Handle a gui change by setting the new param value, + calling the callback (if applicable), and updating. + """ + #set the new value + self.param.set_value(self.get_text()) + #call the callback + if self._callback: self._callback(*args) + else: self.param.validate() + #gui update + self._update_gui() + +class EntryParam(InputParam): + """Provide an entry box for strings and numbers.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self.entry = input = gtk.Entry() + input.set_text(self.param.get_value()) + input.connect('changed', self._handle_changed) + self.pack_start(input, True) + self.get_text = input.get_text + #tool tip + self.tp = gtk.Tooltips() + self.tp.set_tip(self.entry, '') + self.tp.enable() + def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + +class EnumParam(InputParam): + """Provide an entry box for Enum types with a drop down menu.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.combo_box_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + self._input.connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): return self.param.get_option_keys()[self._input.get_active()] + +class EnumEntryParam(InputParam): + """Provide an entry box and drop down menu for Raw Enum types.""" + + def __init__(self, *args, **kwargs): + InputParam.__init__(self, *args, **kwargs) + self._input = gtk.combo_box_entry_new_text() + for option in self.param.get_options(): self._input.append_text(option.get_name()) + try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value())) + except: + self._input.set_active(-1) + self._input.get_child().set_text(self.param.get_value()) + self._input.connect('changed', self._handle_changed) + self._input.get_child().connect('changed', self._handle_changed) + self.pack_start(self._input, False) + def get_text(self): + if self._input.get_active() == -1: return self._input.get_child().get_text() + return self.param.get_option_keys()[self._input.get_active()] + def set_color(self, color): + if self._input.get_active() == -1: #custom entry, use color + self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + else: #from enum, make white background + self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff')) + PARAM_MARKUP_TMPL="""\ #set $foreground = $param.is_valid() and 'black' or 'red' <span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode(repr($param))</span>""" @@ -49,49 +149,19 @@ Error: class Param(Element): """The graphical parameter.""" - def update(self): - """ - Called when an external change occurs. - Update the graphical input by calling the change handler. - """ - if hasattr(self, '_input'): self._handle_changed() - - def get_input_object(self, callback=None): - """ - Get the graphical gtk object to represent this parameter. - Create the input object with this data type and the handle changed method. - @param callback a function of one argument(this param) to be called from the change handler - @return gtk input object - """ - self._callback = callback - self._input = self.get_input_class()(self, self._handle_changed) - if not self._callback: self.update() - return self._input + def __init__(self): Element.__init__(self) - def _handle_changed(self, widget=None): + def get_input(self, *args, **kwargs): """ - When the input changes, write the inputs to the data type. - Finish by calling the exteral callback. + Get the graphical gtk class to represent this parameter. + An enum requires and combo parameter. + A non-enum with options gets a combined entry/combo parameter. + All others get a standard entry parameter. + @return gtk input class """ - self.set_value(self._input.get_text()) - self.validate() - #is param is involved in a callback? #FIXME: messy - has_cb = \ - hasattr(self.get_parent(), 'get_callbacks') and \ - filter(lambda c: self.get_key() in c, self.get_parent()._callbacks) - self._input.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self, has_cb=has_cb)) - #hide/show - if self.get_hide() == 'all': self._input.hide_all() - else: self._input.show_all() - #set the color - self._input.set_color(self.get_color()) - #set the tooltip - if self._input.tp: self._input.tp.set_tip( - self._input.entry, - Utils.parse_template(TIP_MARKUP_TMPL, param=self).strip(), - ) - #execute the external callback - if self._callback: self._callback(self) + if self.is_enum(): return EnumParam(self, *args, **kwargs) + if self.get_options(): return EnumEntryParam(self, *args, **kwargs) + return EntryParam(self, *args, **kwargs) def get_layout(self): """ diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py index a32b0209f..8bbfaca23 100644 --- a/grc/gui/Platform.py +++ b/grc/gui/Platform.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +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 @@ -17,32 +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 """ -from FlowGraph import FlowGraph -from Connection import Connection -from Block import Block -from Port import Port -from Param import Param +from Element import Element -def conjoin_classes(name, c1, c2): - exec(""" -class %s(c1, c2): - def __init__(self, *args, **kwargs): - c1.__init__(self, *args, **kwargs) - c2.__init__(self, *args, **kwargs) -"""%name, locals()) - return locals()[name] - -def Platform(platform): - #combine with gui class - for attr, value in ( - ('FlowGraph', FlowGraph), - ('Connection', Connection), - ('Block', Block), - ('Source', Port), - ('Sink', Port), - ('Param', Param), - ): - old_value = getattr(platform, attr) - c = conjoin_classes(attr, old_value, value) - setattr(platform, attr, c) - return platform +class Platform(Element): + def __init__(self): Element.__init__(self) diff --git a/grc/gui/Port.py b/grc/gui/Port.py index d1f36f8b9..6763f6cbd 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 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 @@ -34,7 +34,7 @@ PORT_MARKUP_TMPL="""\ class Port(Element): """The graphical port.""" - def __init__(self, *args, **kwargs): + def __init__(self): """ Port contructor. Create list of connector coordinates. @@ -42,9 +42,9 @@ class Port(Element): Element.__init__(self) self.connector_coordinates = dict() - def update(self): + def create_shapes(self): """Create new areas and labels for the port.""" - self.clear() + Element.create_shapes(self) #get current rotation rotation = self.get_rotation() #get all sibling ports @@ -82,8 +82,9 @@ class Port(Element): #the connector length self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index - def _create_labels(self): + def create_labels(self): """Create the labels for the socket.""" + Element.create_labels(self) self._bg_color = Colors.get_color(self.get_color()) #create the layout layout = gtk.DrawingArea().create_pango_layout('') @@ -114,7 +115,7 @@ class Port(Element): border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, ) X,Y = self.get_coordinate() - (x,y),(w,h) = self.areas_dict[self.get_rotation()][0] #use the first area's sizes to place the labels + (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels if self.is_horizontal(): window.draw_image(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) elif self.is_vertical(): diff --git a/grc/gui/ParamsDialog.py b/grc/gui/PropsDialog.py index ccf19d1a2..a7822b228 100644 --- a/grc/gui/ParamsDialog.py +++ b/grc/gui/PropsDialog.py @@ -37,70 +37,118 @@ def get_title_label(title): hbox.pack_start(label, False, False, padding=11) return hbox -class ParamsDialog(gtk.Dialog): - """A dialog box to set block parameters.""" +class PropsDialog(gtk.Dialog): + """ + A dialog to set block parameters, view errors, and view documentation. + """ def __init__(self, block): """ - SignalBlockParamsDialog contructor. - @param block the signal block + Properties dialog contructor. + @param block a block instance """ + self._hash = 0 + LABEL_SPACING = 7 gtk.Dialog.__init__(self, title='Properties: %s'%block.get_name(), - buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT), ) - self.block = block + self._block = block self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) vbox = gtk.VBox() - #Add the title label - vbox.pack_start(get_title_label('Parameters'), False) #Create the scrolled window to hold all the parameters scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(vbox) self.vbox.pack_start(scrolled_window, True) + #Params box for block parameters + self._params_box = gtk.VBox() + self._params_box.pack_start(get_title_label('Parameters'), False) + self._input_object_params = list() #Error Messages for the block self._error_box = gtk.VBox() self._error_messages_text_display = TextDisplay() - self._error_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) self._error_box.pack_start(get_title_label('Error Messages'), False) self._error_box.pack_start(self._error_messages_text_display, False) #Docs for the block self._docs_box = err_box = gtk.VBox() self._docs_text_display = TextDisplay() - self._docs_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) self._docs_box.pack_start(get_title_label('Documentation'), False) self._docs_box.pack_start(self._docs_text_display, False) - #Add all the parameters - for param in self.block.get_params(): - vbox.pack_start(param.get_input_object(self._handle_changed), False) - #Add the error and docs box + #Add the boxes + vbox.pack_start(self._params_box, False) vbox.pack_start(self._error_box, False) vbox.pack_start(self._docs_box, False) - #connect and show - self.connect('key_press_event', self._handle_key_press) + #connect events + self.connect('key-press-event', self._handle_key_press) + self.connect('show', self._update_gui) + #show all (performs initial gui update) self.show_all() - #initial update - for param in self.block.get_params(): param.update() - self._update() - def _update(self): + def _params_changed(self): + """ + Have the params in this dialog changed? + Ex: Added, removed, type change, hide change... + To the props dialog, the hide setting of 'none' and 'part' are identical. + Therfore, the props dialog only cares if the hide setting is/not 'all'. + Make a hash that uniquely represents the params state. + @return true if changed + """ + old_hash = self._hash + self._hash = 0 + for param in self._block.get_params(): + self._hash ^= hash(param) + self._hash ^= hash(param.get_type()) + self._hash ^= hash(param.get_hide() == 'all') + return self._hash != old_hash + + def _handle_changed(self, *args): + """ + A change occured within a param: + Rewrite/validate the block and update the gui. """ + #update for the block + self._block.rewrite() + self._block.validate() + self._update_gui() + + def _update_gui(self, *args): + """ + Repopulate the parameters box (if changed). + Update all the input parameters. Update the error messages box. Hide the box if there are no errors. Update the documentation block. Hide the box if there are no docs. """ - self.block.validate() + #update the params box + if self._params_changed(): + #hide params box before changing + self._params_box.hide_all() + #empty the params box + for io_param in list(self._input_object_params): + self._params_box.remove(io_param) + self._input_object_params.remove(io_param) + io_param.destroy() + #repopulate the params box + for param in self._block.get_params(): + if param.get_hide() == 'all': continue + io_param = param.get_input(self._handle_changed) + self._input_object_params.append(io_param) + self._params_box.pack_start(io_param, False) + #show params box with new params + self._params_box.show_all() #update the errors box - if self.block.is_valid(): self._error_box.hide() + if self._block.is_valid(): self._error_box.hide() else: self._error_box.show() - messages = '\n\n'.join(self.block.get_error_messages()) + messages = '\n\n'.join(self._block.get_error_messages()) self._error_messages_text_display.set_text(messages) #update the docs box - if self.block.get_doc(): self._docs_box.show() + if self._block.get_doc(): self._docs_box.show() else: self._docs_box.hide() - self._docs_text_display.set_text(self.block.get_doc()) + self._docs_text_display.set_text(self._block.get_doc()) def _handle_key_press(self, widget, event): """ @@ -108,38 +156,16 @@ class ParamsDialog(gtk.Dialog): Call the ok response when enter is pressed. @return false to forward the keypress """ - keyname = gtk.gdk.keyval_name(event.keyval) - if keyname == 'Return': self.response(gtk.RESPONSE_OK) + if event.keyval == gtk.keysyms.Return: + self.response(gtk.RESPONSE_ACCEPT) + return True #handled here return False #forward the keypress - def _handle_changed(self, param): - """ - A change occured, update any dependent parameters: - The enum inside the variable type may have changed and, - the variable param will need an external update. - @param param the graphical parameter that initiated the callback - """ - #update dependent params - if param.is_enum(): - for other_param in param.get_parent().get_params(): - if param.get_key() is not other_param.get_key() and ( - param.get_key() in other_param._type or \ - param.get_key() in other_param._hide): other_param.update() - #update - self._update() - return True - def run(self): """ - Call run(). - @return true if a change occured. + Run the dialog and get its response. + @return true if the response was accept """ - original_data = list() - for param in self.block.get_params(): - original_data.append(param.get_value()) - gtk.Dialog.run(self) + response = gtk.Dialog.run(self) self.destroy() - new_data = list() - for param in self.block.get_params(): - new_data.append(param.get_value()) - return original_data != new_data + return response == gtk.RESPONSE_ACCEPT diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py index 04b18b18a..3f6b79224 100644 --- a/grc/gui/StateCache.py +++ b/grc/gui/StateCache.py @@ -17,7 +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 """ -from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO, get_action_from_name +import Actions from Constants import STATE_CACHE_SIZE class StateCache(object): @@ -88,5 +88,5 @@ class StateCache(object): """ Update the undo and redo actions based on the number of next and prev states. """ - get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(self.num_next_states != 0) - get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(self.num_prev_states != 0) + Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) + Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index ee6dc6cdc..83036a4b8 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Constants import POSSIBLE_ROTATIONS from Cheetah.Template import Template +import gobject def get_rotated_coordinate(coor, rotation): """ @@ -54,23 +55,6 @@ def get_angle_from_coordinates((x1,y1), (x2,y2)): if y2 > y1: return 270 else: return 90 -def xml_encode(string): - """ - Encode a string into an xml safe string by replacing special characters. - Needed for gtk pango markup in labels. - @param string the input string - @return output string with safe characters - """ - string = str(string) - for char, safe in ( - ('&', '&'), - ('<', '<'), - ('>', '>'), - ('"', '"'), - ("'", '''), - ): string = string.replace(char, safe) - return string - def parse_template(tmpl_str, **kwargs): """ Parse the template string with the given args. @@ -78,5 +62,5 @@ def parse_template(tmpl_str, **kwargs): @param tmpl_str the template as a string @return a string of the parsed template """ - kwargs['encode'] = xml_encode + kwargs['encode'] = gobject.markup_escape_text return str(Template(tmpl_str, kwargs)) diff --git a/grc/python/Block.py b/grc/python/Block.py index 47fe13a3c..dd39b095d 100644 --- a/grc/python/Block.py +++ b/grc/python/Block.py @@ -18,10 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from .. base.Block import Block as _Block +from .. gui.Block import Block as _GUIBlock import extract_docs import extract_category -class Block(_Block): +class Block(_Block, _GUIBlock): + + def is_virtual_sink(self): return self.get_key() == 'virtual_sink' + def is_virtual_source(self): return self.get_key() == 'virtual_source' ##for make source to keep track of indexes _source_count = 0 @@ -48,13 +52,13 @@ class Block(_Block): flow_graph=flow_graph, n=n, ) + _GUIBlock.__init__(self) def validate(self): """ Validate this block. Call the base class validate. Evaluate the checks: each check must evaluate to True. - Adjust the nports. """ _Block.validate(self) #evaluate the checks @@ -65,6 +69,12 @@ class Block(_Block): try: assert check_eval except AssertionError: self.add_error_message('Check "%s" failed.'%check) except: self.add_error_message('Check "%s" did not evaluate.'%check) + + def rewrite(self): + """ + Add and remove ports to adjust for the nports. + """ + _Block.rewrite(self) #adjust nports for get_ports, get_port in ( (self.get_sources, self.get_source), diff --git a/grc/python/Connection.py b/grc/python/Connection.py index 5eba9f24d..edc18841a 100644 --- a/grc/python/Connection.py +++ b/grc/python/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +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 @@ -18,8 +18,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from .. base.Connection import Connection as _Connection +from .. gui.Connection import Connection as _GUIConnection -class Connection(_Connection): +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' diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py index 8cad8be49..4dd18a81f 100644 --- a/grc/python/FlowGraph.py +++ b/grc/python/FlowGraph.py @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import expr_utils from .. base.FlowGraph import FlowGraph as _FlowGraph +from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph from Block import Block from Connection import Connection import re @@ -26,9 +27,13 @@ import re _variable_matcher = re.compile('^(variable\w*)$') _parameter_matcher = re.compile('^(parameter)$') -class FlowGraph(_FlowGraph): +class FlowGraph(_FlowGraph, _GUIFlowGraph): + + def __init__(self, **kwargs): + _FlowGraph.__init__(self, **kwargs) + _GUIFlowGraph.__init__(self) + self._eval_cache = dict() - _eval_cache = dict() def _eval(self, code, namespace, namespace_hash): """ Evaluate the code with the given namespace. @@ -37,6 +42,7 @@ class FlowGraph(_FlowGraph): @param namespace_hash a unique hash for the namespace @return 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): @@ -109,6 +115,13 @@ class FlowGraph(_FlowGraph): parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks()) return parameters + def rewrite(self): + """ + Flag the namespace to be renewed. + """ + self._renew_eval_ns = True + _FlowGraph.rewrite(self) + def evaluate(self, expr): """ Evaluate the expression. @@ -116,8 +129,8 @@ class FlowGraph(_FlowGraph): @throw Exception bad expression @return the evaluated data """ - if self.is_flagged(): - self.deflag() + if self._renew_eval_ns: + self._renew_eval_ns = False #reload namespace n = dict() #load imports diff --git a/grc/python/Param.py b/grc/python/Param.py index f971d0c3f..34d5ab116 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ import expr_utils -from .. base.Param import Param as _Param, EntryParam +from .. base.Param import Param as _Param +from .. gui.Param import Param as _GUIParam +from .. gui.Param import EntryParam import Constants import numpy import os @@ -83,21 +85,24 @@ COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) REAL_TYPES = tuple(REAL_TYPES + INT_TYPES) INT_TYPES = tuple(INT_TYPES) -class Param(_Param): +class Param(_Param, _GUIParam): - _init = False - _hostage_cells = list() + def __init__(self, **kwargs): + _Param.__init__(self, **kwargs) + _GUIParam.__init__(self) + self._init = False + self._hostage_cells = list() - ##possible param types - TYPES = _Param.TYPES + [ + def get_types(self): return ( + 'raw', 'enum', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex', 'string', 'bool', 'file_open', 'file_save', - 'id', + 'id', 'stream_id', 'grid_pos', 'notebook', 'import', - ] + ) def __repr__(self): """ @@ -148,9 +153,9 @@ class Param(_Param): dt_str = dt_str[:max_len-3] + '...' return dt_str - def get_input_class(self): - if self.get_type() in ('file_open', 'file_save'): return FileParam - return _Param.get_input_class(self) + def get_input(self, *args, **kwargs): + if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs) + return _GUIParam.get_input(self, *args, **kwargs) def get_color(self): """ @@ -172,6 +177,7 @@ class Param(_Param): '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, @@ -248,7 +254,7 @@ class Param(_Param): elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', '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: %s'%(v, e) + 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': @@ -310,14 +316,31 @@ class Param(_Param): #can python use this as a variable? try: assert _check_id_matcher.match(v) except AssertionError: raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v - params = self.get_all_params('id') - keys = [param.get_value() for param in params] - try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled + ids = [param.get_value() for param in self.get_all_params(t)] + try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled except: raise Exception, 'ID "%s" is not unique.'%v try: assert v not in ID_BLACKLIST except: 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(): + try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled + except: 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(): + try: assert v in ids + except: raise Exception, 'Stream ID "%s" is not found.'%v + return v + ######################### # Grid Position Type ######################### elif t == 'grid_pos': @@ -362,7 +385,7 @@ class Param(_Param): 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 - try: assert int(page_index) in range(len(notebook_block.get_param('labels').get_evaluated())) + try: assert int(page_index) in range(len(notebook_block.get_param('labels').evaluate())) except: raise Exception, 'Page index "%s" is not a valid index number.'%page_index return notebook_id, page_index ######################### @@ -380,17 +403,18 @@ class Param(_Param): 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. @return a string representing the code """ - #run init tasks in evaluate - #such as setting flags - if not self._init: self.evaluate() v = self.get_value() t = self.get_type() if t in ('string', 'file_open', 'file_save'): #string types + if not self._init: self.evaluate() if self._stringify_flag: return '"%s"'%v.replace('"', '\"') else: return v elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types + if not self._init: self.evaluate() if self._lisitify_flag: return '(%s, )'%v else: return '(%s)'%v else: return v diff --git a/grc/python/Platform.py b/grc/python/Platform.py index d55dbf4ce..bb56d361b 100644 --- a/grc/python/Platform.py +++ b/grc/python/Platform.py @@ -20,10 +20,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os from gnuradio import gr from .. base.Platform import Platform as _Platform +from .. gui.Platform import Platform as _GUIPlatform from FlowGraph import FlowGraph as _FlowGraph from Connection import Connection as _Connection from Block import Block as _Block -from Port import Source,Sink +from Port import Port as _Port from Param import Param as _Param from Generator import Generator from Constants import \ @@ -46,7 +47,7 @@ COLORS = (#title, #color spec ('Message', Constants.MSG_COLOR_SPEC), ) -class Platform(_Platform): +class Platform(_Platform, _GUIPlatform): def __init__(self): """ @@ -70,6 +71,7 @@ class Platform(_Platform): generator=Generator, colors=COLORS, ) + _GUIPlatform.__init__(self) ############################################## # Constructors @@ -77,6 +79,5 @@ class Platform(_Platform): FlowGraph = _FlowGraph Connection = _Connection Block = _Block - Source = Source - Sink = Sink + Port = _Port Param = _Param diff --git a/grc/python/Port.py b/grc/python/Port.py index daf8f9ca3..6965371df 100644 --- a/grc/python/Port.py +++ b/grc/python/Port.py @@ -18,41 +18,100 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from .. base.Port import Port as _Port +from .. gui.Port import Port as _GUIPort import Constants -class Port(_Port): - - ##possible port types - TYPES = ['complex', 'float', 'int', 'short', 'byte', 'msg'] - - def __init__(self, block, n): +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 + +class Port(_Port, _GUIPort): + + def __init__(self, block, n, dir): """ Make a new port from nested data. @param block the parent element @param n the nested odict + @param dir the direction """ + self._n = n + if n['type'] == 'msg': n['key'] = 'msg' + if dir == 'source' and not n.find('key'): + n['key'] = str(block._source_count) + block._source_count += 1 + if dir == 'sink' and not n.find('key'): + n['key'] = str(block._sink_count) + block._sink_count += 1 #build the port _Port.__init__( self, block=block, n=n, + dir=dir, ) + _GUIPort.__init__(self) self._nports = n.find('nports') or '' self._vlen = n.find('vlen') or '' self._optional = bool(n.find('optional')) + def get_types(self): return ('complex', 'float', 'int', 'short', 'byte', 'msg', '') + def validate(self): _Port.validate(self) try: assert self.get_enabled_connections() or self.get_optional() except AssertionError: self.add_error_message('Port is not connected.') try: assert self.is_source() or len(self.get_enabled_connections()) <= 1 except AssertionError: self.add_error_message('Port has too many connections.') + #message port logic if self.get_type() == 'msg': try: assert not self.get_nports() except AssertionError: self.add_error_message('A port of type "msg" cannot have "nports" set.') try: assert self.get_vlen() == 1 except AssertionError: self.add_error_message('A port of type "msg" must have a "vlen" of 1.') + def rewrite(self): + """ + Handle the port cloning for virtual blocks. + """ + _Port.rewrite(self) + if self.get_parent().is_virtual_sink() or self.get_parent().is_virtual_source(): + try: #clone type and vlen + source = self.resolve_virtual_source() + self._type = str(source.get_type()) + self._vlen = str(source.get_vlen()) + except: #reset type and vlen + self._type = '' + self._vlen = '' + + def resolve_virtual_source(self): + if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self) + if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self) + def get_vlen(self): """ Get the vector length. @@ -109,24 +168,4 @@ class Port(_Port): def copy(self, new_key=None): n = self._n.copy() if new_key: n['key'] = new_key - return self.__class__(self.get_parent(), n) - -class Source(Port): - - def __init__(self, block, n): - self._n = n #save n - if n['type'] == 'msg': n['key'] = 'msg' - if not n.find('key'): - n['key'] = str(block._source_count) - block._source_count = block._source_count + 1 - Port.__init__(self, block, n) - -class Sink(Port): - - def __init__(self, block, n): - self._n = n #save n - if n['type'] == 'msg': n['key'] = 'msg' - if not n.find('key'): - n['key'] = str(block._sink_count) - block._sink_count = block._sink_count + 1 - Port.__init__(self, block, n) + return self.__class__(self.get_parent(), n, self._dir) diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl index df346dd16..dce4037d5 100644 --- a/grc/python/flow_graph.tmpl +++ b/grc/python/flow_graph.tmpl @@ -154,6 +154,13 @@ class $(class_name)(gr.hier_block2): ## The port name should be the id of the parent block. ## However, port names for IO pads should be self. ######################################################## +#def make_port_name($port) + #if $port.get_parent().get_key().startswith('pad_') +self#slurp + #else +self.$port.get_parent().get_id()#slurp + #end if +#end def #if $connections $DIVIDER @@ -163,17 +170,14 @@ class $(class_name)(gr.hier_block2): #for $con in $connections #set $source = $con.get_source() #set $sink = $con.get_sink() - #if $source.get_parent().get_key() == 'pad_source' - #set $source_name = 'self' - #else - #set $source_name = 'self.' + $source.get_parent().get_id() + ##resolve virtual sources to the actual sources + #if $source.get_parent().is_virtual_source() + #set $source = $source.resolve_virtual_source() #end if - #if $sink.get_parent().get_key() == 'pad_sink' - #set $sink_name = 'self' - #else - #set $sink_name = 'self.' + $sink.get_parent().get_id() + ##do not generate connections with virtual sinks + #if not $sink.get_parent().is_virtual_sink() + self.connect(($make_port_name($source), $source.get_key()), ($make_port_name($sink), $sink.get_key())) #end if - self.connect(($source_name, $source.get_key()), ($sink_name, $sink.get_key())) #end for ######################################################## @@ -194,6 +198,20 @@ class $(class_name)(gr.hier_block2): ## For top block code, generate a main routine. ## Instantiate the top block and run as gui or cli. ######################################################## +#def make_default($type, $param) + #if $type == 'eng_float' +eng_notation.num_to_str($param.get_make())#slurp + #else +$param.get_make()#slurp + #end if +#end def +#def make_short_id($param) + #set $short_id = $param.get_param('short_id').get_evaluated() + #if $short_id + #set $short_id = '-' + $short_id + #end if +$short_id#slurp +#end def #if $generate_options != 'hb' if __name__ == '__main__': parser = OptionParser(option_class=eng_option, usage="%prog: [options]") @@ -202,12 +220,8 @@ if __name__ == '__main__': #set $type = $param.get_param('type').get_value() #if $type #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id())) - #set $short_id = $param.get_param('short_id').get_evaluated() - #if $short_id - #set $short_id = '-' + $short_id - #end if - parser.add_option("$short_id", "--$param.get_id()", dest="$param.get_id()", type="$type", default=$param.get_make(), - help="Set $($param.get_param('label').evaluate() or $param.get_id()) [default=%default]") + parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param), + help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]") #end if #end for (options, args) = parser.parse_args() diff --git a/grc/scripts/usrp2_probe b/grc/scripts/usrp2_probe index 00d4366dd..38c8f655c 100755 --- a/grc/scripts/usrp2_probe +++ b/grc/scripts/usrp2_probe @@ -32,9 +32,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay from gnuradio.grc.python.Platform import Platform platform = Platform() -from gnuradio.grc.gui.Platform import Platform -platform = Platform(platform) - flow_graph = platform.get_new_flow_graph() block = flow_graph.get_new_block('usrp2_probe') @@ -42,6 +39,11 @@ block = flow_graph.get_new_block('usrp2_probe') usrp_interface_param = block.get_param('interface') usrp_type_param = block.get_param('type') +def get_input(param): + param.validate() + input = param.get_input() + return input + class USRP2ProbeWindow(gtk.Window): """ The main window for USRP Dignostics. @@ -69,8 +71,8 @@ class USRP2ProbeWindow(gtk.Window): #create vbox for storage vbox = gtk.VBox() frame.add(vbox) - vbox.pack_start(usrp_interface_param.get_input_object(), False) - vbox.pack_start(usrp_type_param.get_input_object(), False) + vbox.pack_start(get_input(usrp_interface_param), False) + vbox.pack_start(get_input(usrp_type_param), False) #make the tree model for holding mac addrs self.treestore = gtk.TreeStore(gobject.TYPE_STRING) self.treeview = gtk.TreeView(self.treestore) diff --git a/grc/scripts/usrp_probe b/grc/scripts/usrp_probe index 6565612c1..d2e92e753 100755 --- a/grc/scripts/usrp_probe +++ b/grc/scripts/usrp_probe @@ -30,9 +30,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay from gnuradio.grc.python.Platform import Platform platform = Platform() -from gnuradio.grc.gui.Platform import Platform -platform = Platform(platform) - flow_graph = platform.get_new_flow_graph() block = flow_graph.get_new_block('usrp_probe') @@ -40,6 +37,11 @@ block = flow_graph.get_new_block('usrp_probe') usrp_which_param = block.get_param('which') usrp_dboard_param = block.get_param('dboard') +def get_input(param): + param.validate() + input = param.get_input() + return input + class USRPProbeWindow(gtk.Window): """ The main window for USRP Dignostics. @@ -66,8 +68,8 @@ class USRPProbeWindow(gtk.Window): #create vbox for storage vbox = gtk.VBox() frame.add(vbox) - vbox.pack_start(usrp_which_param.get_input_object(), False) - vbox.pack_start(usrp_dboard_param.get_input_object(), False) + vbox.pack_start(get_input(usrp_which_param), False) + vbox.pack_start(get_input(usrp_dboard_param), False) self.probe_button = gtk.Button('Probe') self.probe_button.connect('clicked', self._probe_usrp) vbox.pack_start(self.probe_button, False) diff --git a/grc/todo.txt b/grc/todo.txt index bb40e1f16..b4e3af39d 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -25,8 +25,7 @@ * size params for the graphical sinks * callbacks for set average on fft, waterfall, number sinks * add units to params: Sps, Hz, dB... -* command line options should replace _ with - for the --option - * add bool type to command line option store_true or store_false +* add bool type to command line option store_true or store_false ################################################## # Features @@ -59,6 +58,8 @@ ################################################## # 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 @@ -66,15 +67,8 @@ * dont generate py files in saved flowgraph dir * save/restore cwd * threads dont die on exit in probe and variable sink -* overloaded gui classes for each platform, move param input objects into overloaded -* align param titles in paramsdialog -* better error for blank string params +* align param titles in properties dialog * weird grid params misbehaving -* params dialog needs to dynamically update for all params - * will not update for non-enum params - * needs to account for added or removed params - * example with grid params need update after notebook change -* use .strip() on the hide property so we can do away with #slurp(s) in the templates ################################################## # Future diff --git a/gruel/src/lib/.gitignore b/gruel/src/lib/.gitignore index 89a768d46..165e179d6 100644 --- a/gruel/src/lib/.gitignore +++ b/gruel/src/lib/.gitignore @@ -2,3 +2,4 @@ /Makefile.in /.libs /.deps +test_gruel diff --git a/usrp2/firmware/Makefile.am b/usrp2/firmware/Makefile.am index 62b2d5bad..c75136de1 100644 --- a/usrp2/firmware/Makefile.am +++ b/usrp2/firmware/Makefile.am @@ -22,8 +22,8 @@ include $(top_srcdir)/Makefile.common EXTRA_DIST = \ bootstrap \ configure \ - configure.gnu - + configure.gnu \ + u2_flash_tool SUBDIRS = config diff --git a/usrp2/firmware/configure.gnu b/usrp2/firmware/configure.gnu index 60d6d2a7e..53ca9b518 100755 --- a/usrp2/firmware/configure.gnu +++ b/usrp2/firmware/configure.gnu @@ -3,7 +3,7 @@ # wrapper to setup cross-compilation of firmware # -for v in CC CPP CXX AS AR NM RANLIB STRIP F77 CFLAGS CXXFLAGS CPPFLAGS LDFLAGS +for v in CC CPP CXX AS AR NM RANLIB STRIP F77 CFLAGS CXXFLAGS CPPFLAGS LDFLAGS CCAS CCASFLAGS USB_LIBS USB_CFLAGS do unset $v done @@ -26,6 +26,10 @@ do (CXXFLAGS=*) ;; (CPPFLAGS=*) ;; (LDFLAGS=*) ;; + (CCAS=*) ;; + (CCASFLAGS=*) ;; + (USB_CFLAGS=*) ;; + (USB_LIBS=*) ;; (*) args="$args $t" ;; esac done diff --git a/usrp2/fpga/sdr_lib/dsp_core_rx.v b/usrp2/fpga/sdr_lib/dsp_core_rx.v index ee713e4ac..af4f0b9fb 100644 --- a/usrp2/fpga/sdr_lib/dsp_core_rx.v +++ b/usrp2/fpga/sdr_lib/dsp_core_rx.v @@ -139,20 +139,20 @@ module dsp_core_rx always @(posedge clk) strobe_cic_d1 <= strobe_cic; small_hb_dec #(.WIDTH(18)) small_hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb1), + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1)); small_hb_dec #(.WIDTH(18)) small_hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb1), + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1)); wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.cpi(cpi_hb), + (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.cpi(cpi_hb), + (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out)); diff --git a/usrp2/fpga/sdr_lib/hb_dec.v b/usrp2/fpga/sdr_lib/hb_dec.v index b256eb57f..8fb5ba222 100644 --- a/usrp2/fpga/sdr_lib/hb_dec.v +++ b/usrp2/fpga/sdr_lib/hb_dec.v @@ -9,6 +9,7 @@ module hb_dec (input clk, input rst, input bypass, + input run, input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block input stb_in, input [IWIDTH-1:0] data_in, @@ -25,7 +26,7 @@ module hb_dec assign do_mult = 1; always @(posedge clk) - if(rst) + if(rst | ~run) odd <= 0; else if(stb_in) odd <= ~odd; @@ -34,7 +35,7 @@ module hb_dec assign write_even = stb_in & ~odd; always @(posedge clk) - if(rst) + if(rst | ~run) phase <= 0; else if(stb_in & odd) phase <= 1; diff --git a/usrp2/fpga/sdr_lib/small_hb_dec.v b/usrp2/fpga/sdr_lib/small_hb_dec.v index 9957de15a..8519b628a 100644 --- a/usrp2/fpga/sdr_lib/small_hb_dec.v +++ b/usrp2/fpga/sdr_lib/small_hb_dec.v @@ -8,6 +8,7 @@ module small_hb_dec (input clk, input rst, input bypass, + input run, input stb_in, input [WIDTH-1:0] data_in, output reg stb_out, @@ -21,15 +22,26 @@ module small_hb_dec wire go; reg phase, go_d1, go_d2, go_d3, go_d4; always @(posedge clk) - if(rst) + if(rst | ~run) phase <= 0; else if(stb_in_d1) phase <= ~phase; assign go = stb_in_d1 & phase; - always @(posedge clk) go_d1 <= go; - always @(posedge clk) go_d2 <= go_d1; - always @(posedge clk) go_d3 <= go_d2; - always @(posedge clk) go_d4 <= go_d3; + always @(posedge clk) + if(rst | ~run) + begin + go_d1 <= 0; + go_d2 <= 0; + go_d3 <= 0; + go_d4 <= 0; + end + else + begin + go_d1 <= go; + go_d2 <= go_d1; + go_d3 <= go_d2; + go_d4 <= go_d3; + end wire [17:0] coeff_a = -10690; wire [17:0] coeff_b = 75809; diff --git a/vrt/include/vrt/quadradio.h b/vrt/include/vrt/quadradio.h index 83323f093..d30ee14f1 100644 --- a/vrt/include/vrt/quadradio.h +++ b/vrt/include/vrt/quadradio.h @@ -72,12 +72,14 @@ namespace vrt { int *ctrl_fd_ptr, struct in_addr *ctrl_port_inaddr, int *data_fd_ptr, int *data_port_ptr); + // dsprxno selects the Rx DSP pipe (0 or 1) to configure static bool - send_rx_command(int ctrl_fd, bool start, - struct in_addr addr, int data_port, int samples_per_pkt, int siggen_param); + send_rx_command(int ctrl_fd, int rxdspno, bool start, + struct in_addr addr, int data_port, int samples_per_pkt); + // dsprxno selects the Rx DSP pipe (0 or 1) to stop static bool - send_stop_rx_command(int ctrl_fd); + send_stop_rx_command(int ctrl_fd, int rxdspno); static int control_port() { return 790; } int data_socket_fd() const { return d_data_fd; } @@ -94,9 +96,11 @@ namespace vrt { vrt::rx::sptr vrt_rx() const { return d_rx; } + // FIXME add rxdspno as the first parameter bool start_streaming(int samples_per_pkt = 0); - bool stop_streaming(); + // FIXME add rxdspno as the first parameter + bool stop_streaming(); /* convenience methods that ultimately write the dboard pins */ bool set_center_freq(double target_freq); diff --git a/vrt/lib/quadradio.cc b/vrt/lib/quadradio.cc index 8cf542e0f..a8bc3e525 100644 --- a/vrt/lib/quadradio.cc +++ b/vrt/lib/quadradio.cc @@ -76,14 +76,18 @@ vrt::quadradio::open(const char *ip) bool vrt::quadradio::start_streaming(int samples_per_pkt) { - return send_rx_command(d_ctrl_fd, true, d_ctrl_port_inaddr, - d_data_port, samples_per_pkt, 0); + int rxdspno = 0; // FIXME make it the first param + + return send_rx_command(d_ctrl_fd, rxdspno, true, d_ctrl_port_inaddr, + d_data_port, samples_per_pkt); } bool vrt::quadradio::stop_streaming() { - return send_stop_rx_command(d_ctrl_fd); + int rxdspno = 0; // FIXME make it the first param + + return send_stop_rx_command(d_ctrl_fd, rxdspno); } bool @@ -288,9 +292,9 @@ vrt::quadradio::open_sockets(const char *quad_radio_ip, int quad_radio_ctrl_port // ------------------------------------------------------------------------ bool -vrt::quadradio::send_rx_command(int ctrl_fd, bool start, +vrt::quadradio::send_rx_command(int ctrl_fd, int rxdspno, bool start, struct in_addr addr, int data_port, - int samples_per_pkt, int siggen_param) + int samples_per_pkt) { uint32_t cmd[7]; cmd[0] = htonl(0); // verb: set @@ -299,17 +303,17 @@ vrt::quadradio::send_rx_command(int ctrl_fd, bool start, cmd[3] = addr.s_addr; // ip address to send data to (already network endian) cmd[4] = htonl(data_port); // port to send data to cmd[5] = htonl(samples_per_pkt); - cmd[6] = htonl(siggen_param); + cmd[6] = htonl(rxdspno); // the DSP pipeline to configure return send_and_check(ctrl_fd, cmd, sizeof(cmd)); } bool -vrt::quadradio::send_stop_rx_command(int ctrl_fd) +vrt::quadradio::send_stop_rx_command(int ctrl_fd, int rxdspno) { struct in_addr in_addr; in_addr.s_addr = 0; - return send_rx_command(ctrl_fd, false, in_addr, 0, 0, 0); + return send_rx_command(ctrl_fd, rxdspno, false, in_addr, 0, 0); } bool |