+#
+# 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
/compile
/build
/run_tests.sh
-/*-stamp
then
AC_PROG_F77
AC_F77_LIBRARY_LDFLAGS
+ AC_PROG_CC dnl bux fix to restore $ac_ext
fi
])
dnl AX_BOOST_UNIT_TEST_FRAMEWORK
dnl AX_BOOST_WSERIALIZATION
-
-dnl If this is being done from a subversion tree, create variables
-GR_SUBVERSION
BUILD_DATE=`date -R -u`
AC_SUBST(BUILD_DATE)
gr_pfb_channelizer_ccf.cc \
gr_pfb_decimator_ccf.cc \
gr_pfb_interpolator_ccf.cc \
- gr_pfb_arb_resampler_ccf.cc
+ gr_pfb_arb_resampler_ccf.cc \
+ gr_pfb_clock_sync_ccf.cc
libfilter_qa_la_common_SOURCES = \
qa_filter.cc \
gr_pfb_channelizer_ccf.h \
gr_pfb_decimator_ccf.h \
gr_pfb_interpolator_ccf.h \
- gr_pfb_arb_resampler_ccf.h
+ gr_pfb_arb_resampler_ccf.h \
+ gr_pfb_clock_sync_ccf.h
noinst_HEADERS = \
assembly.h \
gr_pfb_decimator_ccf.i \
gr_pfb_interpolator_ccf.i \
gr_pfb_arb_resampler_ccf.i \
+ gr_pfb_clock_sync_ccf.i \
$(GENERATED_I)
endif
#include <gr_pfb_decimator_ccf.h>
#include <gr_pfb_interpolator_ccf.h>
#include <gr_pfb_arb_resampler_ccf.h>
+#include <gr_pfb_clock_sync_ccf.h>
%}
%include "gr_iir_filter_ffd.i"
%include "gr_pfb_decimator_ccf.i"
%include "gr_pfb_interpolator_ccf.i"
%include "gr_pfb_arb_resampler_ccf.i"
+%include "gr_pfb_clock_sync_ccf.i"
%include "filter_generated.i"
#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,
* 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
#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)
* 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>
*
*/
--- /dev/null
+/* -*- 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 <cstdio>
+#include <cmath>
+
+#include <gr_pfb_clock_sync_ccf.h>
+#include <gr_fir_ccf.h>
+#include <gr_fir_util.h>
+#include <gr_io_signature.h>
+#include <gr_math.h>
+
+gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size,
+ float init_phase)
+{
+ return gr_pfb_clock_sync_ccf_sptr (new gr_pfb_clock_sync_ccf (sps, gain, taps,
+ filter_size,
+ init_phase));
+}
+
+
+gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size,
+ float init_phase)
+ : gr_block ("pfb_clock_sync_ccf",
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ gr_make_io_signature2 (2, 2, sizeof(gr_complex), sizeof(float))),
+ d_updated (false), d_sps(sps), d_alpha(gain)
+{
+ d_nfilters = filter_size;
+
+ // Store the last filter between calls to work
+ // The accumulator keeps track of overflow to increment the stride correctly.
+ // set it here to the fractional difference based on the initial phaes
+ // assert(init_phase <= 2*M_PI);
+ float x = init_phase / (2*M_PI); //normalize initial phase
+ d_acc = x*(d_nfilters-1);
+ d_last_filter = (int)floor(d_acc);
+ d_acc = fmodf(d_acc, 1);
+ d_start_count = 0;
+
+
+ d_filters = std::vector<gr_fir_ccf*>(d_nfilters);
+ d_diff_filters = std::vector<gr_fir_ccf*>(d_nfilters);
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<float> vtaps(0, d_nfilters);
+ for(unsigned int i = 0; i < d_nfilters; i++) {
+ d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ }
+
+ // Now, actually set the filters' taps
+ std::vector<float> dtaps;
+ create_diff_taps(taps, dtaps);
+ set_taps(taps, d_taps, d_filters);
+ set_taps(dtaps, d_dtaps, d_diff_filters);
+}
+
+gr_pfb_clock_sync_ccf::~gr_pfb_clock_sync_ccf ()
+{
+ for(unsigned int i = 0; i < d_nfilters; i++) {
+ delete d_filters[i];
+ }
+}
+
+void
+gr_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps,
+ std::vector< std::vector<float> > &ourtaps,
+ std::vector<gr_fir_ccf*> &ourfilter)
+{
+ unsigned int i,j;
+
+ unsigned int ntaps = newtaps.size();
+ d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters);
+
+ // Create d_numchan vectors to store each channel's taps
+ ourtaps.resize(d_nfilters);
+
+ // Make a vector of the taps plus fill it out with 0's to fill
+ // each polyphase filter with exactly d_taps_per_filter
+ std::vector<float> tmp_taps;
+ tmp_taps = newtaps;
+ while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ // Partition the filter
+ for(i = 0; i < d_nfilters; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
+ ourtaps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; // add taps to channels in reverse order
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ ourfilter[i]->set_taps(ourtaps[i]);
+ }
+
+ // Set the history to ensure enough input items for each filter
+ set_history (d_taps_per_filter + d_sps);
+
+ d_updated = true;
+}
+
+void
+gr_pfb_clock_sync_ccf::create_diff_taps(const std::vector<float> &newtaps,
+ std::vector<float> &difftaps)
+{
+ difftaps.clear();
+ difftaps.push_back(0); //newtaps[0]);
+ for(unsigned int i = 1; i < newtaps.size()-1; i++) {
+ difftaps.push_back(newtaps[i+1] - newtaps[i-1]);
+ }
+ difftaps.push_back(0);//-newtaps[newtaps.size()-1]);
+}
+
+void
+gr_pfb_clock_sync_ccf::print_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_nfilters; i++) {
+ printf("filter[%d]: [%.4e, ", i, d_taps[i][0]);
+ for(j = 1; j < d_taps_per_filter-1; j++) {
+ printf("%.4e,", d_taps[i][j]);
+ }
+ printf("%.4e]\n", d_taps[i][j]);
+ }
+}
+
+void
+gr_pfb_clock_sync_ccf::print_diff_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_nfilters; i++) {
+ printf("filter[%d]: [%.4e, ", i, d_dtaps[i][0]);
+ for(j = 1; j < d_taps_per_filter-1; j++) {
+ printf("%.4e,", d_dtaps[i][j]);
+ }
+ printf("%.4e]\n", d_dtaps[i][j]);
+ }
+}
+
+
+std::vector<float>
+gr_pfb_clock_sync_ccf::channel_taps(int channel)
+{
+ std::vector<float> taps;
+ unsigned int i;
+ for(i = 0; i < d_taps_per_filter; i++) {
+ taps.push_back(d_taps[channel][i]);
+ }
+ return taps;
+}
+
+std::vector<float>
+gr_pfb_clock_sync_ccf::diff_channel_taps(int channel)
+{
+ std::vector<float> taps;
+ unsigned int i;
+ for(i = 0; i < d_taps_per_filter; i++) {
+ taps.push_back(d_dtaps[channel][i]);
+ }
+ return taps;
+}
+
+
+int
+gr_pfb_clock_sync_ccf::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex *in = (gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+ float *err = (float *) output_items[1];
+
+ if (d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ // We need this many to process one output
+ int nrequired = ninput_items[0] - d_taps_per_filter;
+
+ int i = 0, count = d_start_count;
+ float error = 0;
+
+ // produce output as long as we can and there are enough input samples
+ while((i < noutput_items) && (count < nrequired)) {
+ out[i] = d_filters[d_last_filter]->filter(&in[count]);
+ error = (out[i] * d_diff_filters[d_last_filter]->filter(&in[count])).real();
+ err[i] = error;
+
+ d_acc += d_alpha*error;
+ gr_branchless_clip(d_acc, 1);
+
+ int newfilter;
+ newfilter = (int)((float)d_last_filter + d_acc);
+ if(newfilter != (int)d_last_filter)
+ d_acc = 0.5;
+
+ if(newfilter >= (int)d_nfilters) {
+ d_last_filter = newfilter - d_nfilters;
+ count++;
+ }
+ else if(newfilter < 0) {
+ d_last_filter = d_nfilters + newfilter;
+ count--;
+ }
+ else {
+ d_last_filter = newfilter;
+ }
+
+ i++;
+ count += d_sps;
+ }
+
+ // Set the start index at the next entrance to the work function
+ // if we stop because we run out of input items, jump ahead in the
+ // next call to work. Otherwise, we can start at zero.
+ if(count > nrequired) {
+ d_start_count = count - (nrequired);
+ consume_each(ninput_items[0]-d_taps_per_filter);
+ }
+ else {
+ d_start_count = 0;
+ consume_each(count);
+ }
+
+ return i;
+}
--- /dev/null
+/* -*- 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_GR_PFB_CLOCK_SYNC_CCF_H
+#define INCLUDED_GR_PFB_CLOCK_SYNC_CCF_H
+
+#include <gr_block.h>
+
+class gr_pfb_clock_sync_ccf;
+typedef boost::shared_ptr<gr_pfb_clock_sync_ccf> gr_pfb_clock_sync_ccf_sptr;
+gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size=32,
+ float init_phase=0);
+
+class gr_fir_ccf;
+
+/*!
+ * \class gr_pfb_clock_sync_ccf
+ *
+ * \brief Timing synchronizer using polyphase filterbanks
+ *
+ * \ingroup filter_blk
+ *
+ */
+
+class gr_pfb_clock_sync_ccf : public gr_block
+{
+ private:
+ /*!
+ * Build the polyphase filterbank timing synchronizer.
+ */
+ friend gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size,
+ float init_phase);
+
+ bool d_updated;
+ unsigned int d_sps;
+ float d_alpha;
+ unsigned int d_nfilters;
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector<gr_fir_ccf*> d_diff_filters;
+ std::vector< std::vector<float> > d_taps;
+ std::vector< std::vector<float> > d_dtaps;
+ float d_acc;
+ unsigned int d_last_filter;
+ unsigned int d_start_count;
+ unsigned int d_taps_per_filter;
+
+ /*!
+ * Build the polyphase filterbank timing synchronizer.
+ */
+ gr_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size,
+ float init_phase);
+
+ void create_diff_taps(const std::vector<float> &newtaps,
+ std::vector<float> &difftaps);
+
+public:
+ ~gr_pfb_clock_sync_ccf ();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ */
+ void set_taps (const std::vector<float> &taps,
+ std::vector< std::vector<float> > &ourtaps,
+ std::vector<gr_fir_ccf*> &ourfilter);
+ std::vector<float> channel_taps(int channel);
+ std::vector<float> diff_channel_taps(int channel);
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+ void print_diff_taps();
+
+ 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
--- /dev/null
+/* -*- 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(gr,pfb_clock_sync_ccf);
+
+gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size=32,
+ float init_phase=0);
+
+class gr_pfb_clock_sync_ccf : public gr_block
+{
+ private:
+ gr_pfb_clock_sync_ccf (float sps, float gain,
+ const std::vector<float> &taps,
+ unsigned int filter_size,
+ float init_phase);
+
+ public:
+ ~gr_pfb_clock_sync_ccf ();
+
+ void set_taps (const std::vector<float> &taps,
+ std::vector< std::vector<float> > &ourtaps,
+ std::vector<gr_fir_ccf*> &ourfilter);
+
+ std::vector<float> channel_taps(int channel);
+ std::vector<float> diff_channel_taps(int channel);
+ void print_taps();
+ void print_diff_taps();
+};
#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,
* 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>
*/
#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)
* 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>
*/
return "@BUILD_DATE@";
}
-const std::string
-gr_svn_date()
-{
- return "@SVNDATE@";
-}
-
-const std::string
-gr_svn_version()
-{
- return "@SVNVERSION@";
-}
-
const std::string
gr_version()
{
*/
const std::string gr_build_date();
-/*!
- * \brief return repository date as set when 'bootstrap' is run
- */
-const std::string gr_svn_date();
-
-/*!
- * \brief return repository version as set when 'bootstrap' is run
- */
-const std::string gr_svn_version();
-
/*!
* \brief return version string defined in configure.ac
*/
%rename(sysconfdir) gr_sysconfdir;
%rename(prefsdir) gr_prefsdir;
%rename(build_date) gr_build_date;
-%rename(svn_date) gr_svn_date;
-%rename(svn_version) gr_svn_version;
%rename(version) gr_version;
const std::string gr_prefix();
const std::string gr_sysconfdir();
const std::string gr_prefsdir();
const std::string gr_build_date();
-const std::string gr_svn_date();
-const std::string gr_svn_version();
const std::string gr_version();
("prefsdir", "print gnuradio preferences directory")
("builddate", "print gnuradio build date (RFC2822 format)")
("version,v", "print gnuradio version")
- ("svnversion", "print SVN repository version (SVN format)")
- ("svndate", "print SVN repository date")
;
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("version"))
std::cout << gr_version() << std::endl;
- if (vm.count("svnversion"))
- std::cout << gr_svn_version() << std::endl;
-
- if (vm.count("svndate"))
- std::cout << gr_svn_date() << std::endl;
-
return 0;
}
packet_utils.py \
gr_unittest.py \
optfir.py \
+ usrp_options.py \
window.py
endif
filterbank.py \
fm_demod.py \
fm_emph.py \
+ generic_usrp.py \
gmsk.py \
cpm.py \
logpwrfft.py \
--- /dev/null
+#
+# 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.
+#
+
+USRP1_TYPE = 'usrp1'
+USRP2_TYPE = 'usrp2'
+DUMMY_TYPE = 'dummy'
+#usrp2 rates common for decim and interp
+_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
+#dummy common rates
+_DUMMY_XRATES = range(4, 512, 2)
+_DUMMY_CONVERTER_RATE = 100e6
+#dummy freq result
+class _dummy_freq_result(object):
+ def __init__(self, target_freq):
+ self.baseband_freq = target_freq
+ self.dxc_freq = 0
+ self.residual_freq = 0
+from gnuradio import gr
+
+########################################################################
+# generic usrp common stuff
+########################################################################
+class _generic_usrp_base(object):
+
+ def __init__(self, which=0, subdev_spec=None, interface="", mac_addr="",
+ fusb_block_size=0, fusb_nblocks=0, usrpx=None, lo_offset=None, gain=None):
+ self._lo_offset = lo_offset
+ #usrp options
+ self._which = which
+ self._subdev_spec = subdev_spec
+ #usrp2 options
+ self._interface = interface
+ self._mac_addr = mac_addr
+ #fusb options
+ self._fusb_block_size = fusb_block_size
+ self._fusb_nblocks = fusb_nblocks
+ #pick which usrp model
+ if usrpx == '0': self._setup_usrpx(DUMMY_TYPE)
+ elif usrpx == '1' or self._subdev_spec: self._setup_usrpx(USRP1_TYPE)
+ elif usrpx == '2' or self._mac_addr: self._setup_usrpx(USRP2_TYPE)
+ else: #automatic
+ try: self._setup_usrpx(USRP2_TYPE)
+ except:
+ try: self._setup_usrpx(USRP1_TYPE)
+ except: raise Exception, 'Failed to automatically setup a usrp device.'
+ #post usrp setup
+ if self._lo_offset is not None:
+ self.set_lo_offset(self._lo_offset)
+ self.set_gain(gain)
+ self.set_auto_tr(True)
+
+ def _setup_usrpx(self, type):
+ """
+ Call the appropriate setup method.
+ @param type the usrp type constant
+ """
+ self._type = type
+ if self._type == USRP1_TYPE: self._setup_usrp1()
+ elif self._type == USRP2_TYPE: self._setup_usrp2()
+ elif self._type == DUMMY_TYPE: self._setup_dummy()
+
+ def __str__(self):
+ if self._type == USRP1_TYPE: return self._subdev.side_and_name()
+ elif self._type == USRP2_TYPE:
+ return 'Interface: %s MAC Address: %s D-Board ID: 0x%.2x'%(
+ self._u.interface_name(), self._u.mac_addr(), self._u.daughterboard_id())
+ elif self._type == DUMMY_TYPE: return 'Dummy USRP Device'
+
+ def gain(self): return self._gain
+
+ def set_gain(self, gain=None):
+ #automatic gain calculation
+ r = self.gain_range()
+ if gain is None: gain = (r[0] + r[1])/2 # set gain to midpoint
+ #set gain for usrp
+ self._gain = gain
+ if self._type == USRP1_TYPE: return self._subdev.set_gain(gain)
+ elif self._type == USRP2_TYPE: return self._u.set_gain(gain)
+ elif self._type == DUMMY_TYPE: return True
+
+ def gain_range(self):
+ if self._type == USRP1_TYPE: return self._subdev.gain_range()
+ elif self._type == USRP2_TYPE: return self._u.gain_range()
+ elif self._type == DUMMY_TYPE: return (0, 0, 0)
+
+ def set_center_freq(self, target_freq):
+ if self._type == USRP1_TYPE:
+ return self._u.tune(self._dxc, self._subdev, target_freq)
+ elif self._type == USRP2_TYPE:
+ return self._u.set_center_freq(target_freq)
+ elif self._type == DUMMY_TYPE: return _dummy_freq_result(target_freq)
+
+ def freq_range(self):
+ if self._type == USRP1_TYPE: return self._subdev.freq_range()
+ elif self._type == USRP2_TYPE: return self._u.freq_range()
+ elif self._type == DUMMY_TYPE: return (-10e9, 10e9, 100e3)
+
+ def set_lo_offset(self, lo_offset):
+ if self._type == USRP1_TYPE: return self._subdev.set_lo_offset(lo_offset)
+ elif self._type == USRP2_TYPE: return self._u.set_lo_offset(lo_offset)
+ elif self._type == DUMMY_TYPE: return True
+
+ def set_auto_tr(self, enable):
+ if self._type == USRP1_TYPE: return self._subdev.set_auto_tr(enable)
+
+ def __del__(self):
+ try: # Avoid weak reference error
+ del self._u
+ del self._subdev
+ except: pass
+
+########################################################################
+# generic usrp source
+########################################################################
+class generic_usrp_source_c(_generic_usrp_base, gr.hier_block2):
+ """
+ Create a generic usrp source that represents usrp and usrp2.
+ Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2.
+ Provide generic access methods so the API looks the same for both.
+ """
+
+ def __init__(self, **kwargs):
+ gr.hier_block2.__init__(self, "generic_usrp_source",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+ _generic_usrp_base.__init__(self, **kwargs)
+ self.connect(self._u, self)
+
+ ####################################################################
+ # generic access methods
+ ####################################################################
+ def set_decim(self, decim):
+ if decim not in self.get_decim_rates(): return False
+ if self._type == USRP1_TYPE: return self._u.set_decim_rate(decim)
+ elif self._type == USRP2_TYPE: return self._u.set_decim(decim)
+ elif self._type == DUMMY_TYPE: return True
+
+ def get_decim_rates(self):
+ if self._type == USRP1_TYPE: return range(8, 256+1, 2) #default firmware w/ hb filters
+ if self._type == USRP2_TYPE: return _USRP2_RATES
+ elif self._type == DUMMY_TYPE: return _DUMMY_XRATES
+
+ def adc_rate(self):
+ if self._type == USRP1_TYPE: return self._u.adc_rate()
+ if self._type == USRP2_TYPE: return self._u.adc_rate()
+ elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE
+
+ ####################################################################
+ # 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)
+ # determine the daughterboard subdevice we're using
+ if self._subdev_spec is None:
+ self._subdev_spec = usrp.pick_rx_subdevice(self._u)
+ self._subdev = usrp.selected_subdev(self._u, self._subdev_spec)
+ self._u.set_mux(usrp.determine_rx_mux_value(self._u, self._subdev_spec))
+ 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)
+
+########################################################################
+# generic usrp sink
+########################################################################
+class generic_usrp_sink_c(_generic_usrp_base, gr.hier_block2):
+ """
+ Create a generic usrp sink that represents usrp and usrp2.
+ Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2.
+ Provide generic access methods so the API looks the same for both.
+ """
+
+ def __init__(self, **kwargs):
+ gr.hier_block2.__init__(self, "generic_usrp_sink",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
+ _generic_usrp_base.__init__(self, **kwargs)
+ if self._type == USRP1_TYPE: #scale 0.0 to 1.0 input for usrp1
+ self.connect(self, gr.multiply_const_cc((2**15)-1), self._u)
+ else: self.connect(self, self._u)
+
+ ####################################################################
+ # generic access methods
+ ####################################################################
+ def set_interp(self, interp):
+ if interp not in self.get_interp_rates(): return False
+ if self._type == USRP1_TYPE: return self._u.set_interp_rate(interp)
+ elif self._type == USRP2_TYPE: return self._u.set_interp(interp)
+ elif self._type == DUMMY_TYPE: return True
+
+ def get_interp_rates(self):
+ if self._type == USRP1_TYPE: return range(16, 512+1, 4)
+ if self._type == USRP2_TYPE: return _USRP2_RATES
+ elif self._type == DUMMY_TYPE: return _DUMMY_XRATES
+
+ def dac_rate(self):
+ if self._type == USRP1_TYPE: return self._u.dac_rate()
+ if self._type == USRP2_TYPE: return self._u.dac_rate()
+ elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE
+
+ ####################################################################
+ # 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)
+ # determine the daughterboard subdevice we're using
+ if self._subdev_spec is None:
+ self._subdev_spec = usrp.pick_tx_subdevice(self._u)
+ self._subdev = usrp.selected_subdev(self._u, self._subdev_spec)
+ self._u.set_mux(usrp.determine_tx_mux_value(self._u, self._subdev_spec))
+ self._dxc = self._subdev.which()
+
+ 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)
c2mag = gr.complex_to_mag(fft_size)
self._avg = gr.single_pole_iir_filter_ff(1.0, fft_size)
self._log = gr.nlog10_ff(20, fft_size,
- -10*math.log10(fft_size) # Adjust for number of bins
+ -20*math.log10(fft_size) # Adjust for number of bins
-10*math.log10(window_power/fft_size) # Adjust for windowing loss
- -20*math.log10(ref_scale/2)) # Adjust for reference scale
+ -20*math.log10(ref_scale/2)+3.0) # Adjust for reference scale
self.connect(self, self._sd, fft, c2mag, self._avg, self._log, self)
self._average = average
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))
--- /dev/null
+#
+# 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.
+#
+
+_parser_to_groups_dict = dict()
+class _parser_groups(object):
+ def __init__(self, parser):
+ self.usrpx_grp = parser.add_option_group("General USRP Options")
+ self.usrp1_grp = parser.add_option_group("USRP1 Specific Options")
+ self.usrp1exp_grp = parser.add_option_group("USRP1 Expert Options")
+ self.usrp2_grp = parser.add_option_group("USRP2 Specific Options")
+
+from gnuradio import blks2
+
+def _add_options(parser):
+ """
+ Add options to manually choose between usrp or usrp2.
+ Add options for usb. Add options common to source and sink.
+ @param parser: instance of OptionParser
+ @return the parser group
+ """
+ #cache groups so they dont get added twice on tranceiver apps
+ if not _parser_to_groups_dict.has_key(parser): _parser_to_groups_dict[parser] = _parser_groups(parser)
+ pg = _parser_to_groups_dict[parser]
+ #pick usrp or usrp2
+ pg.usrpx_grp.add_option("-u", "--usrpx", type="string", default=None,
+ help="specify which usrp model: 1 for USRP, 2 for USRP2 [default=auto]")
+ #fast usb options
+ pg.usrp1exp_grp.add_option("-B", "--fusb-block-size", type="int", default=0,
+ help="specify fast usb block size [default=%default]")
+ pg.usrp1exp_grp.add_option("-N", "--fusb-nblocks", type="int", default=0,
+ help="specify number of fast usb blocks [default=%default]")
+ #lo offset
+ pg.usrpx_grp.add_option("--lo-offset", type="eng_float", default=None,
+ help="set LO Offset in Hz [default=automatic].")
+ #usrp options
+ pg.usrp1_grp.add_option("-w", "--which", type="int", default=0,
+ help="select USRP board [default=%default]")
+ #usrp2 options
+ pg.usrp2_grp.add_option("-e", "--interface", type="string", default="eth0",
+ help="Use USRP2 at specified Ethernet interface [default=%default]")
+ pg.usrp2_grp.add_option("-a", "--mac-addr", type="string", default="",
+ help="Use USRP2 at specified MAC address [default=None]")
+ return pg
+
+def add_rx_options(parser):
+ """
+ Add receive specific usrp options.
+ @param parser: instance of OptionParser
+ """
+ pg = _add_options(parser)
+ pg.usrp1_grp.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
+ help="select USRP Rx side A or B")
+ pg.usrpx_grp.add_option("--rx-gain", type="eng_float", default=None, metavar="GAIN",
+ help="set receiver gain in dB [default=midpoint]. See also --show-rx-gain-range")
+ pg.usrpx_grp.add_option("--show-rx-gain-range", action="store_true", default=False,
+ help="print min and max Rx gain available on selected daughterboard")
+ pg.usrpx_grp.add_option("-d", "--decim", type="intx", default=None,
+ help="set fpga decimation rate to DECIM [default=%default]")
+
+def create_usrp_source(options):
+ u = blks2.generic_usrp_source_c(
+ usrpx=options.usrpx,
+ which=options.which,
+ subdev_spec=options.rx_subdev_spec,
+ interface=options.interface,
+ mac_addr=options.mac_addr,
+ fusb_block_size=options.fusb_block_size,
+ fusb_nblocks=options.fusb_nblocks,
+ lo_offset=options.lo_offset,
+ gain=options.rx_gain,
+ )
+ if options.show_rx_gain_range:
+ print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range())
+ return u
+
+def add_tx_options(parser):
+ """
+ Add transmit specific usrp options.
+ @param parser: instance of OptionParser
+ """
+ pg = _add_options(parser)
+ pg.usrp1_grp.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
+ help="select USRP Rx side A or B")
+ pg.usrpx_grp.add_option("--tx-gain", type="eng_float", default=None, metavar="GAIN",
+ help="set transmitter gain in dB [default=midpoint]. See also --show-tx-gain-range")
+ pg.usrpx_grp.add_option("--show-tx-gain-range", action="store_true", default=False,
+ help="print min and max Tx gain available on selected daughterboard")
+ pg.usrpx_grp.add_option("-i", "--interp", type="intx", default=None,
+ help="set fpga interpolation rate to INTERP [default=%default]")
+
+def create_usrp_sink(options):
+ u = blks2.generic_usrp_sink_c(
+ usrpx=options.usrpx,
+ which=options.which,
+ subdev_spec=options.tx_subdev_spec,
+ interface=options.interface,
+ mac_addr=options.mac_addr,
+ fusb_block_size=options.fusb_block_size,
+ fusb_nblocks=options.fusb_nblocks,
+ lo_offset=options.lo_offset,
+ gain=options.tx_gain,
+ )
+ if options.show_tx_gain_range:
+ print "Tx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range())
+ return u
dist_ourdata_DATA = \
README \
- generic_usrp.py \
pick_bitrate.py \
qt_digital_window.ui \
qt_digital_window.py \
qt_rx_window.py \
receive_path.py \
transmit_path.py \
- usrp_options.py \
usrp_receive_path.py \
usrp_transmit_path.py
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
# 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
+++ /dev/null
-#
-# 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.
-#
-
-USRP1_TYPE = 'usrp1'
-USRP2_TYPE = 'usrp2'
-DUMMY_TYPE = 'dummy'
-#usrp2 rates common for decim and interp
-_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
-#dummy common rates
-_DUMMY_XRATES = range(4, 512, 2)
-_DUMMY_CONVERTER_RATE = 100e6
-#dummy freq result
-class _dummy_freq_result(object):
- def __init__(self, target_freq):
- self.baseband_freq = target_freq
- self.dxc_freq = 0
- self.residual_freq = 0
-from gnuradio import gr, usrp, usrp2
-
-########################################################################
-# generic usrp common stuff
-########################################################################
-class _generic_usrp_base(object):
-
- def __init__(self, which=0, subdev_spec=None, interface="", mac_addr="",
- fusb_block_size=0, fusb_nblocks=0, usrpx=None, lo_offset=None, gain=None):
- self._lo_offset = lo_offset
- #usrp options
- self._which = which
- self._subdev_spec = subdev_spec
- #usrp2 options
- self._interface = interface
- self._mac_addr = mac_addr
- #fusb options
- self._fusb_block_size = fusb_block_size
- self._fusb_nblocks = fusb_nblocks
- #pick which usrp model
- if usrpx == '0': self._setup_usrpx(DUMMY_TYPE)
- elif usrpx == '1' or self._subdev_spec: self._setup_usrpx(USRP1_TYPE)
- elif usrpx == '2' or self._mac_addr: self._setup_usrpx(USRP2_TYPE)
- else: #automatic
- try: self._setup_usrpx(USRP2_TYPE)
- except:
- try: self._setup_usrpx(USRP1_TYPE)
- except: raise Exception, 'Failed to automatically setup a usrp device.'
- #post usrp setup
- if self._lo_offset is not None:
- self.set_lo_offset(self._lo_offset)
- self.set_gain(gain)
- self.set_auto_tr(True)
-
- def _setup_usrpx(self, type):
- """
- Call the appropriate setup method.
- @param type the usrp type constant
- """
- self._type = type
- if self._type == USRP1_TYPE: self._setup_usrp1()
- elif self._type == USRP2_TYPE: self._setup_usrp2()
- elif self._type == DUMMY_TYPE: self._setup_dummy()
-
- def __str__(self):
- if self._type == USRP1_TYPE: return self._subdev.side_and_name()
- elif self._type == USRP2_TYPE:
- return 'Interface: %s MAC Address: %s D-Board ID: 0x%.2x'%(
- self._u.interface_name(), self._u.mac_addr(), self._u.daughterboard_id())
- elif self._type == DUMMY_TYPE: return 'Dummy USRP Device'
-
- def gain(self): return self._gain
-
- def set_gain(self, gain=None):
- #automatic gain calculation
- r = self.gain_range()
- if gain is None: gain = (r[0] + r[1])/2 # set gain to midpoint
- #set gain for usrp
- self._gain = gain
- if self._type == USRP1_TYPE: return self._subdev.set_gain(gain)
- elif self._type == USRP2_TYPE: return self._u.set_gain(gain)
- elif self._type == DUMMY_TYPE: return True
-
- def gain_range(self):
- if self._type == USRP1_TYPE: return self._subdev.gain_range()
- elif self._type == USRP2_TYPE: return self._u.gain_range()
- elif self._type == DUMMY_TYPE: return (0, 0, 0)
-
- def set_center_freq(self, target_freq):
- if self._type == USRP1_TYPE:
- return self._u.tune(self._dxc, self._subdev, target_freq)
- elif self._type == USRP2_TYPE:
- return self._u.set_center_freq(target_freq)
- elif self._type == DUMMY_TYPE: return _dummy_freq_result(target_freq)
-
- def freq_range(self):
- if self._type == USRP1_TYPE: return self._subdev.freq_range()
- elif self._type == USRP2_TYPE: return self._u.freq_range()
- elif self._type == DUMMY_TYPE: return (-10e9, 10e9, 100e3)
-
- def set_lo_offset(self, lo_offset):
- if self._type == USRP1_TYPE: return self._subdev.set_lo_offset(lo_offset)
- elif self._type == USRP2_TYPE: return self._u.set_lo_offset(lo_offset)
- elif self._type == DUMMY_TYPE: return True
-
- def set_auto_tr(self, enable):
- if self._type == USRP1_TYPE: return self._subdev.set_auto_tr(enable)
-
- def __del__(self):
- try: # Avoid weak reference error
- del self._u
- del self._subdev
- except: pass
-
-########################################################################
-# generic usrp source
-########################################################################
-class generic_usrp_source_c(_generic_usrp_base, gr.hier_block2):
- """
- Create a generic usrp source that represents usrp and usrp2.
- Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2.
- Provide generic access methods so the API looks the same for both.
- """
-
- def __init__(self, **kwargs):
- gr.hier_block2.__init__(self, "generic_usrp_source",
- gr.io_signature(0, 0, 0), # Input signature
- gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
- _generic_usrp_base.__init__(self, **kwargs)
- self.connect(self._u, self)
-
- ####################################################################
- # generic access methods
- ####################################################################
- def set_decim(self, decim):
- if decim not in self.get_decim_rates(): return False
- if self._type == USRP1_TYPE: return self._u.set_decim_rate(decim)
- elif self._type == USRP2_TYPE: return self._u.set_decim(decim)
- elif self._type == DUMMY_TYPE: return True
-
- def get_decim_rates(self):
- if self._type == USRP1_TYPE: return range(8, 256+1, 2) #default firmware w/ hb filters
- if self._type == USRP2_TYPE: return _USRP2_RATES
- elif self._type == DUMMY_TYPE: return _DUMMY_XRATES
-
- def adc_rate(self):
- if self._type == USRP1_TYPE: return self._u.adc_rate()
- if self._type == USRP2_TYPE: return self._u.adc_rate()
- elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE
-
- ####################################################################
- # setup usrp methods
- ####################################################################
- def _setup_usrp1(self):
- self._u = usrp.source_c (self._which,
- fusb_block_size=self._fusb_block_size,
- fusb_nblocks=self._fusb_nblocks)
- # determine the daughterboard subdevice we're using
- if self._subdev_spec is None:
- self._subdev_spec = usrp.pick_rx_subdevice(self._u)
- self._subdev = usrp.selected_subdev(self._u, self._subdev_spec)
- self._u.set_mux(usrp.determine_rx_mux_value(self._u, self._subdev_spec))
- self._dxc = 0
-
- def _setup_usrp2(self):
- self._u = usrp2.source_32fc(self._interface, self._mac_addr)
-
- def _setup_dummy(self): self._u = gr.null_source(gr.sizeof_gr_complex)
-
-########################################################################
-# generic usrp sink
-########################################################################
-class generic_usrp_sink_c(_generic_usrp_base, gr.hier_block2):
- """
- Create a generic usrp sink that represents usrp and usrp2.
- Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2.
- Provide generic access methods so the API looks the same for both.
- """
-
- def __init__(self, **kwargs):
- gr.hier_block2.__init__(self, "generic_usrp_sink",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(0, 0, 0)) # Output signature
- _generic_usrp_base.__init__(self, **kwargs)
- if self._type == USRP1_TYPE: #scale 0.0 to 1.0 input for usrp1
- self.connect(self, gr.multiply_const_cc((2**15)-1), self._u)
- else: self.connect(self, self._u)
-
- ####################################################################
- # generic access methods
- ####################################################################
- def set_interp(self, interp):
- if interp not in self.get_interp_rates(): return False
- if self._type == USRP1_TYPE: return self._u.set_interp_rate(interp)
- elif self._type == USRP2_TYPE: return self._u.set_interp(interp)
- elif self._type == DUMMY_TYPE: return True
-
- def get_interp_rates(self):
- if self._type == USRP1_TYPE: return range(16, 512+1, 4)
- if self._type == USRP2_TYPE: return _USRP2_RATES
- elif self._type == DUMMY_TYPE: return _DUMMY_XRATES
-
- def dac_rate(self):
- if self._type == USRP1_TYPE: return self._u.dac_rate()
- if self._type == USRP2_TYPE: return self._u.dac_rate()
- elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE
-
- ####################################################################
- # setup usrp methods
- ####################################################################
- def _setup_usrp1(self):
- self._u = usrp.sink_c (self._which,
- fusb_block_size=self._fusb_block_size,
- fusb_nblocks=self._fusb_nblocks)
- # determine the daughterboard subdevice we're using
- if self._subdev_spec is None:
- self._subdev_spec = usrp.pick_tx_subdevice(self._u)
- self._subdev = usrp.selected_subdev(self._u, self._subdev_spec)
- 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_dummy(self): self._u = gr.null_sink(gr.sizeof_gr_complex)
+++ /dev/null
-#
-# 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.
-#
-
-_parser_to_groups_dict = dict()
-class _parser_groups(object):
- def __init__(self, parser):
- self.usrpx_grp = parser.add_option_group("General USRP Options")
- self.usrp1_grp = parser.add_option_group("USRP1 Specific Options")
- self.usrp1exp_grp = parser.add_option_group("USRP1 Expert Options")
- self.usrp2_grp = parser.add_option_group("USRP2 Specific Options")
-
-import generic_usrp
-
-def _add_options(parser):
- """
- Add options to manually choose between usrp or usrp2.
- Add options for usb. Add options common to source and sink.
- @param parser: instance of OptionParser
- @return the parser group
- """
- #cache groups so they dont get added twice on tranceiver apps
- if not _parser_to_groups_dict.has_key(parser): _parser_to_groups_dict[parser] = _parser_groups(parser)
- pg = _parser_to_groups_dict[parser]
- #pick usrp or usrp2
- pg.usrpx_grp.add_option("-u", "--usrpx", type="string", default=None,
- help="specify which usrp model: 1 for USRP, 2 for USRP2 [default=auto]")
- #fast usb options
- pg.usrp1exp_grp.add_option("-B", "--fusb-block-size", type="int", default=0,
- help="specify fast usb block size [default=%default]")
- pg.usrp1exp_grp.add_option("-N", "--fusb-nblocks", type="int", default=0,
- help="specify number of fast usb blocks [default=%default]")
- #lo offset
- pg.usrpx_grp.add_option("--lo-offset", type="eng_float", default=None,
- help="set LO Offset in Hz [default=automatic].")
- #usrp options
- pg.usrp1_grp.add_option("-w", "--which", type="int", default=0,
- help="select USRP board [default=%default]")
- #usrp2 options
- pg.usrp2_grp.add_option("-e", "--interface", type="string", default="eth0",
- help="Use USRP2 at specified Ethernet interface [default=%default]")
- pg.usrp2_grp.add_option("-a", "--mac-addr", type="string", default="",
- help="Use USRP2 at specified MAC address [default=None]")
- return pg
-
-def add_rx_options(parser):
- """
- Add receive specific usrp options.
- @param parser: instance of OptionParser
- """
- pg = _add_options(parser)
- pg.usrp1_grp.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
- help="select USRP Rx side A or B")
- pg.usrpx_grp.add_option("--rx-gain", type="eng_float", default=None, metavar="GAIN",
- help="set receiver gain in dB [default=midpoint]. See also --show-rx-gain-range")
- pg.usrpx_grp.add_option("--show-rx-gain-range", action="store_true", default=False,
- help="print min and max Rx gain available on selected daughterboard")
- pg.usrpx_grp.add_option("-d", "--decim", type="intx", default=None,
- help="set fpga decimation rate to DECIM [default=%default]")
-
-def create_usrp_source(options):
- u = generic_usrp.generic_usrp_source_c(
- usrpx=options.usrpx,
- which=options.which,
- subdev_spec=options.rx_subdev_spec,
- interface=options.interface,
- mac_addr=options.mac_addr,
- fusb_block_size=options.fusb_block_size,
- fusb_nblocks=options.fusb_nblocks,
- lo_offset=options.lo_offset,
- gain=options.rx_gain,
- )
- if options.show_rx_gain_range:
- print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range())
- return u
-
-def add_tx_options(parser):
- """
- Add transmit specific usrp options.
- @param parser: instance of OptionParser
- """
- pg = _add_options(parser)
- pg.usrp1_grp.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
- help="select USRP Rx side A or B")
- pg.usrpx_grp.add_option("--tx-gain", type="eng_float", default=None, metavar="GAIN",
- help="set transmitter gain in dB [default=midpoint]. See also --show-tx-gain-range")
- pg.usrpx_grp.add_option("--show-tx-gain-range", action="store_true", default=False,
- help="print min and max Tx gain available on selected daughterboard")
- pg.usrpx_grp.add_option("-i", "--interp", type="intx", default=None,
- help="set fpga interpolation rate to INTERP [default=%default]")
-
-def create_usrp_sink(options):
- u = generic_usrp.generic_usrp_sink_c(
- usrpx=options.usrpx,
- which=options.which,
- subdev_spec=options.tx_subdev_spec,
- interface=options.interface,
- mac_addr=options.mac_addr,
- fusb_block_size=options.fusb_block_size,
- fusb_nblocks=options.fusb_nblocks,
- lo_offset=options.lo_offset,
- gain=options.tx_gain,
- )
- if options.show_tx_gain_range:
- print "Tx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range())
- return u
#
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
#
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
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
+++ /dev/null
-#!/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 ()
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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)
#!/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
#
# 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 ()
--- /dev/null
+#!/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)
scale_factor = 3
mean = numpy.average(samples)
rms = numpy.max([scale_factor*((numpy.sum((samples-mean)**2)/len(samples))**.5), .1])
- min = mean - rms
- max = mean + rms
- return min, max
+ min_val = mean - rms
+ max_val = mean + rms
+ return min_val, max_val
+
+def get_min_max_fft(fft_samps):
+ """
+ Get the minimum and maximum bounds for an array of fft samples.
+ @param samples the array of real values
+ @return a tuple of min, max
+ """
+ #get the peak level (max of the samples)
+ peak_level = numpy.max(fft_samps)
+ #separate noise samples
+ noise_samps = numpy.sort(fft_samps)[:len(fft_samps)/2]
+ #get the noise floor
+ noise_floor = numpy.average(noise_samps)
+ #get the noise deviation
+ noise_dev = numpy.std(noise_samps)
+ #determine the maximum and minimum levels
+ max_level = peak_level
+ min_level = noise_floor - abs(2*noise_dev)
+ return min_level, max_level
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
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
Set the dynamic range and reference level.
"""
if not len(self.samples): return
- #get the peak level (max of the samples)
- peak_level = numpy.max(self.samples)
- #get the noise floor (averge the smallest samples)
- noise_floor = numpy.average(numpy.sort(self.samples)[:len(self.samples)/4])
- #padding
- noise_floor -= abs(noise_floor)*.5
- peak_level += abs(peak_level)*.1
- #set the reference level to a multiple of y divs
- self[REF_LEVEL_KEY] = self[Y_DIVS_KEY]*math.ceil(peak_level/self[Y_DIVS_KEY])
+ min_level, max_level = common.get_min_max_fft(self.samples)
#set the range to a clean number of the dynamic range
- self[Y_PER_DIV_KEY] = common.get_clean_num((peak_level - noise_floor)/self[Y_DIVS_KEY])
+ self[Y_PER_DIV_KEY] = common.get_clean_num(1+(max_level - min_level)/self[Y_DIVS_KEY])
+ #set the reference level to a multiple of y per div
+ self[REF_LEVEL_KEY] = self[Y_PER_DIV_KEY]*round(.5+max_level/self[Y_PER_DIV_KEY])
def _reset_peak_vals(self, *args): self.peak_vals = EMPTY_TRACE
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):
"""
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):
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
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
self._pointer = 0
if self._num_lines and self._fft_size:
GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture)
- data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring()
+ data = numpy.zeros(self._num_lines*ceil_log2(self._fft_size)*4, numpy.uint8).tostring()
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data)
self._resize_texture_flag = False
self.connect(self, lpf, mute, (sub, 1))
#subscribe
controller.subscribe(ac_couple_key, lambda x: mute.set_mute(not x))
- controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(2.0/x))
+ controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(0.05))
#initialize
controller[ac_couple_key] = ac_couple
controller[sample_rate_key] = controller[sample_rate_key]
Does not affect the current data in the waterfall.
"""
if not len(self.samples): return
- #get the peak level (max of the samples)
- peak_level = numpy.max(self.samples)
- #get the noise floor (averge the smallest samples)
- noise_floor = numpy.average(numpy.sort(self.samples)[:len(self.samples)/4])
- #padding
- noise_floor -= abs(noise_floor)*.5
- peak_level += abs(peak_level)*.1
+ min_level, max_level = common.get_min_max_fft(self.samples)
#set the range and level
- self[REF_LEVEL_KEY] = peak_level
- self[DYNAMIC_RANGE_KEY] = peak_level - noise_floor
+ self[REF_LEVEL_KEY] = max_level
+ self[DYNAMIC_RANGE_KEY] = max_level - min_level
def handle_msg(self, msg):
"""
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
#
include $(top_srcdir)/Makefile.common
-grc_src_prefix = $(pythondir)/gnuradio/grc
+grc_src_prefix = $(pkgpythondir)/grc
grc_blocksdir = $(pkgdatadir)/grc/blocks
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):
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',
'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()
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()
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):
"""
"""
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()
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
##############################################
"""
-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
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.
+ 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 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
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.
@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)
@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
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():
"""
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
##############################################
#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)
+ self.rewrite() #rewrite all blocks before connections are made (ex: nports)
#build the connections
for connection_n in connections_n:
#try to make the connection
#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
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):
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')
#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
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):
"""
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
"""
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
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'
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
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
FlowGraph = _FlowGraph
Connection = _Connection
Block = _Block
- Source = _Port
- Sink = _Port
+ Port = _Port
Param = _Param
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):
"""
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):
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):
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 \
<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>
</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>
<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>
</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>
<block>gr_wavfile_source</block>
<block>gr_message_source</block>
<block>pad_source</block>
+ <block>virtual_source</block>
</cat>
<cat>
<name>Sinks</name>
<block>gr_wavfile_sink</block>
<block>gr_message_sink</block>
<block>pad_sink</block>
+ <block>virtual_sink</block>
</cat>
<cat>
<name>Graphical Sinks</name>
<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>
<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>
<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>
</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>
<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>
</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>
<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>
<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>
<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>
</option>
<option>
<name>Int</name>
- <key>int</key>
+ <key>intx</key>
<opt>type:int</opt>
</option>
<option>
<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>
<!--
###################################################
##USRP2 Sink
+## Note: the center freq must be set after the lo offset
###################################################
-->
<block>
usrp2.sink_$(type.fcn)($interface, $mac_addr)
#end if
self.$(id).set_interp($interpolation)
-self.$(id).set_center_freq($frequency)
-self.$(id).set_gain($gain)
#if $lo_offset() != float('inf')
self.$(id).set_lo_offset($lo_offset)
-#end if</make>
- <callback>set_lo_offset($lo_offset)</callback>
+#end if
+self.$(id).set_center_freq($frequency)
+self.$(id).set_gain($gain)</make>
<callback>set_interp($interpolation)</callback>
- <callback>set_center_freq($frequency)</callback>
+ <callback>#if $lo_offset() != float('inf')
+self.$(id).set_lo_offset($lo_offset)
+#end if
+self.$(id).set_center_freq($frequency)</callback>
<callback>set_gain($gain)</callback>
<param>
<name>Output Type</name>
<!--
###################################################
##USRP2 Source
+## Note: the center freq must be set after the lo offset
###################################################
-->
<block>
usrp2.source_$(type.fcn)($interface, $mac_addr)
#end if
self.$(id).set_decim($decimation)
-self.$(id).set_center_freq($frequency)
-self.$(id).set_gain($gain)
#if $lo_offset() != float('inf')
self.$(id).set_lo_offset($lo_offset)
-#end if</make>
- <callback>set_lo_offset($lo_offset)</callback>
+#end if
+self.$(id).set_center_freq($frequency)
+self.$(id).set_gain($gain)</make>
<callback>set_decim($decimation)</callback>
- <callback>set_center_freq($frequency)</callback>
+ <callback>#if $lo_offset() != float('inf')
+self.$(id).set_lo_offset($lo_offset)
+#end if
+self.$(id).set_center_freq($frequency)</callback>
<callback>set_gain($gain)</callback>
<param>
<name>Output Type</name>
<import>from grc_gnuradio import usrp as grc_usrp</import>
<make>grc_usrp.dual_sink_$(type.fcn)(which=$which)
self.$(id).set_interp_rate($interpolation)
-self.$(id).set_frequency_a($frequency_a, verbose=True)
-self.$(id).set_frequency_b($frequency_b, verbose=True)
-self.$(id).set_gain_a($gain_a)
-self.$(id).set_gain_b($gain_b)
+self.$(id).set_frequency_a($frequency_a, verbose=True#slurp
#if $lo_offset_a() != float('inf')
-self.$(id).set_lo_offset_a($lo_offset_a)
+, lo_offset=$lo_offset_a#slurp
#end if
+)
+self.$(id).set_frequency_b($frequency_b, verbose=True#slurp
#if $lo_offset_b() != float('inf')
-self.$(id).set_lo_offset_b($lo_offset_b)
+, lo_offset=$lo_offset_b#slurp
#end if
+)
+self.$(id).set_gain_a($gain_a)
+self.$(id).set_gain_b($gain_b)
##################################################
## Flex RF A
##################################################
self.$(id).set_auto_tr_b(True)
#end if</make>
<callback>set_interp_rate($interpolation)</callback>
- <callback>set_frequency_a($frequency_a)</callback>
- <callback>set_frequency_b($frequency_b)</callback>
+ <callback>set_frequency_a($frequency_a#slurp
+#if $lo_offset_a() != float('inf')
+, lo_offset=$lo_offset_a#slurp
+#end if
+)</callback>
+ <callback>set_frequency_b($frequency_b#slurp
+#if $lo_offset_b() != float('inf')
+, lo_offset=$lo_offset_b#slurp
+#end if
+)</callback>
<callback>set_gain_a($gain_a)</callback>
<callback>set_gain_b($gain_b)</callback>
<param>
self.$(id).set_format(width=$format.width, shift=$format.shift)
#end if
self.$(id).set_decim_rate($decimation)
-self.$(id).set_frequency_a($frequency_a, verbose=True)
-self.$(id).set_frequency_b($frequency_b, verbose=True)
-self.$(id).set_gain_a($gain_a)
-self.$(id).set_gain_b($gain_b)
+self.$(id).set_frequency_a($frequency_a, verbose=True#slurp
#if $lo_offset_a() != float('inf')
-self.$(id).set_lo_offset_a($lo_offset_a)
+, lo_offset=$lo_offset_a#slurp
#end if
+)
+self.$(id).set_frequency_b($frequency_b, verbose=True#slurp
#if $lo_offset_b() != float('inf')
-self.$(id).set_lo_offset_b($lo_offset_b)
-#end if</make>
+, lo_offset=$lo_offset_b#slurp
+#end if
+)
+self.$(id).set_gain_a($gain_a)
+self.$(id).set_gain_b($gain_b)</make>
<callback>set_decim_rate($decimation)</callback>
- <callback>set_frequency_a($frequency_a)</callback>
- <callback>set_frequency_b($frequency_b)</callback>
+ <callback>set_frequency_a($frequency_a#slurp
+#if $lo_offset_a() != float('inf')
+, lo_offset=$lo_offset_a#slurp
+#end if
+)</callback>
+ <callback>set_frequency_b($frequency_b#slurp
+#if $lo_offset_b() != float('inf')
+, lo_offset=$lo_offset_b#slurp
+#end if
+)</callback>
<callback>set_gain_a($gain_a)</callback>
<callback>set_gain_b($gain_b)</callback>
<param>
<import>from grc_gnuradio import usrp as grc_usrp</import>
<make>grc_usrp.simple_sink_$(type.fcn)(which=$which, side=$side)
self.$(id).set_interp_rate($interpolation)
-self.$(id).set_frequency($frequency, verbose=True)
+self.$(id).set_frequency($frequency, verbose=True#slurp
+#if $lo_offset() != float('inf')
+, lo_offset=$lo_offset#slurp
+#end if
+)
self.$(id).set_gain($gain)
#if $transmit.tx_enb
self.$(id).set_enable(True)
#end if
#if $transmit.auto_tr
self.$(id).set_auto_tr(True)
-#end if
-#if $lo_offset() != float('inf')
-self.$(id).set_lo_offset($lo_offset)
#end if</make>
- <callback>set_lo_offset($lo_offset)</callback>
<callback>set_interp_rate($interpolation)</callback>
- <callback>set_frequency($frequency)</callback>
+ <callback>set_frequency($frequency#slurp
+#if $lo_offset() != float('inf')
+, lo_offset=$lo_offset#slurp
+#end if
+)</callback>
<callback>set_gain($gain)</callback>
<param>
<name>Input Type</name>
self.$(id).set_format(width=$format.width, shift=$format.shift)
#end if
self.$(id).set_decim_rate($decimation)
-self.$(id).set_frequency($frequency, verbose=True)
-self.$(id).set_gain($gain)
+self.$(id).set_frequency($frequency, verbose=True#slurp
#if $lo_offset() != float('inf')
-self.$(id).set_lo_offset($lo_offset)
-#end if</make>
- <callback>set_lo_offset($lo_offset)</callback>
+, lo_offset=$lo_offset#slurp
+#end if
+)
+self.$(id).set_gain($gain)</make>
<callback>set_decim_rate($decimation)</callback>
- <callback>set_frequency($frequency)</callback>
+ <callback>set_frequency($frequency#slurp
+#if $lo_offset() != float('inf')
+, lo_offset=$lo_offset#slurp
+#end if
+)</callback>
<callback>set_gain($gain)</callback>
<param>
<name>Output Type</name>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
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,
<value>50</value>
<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>
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,
<value>50</value>
<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>
for i in range(2): self.connect((deinter, i), (self, i))
def set_decim_rate(self, decim): self._get_u().set_decim_rate(int(decim))
- def set_frequency_a(self, frequency, verbose=False):
+ def set_frequency_a(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev_a.set_lo_offset(lo_offset)
self._set_frequency(
chan=0, #ddc0
subdev=self._subdev_a,
frequency=frequency,
verbose=verbose,
)
- def set_frequency_b(self, frequency, verbose=False):
+ def set_frequency_b(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev_b.set_lo_offset(lo_offset)
self._set_frequency(
chan=1, #ddc1
subdev=self._subdev_b,
frequency=frequency,
verbose=verbose,
)
- def set_lo_offset_a(self, lo_offset): self._subdev_a.set_lo_offset(lo_offset)
- def set_lo_offset_b(self, lo_offset): self._subdev_b.set_lo_offset(lo_offset)
def set_gain_a(self, gain): self._subdev_a.set_gain(gain)
def set_gain_b(self, gain): self._subdev_b.set_gain(gain)
for i in range(2): self.connect((self, i), (inter, i))
def set_interp_rate(self, interp): self._get_u().set_interp_rate(int(interp))
- def set_frequency_a(self, frequency, verbose=False):
+ def set_frequency_a(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev_a.set_lo_offset(lo_offset)
self._set_frequency(
chan=self._subdev_a.which(),
subdev=self._subdev_a,
frequency=frequency,
verbose=verbose,
)
- def set_frequency_b(self, frequency, verbose=False):
+ def set_frequency_b(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev_b.set_lo_offset(lo_offset)
self._set_frequency(
chan=self._subdev_b.which(),
subdev=self._subdev_b,
frequency=frequency,
verbose=verbose,
)
- def set_lo_offset_a(self, lo_offset): self._subdev_a.set_lo_offset(lo_offset)
- def set_lo_offset_b(self, lo_offset): self._subdev_b.set_lo_offset(lo_offset)
def set_gain_a(self, gain): self._subdev_a.set_gain(gain)
def set_gain_b(self, gain): self._subdev_b.set_gain(gain)
def set_enable_a(self, enable): self._subdev_a.set_enable(enable)
self._get_u().set_decim_rate(int(decim))
if self._no_hb: #set the BW to half the sample rate
self._subdev.set_bw(self._get_u().converter_rate()/decim/2)
- def set_lo_offset(self, lo_offset): self._subdev.set_lo_offset(lo_offset)
- def set_frequency(self, frequency, verbose=False):
+ def set_frequency(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev.set_lo_offset(lo_offset)
self._set_frequency(
chan=0, #ddc0
subdev=self._subdev,
self.connect(self, self._get_u())
def set_interp_rate(self, interp): self._get_u().set_interp_rate(int(interp))
- def set_frequency(self, frequency, verbose=False):
+ def set_frequency(self, frequency, verbose=False, lo_offset=None):
+ if lo_offset is not None: self._subdev.set_lo_offset(lo_offset)
self._set_frequency(
chan=self._subdev.which(),
subdev=self._subdev,
frequency=frequency,
verbose=verbose,
)
- def set_lo_offset(self, lo_offset): self._subdev.set_lo_offset(lo_offset)
def set_gain(self, gain): self._subdev.set_gain(gain)
def set_enable(self, enable): self._subdev.set_enable(enable)
def set_auto_tr(self, auto_tr): self._subdev.set_auto_tr(auto_tr)
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
@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
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()
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):
"""
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 = ['']
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())
##################################################
# 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()
##################################################
# 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())
##################################################
# 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()
##################################################
# 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:
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()
##################################################
# 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:
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.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')
#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):
"""
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."""
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)
-#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
+ def __call__(self):
+ """
+ Emit the activate signal when called with ().
+ """
+ self.emit('activate')
+
+########################################################################
+# Actions
+########################################################################
+PAGE_CHANGE = Action()
+FLOW_GRAPH_NEW = Action(
+ label='_New',
+ tooltip='Create a new flow graph',
+ stock_id=gtk.STOCK_NEW,
+ keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK),
+)
+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),
+)
+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),
+)
]),
(gtk.Action('Help', '_Help', None, None), [
Actions.HELP_WINDOW_DISPLAY,
- Actions.COLORS_WINDOW_DISPLAY,
+ Actions.TYPES_WINDOW_DISPLAY,
None,
Actions.ABOUT_WINDOW_DISPLAY,
]),
"""
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'))
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
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',
})
))
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'GUI Rotation',
'key': '_rotation',
'type': 'raw',
"""
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('')
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
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):
"""
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."""
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)
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
"""
-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
The arrow coloring exposes the enabled and valid states.
"""
+ def __init__(self): Element.__init__(self)
+
def get_coordinate(self):
"""
Get the 0,0 coordinate.
"""
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
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()
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()
#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()))
"""
-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
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
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.
"""
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.
@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)
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):
"""
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
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):
"""
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
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
"""
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
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.
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
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
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
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
#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):
"""
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()
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)))
"""
-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
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
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)
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):
"""
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
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
MainWindow.py \
Messages.py \
NotebookPage.py \
- ParamsDialog.py \
+ PropsDialog.py \
Preferences.py \
StateCache.py \
__init__.py
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
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
@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):
"""
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>"""
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):
"""
+++ /dev/null
-"""
-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
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-GNU Radio Companion is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-from Dialogs import TextDisplay
-from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
-
-def get_title_label(title):
- """
- Get a title label for the params window.
- The title will be bold, underlined, and left justified.
- @param title the text of the title
- @return a gtk object
- """
- label = gtk.Label()
- label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title)
- hbox = gtk.HBox()
- hbox.pack_start(label, False, False, padding=11)
- return hbox
-
-class ParamsDialog(gtk.Dialog):
- """A dialog box to set block parameters."""
-
- def __init__(self, block):
- """
- SignalBlockParamsDialog contructor.
- @param block the signal block
- """
- gtk.Dialog.__init__(self,
- title='Properties: %s'%block.get_name(),
- buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE),
- )
- 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)
- #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(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(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
- 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)
- self.show_all()
- #initial update
- for param in self.block.get_params(): param.update()
- self._update()
-
- def _update(self):
- """
- 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 errors box
- if self.block.is_valid(): self._error_box.hide()
- else: self._error_box.show()
- messages = '\n\n'.join(self.block.get_error_messages())
- self._error_messages_text_display.set_text(messages)
- #update the docs box
- if self.block.get_doc(): self._docs_box.show()
- else: self._docs_box.hide()
- self._docs_text_display.set_text(self.block.get_doc())
-
- def _handle_key_press(self, widget, event):
- """
- Handle key presses from the keyboard.
- Call the ok response when enter is pressed.
- @return false to forward the keypress
- """
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == 'Return': self.response(gtk.RESPONSE_OK)
- 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.
- """
- original_data = list()
- for param in self.block.get_params():
- original_data.append(param.get_value())
- 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
"""
-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
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)
"""
-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
class Port(Element):
"""The graphical port."""
- def __init__(self, *args, **kwargs):
+ def __init__(self):
"""
Port contructor.
Create list of connector coordinates.
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
#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('')
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():
--- /dev/null
+"""
+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
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+"""
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+from Dialogs import TextDisplay
+from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT
+
+def get_title_label(title):
+ """
+ Get a title label for the params window.
+ The title will be bold, underlined, and left justified.
+ @param title the text of the title
+ @return a gtk object
+ """
+ label = gtk.Label()
+ label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title)
+ hbox = gtk.HBox()
+ hbox.pack_start(label, False, False, padding=11)
+ return hbox
+
+class PropsDialog(gtk.Dialog):
+ """
+ A dialog to set block parameters, view errors, and view documentation.
+ """
+
+ def __init__(self, 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_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT),
+ )
+ self._block = block
+ self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ vbox = gtk.VBox()
+ #Create the scrolled window to hold all the parameters
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(vbox)
+ self.vbox.pack_start(scrolled_window, True)
+ #Params box for block parameters
+ self._params_box = gtk.VBox()
+ self._params_box.pack_start(get_title_label('Parameters'), False)
+ self._input_object_params = list()
+ #Error Messages for the block
+ self._error_box = gtk.VBox()
+ self._error_messages_text_display = TextDisplay()
+ self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
+ self._error_box.pack_start(get_title_label('Error Messages'), False)
+ self._error_box.pack_start(self._error_messages_text_display, False)
+ #Docs for the block
+ self._docs_box = err_box = gtk.VBox()
+ self._docs_text_display = TextDisplay()
+ self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING)
+ self._docs_box.pack_start(get_title_label('Documentation'), False)
+ self._docs_box.pack_start(self._docs_text_display, False)
+ #Add the boxes
+ vbox.pack_start(self._params_box, False)
+ vbox.pack_start(self._error_box, False)
+ vbox.pack_start(self._docs_box, False)
+ #connect events
+ self.connect('key-press-event', self._handle_key_press)
+ self.connect('show', self._update_gui)
+ #show all (performs initial gui update)
+ self.show_all()
+
+ def _params_changed(self):
+ """
+ Have the params in this dialog changed?
+ Ex: Added, removed, type change, hide change...
+ To the props dialog, the hide setting of 'none' and 'part' are identical.
+ Therfore, the props dialog only cares if the hide setting is/not 'all'.
+ Make a hash that uniquely represents the params state.
+ @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.
+ """
+ #update the params box
+ if self._params_changed():
+ #hide params box before changing
+ self._params_box.hide_all()
+ #empty the params box
+ for io_param in list(self._input_object_params):
+ self._params_box.remove(io_param)
+ self._input_object_params.remove(io_param)
+ io_param.destroy()
+ #repopulate the params box
+ for param in self._block.get_params():
+ if param.get_hide() == 'all': continue
+ io_param = param.get_input(self._handle_changed)
+ self._input_object_params.append(io_param)
+ self._params_box.pack_start(io_param, False)
+ #show params box with new params
+ self._params_box.show_all()
+ #update the errors box
+ if self._block.is_valid(): self._error_box.hide()
+ else: self._error_box.show()
+ messages = '\n\n'.join(self._block.get_error_messages())
+ self._error_messages_text_display.set_text(messages)
+ #update the docs box
+ if self._block.get_doc(): self._docs_box.show()
+ else: self._docs_box.hide()
+ self._docs_text_display.set_text(self._block.get_doc())
+
+ def _handle_key_press(self, widget, event):
+ """
+ Handle key presses from the keyboard.
+ Call the ok response when enter is pressed.
+ @return false to forward the keypress
+ """
+ if event.keyval == gtk.keysyms.Return:
+ self.response(gtk.RESPONSE_ACCEPT)
+ return True #handled here
+ return False #forward the keypress
+
+ def run(self):
+ """
+ Run the dialog and get its response.
+ @return true if the response was accept
+ """
+ response = gtk.Dialog.run(self)
+ self.destroy()
+ return response == gtk.RESPONSE_ACCEPT
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):
"""
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)
from Constants import POSSIBLE_ROTATIONS
from Cheetah.Template import Template
+import gobject
def get_rotated_coordinate(coor, rotation):
"""
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.
@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))
"""
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
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
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),
"""
-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
"""
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'
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
_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.
@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):
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.
@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
"""
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
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):
"""
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):
"""
'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,
#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':
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
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 \
('Message', Constants.MSG_COLOR_SPEC),
)
-class Platform(_Platform):
+class Platform(_Platform, _GUIPlatform):
def __init__(self):
"""
generator=Generator,
colors=COLORS,
)
+ _GUIPlatform.__init__(self)
##############################################
# Constructors
FlowGraph = _FlowGraph
Connection = _Connection
Block = _Block
- Source = Source
- Sink = Sink
+ Port = _Port
Param = _Param
"""
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.
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)
## 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
#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
########################################################
## 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]")
#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()
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')
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.
#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)
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')
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.
#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)
* 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
##################################################
# 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
* 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
+* the block's import data does not handle variable params
+ * call rewrite after load, if new params appear, try load again...
##################################################
# Future
/Makefile.in
/.libs
/.deps
+test_gruel
double
_2400_common::freq_max()
{
- return 2700e6;
+ return 2900e6;
}
//----------------------------------------------------------------------
double
_1200_common::freq_max()
{
- return 1350e6;
+ return 1450e6;
}
//-------------------------------------------------------------------------
double
_1800_common::freq_min()
{
- return 1600e6;
+ return 1500e6;
}
double
_1800_common::freq_max()
{
- return 2000e6;
+ return 2100e6;
}
//-------------------------------------------------------------------------
double
_900_common::freq_min()
{
- return 800e6;
+ return 750e6;
}
double
_900_common::freq_max()
{
- return 1000e6;
+ return 1050e6;
}
//-------------------------------------------------------------------------
EXTRA_DIST = \
bootstrap \
configure \
- configure.gnu
-
+ configure.gnu \
+ u2_flash_tool
SUBDIRS = config
.base.is_tx = false,
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
- .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(800e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1000e6),
+ .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(750e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1050e6),
.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(0),
.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(70),
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(0.034),
.base.is_tx = true,
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
- .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(800e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1000e6),
+ .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(750e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1050e6),
//.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(xxx),
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
.base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1150e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1350e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1450e6),
.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(0),
.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(70),
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(0.034),
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
.base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1150e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1350e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(1450e6),
//.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(xxx),
.base.is_tx = false,
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
- .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1600e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2000e6),
+ .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1500e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2100e6),
.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(0),
.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(70),
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(0.034),
.base.is_tx = true,
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
- .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1600e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2000e6),
+ .base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(1500e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2100e6),
//.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(xxx),
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
.base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(2300e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2700e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2900e6),
.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(0),
.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(70),
.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(0.034),
.base.output_enables = 0x00E0,
.base.used_pins = 0x00FF,
.base.freq_min = U2_DOUBLE_TO_FXPT_FREQ(2300e6),
- .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2700e6),
+ .base.freq_max = U2_DOUBLE_TO_FXPT_FREQ(2900e6),
//.base.gain_min = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_max = U2_DOUBLE_TO_FXPT_GAIN(xxx),
//.base.gain_step_size = U2_DOUBLE_TO_FXPT_GAIN(xxx),
namespace usrp2 {
pending_reply::pending_reply(unsigned int rid, void *buffer, size_t len)
- : d_rid(rid), d_mutex(), d_cond(&d_mutex), d_buffer(buffer), d_len(len)
+ : d_rid(rid), d_buffer(buffer), d_len(len), d_mutex(), d_cond(&d_mutex),
+ d_complete(false)
{
}
pending_reply::~pending_reply()
{
- signal(); // Needed?
+ notify_completion(); // Needed?
}
int
- pending_reply::wait(double secs)
+ pending_reply::wait_for_completion(double secs)
{
- omni_mutex_lock l(d_mutex);
omni_time abs_timeout = omni_time::time(omni_time(secs));
- return d_cond.timedwait(abs_timeout.d_secs, abs_timeout.d_nsecs);
+ omni_mutex_lock l(d_mutex);
+ while (!d_complete){
+ int r = d_cond.timedwait(abs_timeout.d_secs, abs_timeout.d_nsecs);
+ if (r == 0) // timed out
+ return 0;
+ }
+ return 1;
}
void
- pending_reply::signal()
+ pending_reply::notify_completion()
{
+ omni_mutex_lock l(d_mutex);
+ d_complete = true;
d_cond.signal();
}
{
private:
unsigned int d_rid;
- omni_mutex d_mutex;
- omni_condition d_cond;
void *d_buffer;
size_t d_len;
+
+ // d_mutex is used with d_cond and also protects d_complete
+ omni_mutex d_mutex;
+ omni_condition d_cond;
+ bool d_complete;
public:
/*!
* Returns: 1 = ok, reply packet in buffer
* 0 = timeout
*/
- int wait(double secs);
+ int wait_for_completion(double secs);
/*!
* Allows creating thread to resume after copying reply into buffer
*/
- void signal();
+ void notify_completion();
/*!
* Retrieve pending reply ID
d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
- d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0)
+ d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true)
{
if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
throw std::runtime_error("Unable to register USRP2 protocol");
cmd->eop.len = sizeof(cmd->eop);
}
+
+ bool
+ usrp2::impl::transmit_cmd(void *cmd_, size_t len_)
+ {
+ const void *cmd = cmd_;
+ int len = len_;
+ unsigned char tmp[64];
+
+ if (len_ < 64){ // pad to minimum ethernet frame size
+ memset(tmp, 0, sizeof(tmp));
+ memcpy(tmp, cmd_, len_);
+ cmd = tmp;
+ len = sizeof(tmp);
+ }
+
+ return d_eth_buf->tx_frame(cmd, len) == eth_buffer::EB_OK;
+ }
+
bool
- usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
+ usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
{
- if (p)
- d_pending_replies[p->rid()] = p;
+ d_pending_replies[p->rid()] = p;
- // Transmit command
- if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
+ if (!transmit_cmd(cmd, len)){
d_pending_replies[p->rid()] = 0;
return false;
}
- int res = 1;
- if (p)
- res = p->wait(secs);
-
+ int res = p->wait_for_completion(secs);
d_pending_replies[p->rid()] = 0;
return res == 1;
}
return handle_control_packet(base, len);
}
else { // data packets
+
+ if (d_dont_enqueue) // toss packet
+ return data_handler::RELEASE;
+
return handle_data_packet(base, len);
}
// Copy reply into caller's buffer
memcpy(rp->buffer(), p, std::min(oplen, buflen));
- rp->signal();
+ rp->notify_completion();
d_pending_replies[rid] = 0;
return data_handler::RELEASE;
}
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.decim = htonl(decimation_factor);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.opcode = OP_EOP;
cmd.eop.len = sizeof(cmd.eop);
+ d_dont_enqueue = false;
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
success = success && (ntohx(reply.ok) == 1);
if (success)
d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
+ else
+ d_dont_enqueue = true;
+ //fprintf(stderr, "usrp2::start_rx_streaming: success = %d\n", success);
return success;
}
}
return false;
}
+ d_dont_enqueue = true; // no new samples
+ flush_rx_samples(channel); // dump any we may already have
+
op_stop_rx_cmd cmd;
op_generic_t reply;
bool success = false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
+ success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
success = success && (ntohx(reply.ok) == 1);
d_channel_rings[channel].reset();
+ //fprintf(stderr, "usrp2::stop_rx_streaming: success = %d\n", success);
return success;
}
}
return true;
}
+ bool
+ usrp2::impl::flush_rx_samples(unsigned int channel)
+ {
+ if (channel > MAX_CHAN) {
+ std::cerr << "usrp2: invalid channel (" << channel
+ << " )" << std::endl;
+ return false;
+ }
+
+ if (channel > 0) {
+ std::cerr << "usrp2: channel " << channel
+ << " not implemented" << std::endl;
+ return false;
+ }
+
+ ring_sptr rp = d_channel_rings[channel];
+ if (!rp){
+ return false;
+ }
+
+ // Iterate through frames and drop them
+ void *p;
+ size_t frame_len_in_bytes;
+ while (rp->dequeue(&p, &frame_len_in_bytes)) {
+ d_eth_buf->release_frame(p);
+ dec_enqueued();
+ }
+ return true;
+ }
+
// ----------------------------------------------------------------
// Transmit
// ----------------------------------------------------------------
cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.interp = htonl(interpolation_factor);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
return ntohx(reply.ok) == 1;
return false;
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
return ntohx(reply.ok) == 1;
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
return ntohx(reply.ok) == 1;
reply = (op_generic_t *)malloc(rlen+bytes);
pending_reply p(cmd.op.rid, reply, rlen+bytes);
- if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
+ if (transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
uint32_t *data = (uint32_t *)(reply+rlen/wlen);
for (unsigned int i = 0; i < nwords; i++)
bool ok = false;
op_generic_t reply;
pending_reply p(cmd->op.rid, &reply, sizeof(reply));
- if (transmit_cmd(cmd, l, &p, DEF_CMD_TIMEOUT))
+ if (transmit_cmd_and_wait(cmd, l, &p, DEF_CMD_TIMEOUT))
ok = (ntohx(reply.ok) == 1);
free(cmd);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
cmd.eop.len = sizeof(cmd.eop);
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
- if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
+ if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
return false;
bool success = (ntohx(reply.ok) == 1);
int d_tx_interp; // shadow tx interp
int d_rx_decim; // shadow rx decim
+ bool d_dont_enqueue;
+
void inc_enqueued() {
omni_mutex_lock l(d_enqueued_mutex);
d_num_enqueued++;
void stop_bg();
void init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd);
void init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd);
- bool transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs=0.0);
+ bool transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs=0.0);
+ bool transmit_cmd(void *cmd, size_t len);
virtual data_handler::result operator()(const void *base, size_t len);
data_handler::result handle_control_packet(const void *base, size_t len);
data_handler::result handle_data_packet(const void *base, size_t len);
bool read_gpio(int bank, uint16_t *value);
bool start_rx_streaming(unsigned int channel, unsigned int items_per_frame);
bool rx_samples(unsigned int channel, rx_sample_handler *handler);
+ bool flush_rx_samples(unsigned int channel);
bool stop_rx_streaming(unsigned int channel);
unsigned int rx_overruns() const { return d_num_rx_overruns; }
unsigned int rx_missing() const { return d_num_rx_missing; }