Merge branch 'utils' of http://gnuradio.org/git/trondeau into master
authorJohnathan Corgan <jcorgan@corganenterprises.com>
Wed, 16 Sep 2009 14:59:16 +0000 (07:59 -0700)
committerJohnathan Corgan <jcorgan@corganenterprises.com>
Wed, 16 Sep 2009 14:59:16 +0000 (07:59 -0700)
* 'utils' of http://gnuradio.org/git/trondeau:
  Fixed slider behavior when the end of the file is reached.
  Handling a few exceptions when no file is loaded.
  Can now change the size of the symbols. Also fixes some layout issues.
  Adding ability to change line width and style (only a handful of current styles enabled).
  Removing plot picker that addd nothing to the interface.
  Adding a Reload option (Ctrl+R) option to quickly reread the file and reset the state.

113 files changed:
.gitignore
config/gr_fortran.m4
configure.ac
gnuradio-core/src/lib/filter/Makefile.am
gnuradio-core/src/lib/filter/filter.i
gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc [new file with mode: 0644]
gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h [new file with mode: 0644]
gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i [new file with mode: 0644]
gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc
gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc
gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
gnuradio-core/src/lib/general/gr_constants.cc.in
gnuradio-core/src/lib/general/gr_constants.h
gnuradio-core/src/lib/general/gr_constants.i
gnuradio-core/src/lib/gnuradio-config-info.cc
gnuradio-core/src/python/gnuradio/Makefile.am
gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/logpwrfft.py
gnuradio-core/src/python/gnuradio/eng_option.py
gnuradio-core/src/python/gnuradio/usrp_options.py [new file with mode: 0644]
gnuradio-examples/python/digital/Makefile.am
gnuradio-examples/python/digital/benchmark_qt_rx.py
gnuradio-examples/python/digital/generic_usrp.py [deleted file]
gnuradio-examples/python/digital/usrp_options.py [deleted file]
gnuradio-examples/python/digital/usrp_receive_path.py
gnuradio-examples/python/digital/usrp_transmit_path.py
gr-utils/src/python/Makefile.am
gr-utils/src/python/qr_fft.py [deleted file]
gr-utils/src/python/usrp2_siggen.py [deleted file]
gr-utils/src/python/usrp2_siggen_gui.py [deleted file]
gr-utils/src/python/usrp_siggen.py
gr-utils/src/python/usrp_siggen_gui.py [new file with mode: 0755]
gr-wxgui/src/python/common.py
gr-wxgui/src/python/fft_window.py
gr-wxgui/src/python/forms/converters.py
gr-wxgui/src/python/forms/forms.py
gr-wxgui/src/python/plotter/waterfall_plotter.py
gr-wxgui/src/python/scopesink_gl.py
gr-wxgui/src/python/waterfall_window.py
grc/Makefile.inc
grc/base/Block.py
grc/base/Element.py
grc/base/FlowGraph.py
grc/base/Param.py
grc/base/Platform.py
grc/base/Port.py
grc/blocks/Makefile.am
grc/blocks/band_pass_filter.xml
grc/blocks/band_reject_filter.xml
grc/blocks/block_tree.xml
grc/blocks/gr_noise_source_x.xml
grc/blocks/gr_sig_source_x.xml
grc/blocks/high_pass_filter.xml
grc/blocks/low_pass_filter.xml
grc/blocks/options.xml
grc/blocks/pad_sink.xml
grc/blocks/pad_source.xml
grc/blocks/parameter.xml
grc/blocks/usrp2_sink_xxxx.xml
grc/blocks/usrp2_source_xxxx.xml
grc/blocks/usrp_dual_sink_x.xml
grc/blocks/usrp_dual_source_x.xml
grc/blocks/usrp_simple_sink_x.xml
grc/blocks/usrp_simple_source_x.xml
grc/blocks/virtual_sink.xml [new file with mode: 0644]
grc/blocks/virtual_source.xml [new file with mode: 0644]
grc/blocks/wxgui_fftsink2.xml
grc/blocks/wxgui_waterfallsink2.xml
grc/grc_gnuradio/usrp/dual_usrp.py
grc/grc_gnuradio/usrp/simple_usrp.py
grc/gui/ActionHandler.py
grc/gui/Actions.py
grc/gui/Bars.py
grc/gui/Block.py
grc/gui/BlockTreeWindow.py
grc/gui/Connection.py
grc/gui/Dialogs.py
grc/gui/Element.py
grc/gui/FlowGraph.py
grc/gui/MainWindow.py
grc/gui/Makefile.am
grc/gui/NotebookPage.py
grc/gui/Param.py
grc/gui/ParamsDialog.py [deleted file]
grc/gui/Platform.py
grc/gui/Port.py
grc/gui/PropsDialog.py [new file with mode: 0644]
grc/gui/StateCache.py
grc/gui/Utils.py
grc/python/Block.py
grc/python/Connection.py
grc/python/FlowGraph.py
grc/python/Param.py
grc/python/Platform.py
grc/python/Port.py
grc/python/flow_graph.tmpl
grc/scripts/usrp2_probe
grc/scripts/usrp_probe
grc/todo.txt
gruel/src/lib/.gitignore
usrp/host/lib/db_flexrf.cc
usrp2/firmware/Makefile.am
usrp2/firmware/lib/db_rfx.c
usrp2/host/lib/control.cc
usrp2/host/lib/control.h
usrp2/host/lib/usrp2_impl.cc
usrp2/host/lib/usrp2_impl.h

index b11bb113a1b66c8762a0312c7eb8c436b7fc2e7e..b333709ee11bbe673fcfbfc4fd94f0ee99cce818 100644 (file)
@@ -1,3 +1,30 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+.*
+*.o
+*.a
+*.ko
+*.so
+*.la
+*.lo
+*.py[oc]
+*.gz
+*.patch
+*~
+\#*#
+.deps
+.libs
+TAGS
+*-stamp
+!.gitignore
+make.log
 /configure
 /Makefile.in
 /config.log
@@ -17,4 +44,3 @@
 /compile
 /build
 /run_tests.sh
-/*-stamp
index b5b0470f45c2ce78cb525490bf56d32b0548f140..a558b2f7e3f00eaecddd39bc5248a0ece883c543 100644 (file)
@@ -28,5 +28,6 @@ AC_DEFUN([GR_FORTRAN],[
     then
         AC_PROG_F77
         AC_F77_LIBRARY_LDFLAGS
+       AC_PROG_CC dnl bux fix to restore $ac_ext
     fi
 ])
index 1764b46abe2abad7cb054ca2a6abae3d1771a465..2bb37935e9a4cb1ef10b664c6a1463f13368a064 100644 (file)
@@ -286,9 +286,6 @@ dnl AX_BOOST_TEST_EXEC_MONITOR
 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)
 
index 838f69b92d39163d50c70719e664bef960121eb3..d5afd571bac31bd10aba7d3f30858bae6a9b130f 100644 (file)
@@ -205,7 +205,8 @@ libfilter_la_common_SOURCES =               \
        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                    \
@@ -284,7 +285,8 @@ grinclude_HEADERS =                         \
        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                      \
@@ -339,6 +341,7 @@ swiginclude_HEADERS =                       \
        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
 
index 16b8005be5072b272895588a96d31591fc7c1e58..91f55c5142610326c137b57510a13490ce7d7141 100644 (file)
@@ -36,6 +36,7 @@
 #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"
@@ -56,5 +57,6 @@
 %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"
index bfc4c04675904dac22e59004e8dfe07319438b96..8971d3d39bb5001598559ddee61a6b039c208894 100644 (file)
@@ -28,6 +28,7 @@
 #include <gr_fir_ccf.h>
 #include <gr_fir_util.h>
 #include <gr_io_signature.h>
+#include <cstdio>
 
 gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate, 
                                                             const std::vector<float> &taps,
index b79a89fe93027c834f762f3ffc356f36f0ffeb60..d4c886ec378b439458914ca51c15e1ab6e0cc9be 100644 (file)
@@ -91,8 +91,8 @@ class gr_fir_ccf;
  * The theory behind this block can be found in Chapter 7.5 of 
  * the following book.
  *
- *    <B><EM>f. harris, Multirate Signal Processing for Communication 
- *       Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
+ *    <B><EM>f. harris, "Multirate Signal Processing for Communication 
+ *       Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
  */
 
 class gr_pfb_arb_resampler_ccf : public gr_block
index 7be611e236049bd309878313197df03afdc40a4f..a7e8de62ad6a65e7bb1e8914e748c72ecd73a2c6 100644 (file)
@@ -29,6 +29,7 @@
 #include <gr_fir_util.h>
 #include <gri_fft.h>
 #include <gr_io_signature.h>
+#include <cstdio>
 
 gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, 
                                                         const std::vector<float> &taps)
index 7d0a31c5985c24bbc20a94733bf07f0fcf71e725..b2e67e8173a5558b16499698d4134d6da480c860 100644 (file)
@@ -91,8 +91,8 @@ class gri_fft_complex;
  * The theory behind this block can be found in Chapter 6 of 
  * the following book.
  *
- *    <B><EM>f. harris, Multirate Signal Processing for Communication 
- *       Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.
+ *    <B><EM>f. harris, "Multirate Signal Processing for Communication 
+ *       Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
  *
  */
 
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
new file mode 100644 (file)
index 0000000..91cbf74
--- /dev/null
@@ -0,0 +1,258 @@
+/* -*- 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;
+}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
new file mode 100644 (file)
index 0000000..1a04e55
--- /dev/null
@@ -0,0 +1,106 @@
+/* -*- 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
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i
new file mode 100644 (file)
index 0000000..729d4a1
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- 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();
+};
index b334f58781a78b1e0c4c7678815ac158ef07a596..e05e18ff2e0f04c38bd3ce6c152402e6876806d5 100644 (file)
@@ -30,6 +30,7 @@
 #include <gri_fft.h>
 #include <gr_io_signature.h>
 #include <gr_expj.h>
+#include <cstdio>
 
 gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim, 
                                                     const std::vector<float> &taps,
index 83997c0c901dcb0aede1e50ed12440ea3cd63c68..200adee3d32c6fb74d85fe06dc1b579794fd4d7c 100644 (file)
@@ -88,7 +88,7 @@ class gri_fft_complex;
  * The theory behind this block can be found in Chapter 6 of 
  * the following book.
  *
- *    <B><EM>f. harris, Multirate Signal Processing for Communication 
+ *    <B><EM>f. harris, "Multirate Signal Processing for Communication 
  *       Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
  */
 
index d5eba885ca98df622c7013bbabe6db74ba4ebbdc..6a9598f344584b51ccb350d96ad5ead2a63143df 100644 (file)
@@ -28,6 +28,7 @@
 #include <gr_fir_ccf.h>
 #include <gr_fir_util.h>
 #include <gr_io_signature.h>
+#include <cstdio>
 
 gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp, 
                                                           const std::vector<float> &taps)
index 50849d5108bea2b118866cda676c32bf09f0ff85..d2efc591abf2797a7418390dc1cf4d9dfe23962e 100644 (file)
@@ -74,7 +74,7 @@ class gr_fir_ccf;
  * The theory behind this block can be found in Chapter 7.1 of the
  * following book.
  *
- *    <B><EM>f. harris, <EM>Multirate Signal Processing for Communication
+ *    <B><EM>f. harris, "Multirate Signal Processing for Communication
  *       Systems</EM>," Upper Saddle River, NJ: Prentice Hall,
  *       Inc. 2004.</EM></B>
  */
index efb0f1c776695e7ef259ec2b8c7e0322fdbedba8..71a47eb5102450aeb6bb79dd9f49ecc00cbebe49 100644 (file)
@@ -50,18 +50,6 @@ gr_build_date()
   return "@BUILD_DATE@";
 }
 
-const std::string
-gr_svn_date()
-{
-  return "@SVNDATE@";
-}
-
-const std::string
-gr_svn_version()
-{
-  return "@SVNVERSION@";
-}
-
 const std::string
 gr_version()
 {
index e44890be0176061810972004b2a7a7d26e1c264c..449d41c174c1461414f4444908d006c8cb5d921c 100644 (file)
@@ -44,16 +44,6 @@ const std::string gr_prefsdir();
  */
 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
  */
index 156af4a3655fbae0a15382d349d434e2b3fcf50e..a5aef14925da5e1103c2296c23eb2ef4f6732e58 100644 (file)
@@ -4,14 +4,10 @@
 %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();
index df78ea2ddf9bea047de6d65e86520d92fd31a242..6fa53b87762954b8bfe8aa55d0366c92a7ffb57f 100644 (file)
@@ -43,8 +43,6 @@ main(int argc, char **argv)
     ("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);
@@ -70,11 +68,5 @@ main(int argc, char **argv)
   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;
 }
index ed36bbae7c479e2d8c2cc8c959a2b8ca2a3b3943..dcc0017b3c16660fd7b238a2a106e76720d2b4ee 100644 (file)
@@ -34,5 +34,6 @@ grpython_PYTHON =                     \
        packet_utils.py                 \
        gr_unittest.py                  \
        optfir.py                       \
+       usrp_options.py         \
        window.py
 endif
index 17be09cc73b35ed9239c97700db5e3b463823f5c..f0825b15135fb7cfe19c508578c9466ec2c106c4 100644 (file)
@@ -36,6 +36,7 @@ grblkspython_PYTHON =         \
        filterbank.py           \
        fm_demod.py             \
        fm_emph.py              \
+       generic_usrp.py \
        gmsk.py                 \
        cpm.py                  \
        logpwrfft.py            \
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py
new file mode 100644 (file)
index 0000000..5abbaf9
--- /dev/null
@@ -0,0 +1,244 @@
+#
+# 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)
index cf8eb1be78597fae71ed617307ddf4e707e0e7f4..7ef40be40a92bb4f55a872e05802e95fd2b3f0c2 100644 (file)
@@ -55,9 +55,9 @@ class _logpwrfft_base(gr.hier_block2):
         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
index 09c3e1d87771a0a5a26ea2ce0f52b2f62a8def06..e10235f143958329b3ccfbdb70f6e08f4d91eb33 100644 (file)
 
 from copy import copy
 from optparse import Option, OptionValueError
-
-scale_factor = {}
-scale_factor['E'] = 1e18
-scale_factor['P'] = 1e15
-scale_factor['T'] = 1e12
-scale_factor['G'] = 1e9
-scale_factor['M'] = 1e6
-scale_factor['k'] = 1e3
-scale_factor['m'] = 1e-3
-scale_factor['u'] = 1e-6
-scale_factor['n'] = 1e-9
-scale_factor['p'] = 1e-12
-scale_factor['f'] = 1e-15
-scale_factor['a'] = 1e-18
-
+import eng_notation
 
 def check_eng_float (option, opt, value):
     try:
-        scale = 1.0
-        suffix = value[-1]
-        if scale_factor.has_key (suffix):
-            return float (value[0:-1]) * scale_factor[suffix]
-        return float (value)
+        return eng_notation.str_to_num(value)
     except:
         raise OptionValueError (
             "option %s: invalid engineering notation value: %r" % (opt, value))
diff --git a/gnuradio-core/src/python/gnuradio/usrp_options.py b/gnuradio-core/src/python/gnuradio/usrp_options.py
new file mode 100644 (file)
index 0000000..86dba2f
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# 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
index 64ce4ec46625e0d9c6dc51a8ec472bbadad0294c..e32180cd493dd8a7caef30810a944dfd22de90c3 100644 (file)
@@ -25,7 +25,6 @@ ourdatadir = $(exampledir)/digital
 
 dist_ourdata_DATA =            \
        README                  \
-       generic_usrp.py         \
        pick_bitrate.py         \
        qt_digital_window.ui    \
        qt_digital_window.py    \
@@ -33,7 +32,6 @@ dist_ourdata_DATA =           \
        qt_rx_window.py         \
        receive_path.py         \
        transmit_path.py        \
-       usrp_options.py \
        usrp_receive_path.py \
        usrp_transmit_path.py
 
index 33cf94a5c5a9235d2a24b04a5d15b797da7d8c0c..0cbb68d23ee5cbde40c086ddb96b96a5b7cd317d 100755 (executable)
@@ -25,6 +25,7 @@ from gnuradio import usrp
 from gnuradio import eng_notation
 from gnuradio.eng_option import eng_option
 from optparse import OptionParser
+from gnuradio import usrp_options
 
 import random
 import struct
@@ -33,7 +34,6 @@ import sys
 # from current dir
 from receive_path import receive_path
 from pick_bitrate import pick_rx_bitrate
-import usrp_options
 
 try:
     from gnuradio.qtgui import qtgui
diff --git a/gnuradio-examples/python/digital/generic_usrp.py b/gnuradio-examples/python/digital/generic_usrp.py
deleted file mode 100644 (file)
index c7ccbe5..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-#
-# 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)
diff --git a/gnuradio-examples/python/digital/usrp_options.py b/gnuradio-examples/python/digital/usrp_options.py
deleted file mode 100644 (file)
index 380ef60..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#
-# 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
index fd47c2725daee854e14475006cbccae440aa64e4..e28eb0a8cedcbdcfca84a3f69fbacfdb36e80a87 100644 (file)
@@ -20,7 +20,7 @@
 # 
 
 from gnuradio import gr
-import usrp_options
+from gnuradio import usrp_options
 import receive_path
 from pick_bitrate import pick_rx_bitrate
 from gnuradio import eng_notation
index ed2603fa3e632a35580e4559b07440801b06adaa..ad9f741a6309dec1b82106513525ebcb2a324c2f 100644 (file)
@@ -20,7 +20,7 @@
 # 
 
 from gnuradio import gr
-import usrp_options
+from gnuradio import usrp_options
 import transmit_path
 from pick_bitrate import pick_tx_bitrate
 from gnuradio import eng_notation
index 59ca215a764a920392979754e8b5e46b715601fb..fb21e4f449b8eb817a34c792209f1bc2da1029bc 100644 (file)
@@ -50,17 +50,15 @@ bin_SCRIPTS = \
     gr_plot_qt.py \
     gr_filter_design.py \
     lsusrp \
-    qr_fft.py \
     usrp_fft.py \
     usrp_oscope.py \
     usrp_print_db.py \
     usrp_rx_cfile.py \
     usrp_rx_nogui.py \
     usrp_siggen.py \
+    usrp_siggen_gui.py \
     usrp_test_counting.py \
     usrp_test_loopback.py \
     usrp2_fft.py \
-    usrp2_rx_cfile.py \
-    usrp2_siggen.py \
-    usrp2_siggen_gui.py
+    usrp2_rx_cfile.py
 
diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py
deleted file mode 100755 (executable)
index c2f06d7..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc.
-# 
-# This file is part of GNU Radio
-# 
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-from gnuradio.wxgui import forms
-from gnuradio import gr, gru
-from gnuradio import vrt
-from gnuradio import eng_notation
-from gnuradio.eng_option import eng_option
-from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider
-from gnuradio.gr import pubsub
-from optparse import OptionParser
-import wx
-import sys
-import numpy
-import time
-
-class app_top_block(stdgui2.std_top_block, pubsub.pubsub):
-    def __init__(self, frame, panel, vbox, argv):
-        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
-        pubsub.pubsub.__init__(self)
-        self.frame = frame
-        self.panel = panel
-        
-        parser = OptionParser(option_class=eng_option)
-        #parser.add_option("-e", "--interface", type="string", default="eth0",
-        #                  help="select Ethernet interface, default is eth0")
-        #parser.add_option("-m", "--mac-addr", type="string", default="",
-        #                  help="select USRP by MAC address, default is auto-select")
-        #parser.add_option("-A", "--antenna", default=None,
-        #                  help="select Rx Antenna (only on RFX-series boards)")
-        #parser.add_option("-d", "--decim", type="int", default=16,
-        #                  help="set fgpa decimation rate to DECIM [default=%default]")
-        #parser.add_option("-f", "--freq", type="eng_float", default=None,
-        #                  help="set frequency to FREQ", metavar="FREQ")
-        #parser.add_option("-g", "--gain", type="eng_float", default=None,
-        #                  help="set gain in dB (default is midpoint)")
-        parser.add_option("-W", "--waterfall", action="store_true", default=False,
-                          help="Enable waterfall display")
-        parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
-                          help="Enable oscilloscope display")
-       parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1,
-                         help="Set fftsink averaging factor, default=[%default]")
-       parser.add_option("", "--ref-scale", type="eng_float", default=1.0,
-                         help="Set dBFS=0dB input value, default=[%default]")
-        parser.add_option("--fft-size", type="int", default=1024,
-                          help="Set number of FFT bins [default=%default]")
-        parser.add_option("--samples-per-pkt", type="int", default=0,
-                          help="Set number of SAMPLES-PER-PKT [default=%default]")
-        parser.add_option("", "--ip-addr", type="string", default="192.168.10.2",
-                          help="IP address default=[%default]")
-        (options, args) = parser.parse_args()
-        if len(args) != 0:
-            parser.print_help()
-            sys.exit(1)
-       self.options = options
-        self.show_debug_info = True
-        
-        self.u = vrt.quadradio_source_32fc(options.ip_addr,
-                                           int(62.5e6), options.samples_per_pkt)
-        #self.u.set_decim(options.decim)
-        
-        #input_rate = self.u.adc_rate() / self.u.decim()
-        input_rate = int(120e6/4)
-        
-        if options.waterfall:
-            self.scope = \
-              waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate)
-        elif options.oscilloscope:
-            self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
-        else:
-            self.scope = fftsink2.fft_sink_c (panel,
-                                              fft_size=options.fft_size,
-                                              sample_rate=input_rate, 
-                                             ref_scale=options.ref_scale,
-                                              ref_level=20.0,
-                                              y_divs = 12,
-                                             avg_alpha=options.avg_alpha)
-
-        self.connect(self.u, self.scope)
-
-        self._build_gui(vbox)
-       self._setup_events()
-       
-        # set initial values
-
-        #if options.gain is None:
-        #    # if no gain was specified, use the mid-point in dB
-        #    g = self.u.gain_range()
-        #    options.gain = float(g[0]+g[1])/2
-
-        #if options.freq is None:
-        #    # if no freq was specified, use the mid-point
-        #    r = self.u.freq_range()
-        #    options.freq = float(r[0]+r[1])/2
-            
-        #self.set_gain(options.gain)
-
-       #if options.antenna is not None:
-        #    print "Selecting antenna %s" % (options.antenna,)
-        #    self.subdev.select_rx_antenna(options.antenna)
-
-        if self.show_debug_info:
-        #    self.myform['decim'].set_value(self.u.decim())
-            self.myform['fs@gbe'].set_value(input_rate)
-        #    self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name
-            self.myform['baseband'].set_value(0)
-            self.myform['ddc'].set_value(0)
-
-        #if not(self.set_freq(options.freq)):
-        #    self._set_status_msg("Failed to set initial frequency")
-
-    def _set_status_msg(self, msg):
-        self.frame.GetStatusBar().SetStatusText(msg, 0)
-
-    def _build_gui(self, vbox):
-
-        def _form_set_freq(kv):
-            return self.set_freq(kv['freq'])
-            
-        vbox.Add(self.scope.win, 10, wx.EXPAND)
-        
-        # add control area at the bottom
-        self.myform = myform = form.form()
-        hbox = wx.BoxSizer(wx.HORIZONTAL)
-        hbox.Add((5,0), 0, 0)
-        myform['freq'] = form.float_field(
-            parent=self.panel, sizer=hbox, label="Center freq", weight=1,
-            callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
-
-        hbox.Add((5,0), 0, 0)
-        #g = self.u.gain_range()
-
-       # some configurations don't have gain control
-       if 0 and g[1] > g[0]:
-           myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain",
-                                           weight=3,
-                                           min=int(g[0]), max=int(g[1]),
-                                           callback=self.set_gain)
-
-        hbox.Add((5,0), 0, 0)
-        vbox.Add(hbox, 0, wx.EXPAND)
-
-        self._build_subpanel(vbox)
-
-    def _build_subpanel(self, vbox_arg):
-        # build a secondary information panel (sometimes hidden)
-
-        # FIXME figure out how to have this be a subpanel that is always
-        # created, but has its visibility controlled by foo.Show(True/False)
-        
-        def _form_set_decim(kv):
-            return self.set_decim(kv['decim'])
-
-        if not(self.show_debug_info):
-            return
-
-        panel = self.panel
-        vbox = vbox_arg
-        myform = self.myform
-
-        #panel = wx.Panel(self.panel, -1)
-        #vbox = wx.BoxSizer(wx.VERTICAL)
-
-        hbox = wx.BoxSizer(wx.HORIZONTAL)
-        hbox.Add((5,0), 0)
-
-        myform['decim'] = form.int_field(
-            parent=panel, sizer=hbox, label="Decim",
-            callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg))
-
-        hbox.Add((5,0), 1)
-        myform['fs@gbe'] = form.static_float_field(
-            parent=panel, sizer=hbox, label="Fs@GbE")
-
-        hbox.Add((5,0), 1)
-        myform['dbname'] = form.static_text_field(
-            parent=panel, sizer=hbox)
-
-        hbox.Add((5,0), 1)
-        myform['baseband'] = form.static_float_field(
-            parent=panel, sizer=hbox, label="Analog BB")
-
-        hbox.Add((5,0), 1)
-        myform['ddc'] = form.static_float_field(
-            parent=panel, sizer=hbox, label="DDC")
-
-        hbox.Add((5,0), 0)
-        vbox.Add(hbox, 0, wx.EXPAND)
-        ##### db control stuff #####
-        self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01))
-        self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq
-        self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01))
-        self.subscribe('db_ctrl_atten0', self.u.set_attenuation0)
-        self.subscribe('db_ctrl_atten1', self.u.set_attenuation1)
-        self.subscribe('sys_beaming', self.u.set_beamforming)
-        #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten)
-        self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain)
-        self.subscribe('db_ctrl_diggain', self.u.set_digital_gain)
-        self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp)
-        self.subscribe('db_ctrl_bandsel', self.u.set_band_select)
-        self.subscribe('db_ctrl_type', self.u.select_rx_antenna)
-        self.subscribe('db_test_signal', self.u.set_test_signal)
-        self['db_ctrl_bandsel'] = 'A'
-        self['cal_div_lo_freq'] = 2.1e9
-        self['cal_div_cal_freq'] = 2.102e9
-        self['db_ctrl_atten0'] = 0
-        self['db_ctrl_atten1'] = 0
-        #self['db_ctrl_10db'] = False
-        self['db_ctrl_adcgain'] = False
-        self['db_ctrl_dcoffset'] = False
-        self['db_ctrl_diggain'] = 0.0
-        self['db_ctrl_type'] = 'rf'
-        self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL
-       self['sys_beaming'] = [16.7e6, 0, 0, 0]
-        #slider and box for freqs
-        for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')):
-            hbox = wx.BoxSizer(wx.HORIZONTAL)
-            hbox.AddSpacer(10)
-            forms.text_box(
-                label=name,
-                ps=self,
-                key=key,
-                sizer=hbox,
-                parent=panel,
-                proportion=0,
-                converter=forms.float_converter()
-            )
-            hbox.AddSpacer(20)
-            forms.slider(
-                ps=self,
-                key=key,
-                minimum=0,   #TODO get bounds from cal_div, from vrt...
-                maximum=int(3.5e9),
-                step_size=int(5e6),
-                cast=float,
-                sizer=hbox,
-                parent=panel,
-                proportion=2,
-            )
-            hbox.AddSpacer(10)
-            vbox.Add(hbox, 0, wx.EXPAND)
-        ############################################
-        hbox = wx.BoxSizer(wx.HORIZONTAL)
-        hbox.AddSpacer(10)
-        #create slider for atten
-        atten0_txt_box = forms.static_text(
-            label='Attenuation (0)',
-            ps=self,
-            key='db_ctrl_atten0',
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-            converter=forms.int_converter()
-        )
-        hbox.AddSpacer(20)
-        atten0_slider = forms.slider(
-            ps=self,
-            key='db_ctrl_atten0',
-            minimum=0,
-            maximum=31,
-            step_size=1,
-            cast=int,
-            sizer=hbox,
-            parent=panel,
-            proportion=2,
-        )
-        hbox.AddSpacer(10)
-        #create slider for atten
-        forms.static_text(
-            label='Attenuation (1)',
-            ps=self,
-            key='db_ctrl_atten1',
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-            converter=forms.int_converter()
-        )
-        hbox.AddSpacer(20)
-        forms.slider(
-            ps=self,
-            key='db_ctrl_atten1',
-            minimum=0,
-            maximum=31,
-            step_size=1,
-            cast=int,
-            sizer=hbox,
-            parent=panel,
-            proportion=2,
-        )
-        hbox.AddSpacer(10)
-        def update_atten0(*args):
-            for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B')
-        update_atten0()
-        self.subscribe('db_ctrl_bandsel', update_atten0)
-        #create checkbox for 10dB att
-        #forms.check_box(
-        #    label='10dB Attenuation',
-        #    ps=self,
-        #    key='db_ctrl_10db',
-        #    sizer=hbox,
-        #    parent=panel,
-        #    proportion=1,
-        #)
-        #hbox.AddSpacer(10)
-        vbox.Add(hbox, 0, wx.EXPAND)
-        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
-        hbox2.AddSpacer(10)
-        forms.static_text(
-            label='ADC Controls',
-            ps=self,
-            key='db_ctrl_diggain',
-            sizer=hbox2,
-            parent=panel,
-            proportion=0,
-            converter=forms.float_converter()
-        )
-        hbox2.AddSpacer(20)
-        #create checkbox for ADC digital gain
-        forms.slider(
-            #label='ADC Digital Gain',
-            ps=self,
-            minimum=0,
-            maximum=6,
-            step_size=0.5,
-            key='db_ctrl_diggain',
-            sizer=hbox2,
-            parent=panel,
-            proportion=2,
-        )
-        hbox2.AddSpacer(10)
-        #create checkbox for 3.5dB ADC gain
-        forms.check_box(
-            label='3.5dB ADC Gain',
-            ps=self,
-            key='db_ctrl_adcgain',
-            sizer=hbox2,
-            parent=panel,
-            proportion=1,
-        )
-        hbox2.AddSpacer(10)
-        #create checkbox for DC Offset Correction in ADC
-        forms.check_box(
-            label='DC Offset Correction',
-            ps=self,
-            key='db_ctrl_dcoffset',
-            sizer=hbox2,
-            parent=panel,
-            proportion=2,
-        )
-        hbox2.AddSpacer(10)
-        vbox.Add(hbox2, 0, wx.EXPAND)
-        hbox = wx.BoxSizer(wx.HORIZONTAL)
-        hbox.AddSpacer(10)
-        #create radio buttons for band sel
-        forms.radio_buttons(
-            label='Band Select',
-            ps=self,
-            key='db_ctrl_bandsel',
-            choices=['A', 'B', 'C', 'D'],
-            labels=['A', 'B', 'C', 'D'],
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-        )
-        hbox.AddSpacer(10)
-        forms.radio_buttons(
-            label='RF Input',
-            ps=self,
-            key='db_ctrl_type',
-            choices=['rf', 'cal'],
-            labels=['Main RF', 'Calibrator'],
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-        )
-        hbox.AddSpacer(10)
-        #create radio buttons for band sel
-        types = sorted(
-            filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)),
-            lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)),
-        )
-        forms.drop_down(
-            label='Test Signal',
-            ps=self,
-            key='db_test_signal',
-            choices=map(lambda a: getattr(vrt, a), types),
-            labels=types,
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-        )
-        hbox.AddSpacer(10)
-        #create radio buttons for type
-        forms.drop_down(
-            label='Beamformer',
-            ps=self,
-            key='sys_beaming',
-            choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4],
-            labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'],
-            sizer=hbox,
-            parent=panel,
-            proportion=0,
-        )
-        hbox.AddSpacer(10)
-        vbox.Add(hbox, 0, wx.EXPAND)
-            
-    def set_freq(self, target_freq):
-        """
-        Set the center frequency we're interested in.
-
-        @param target_freq: frequency in Hz
-        @rypte: bool
-
-        Tuning is a two step process.  First we ask the front-end to
-        tune as close to the desired frequency as it can.  Then we use
-        the result of that operation and our target_frequency to
-        determine the value for the digital down converter.
-        """
-        return True
-    
-        r = self.u.set_center_freq(target_freq)
-        
-        if r:
-            self.myform['freq'].set_value(target_freq)     # update displayed value
-            if self.show_debug_info:
-                self.myform['baseband'].set_value(r.baseband_freq)
-                self.myform['ddc'].set_value(r.dxc_freq)
-           if not self.options.oscilloscope:
-               self.scope.win.set_baseband_freq(target_freq)
-           return True
-
-        return False
-
-    def set_gain(self, gain):
-        return True
-    
-       if self.myform.has_key('gain'):
-           self.myform['gain'].set_value(gain)     # update displayed value
-        self.u.set_gain(gain)
-
-    def set_decim(self, decim):
-        return True
-    
-        ok = self.u.set_decim(decim)
-        if not ok:
-            print "set_decim failed"
-        #input_rate = self.u.adc_rate() / self.u.decim()
-        input_rate = 120e6/4
-        self.scope.set_sample_rate(input_rate)
-        if self.show_debug_info:  # update displayed values
-            self.myform['decim'].set_value(self.u.decim())
-            self.myform['fs@gbe'].set_value(input_rate)
-        return ok
-
-    def _setup_events(self):
-       if not self.options.waterfall and not self.options.oscilloscope:
-           self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick)
-           
-    def evt_left_dclick(self, event):
-       (ux, uy) = self.scope.win.GetXY(event)
-       if event.CmdDown():
-           # Re-center on maximum power
-           points = self.scope.win._points
-           if self.scope.win.peak_hold:
-               if self.scope.win.peak_vals is not None:
-                   ind = numpy.argmax(self.scope.win.peak_vals)
-               else:
-                   ind = int(points.shape()[0]/2)
-           else:
-               ind = numpy.argmax(points[:,1])
-            (freq, pwr) = points[ind]
-           target_freq = freq/self.scope.win._scale_factor
-           print ind, freq, pwr
-            self.set_freq(target_freq)            
-       else:
-           # Re-center on clicked frequency
-           target_freq = ux/self.scope.win._scale_factor
-           self.set_freq(target_freq)
-           
-       
-def main ():
-    app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1)
-    app.MainLoop()
-
-if __name__ == '__main__':
-    main ()
diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py
deleted file mode 100755 (executable)
index 9ade933..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-# 
-# This file is part of GNU Radio
-# 
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-from gnuradio import gr, eng_notation, usrp2
-from gnuradio.eng_option import eng_option
-from optparse import OptionParser
-import sys
-import math
-
-n2s = eng_notation.num_to_str
-
-waveforms = { gr.GR_SIN_WAVE   : "Complex Sinusoid",
-              gr.GR_CONST_WAVE : "Constant",
-              gr.GR_GAUSSIAN   : "Gaussian Noise",
-              gr.GR_UNIFORM    : "Uniform Noise",
-              "2tone"          : "Two Tone",
-              "sweep"          : "Sweep" }
-
-#
-# GUI-unaware GNU Radio flowgraph.  This may be used either with command
-# line applications or GUI applications.
-#
-class top_block(gr.top_block):
-    def __init__(self, options, args):
-        gr.top_block.__init__(self)
-        self._verbose = options.verbose
-
-        self._interp = 0 
-        self._gain = 0
-        self._freq = None       # Indicates frequency hasn't been successfully set yet
-        self._bb_freq = 0
-        self._ddc_freq = 0
-        self._amplitude = 0
-        self._type = None       # Indicates waveform flowgraph not created yet
-        self._offset = options.offset
-
-        self.set_usrp2(options.interface, options.mac_addr)
-        self.set_interp(options.interp)
-        self.set_gain(options.gain)
-        self.set_freq(options.tx_freq, options.lo_offset)
-        self.set_amplitude(options.amplitude)
-
-        self.set_waveform_freq(options.waveform_freq)
-        self.set_waveform2_freq(options.waveform2_freq)
-        self.set_waveform(options.type)
-
-    def set_usrp2(self, interface, mac_addr):
-        self._u = usrp2.sink_32fc(interface, mac_addr)
-        self._dac_rate = self._u.dac_rate()
-        if self._verbose:
-            print "Network interface:", interface
-            print "Network address:", self._u.mac_addr()
-            print "Daughterboard ID:", hex(self._u.daughterboard_id())
-
-    def set_interp(self, interp):
-        if interp < 4 or interp > 512: # FIXME get from flowgraph
-            if self._verbose: print "Interpolation rate out of range:", interp
-            return False
-
-        if not self._u.set_interp(interp):
-            raise RuntimeError("Failed to set interpolation rate %i" % (interp,))
-
-        self._interp = interp
-        self._eth_rate = self._dac_rate/self._interp
-        if self._verbose:
-            print "USRP2 interpolation rate:", self._interp
-            print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),)
-
-        if (self._type == gr.GR_SIN_WAVE or 
-            self._type == gr.GR_CONST_WAVE):
-            self._src.set_sampling_freq(self._eth_rate)
-        elif self._type == "2tone":
-            self._src1.set_sampling_freq(self._eth_rate)
-            self._src1.set_sampling_freq(self._eth_rate)
-        elif self._type == "sweep":
-            self._src1.set_sampling_freq(self._eth_rate)
-            self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate)
-        else:
-            return True # Waveform not yet set
-        
-        if self._verbose: print "Set interpolation rate to:", interp
-        return True
-
-    def set_gain(self, gain):
-        if gain is None:
-            g = self._u.gain_range()
-            gain = float(g[0]+g[1])/2
-            if self._verbose:
-                print "Using auto-calculated mid-point TX gain"
-        self._u.set_gain(gain)
-        self._gain = gain
-        if self._verbose:
-            print "Set TX gain to:", self._gain
-
-    def set_freq(self, target_freq, lo_offset=None):
-        if lo_offset is not None:
-            self._lo_offset = lo_offset
-            self._u.set_lo_offset(self._lo_offset)
-            if self._verbose:
-                print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),)
-
-        if target_freq is None:
-            f = self._u.freq_range()
-            target_freq = float(f[0]+f[1])/2.0
-            if self._verbose:
-                print "Using auto-calculated mid-point frequency"
-
-        tr = self._u.set_center_freq(target_freq)
-        fs = "%sHz" % (n2s(target_freq),)
-        if tr is not None:
-            self._freq = target_freq
-
-        else:
-            return True # Waveform not yet set
-        
-        if self._verbose: print "Set amplitude to:", amplitude
-        return True
-
-    def set_gain(self, gain):
-        if gain is None:
-            g = self._u.gain_range()
-            gain = float(g[0]+g[1])/2
-            if self._verbose:
-                print "Using auto-calculated mid-point TX gain"
-        self._u.set_gain(gain)
-        self._gain = gain
-        if self._verbose:
-            print "Set TX gain to:", self._gain
-
-    def set_freq(self, target_freq, lo_offset=None):
-        if lo_offset is not None:
-            self._lo_offset = lo_offset
-            self._u.set_lo_offset(self._lo_offset)
-            if self._verbose:
-                print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),)
-
-        if target_freq is None:
-            f = self._u.freq_range()
-            target_freq = float(f[0]+f[1])/2.0
-            if self._verbose:
-                print "Using auto-calculated mid-point frequency"
-
-        tr = self._u.set_center_freq(target_freq)
-        fs = "%sHz" % (n2s(target_freq),)
-        if tr is not None:
-            self._freq = target_freq
-            self._ddc_freq = tr.dxc_freq
-            self._bb_freq = tr.baseband_freq
-            if self._verbose:
-                print "Set center frequency to", fs
-                print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),)
-                print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),)
-                print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),)
-                
-        return tr
-
-    def set_waveform_freq(self, freq):
-        self._waveform_freq = freq
-        if self._type == gr.GR_SIN_WAVE:
-            self._src.set_frequency(freq)
-        elif self._type == "2tone" or self._type == "sweep":
-            self._src1.set_frequency(freq)
-        return True
-
-    def set_waveform2_freq(self, freq):
-        self._waveform2_freq = freq
-        if self._type == "2tone":
-            self._src2.set_frequency(freq)
-        elif self._type == "sweep":
-            self._src1.set_frequency(freq)
-        return True
-
-    def set_waveform(self, type):
-        self.lock()
-        self.disconnect_all()
-
-        if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
-            self._src = gr.sig_source_c(self._eth_rate,      # Sample rate
-                                        type,                # Waveform type
-                                        self._waveform_freq, # Waveform frequency
-                                        self._amplitude,     # Waveform amplitude
-                                        self._offset)        # Waveform offset
-        elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
-            self._src = gr.noise_source_c(type, self._amplitude)
-        elif type == "2tone":
-            self._src1 = gr.sig_source_c(self._eth_rate,
-                                         gr.GR_SIN_WAVE,
-                                         self._waveform_freq,
-                                         self._amplitude/2.0,
-                                         0)
-            if(self._waveform2_freq is None):
-                self._waveform2_freq = -self._waveform_freq
-
-            self._src2 = gr.sig_source_c(self._eth_rate,
-                                         gr.GR_SIN_WAVE,
-                                         self._waveform2_freq,
-                                         self._amplitude/2.0,
-                                         0)
-            self._src = gr.add_cc()
-            self.connect(self._src1,(self._src,0))
-            self.connect(self._src2,(self._src,1))
-        elif type == "sweep":
-            # rf freq is center frequency
-            # waveform_freq is total swept width
-            # waveform2_freq is sweep rate
-            # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2)
-            if self._waveform2_freq is None:
-                self._waveform2_freq = 0.1
-
-            self._src1 = gr.sig_source_f(self._eth_rate,
-                                         gr.GR_TRI_WAVE,
-                                         self._waveform2_freq,
-                                         1.0,
-                                         -0.5)
-            self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate)
-            self._src = gr.multiply_const_cc(self._amplitude)
-            self.connect(self._src1,self._src2,self._src)
-        else:
-            raise RuntimeError("Unknown waveform type")
-
-        self.connect(self._src, self._u)
-        self._type = type
-        self.unlock()
-
-        if self._verbose:
-            print "Set baseband modulation to:", waveforms[self._type]
-            if type == gr.GR_SIN_WAVE:
-                print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),)
-                print "Initial phase:", self._offset
-            elif type == "2tone":
-                print "Tone 1: %sHz" % (n2s(self._waveform_freq),)
-                print "Tone 2: %sHz" % (n2s(self._waveform2_freq),)
-            elif type == "sweep":
-                print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0))
-                print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),)
-            print "TX amplitude:", self._amplitude
-
-
-    def set_amplitude(self, amplitude):
-        if amplitude < 0.0 or amplitude > 1.0:
-            if self._verbose: print "Amplitude out of range:", amplitude
-            return False
-
-        self._amplitude = amplitude
-
-        if (self._type == gr.GR_SIN_WAVE or 
-            self._type == gr.GR_CONST_WAVE or
-            self._type == gr.GR_GAUSSIAN or
-            self._type == gr.GR_UNIFORM):
-            self._src.set_amplitude(amplitude)
-        elif self._type == "2tone":
-            self._src1.set_amplitude(amplitude/2.0)
-            self._src2.set_amplitude(amplitude/2.0)
-        elif self._type == "sweep":
-            self._src.set_k(amplitude)
-        else:
-            return True # Waveform not yet set
-        
-        if self._verbose: print "Set amplitude to:", amplitude
-        return True
-
-
-    # Property getters
-
-    def mac_addr(self):
-        return self._u.mac_addr()
-
-    def interface_name(self):
-        return self._u.interface_name()
-
-    def daughterboard_id(self):
-        return self._u.daughterboard_id()
-
-    def interp_rate(self):
-        return self._interp
-
-    def eth_rate(self):
-        return self._eth_rate
-
-    def freq(self):
-        return self._freq
-
-    def freq_range(self):
-        return self._u.freq_range()
-
-    def ddc_freq(self):
-        return self._ddc_freq
-
-    def baseband_freq(self):
-        return self._bb_freq
-
-    def amplitude(self):
-        return self._amplitude
-
-    def waveform_type(self):
-        return self._type
-
-    def waveform_freq(self):
-        return self._waveform_freq
-
-    def waveform2_freq(self):
-        if self._waveform2_freq is None:
-            return -self._waveform_freq
-        else:
-            return self._waveform2_freq
-
-def get_options():
-    usage="%prog: [options]"
-
-    parser = OptionParser(option_class=eng_option, usage=usage)
-
-    parser.add_option("-e", "--interface", type="string", default="eth0",
-                      help="Use specified Ethernet interface [default=%default]")
-    parser.add_option("-m", "--mac-addr", type="string", default="",
-                      help="Use USRP2 at specified MAC address [default=None]")  
-    parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP",
-                      help="Set FPGA interpolation rate of INTERP [default=%default]")
-    parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
-                      help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ")
-    parser.add_option("--lo-offset", type="eng_float", default=None,
-                      help="set daughterboard LO offset to OFFSET [default=hw default]")
-    parser.add_option("-g", "--gain", type="eng_float", default=None,
-                      help="Set TX gain to GAIN [default=mid-point]")
-    parser.add_option("-w", "--waveform-freq", type="eng_float", default=0,
-                      help="Set baseband waveform frequency to FREQ [default=%default]")
-    parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None,
-                      help="Set 2nd waveform frequency to FREQ [default=%default]")
-    parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE,
-                      help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE)
-    parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, 
-                      help="Generate a constant carrier")
-    parser.add_option("--offset", type="eng_float", default=0,
-                      help="Set waveform phase offset to OFFSET [default=%default]")
-    parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN,
-                      help="Generate Gaussian random output")
-    parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM,
-                      help="Generate Uniform random output")
-    parser.add_option("--2tone", dest="type", action="store_const", const="2tone",
-                      help="Generate Two Tone signal for IMD testing")
-    parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
-                      help="Generate a swept sine wave")
-    parser.add_option("-a", "--amplitude", type="eng_float", default=0.1,
-                      help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL")
-    parser.add_option("-v", "--verbose", action="store_true", default=False,
-                      help="Use verbose console output [default=%default]")
-
-    (options, args) = parser.parse_args()
-
-    return (options, args)
-
-# If this script is executed, the following runs. If it is imported, the below does not run.
-if __name__ == "__main__":
-    if gr.enable_realtime_scheduling() != gr.RT_OK:
-        print "Note: failed to enable realtime scheduling, continuing"
-    
-    # Grab command line options and create top block
-    try:
-        (options, args) = get_options()
-        tb = top_block(options, args)
-
-    except RuntimeError, e:
-        print e
-        sys.exit(1)
-
-    # Run it
-    try:
-        tb.run()
-
-    except KeyboardInterrupt:
-        pass
diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py
deleted file mode 100755 (executable)
index 89bc6e5..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2009 Free Software Foundation, Inc.
-# 
-# This file is part of GNU Radio
-# 
-# GNU Radio is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import wx
-from gnuradio.wxgui import form, slider, gui
-import usrp2_siggen
-import sys, math
-
-class app_gui(object):
-    def __init__(self, frame, panel, vbox, top_block, options, args):
-        self.frame = frame      # Use for top-level application window frame
-        self.panel = panel      # Use as parent class for created windows
-        self.vbox = vbox        # Use as sizer for created windows
-        self.tb = top_block     # GUI-unaware flowgraph class
-        self.options = options  # Supplied command-line options
-        self.args = args        # Supplied command-line arguments
-
-        freq_range = self.tb.freq_range()
-        self.min_freq = freq_range[0]
-        self.max_freq = freq_range[1]
-        self.freq_step = (self.max_freq-self.min_freq)/100.0
-        self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items())
-
-        self.build_gui()
-
-        # TODO: turn these into listeners
-        self.myform['ifc'].set_value(self.tb.interface_name())
-        self.myform['mac'].set_value(self.tb.mac_addr())
-        dbid = self.tb.daughterboard_id()
-        self.myform['dbid'].set_value("%04x" % (dbid,))
-
-        w = usrp2_siggen.waveforms[self.tb.waveform_type()]
-        self.myform['type'].set_value(w)
-        self.myform['w1freq'].set_value(self.tb.waveform_freq())
-        self.myform['w2freq'].set_value(self.tb.waveform2_freq())
-
-        freq = self.tb.freq()
-        if freq is None:
-            self.evt_set_status_msg("Failed to set initial frequency")
-        else:
-            self.myform['freq'].set_value(freq)
-            self.myform['freq_slider'].set_value(self.tb.freq())
-
-        amp = self.tb.amplitude()
-        if (amp > 0.0):
-            db = 20*math.log10(amp)
-        else:
-            db = -100.0
-        self.myform['amp'].set_value(amp)
-        self.myform['amp_slider'].set_value(db)
-        self.myform['eth'].set_value(self.tb.eth_rate())
-        self.myform['gbe'].set_value(self.tb.eth_rate()*32)
-        self.myform['interp'].set_value(self.tb.interp_rate())
-        self.myform['DDC'].set_value(self.tb.ddc_freq())
-        self.myform['analog'].set_value(self.tb.baseband_freq())
-
-    # Event response handlers
-    def evt_set_status_msg(self, msg):
-        self.frame.SetStatusText(msg, 0)
-
-    def evt_set_freq1(self, kv):
-        return self.tb.set_waveform_freq(kv['w1freq'])
-
-    def evt_set_freq2(self, kv):
-        return self.tb.set_waveform2_freq(kv['w2freq'])
-
-    def evt_set_freq(self, kv):
-        if type(kv) == type(0.0):              # Set from slider
-            tr = self.tb.set_freq(kv)
-            if tr is not None:
-                self.myform['freq'].set_value(kv)
-        else:                                  # Set from edit box
-            f = kv['freq']
-            tr = self.tb.set_freq(f)
-            if tr is not None:
-                self.myform['freq_slider'].set_value(f)
-
-        if tr is not None:
-            self.myform['DDC'].set_value(tr.dxc_freq)
-            self.myform['analog'].set_value(tr.baseband_freq)
-
-        return (tr is not None)
-
-    def evt_set_amplitude(self, kv):
-        if type(kv) == type(0.0):              # Set from slider
-            amp = math.pow(10, kv/20.0)
-            self.myform['amp'].set_value(amp)
-            return self.tb.set_amplitude(amp)
-        else:                                  # Set from edit box
-            amp = kv['amp']
-            if amp < 0.0 or amp > 1.0:
-                return False
-            if amp == 0.0:
-                db = -100.0
-            else:
-                db = 20*math.log10(amp)
-            self.myform['amp_slider'].set_value(db)
-            return self.tb.set_amplitude(amp)
-
-    def evt_set_interp(self):
-        interp = self.myform['interp'].get_value()
-        if self.tb.set_interp(interp):
-            eth_rate = self.tb.eth_rate()
-            self.myform['eth'].set_value(eth_rate)
-            self.myform['gbe'].set_value(eth_rate*32)
-            return True
-        return False
-
-    def evt_set_waveform_type(self, type):
-        # TODO: update frequency labels
-        return self.tb.set_waveform(self._types[type])
-
-    # GUI construction
-    def build_gui(self):
-        self.myform = myform = form.form()
-
-        # Baseband controls
-        bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation")
-        bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit
-
-        # First row of baseband controls (modulation type)
-        mod_hbox = wx.BoxSizer(wx.HORIZONTAL)
-        mod_hbox.Add((10,0), 0, 0)
-        myform['type'] = form.radiobox_field(
-            parent=self.panel, label="Type", sizer=mod_hbox, value=None,
-            callback=self.evt_set_waveform_type, weight=1, major_dimension=0,
-            choices=usrp2_siggen.waveforms.values() )
-        bb_vbox.Add((0,10), 0, 0)
-        bb_vbox.Add(mod_hbox, 0, wx.EXPAND)
-
-        # Second row of baseband controls (frequencies)
-        bbf_hbox = wx.BoxSizer(wx.HORIZONTAL)
-        bbf_hbox.Add((10,0), 0, 0)
-        myform['w1freq'] = form.float_field(
-            parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1,
-            callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) )
-        bbf_hbox.Add((10,0), 0, 0)
-        myform['w2freq'] = form.float_field(
-            parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1,
-            callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) )
-        bbf_hbox.Add((10,0), 0, 0)
-        
-        bb_vbox.Add((0,10), 0, 0)
-        bb_vbox.Add(bbf_hbox, 0, wx.EXPAND)
-
-        # Add baseband controls to top window sizer
-        self.vbox.Add((0,10), 0, 0)
-        self.vbox.Add(bb_vbox, 0, wx.EXPAND)
-
-        # Frequency controls
-        fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency")
-        fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit
-
-        # First row of frequency controls (center frequency)
-        freq_hbox = wx.BoxSizer(wx.HORIZONTAL)
-        freq_hbox.Add((10,0), 0, 0)
-        myform['freq'] = form.float_field(
-            parent=self.panel, sizer=freq_hbox, label=None, weight=1,
-            callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) )
-        freq_hbox.Add((10,0), 0, 0)
-        myform['freq_slider'] = form.quantized_slider_field(
-            parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4,
-            range = (self.min_freq, self.max_freq, self.freq_step),
-            callback=self.evt_set_freq)
-        freq_hbox.Add((10,0), 0, 0)
-
-        fc_vbox.Add((10,0), 0, 0)
-        fc_vbox.Add(freq_hbox, 0, wx.EXPAND)
-
-        # Second row of frequency controls (results)
-        tr_hbox = wx.BoxSizer(wx.HORIZONTAL)
-        tr_hbox.Add((10,0), 0, 0)
-        myform['analog'] = form.static_float_field(
-            parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1)
-        tr_hbox.Add((10,0), 0, 0)
-        myform['DDC'] = form.static_float_field(
-            parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1)
-        tr_hbox.Add((10,0), 0, 0)
-        fc_vbox.Add(tr_hbox, 0, wx.EXPAND)
-
-        # Add frequency controls to top window sizer
-        self.vbox.Add((0,10), 0, 0)
-        self.vbox.Add(fc_vbox, 0, wx.EXPAND)
-
-        # Amplitude row
-        amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude")
-        amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL)
-        amp_hbox.Add((10,0), 0, 0)
-        myform['amp'] = form.float_field(
-            parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1,
-            callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) )
-        amp_hbox.Add((10,0), 0, 0)
-        myform['amp_slider'] = form.quantized_slider_field(
-            parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4,
-            range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude)
-        amp_hbox.Add((10,0), 0, 0)
-        self.vbox.Add((0,10), 0, 0)
-        self.vbox.Add(amp_hbox, 0, wx.EXPAND)
-
-        # Sample rate row
-        sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate")
-        sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL)
-        sam_hbox.Add((10,0), 0, 0)
-        myform['interp'] = form.int_field(
-            parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1,
-            callback=self.evt_set_interp)
-        sam_hbox.Add((10,0), 0, 0)
-        myform['eth'] = form.static_float_field(
-            parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1)
-        sam_hbox.Add((10,0), 0, 0)
-        myform['gbe'] = form.static_float_field(
-            parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1)
-        sam_hbox.Add((10,0), 0, 0)
-        self.vbox.Add((0,10), 0, 0)
-        self.vbox.Add(sam_hbox, 0, wx.EXPAND)
-
-        # USRP2 row
-        u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware")
-        u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL)
-        u2_hbox.Add((10,0), 0, 0)
-        myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, 
-                                               label="Interface", weight=2)
-        u2_hbox.Add((10,0), 0, 0)
-        myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, 
-                                               label="MAC Address", weight=2)
-        u2_hbox.Add((10,0), 0, 0)
-        myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, 
-                                                label="Daughterboard ID", weight=1)
-        self.vbox.Add((0,10), 0, 0)
-        self.vbox.Add(u2_hbox, 0, wx.EXPAND)
-        self.vbox.Add((0,20), 0, 0)
-
-if __name__ == "__main__":
-    try:
-        # Get command line parameters
-        (options, args) = usrp2_siggen.get_options()
-
-        # Create the top block using these
-        tb = usrp2_siggen.top_block(options, args)
-
-        # Create the GUI application
-        app = gui.app(top_block=tb,                    # Constructed top block
-                      gui=app_gui,                     # User interface class
-                      options=options,                 # Command line options
-                      args=args,                       # Command line args
-                      title="USRP2 Signal Generator",  # Top window title
-                      nstatus=1,                       # Number of status lines
-                      start=True,                      # Whether to start flowgraph
-                      realtime=True)                   # Whether to set realtime priority
-
-        # And run it
-        app.MainLoop()
-
-    except RuntimeError, e:
-        print e
-        sys.exit(1)
index 8ae2fbfbfd93ade4518cff28311ab3ba946108d6..8ee8cfd2ad4696d9fd1ba586dc8d62e8c96da9c3 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc.
+# Copyright 2008,2009 Free Software Foundation, Inc.
 # 
 # This file is part of GNU Radio
 # 
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, gru
-from gnuradio import usrp
+DESC_KEY = 'desc'
+SAMP_RATE_KEY = 'samp_rate'
+LINK_RATE_KEY = 'link_rate'
+DAC_RATE_KEY = 'dac_rate'
+INTERP_KEY = 'interp'
+GAIN_KEY = 'gain'
+TX_FREQ_KEY = 'tx_freq'
+DDC_FREQ_KEY = 'ddc_freq'
+BB_FREQ_KEY = 'bb_freq'
+AMPLITUDE_KEY = 'amplitude'
+AMPL_RANGE_KEY = 'ampl_range'
+WAVEFORM_FREQ_KEY = 'waveform_freq'
+WAVEFORM_OFFSET_KEY = 'waveform_offset'
+WAVEFORM2_FREQ_KEY = 'waveform2_freq'
+FREQ_RANGE_KEY = 'freq_range'
+GAIN_RANGE_KEY = 'gain_range'
+TYPE_KEY = 'type'
+
+def setter(ps, key, val): ps[key] = val
+
+from gnuradio import gr, eng_notation
+from gnuradio.gr.pubsub import pubsub
 from gnuradio.eng_option import eng_option
-from gnuradio import eng_notation
+from gnuradio import usrp_options
 from optparse import OptionParser
 import sys
+import math
 
+n2s = eng_notation.num_to_str
 
-class my_top_block(gr.top_block):
-    def __init__ (self, nsamples):
+waveforms = { gr.GR_SIN_WAVE   : "Complex Sinusoid",
+              gr.GR_CONST_WAVE : "Constant",
+              gr.GR_GAUSSIAN   : "Gaussian Noise",
+              gr.GR_UNIFORM    : "Uniform Noise",
+              "2tone"          : "Two Tone",
+              "sweep"          : "Sweep" }
+
+#
+# GUI-unaware GNU Radio flowgraph.  This may be used either with command
+# line applications or GUI applications.
+#
+class top_block(gr.top_block, pubsub):
+    def __init__(self, options, args):
         gr.top_block.__init__(self)
+        pubsub.__init__(self)
+        self._verbose = options.verbose
+        #initialize values from options
+        self._setup_usrpx(options)
+        self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i))
+        self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32))
+        self[INTERP_KEY] = options.interp or 16
+        self[TX_FREQ_KEY] = options.tx_freq
+        self[AMPLITUDE_KEY] = options.amplitude
+        self[WAVEFORM_FREQ_KEY] = options.waveform_freq
+        self[WAVEFORM_OFFSET_KEY] = options.offset
+        self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq
+        self[BB_FREQ_KEY] = 0
+        self[DDC_FREQ_KEY] = 0
+        #subscribe set methods
+        self.subscribe(INTERP_KEY, self.set_interp)
+        self.subscribe(GAIN_KEY, self.set_gain)
+        self.subscribe(TX_FREQ_KEY, self.set_freq)
+        self.subscribe(AMPLITUDE_KEY, self.set_amplitude)
+        self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq)
+        self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq)
+        self.subscribe(TYPE_KEY, self.set_waveform)
+        #force update on pubsub keys
+        for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY,
+            AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY):
+            self[key] = self[key]
+        self[TYPE_KEY] = options.type #set type last
+
+    def _setup_usrpx(self, options):
+        self._u = usrp_options.create_usrp_sink(options)
+        self.publish(DESC_KEY, lambda: str(self._u))
+        self.publish(DAC_RATE_KEY, self._u.dac_rate)
+        self.publish(FREQ_RANGE_KEY, self._u.freq_range)
+        self.publish(GAIN_RANGE_KEY, self._u.gain_range)
+        self.publish(GAIN_KEY, self._u.gain)
+        if self._verbose: print str(self._u)
+
+    def _set_tx_amplitude(self, ampl):
+        """
+        Sets the transmit amplitude sent to the USRP
+        @param ampl the amplitude or None for automatic
+        """
+        ampl_range = self[AMPL_RANGE_KEY]
+        if ampl is None: ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0]
+        self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1]))
+
+    def set_interp(self, interp):
+        if not self._u.set_interp(interp):
+            raise RuntimeError("Failed to set interpolation rate %i" % (interp,))
+
+        if self._verbose:
+            print "USRP interpolation rate:", interp
+            print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),)
+
+        if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE):
+            self._src.set_sampling_freq(self[SAMP_RATE_KEY])
+        elif self[TYPE_KEY] == "2tone":
+            self._src1.set_sampling_freq(self[SAMP_RATE_KEY])
+            self._src2.set_sampling_freq(self[SAMP_RATE_KEY])
+        elif self[TYPE_KEY] == "sweep":
+            self._src1.set_sampling_freq(self[SAMP_RATE_KEY])
+            self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
+        else:
+            return True # Waveform not yet set
         
-        # controllable values
-        self.interp = 64
-        self.waveform_type = gr.GR_SIN_WAVE
-        self.waveform_ampl = 16000
-        self.waveform_freq = 100.12345e3
-        self.waveform_offset = 0
-        self.nsamples = nsamples
-        self._instantiate_blocks ()
-        self.set_waveform_type (self.waveform_type)
-
-    def usb_freq (self):
-        return self.u.dac_freq() / self.interp
-
-    def usb_throughput (self):
-        return self.usb_freq () * 4
-        
-    def set_waveform_type (self, type):
-        '''
-        valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE,
-        gr.GR_UNIFORM and gr.GR_GAUSSIAN
-        '''
-        self._configure_graph (type)
-        self.waveform_type = type
-
-    def set_waveform_ampl (self, ampl):
-        self.waveform_ampl = ampl
-        self.siggen.set_amplitude (ampl)
-        self.noisegen.set_amplitude (ampl)
-
-    def set_waveform_freq (self, freq):
-        self.waveform_freq = freq
-        self.siggen.set_frequency (freq)
-        
-    def set_waveform_offset (self, offset):
-        self.waveform_offset = offset
-        self.siggen.set_offset (offset)
-
-    def set_interpolator (self, interp):
-        self.interp = interp
-        self.siggen.set_sampling_freq (self.usb_freq ())
-        self.u.set_interp_rate (interp)
-
-    def _instantiate_blocks (self):
-        self.src = None
-        self.u = usrp.sink_c (0, self.interp)
-        
-        self.siggen = gr.sig_source_c (self.usb_freq (),
-                                       gr.GR_SIN_WAVE,
-                                       self.waveform_freq,
-                                       self.waveform_ampl,
-                                       self.waveform_offset)
-
-        self.noisegen = gr.noise_source_c (gr.GR_UNIFORM,
-                                           self.waveform_ampl)
-
-        self.head = None
-        if self.nsamples > 0:
-            self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples))
-
-        # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat")
-
-    def _configure_graph (self, type):
-        try:
-            self.lock()
-            self.disconnect_all ()
-
-            if self.head:
-                self.connect(self.head, self.u)
-                tail = self.head
-            else:
-                tail = self.u
-                
-            if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
-                self.connect (self.siggen, tail)
-                # self.connect (self.siggen, self.file_sink)
-                self.siggen.set_waveform (type)
-                self.src = self.siggen
-            elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN:
-                self.connect (self.noisegen, tail)
-                self.noisegen.set_type (type)
-                self.src = self.noisegen
-            else:
-                raise ValueError, type
-        finally:
-            self.unlock()
+        if self._verbose: print "Set interpolation rate to:", interp
+        return True
+
+    def set_gain(self, gain):
+        if gain is None:
+            g = self[GAIN_RANGE_KEY]
+            gain = float(g[0]+g[1])/2
+            if self._verbose:
+                print "Using auto-calculated mid-point TX gain"
+            self[GAIN_KEY] = gain
+            return
+        self._u.set_gain(gain)
+        if self._verbose:
+            print "Set TX gain to:", gain
 
     def set_freq(self, target_freq):
-        """
-        Set the center frequency we're interested in.
 
-        @param target_freq: frequency in Hz
-        @rypte: bool
-
-        Tuning is a two step process.  First we ask the front-end to
-        tune as close to the desired frequency as it can.  Then we use
-        the result of that operation and our target_frequency to
-        determine the value for the digital up converter.
-        """
-        r = self.u.tune(self.subdev.which(), self.subdev, target_freq)
-        if r:
-            #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq)
-            #print "r.dxc_freq      =", eng_notation.num_to_str(r.dxc_freq)
-            #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq)
-            #print "r.inverted      =", r.inverted
-            return True
-
-        return False
-
-
-
-def main ():
-    parser = OptionParser (option_class=eng_option)
-    parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0),
-                       help="select USRP Tx side A or B")
-    parser.add_option ("-f", "--rf-freq", type="eng_float", default=None,
-                       help="set RF center frequency to FREQ")
-    parser.add_option ("-i", "--interp", type="int", default=64,
-                       help="set fgpa interpolation rate to INTERP [default=%default]")
-
-    parser.add_option ("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE,
-                       help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE)
-    parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, 
-                       help="generate a constant output")
-    parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN,
-                       help="generate Gaussian random output")
-    parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM,
-                       help="generate Uniform random output")
-
-    parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0,
-                       help="set waveform frequency to FREQ [default=%default]")
-    parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3,
-                       help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL")
-    parser.add_option ("-g", "--gain", type="eng_float", default=None,
-                       help="set output gain to GAIN [default=%default]")
-    parser.add_option ("-o", "--offset", type="eng_float", default=0,
-                       help="set waveform offset to OFFSET [default=%default]")
-    parser.add_option ("-N", "--nsamples", type="eng_float", default=0,
-                       help="set number of samples to transmit [default=+inf]")
-    (options, args) = parser.parse_args ()
-
-    if len(args) != 0:
-        parser.print_help()
-        raise SystemExit
-
-    if options.rf_freq is None:
-        sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n")
-        parser.print_help()
-        raise SystemExit
-
-    tb = my_top_block(options.nsamples)
-    tb.set_interpolator (options.interp)
-    tb.set_waveform_type (options.type)
-    tb.set_waveform_freq (options.waveform_freq)
-    tb.set_waveform_ampl (options.amplitude)
-    tb.set_waveform_offset (options.offset)
-
-    # determine the daughterboard subdevice we're using
-    if options.tx_subdev_spec is None:
-        options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u)
-
-    m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec)
-    #print "mux = %#04x" % (m,)
-    tb.u.set_mux(m)
-    tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec)
-    print "Using TX d'board %s" % (tb.subdev.side_and_name(),)
-    
-    if options.gain is None:
-        tb.subdev.set_gain(tb.subdev.gain_range()[1])    # set max Tx gain
-    else:
-        tb.subdev.set_gain(options.gain)    # set max Tx gain
-
-    if not tb.set_freq(options.rf_freq):
-        sys.stderr.write('Failed to set RF frequency\n')
-        raise SystemExit
+        if target_freq is None:
+            f = self[FREQ_RANGE_KEY]
+            target_freq = float(f[0]+f[1])/2.0
+            if self._verbose:
+                print "Using auto-calculated mid-point frequency"
+            self[TX_FREQ_KEY] = target_freq
+            return
+
+        tr = self._u.set_center_freq(target_freq)
+        fs = "%sHz" % (n2s(target_freq),)
+        if tr is not None:
+            self._freq = target_freq
+            self[DDC_FREQ_KEY] = tr.dxc_freq
+            self[BB_FREQ_KEY] = tr.baseband_freq
+            if self._verbose:
+                print "Set center frequency to", fs
+                print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),)
+                print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),)
+                print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),)
+        elif self._verbose: print "Failed to set freq." 
+        return tr
+
+    def set_waveform_freq(self, freq):
+        if self[TYPE_KEY] == gr.GR_SIN_WAVE:
+            self._src.set_frequency(freq)
+        elif self[TYPE_KEY] == "2tone":
+            self._src1.set_frequency(freq)
+        elif self[TYPE_KEY] == 'sweep':
+            #there is no set sensitivity, redo fg
+            self[TYPE_KEY] = self[TYPE_KEY]
+        return True
+
+    def set_waveform2_freq(self, freq):
+        if freq is None:
+            self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY]
+            return
+        if self[TYPE_KEY] == "2tone":
+            self._src2.set_frequency(freq)
+        elif self[TYPE_KEY] == "sweep":
+            self._src1.set_frequency(freq)
+        return True
+
+    def set_waveform(self, type):
+        self.lock()
+        self.disconnect_all()
+        if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
+            self._src = gr.sig_source_c(self[SAMP_RATE_KEY],      # Sample rate
+                                        type,                # Waveform type
+                                        self[WAVEFORM_FREQ_KEY], # Waveform frequency
+                                        self[AMPLITUDE_KEY],     # Waveform amplitude
+                                        self[WAVEFORM_OFFSET_KEY])        # Waveform offset
+        elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
+            self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY])
+        elif type == "2tone":
+            self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY],
+                                         gr.GR_SIN_WAVE,
+                                         self[WAVEFORM_FREQ_KEY],
+                                         self[AMPLITUDE_KEY]/2.0,
+                                         0)
+            if(self[WAVEFORM2_FREQ_KEY] is None):
+                self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY]
+
+            self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY],
+                                         gr.GR_SIN_WAVE,
+                                         self[WAVEFORM2_FREQ_KEY],
+                                         self[AMPLITUDE_KEY]/2.0,
+                                         0)
+            self._src = gr.add_cc()
+            self.connect(self._src1,(self._src,0))
+            self.connect(self._src2,(self._src,1))
+        elif type == "sweep":
+            # rf freq is center frequency
+            # waveform_freq is total swept width
+            # waveform2_freq is sweep rate
+            # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2)
+            if self[WAVEFORM2_FREQ_KEY] is None:
+                self[WAVEFORM2_FREQ_KEY] = 0.1
+
+            self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY],
+                                         gr.GR_TRI_WAVE,
+                                         self[WAVEFORM2_FREQ_KEY],
+                                         1.0,
+                                         -0.5)
+            self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY])
+            self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY])
+            self.connect(self._src1,self._src2,self._src)
+        else:
+            raise RuntimeError("Unknown waveform type")
+
+        self.connect(self._src, self._u)
+        self.unlock()
+
+        if self._verbose:
+            print "Set baseband modulation to:", waveforms[type]
+            if type == gr.GR_SIN_WAVE:
+                print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)
+                print "Initial phase:", self[WAVEFORM_OFFSET_KEY]
+            elif type == "2tone":
+                print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)
+                print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
+            elif type == "sweep":
+                print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0))
+                print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)
+            print "TX amplitude:", self[AMPLITUDE_KEY]
+
+
+    def set_amplitude(self, amplitude):
+        if amplitude < 0.0 or amplitude > 1.0:
+            if self._verbose: print "Amplitude out of range:", amplitude
+            return False
+
+        if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM):
+            self._src.set_amplitude(amplitude)
+        elif self[TYPE_KEY] == "2tone":
+            self._src1.set_amplitude(amplitude/2.0)
+            self._src2.set_amplitude(amplitude/2.0)
+        elif self[TYPE_KEY] == "sweep":
+            self._src.set_k(amplitude)
+        else:
+            return True # Waveform not yet set
+        
+        if self._verbose: print "Set amplitude to:", amplitude
+        return True
+
+def get_options():
+    usage="%prog: [options]"
+
+    parser = OptionParser(option_class=eng_option, usage=usage)
+    usrp_options.add_tx_options(parser)
+    parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
+                      help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ")
+    parser.add_option("-x", "--waveform-freq", type="eng_float", default=0,
+                      help="Set baseband waveform frequency to FREQ [default=%default]")
+    parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None,
+                      help="Set 2nd waveform frequency to FREQ [default=%default]")
+    parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE,
+                      help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE)
+    parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, 
+                      help="Generate a constant carrier")
+    parser.add_option("--offset", type="eng_float", default=0,
+                      help="Set waveform phase offset to OFFSET [default=%default]")
+    parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN,
+                      help="Generate Gaussian random output")
+    parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM,
+                      help="Generate Uniform random output")
+    parser.add_option("--2tone", dest="type", action="store_const", const="2tone",
+                      help="Generate Two Tone signal for IMD testing")
+    parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
+                      help="Generate a swept sine wave")
+    parser.add_option("-A", "--amplitude", type="eng_float", default=0.15,
+                      help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL")
+    parser.add_option("-v", "--verbose", action="store_true", default=False,
+                      help="Use verbose console output [default=%default]")
+
+    (options, args) = parser.parse_args()
+
+    return (options, args)
+
+# If this script is executed, the following runs. If it is imported, the below does not run.
+if __name__ == "__main__":
+    if gr.enable_realtime_scheduling() != gr.RT_OK:
+        print "Note: failed to enable realtime scheduling, continuing"
     
-    tb.subdev.set_enable(True)                       # enable transmitter
+    # Grab command line options and create top block
+    try:
+        (options, args) = get_options()
+        tb = top_block(options, args)
 
+    except RuntimeError, e:
+        print e
+        sys.exit(1)
+
+    # Run it
     try:
         tb.run()
+
     except KeyboardInterrupt:
         pass
-
-
-if __name__ == '__main__':
-    main ()
diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py
new file mode 100755 (executable)
index 0000000..40848fb
--- /dev/null
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Free Software Foundation, Inc.
+# 
+# This file is part of GNU Radio
+# 
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import wx
+from gnuradio import gr
+from gnuradio.gr.pubsub import pubsub
+from gnuradio.wxgui import gui, forms
+import usrp_siggen
+import sys, math
+
+class app_gui(pubsub):
+    def __init__(self, frame, panel, vbox, top_block, options, args):
+        pubsub.__init__(self)
+        self.frame = frame      # Use for top-level application window frame
+        self.panel = panel      # Use as parent class for created windows
+        self.vbox = vbox        # Use as sizer for created windows
+        self.tb = top_block     # GUI-unaware flowgraph class
+        self.options = options  # Supplied command-line options
+        self.args = args        # Supplied command-line arguments
+        self.build_gui()
+
+    # Event response handlers
+    def evt_set_status_msg(self, msg):
+        self.frame.SetStatusText(msg, 0)
+
+    # GUI construction
+    def build_gui(self):
+        self.vbox.AddSpacer(5)
+        self.vbox.AddStretchSpacer()
+        ##################################################
+        # Baseband controls
+        ##################################################
+        bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True)
+        self.vbox.Add(bb_vbox, 0, wx.EXPAND)
+        sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        self.vbox.AddSpacer(10)
+        self.vbox.AddStretchSpacer()
+        #callback to show/hide forms
+        def set_type(type):
+            sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE)
+            sweep_bb_hbox.ShowItems(type == 'sweep')
+            tone_bb_hbox.ShowItems(type == '2tone')
+            self.vbox.Layout()
+        self.tb.subscribe(usrp_siggen.TYPE_KEY, set_type)
+        #create sine forms
+        sine_bb_hbox.AddSpacer(10)
+        forms.text_box(
+            parent=self.panel, sizer=sine_bb_hbox,
+            label='Frequency (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.WAVEFORM_FREQ_KEY,
+            converter=forms.float_converter(),
+        )
+        sine_bb_hbox.AddStretchSpacer()
+        #create sweep forms
+        sweep_bb_hbox.AddSpacer(10)
+        forms.text_box(
+            parent=self.panel, sizer=sweep_bb_hbox,
+            label='Sweep Width (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.WAVEFORM_FREQ_KEY,
+            converter=forms.float_converter(),
+        )
+        sweep_bb_hbox.AddStretchSpacer()
+        forms.text_box(
+            parent=self.panel, sizer=sweep_bb_hbox,
+            label='Sweep Rate (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.WAVEFORM2_FREQ_KEY,
+            converter=forms.float_converter(),
+        )
+        sweep_bb_hbox.AddStretchSpacer()
+        #create 2tone forms
+        tone_bb_hbox.AddSpacer(10)
+        forms.text_box(
+            parent=self.panel, sizer=tone_bb_hbox,
+            label='Tone 1 (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.WAVEFORM_FREQ_KEY,
+            converter=forms.float_converter(),
+        )
+        tone_bb_hbox.AddStretchSpacer()
+        forms.text_box(
+            parent=self.panel, sizer=tone_bb_hbox,
+            label='Tone 2 (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.WAVEFORM2_FREQ_KEY,
+            converter=forms.float_converter(),
+        )
+        tone_bb_hbox.AddStretchSpacer()
+        forms.radio_buttons(
+            parent=self.panel, sizer=bb_vbox,
+            choices=usrp_siggen.waveforms.keys(),
+            labels=usrp_siggen.waveforms.values(),
+            ps=self.tb,
+            key=usrp_siggen.TYPE_KEY,
+            style=wx.NO_BORDER | wx.RA_HORIZONTAL,
+        )
+        bb_vbox.AddSpacer(10)
+        bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND)
+        bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND)
+        bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND)
+        set_type(self.tb[usrp_siggen.TYPE_KEY])
+        ##################################################
+        # Frequency controls
+        ##################################################
+        fc_vbox = forms.static_box_sizer(parent=self.panel, label="Center Frequency", orient=wx.VERTICAL, bold=True)
+        fc_vbox.AddSpacer(5)
+        # First row of frequency controls (center frequency)
+        freq_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        fc_vbox.Add(freq_hbox, 0, wx.EXPAND)
+        fc_vbox.AddSpacer(10)
+        # Second row of frequency controls (results)
+        tr_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        fc_vbox.Add(tr_hbox, 0, wx.EXPAND)
+        fc_vbox.AddSpacer(5)
+        # Add frequency controls to top window sizer
+        self.vbox.Add(fc_vbox, 0, wx.EXPAND)
+        self.vbox.AddSpacer(10)
+        self.vbox.AddStretchSpacer()
+        freq_hbox.AddSpacer(5)
+        forms.text_box(
+            parent=self.panel, sizer=freq_hbox,
+            proportion=1,
+            converter=forms.float_converter(),
+            ps=self.tb,
+            key=usrp_siggen.TX_FREQ_KEY,
+        )
+        freq_hbox.AddSpacer(10)
+        forms.slider(
+            parent=self.panel, sizer=freq_hbox,
+            proportion=2,
+            ps=self.tb,
+            key=usrp_siggen.TX_FREQ_KEY,
+            minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0],
+            maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1],
+            num_steps=100,
+        )
+        freq_hbox.AddSpacer(5)
+        tr_hbox.AddSpacer(5)
+        forms.static_text(
+            parent=self.panel, sizer=tr_hbox,
+            label='Daughterboard (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.BB_FREQ_KEY,
+            converter=forms.float_converter(),
+            proportion=1,
+        )
+        tr_hbox.AddSpacer(10)
+        forms.static_text(
+            parent=self.panel, sizer=tr_hbox,
+            label='USRP DDC (Hz)',
+            ps=self.tb,
+            key=usrp_siggen.DDC_FREQ_KEY,
+            converter=forms.float_converter(),
+            proportion=1,
+        )
+        tr_hbox.AddSpacer(5)
+        ##################################################
+        # Amplitude controls
+        ##################################################
+        amp_hbox = forms.static_box_sizer(parent=self.panel, label="Amplitude", orient=wx.VERTICAL, bold=True)
+        amp_hbox.AddSpacer(5)
+        # First row of amp controls (ampl)
+        lvl_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        amp_hbox.Add(lvl_hbox, 0, wx.EXPAND)
+        amp_hbox.AddSpacer(10)
+        # Second row of amp controls (tx gain)
+        gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
+        amp_hbox.Add(gain_hbox, 0, wx.EXPAND)
+        amp_hbox.AddSpacer(5)
+        self.vbox.Add(amp_hbox, 0, wx.EXPAND)
+        self.vbox.AddSpacer(10)
+        self.vbox.AddStretchSpacer()
+        lvl_hbox.AddSpacer(5)
+        forms.text_box(
+            parent=self.panel, sizer=lvl_hbox,
+            proportion=1,
+            converter=forms.float_converter(),
+            ps=self.tb,
+            key=usrp_siggen.AMPLITUDE_KEY,
+            label="Level (0.0-1.0)",
+        )
+        lvl_hbox.AddSpacer(10)
+        forms.log_slider(
+            parent=self.panel, sizer=lvl_hbox,
+            proportion=2,
+            ps=self.tb,
+            key=usrp_siggen.AMPLITUDE_KEY,
+            min_exp=-6,
+            max_exp=0,
+            base=10,
+            num_steps=100,
+        )
+        lvl_hbox.AddSpacer(5)
+        if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]:
+            gain_hbox.AddSpacer(5)
+            forms.text_box(
+                parent=self.panel, sizer=gain_hbox,
+                proportion=1,
+                converter=forms.float_converter(),
+                ps=self.tb,
+                key=usrp_siggen.GAIN_KEY,
+                label="TX Gain (dB)",
+            )
+            gain_hbox.AddSpacer(10)
+            forms.slider(
+                parent=self.panel, sizer=gain_hbox,
+                proportion=2,
+                ps=self.tb,
+                key=usrp_siggen.GAIN_KEY,
+                minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0],
+                maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1],
+                step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2],
+            )
+            gain_hbox.AddSpacer(5)
+        ##################################################
+        # Sample Rate controls
+        ##################################################
+        sam_hbox = forms.static_box_sizer(parent=self.panel, label="Sample Rate", orient=wx.HORIZONTAL, bold=True)
+        self.vbox.Add(sam_hbox, 0, wx.EXPAND)
+        self.vbox.AddSpacer(10)
+        self.vbox.AddStretchSpacer()
+        sam_hbox.AddSpacer(5)
+        forms.text_box(
+            parent=self.panel, sizer=sam_hbox,
+            converter=forms.int_converter(),
+            ps=self.tb,
+            key=usrp_siggen.INTERP_KEY,
+            label="Interpolation",
+        )
+        sam_hbox.AddStretchSpacer(20)
+        forms.static_text(
+            parent=self.panel, sizer=sam_hbox,
+            label='Sample Rate (sps)',
+            ps=self.tb,
+            key=usrp_siggen.SAMP_RATE_KEY,
+            converter=forms.float_converter(),
+        )
+        sam_hbox.AddStretchSpacer(20)
+        forms.static_text(
+            parent=self.panel, sizer=sam_hbox,
+            label='Link Rate (bits/sec)',
+            ps=self.tb,
+            key=usrp_siggen.LINK_RATE_KEY,
+            converter=forms.float_converter(),
+        )
+        sam_hbox.AddSpacer(5)
+        ##################################################
+        # USRP status
+        ##################################################
+        u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", orient=wx.HORIZONTAL, bold=True)
+        self.vbox.Add(u2_hbox, 0, wx.EXPAND)
+        self.vbox.AddSpacer(10)
+        self.vbox.AddStretchSpacer()
+        u2_hbox.AddSpacer(10)
+        forms.static_text(
+            parent=self.panel, sizer=u2_hbox,
+            ps=self.tb,
+            key=usrp_siggen.DESC_KEY,
+            converter=forms.str_converter(),
+        )
+        self.vbox.AddSpacer(5)
+        self.vbox.AddStretchSpacer()
+
+if __name__ == "__main__":
+    try:
+        # Get command line parameters
+        (options, args) = usrp_siggen.get_options()
+
+        # Create the top block using these
+        tb = usrp_siggen.top_block(options, args)
+
+        # Create the GUI application
+        app = gui.app(top_block=tb,                    # Constructed top block
+                      gui=app_gui,                     # User interface class
+                      options=options,                 # Command line options
+                      args=args,                       # Command line args
+                      title="USRP Signal Generator",  # Top window title
+                      nstatus=1,                       # Number of status lines
+                      start=True,                      # Whether to start flowgraph
+                      realtime=True)                   # Whether to set realtime priority
+
+        # And run it
+        app.MainLoop()
+
+    except RuntimeError, e:
+        print e
+        sys.exit(1)
index d555a1f055a9c3b824e2b71cb0c793c0ec562fcb..9c97ce1ecad898a32e1871f9445c42713db7fd9e 100644 (file)
@@ -137,6 +137,25 @@ def get_min_max(samples):
        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
index 0529e6a5d6d77eb2070fbda7468fa2c1cecb1fb8..e025c28dd71872679776064878c26be1970a03e7 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -156,9 +156,9 @@ class control_panel(wx.Panel):
        def _on_decr_ref_level(self, event):
                self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] - self.parent[Y_PER_DIV_KEY]
        def _on_incr_db_div(self, event):
-               self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, self.parent[Y_PER_DIV_KEY]*2)
+               self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, common.get_clean_incr(self.parent[Y_PER_DIV_KEY]))
        def _on_decr_db_div(self, event):
-               self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, self.parent[Y_PER_DIV_KEY]/2)
+               self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, common.get_clean_decr(self.parent[Y_PER_DIV_KEY]))
 
 ##################################################
 # FFT window with plotter and control panel
@@ -254,17 +254,11 @@ class fft_window(wx.Panel, pubsub.pubsub):
                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
 
index 9f757aa8410eb24b7d226e9c828da4caa8a2fd6c..db14d2752c19ba6f3fa891129e86dc71407607bf 100644 (file)
@@ -72,12 +72,14 @@ class bool_converter(abstract_converter):
                self._true = true
                self._false = false
        def external_to_internal(self, v):
-               return bool(v)
+               if v == self._true: return True
+               if v == self._false: return False
+               raise Exception, 'Value "%s" is not a possible option.'%v
        def internal_to_external(self, v):
                if v: return self._true
                else: return self._false
        def help(self):
-               return "Value must be cast-able to type bool."
+               return "Value must be in (%s, %s)."%(self._true, self._false)
 
 class eval_converter(abstract_converter):
        """
@@ -134,8 +136,7 @@ class slider_converter(abstract_converter):
                self._scaler = float(maximum - minimum)/num_steps
                self._cast = cast
        def external_to_internal(self, v):
-               #slider's internal representation is an integer
-               return int(round((v - self._offset)/self._scaler))
+               return (v - self._offset)/self._scaler
        def internal_to_external(self, v):
                return self._cast(v*self._scaler + self._offset)
        def help(self):
index c69315b0358906c531bd1ceaeaeb23defe9237e1..8dc58367d9deac34251467061d307388b816945e 100644 (file)
@@ -176,7 +176,7 @@ class _slider_base(_form_base):
                self._add_widget(self._slider, label, flag=wx.EXPAND)
 
        def _handle(self, event): self[INT_KEY] = self._slider.GetValue()
-       def _update(self, value): self._slider.SetValue(value)
+       def _update(self, value): self._slider.SetValue(int(round(value)))
 
 ########################################################################
 # Static Text Form
@@ -224,11 +224,18 @@ class text_box(_form_base):
        def __init__(self, label='', width=-1, converter=converters.eval_converter(), **kwargs):
                _form_base.__init__(self, converter=converter, **kwargs)
                self._text_box = wx.TextCtrl(self._parent, size=wx.Size(width, -1), style=wx.TE_PROCESS_ENTER)
+               self._default_bg_colour = self._text_box.GetBackgroundColour()
                self._text_box.Bind(wx.EVT_TEXT_ENTER, self._handle)
+               self._text_box.Bind(wx.EVT_TEXT, self._update_color)
                self._add_widget(self._text_box, label)
 
+       def _update_color(self, *args):
+               if self._text_box.GetValue() == self[INT_KEY]:
+                       self._text_box.SetBackgroundColour(self._default_bg_colour)
+               else: self._text_box.SetBackgroundColour('#EEDDDD')
+
        def _handle(self, event): self[INT_KEY] = self._text_box.GetValue()
-       def _update(self, value): self._text_box.SetValue(value)
+       def _update(self, value): self._text_box.SetValue(value); self._update_color()
 
 ########################################################################
 # Slider Form
index 2e0669961badf81da5e6494186746600bc47145a..d32b0ca0a631f07935c78654d70337bbf4e02328 100644 (file)
@@ -209,7 +209,7 @@ class waterfall_plotter(grid_plotter_base):
                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
 
index b4ae0f3391df3a86b51e5b20dbcd7a746a05ba6e..a5e3ca3ce32fc7f9c40fd305d5c7fd4bd2d709e5 100644 (file)
@@ -50,7 +50,7 @@ class ac_couple_block(gr.hier_block2):
                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]
index c00992e14fee13598112a12beeb8411852daaa60..28e67a83006aa6af3123107fe4d3f79db06062d6 100644 (file)
@@ -237,16 +237,10 @@ class waterfall_window(wx.Panel, pubsub.pubsub):
                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):
                """
index 96ee11b67e721d44581a5c1d296ae6f287ca497c..c45d1ce1f33bee6cd49262aa8016f43a25447d0f 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -20,5 +20,5 @@
 #
 
 include $(top_srcdir)/Makefile.common
-grc_src_prefix = $(pythondir)/gnuradio/grc
+grc_src_prefix = $(pkgpythondir)/grc
 grc_blocksdir = $(pkgdatadir)/grc/blocks
index d5e1047852b7df5bfcd71b89135483debc183f18..cb21c3958a2f0e3da1fb32025ec747e32528ad1e 100644 (file)
@@ -47,7 +47,9 @@ class TemplateArg(UserDict):
                return self._param.get_evaluated()
 
 def _get_keys(lst): return [elem.get_key() for elem in lst]
-def _get_elem(lst, key): return lst[_get_keys(lst).index(key)]
+def _get_elem(lst, key):
+       try: return lst[_get_keys(lst).index(key)]
+       except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
 
 class Block(Element):
 
@@ -72,16 +74,16 @@ class Block(Element):
                self._params = list()
                #add the id param
                self.get_params().append(self.get_parent().get_parent().Param(
-                       self,
-                       odict({
+                       block=self,
+                       n=odict({
                                'name': 'ID',
                                'key': 'id',
                                'type': 'id',
                        })
                ))
                self.get_params().append(self.get_parent().get_parent().Param(
-                       self,
-                       odict({
+                       block=self,
+                       n=odict({
                                'name': 'Enabled',
                                'key': '_enabled',
                                'type': 'raw',
@@ -89,7 +91,7 @@ class Block(Element):
                                'hide': 'all',
                        })
                ))
-               for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
+               for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
                        key = param.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_param_keys()
@@ -98,7 +100,7 @@ class Block(Element):
                        self.get_params().append(param)
                #create the source objects
                self._sources = list()
-               for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
+               for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
                        key = source.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_source_keys()
@@ -107,21 +109,13 @@ class Block(Element):
                        self.get_sources().append(source)
                #create the sink objects
                self._sinks = list()
-               for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks):
+               for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
                        key = sink.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_sink_keys()
                        except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key
                        #store the port
                        self.get_sinks().append(sink)
-               #begin the testing
-               self.test()
-
-       def test(self):
-               """
-               Call test on all children.
-               """
-               map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources())
 
        def get_enabled(self):
                """
@@ -138,21 +132,6 @@ class Block(Element):
                """
                self.get_param('_enabled').set_value(str(enabled))
 
-       def validate(self):
-               """
-               Validate the block.
-               All ports and params must be valid.
-               All checks must evaluate to true.
-               """
-               Element.validate(self)
-               for c in self.get_params() + self.get_ports() + self.get_connections():
-                       try:
-                               c.validate()
-                               assert c.is_valid()
-                       except AssertionError:
-                               for msg in c.get_error_messages():
-                                       self.add_error_message('>>> %s:\n\t%s'%(c, msg))
-
        def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
 
        def get_id(self): return self.get_param('id').get_value()
@@ -162,6 +141,7 @@ class Block(Element):
        def get_category(self): return self._category
        def get_doc(self): return ''
        def get_ports(self): return self.get_sources() + self.get_sinks()
+       def get_children(self): return self.get_ports() + self.get_params()
        def get_block_wrapper_path(self): return self._block_wrapper_path
 
        ##############################################
index 16000c46c0a87068491da35f6228c58577c3be37..e77e7ce0891447c4d3ee53d2fe16b1f6755242b0 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -21,37 +21,58 @@ class Element(object):
 
        def __init__(self, parent=None):
                self._parent = parent
-               self.flag()
-
-       def test(self):
-               """
-               Test the element against failures.
-               Overload this method in sub-classes.
-               """
-               pass
 
        ##################################################
        # Element Validation API
        ##################################################
-       def validate(self): self._error_messages = list()
-       def is_valid(self): return not self.get_error_messages() or not self.get_enabled()
-       def add_error_message(self, msg): self._error_messages.append(msg)
-       def get_error_messages(self): return self._error_messages
+       def validate(self):
+               """
+               Validate this element and call validate on all children.
+               Call this base method before adding error messages in the subclass.
+               """
+               self._error_messages = list()
+               for child in self.get_children(): child.validate()
 
-       def get_enabled(self): return True
+       def is_valid(self):
+               """
+               Is this element valid?
+               @return true when the element is enabled and has no error messages
+               """
+               return not self.get_error_messages() or not self.get_enabled()
 
-       def get_parent(self): return self._parent
+       def add_error_message(self, msg):
+               """
+               Add an error message to the list of errors.
+               @param msg the error message string
+               """
+               self._error_messages.append(msg)
+
+       def get_error_messages(self):
+               """
+               Get the list of error messages from this element and all of its children.
+               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
index ea489e948679b6106d9ea4d85b75534ca2627e0a..ce370ca242036486d975c17676c9e0ab0a0cdfa8 100644 (file)
@@ -68,6 +68,7 @@ class FlowGraph(Element):
        def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0]
        def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements())
        def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements())
+       def get_children(self): return self.get_elements()
        def get_elements(self):
                """
                Get a list of all the elements.
@@ -102,7 +103,6 @@ class FlowGraph(Element):
                @param key the block key
                @return the new block or None if not found
                """
-               self.flag()
                if key not in self.get_parent().get_block_keys(): return None
                block = self.get_parent().get_new_block(self, key)
                self.get_elements().append(block)
@@ -116,8 +116,7 @@ class FlowGraph(Element):
                @throw Exception bad connection
                @return the new connection
                """
-               self.flag()
-               connection = self.get_parent().Connection(self, porta, portb)
+               connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
                self.get_elements().append(connection)
                return connection
 
@@ -128,7 +127,6 @@ class FlowGraph(Element):
                If the element is a block, remove its connections.
                If the element is a connection, just remove the connection.
                """
-               self.flag()
                if element not in self.get_elements(): return
                #found a port, set to parent signal block
                if element.is_port():
@@ -147,18 +145,6 @@ class FlowGraph(Element):
                """
                raise NotImplementedError
 
-       def validate(self):
-               """
-               Validate the flow graph.
-               All connections and blocks must be valid.
-               """
-               Element.validate(self)
-               for c in self.get_elements():
-                       try:
-                               c.validate()
-                               assert c.is_valid()
-                       except AssertionError: self.add_error_message('Element "%s" is not valid.'%c)
-
        ##############################################
        ## Import/Export Methods
        ##############################################
@@ -198,7 +184,7 @@ class FlowGraph(Element):
                        #only load the block when the block key was valid
                        if block: block.import_data(block_n)
                        else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
-               self.validate() #validate all blocks before connections are made (in case of nports)
+               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
@@ -225,3 +211,4 @@ class FlowGraph(Element):
                                #build the connection
                                self.connect(source, sink)
                        except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key))
+               self.rewrite() #global rewrite
index 93c1c52bdef38114ccc948c9d08dfe1b5856e9dd..e56eac36e172a4185c2b6f0c2b3d17c10deef984 100644 (file)
@@ -19,74 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 from . import odict
 from Element import Element
-import pygtk
-pygtk.require('2.0')
-import gtk
 
-class InputParam(gtk.HBox):
-       """The base class for an input parameter inside the input parameters dialog."""
-
-       def __init__(self, param, _handle_changed):
-               gtk.HBox.__init__(self)
-               self.param = param
-               self._handle_changed = _handle_changed
-               self.label = gtk.Label('') #no label, markup is added by set_markup
-               self.label.set_size_request(150, -1)
-               self.pack_start(self.label, False)
-               self.set_markup = lambda m: self.label.set_markup(m)
-               self.tp = None
-       def set_color(self, color): pass
-
-class EntryParam(InputParam):
-       """Provide an entry box for strings and numbers."""
-
-       def __init__(self, *args, **kwargs):
-               InputParam.__init__(self, *args, **kwargs)
-               self.entry = input = gtk.Entry()
-               input.set_text(self.param.get_value())
-               input.connect('changed', self._handle_changed)
-               self.pack_start(input, True)
-               self.get_text = input.get_text
-               #tool tip
-               self.tp = gtk.Tooltips()
-               self.tp.set_tip(self.entry, '')
-               self.tp.enable()
-       def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
-
-class EnumParam(InputParam):
-       """Provide an entry box for Enum types with a drop down menu."""
-
-       def __init__(self, *args, **kwargs):
-               InputParam.__init__(self, *args, **kwargs)
-               self._input = gtk.combo_box_new_text()
-               for option in self.param.get_options(): self._input.append_text(option.get_name())
-               self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
-               self._input.connect('changed', self._handle_changed)
-               self.pack_start(self._input, False)
-       def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
-
-class EnumEntryParam(InputParam):
-       """Provide an entry box and drop down menu for Raw Enum types."""
-
-       def __init__(self, *args, **kwargs):
-               InputParam.__init__(self, *args, **kwargs)
-               self._input = gtk.combo_box_entry_new_text()
-               for option in self.param.get_options(): self._input.append_text(option.get_name())
-               try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
-               except:
-                       self._input.set_active(-1)
-                       self._input.get_child().set_text(self.param.get_value())
-               self._input.connect('changed', self._handle_changed)
-               self._input.get_child().connect('changed', self._handle_changed)
-               self.pack_start(self._input, False)
-       def get_text(self):
-               if self._input.get_active() == -1: return self._input.get_child().get_text()
-               return self.param.get_option_keys()[self._input.get_active()]
-       def set_color(self, color):
-               if self._input.get_active() == -1: #custom entry, use color
-                       self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
-               else: #from enum, make white background
-                       self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
+def _get_keys(lst): return [elem.get_key() for elem in lst]
+def _get_elem(lst, key):
+       try: return lst[_get_keys(lst).index(key)]
+       except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
 
 class Option(Element):
 
@@ -123,15 +60,11 @@ class Option(Element):
 
 class Param(Element):
 
-       ##possible param types
-       TYPES = ['enum', 'raw']
-
        def __init__(self, block, n):
                """
                Make a new param from nested data.
                @param block the parent element
                @param n the nested odict
-               @return a new param
                """
                #grab the data
                self._name = n.find('name')
@@ -142,22 +75,22 @@ class Param(Element):
                #build the param
                Element.__init__(self, block)
                #create the Option objects from the n data
-               self._options = odict()
-               for option in map(lambda o: Option(self, o), n.findall('option')):
+               self._options = list()
+               for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
                        key = option.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_option_keys()
                        except AssertionError: raise Exception, 'Key "%s" already exists in options'%key
                        #store the option
-                       self._options[key] = option
+                       self.get_options().append(option)
                #test the enum options
                if self.is_enum():
                        #test against options with identical keys
-                       try: assert len(set(self.get_option_keys())) == len(self._options)
+                       try: assert len(set(self.get_option_keys())) == len(self.get_options())
                        except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
                        #test against inconsistent keys in options
-                       opt_keys = self._options.values()[0].get_opt_keys()
-                       for option in self._options.values():
+                       opt_keys = self.get_options()[0].get_opt_keys()
+                       for option in self.get_options():
                                try: assert set(opt_keys) == set(option.get_opt_keys())
                                except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
                        #if a value is specified, it must be in the options keys
@@ -165,14 +98,6 @@ class Param(Element):
                        try: assert self.get_value() in self.get_option_keys()
                        except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
                else: self._value = value or ''
-               #begin the testing
-               self.test()
-
-       def test(self):
-               """
-               call test on all children
-               """
-               map(lambda c: c.test(), self.get_options())
 
        def validate(self):
                """
@@ -180,7 +105,7 @@ class Param(Element):
                The value must be evaluated and type must a possible type.
                """
                Element.validate(self)
-               try: assert self.get_type() in self.TYPES
+               try: assert self.get_type() in self.get_types()
                except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
 
        def get_evaluated(self): raise NotImplementedError
@@ -192,12 +117,19 @@ class Param(Element):
                """
                raise NotImplementedError
 
+       def get_types(self):
+               """
+               Get a list of all possible param types.
+               @throw NotImplementedError
+               """
+               raise NotImplementedError
+
        def get_color(self): return '#FFFFFF'
        def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
        def is_param(self): return True
        def get_name(self): return self._name
        def get_key(self): return self._key
-       def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)
+       def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
 
        def get_value(self):
                value = self._value
@@ -206,9 +138,7 @@ class Param(Element):
                        self.set_value(value)
                return value
 
-       def set_value(self, value):
-               self.flag()
-               self._value = str(value) #must be a string
+       def set_value(self, value): self._value = str(value) #must be a string
 
        def get_type(self): return self.get_parent().resolve_dependencies(self._type)
        def is_enum(self): return self._type == 'enum'
@@ -223,31 +153,19 @@ class Param(Element):
                if self.is_enum(): return self.get_option(self.get_value()).get_name()
                return self.get_value()
 
-       def get_input_class(self):
-               """
-               Get the graphical gtk class to represent this parameter.
-               An enum requires and combo parameter.
-               A non-enum with options gets a combined entry/combo parameter.
-               All others get a standard entry parameter.
-               @return gtk input class
-               """
-               if self.is_enum(): return EnumParam
-               if self.get_options(): return EnumEntryParam
-               return EntryParam
-
        ##############################################
        # Access Options
        ##############################################
-       def get_option_keys(self): return self._options.keys()
-       def get_option(self, key): return self._options[key]
-       def get_options(self): return self._options.values()
+       def get_option_keys(self): return _get_keys(self.get_options())
+       def get_option(self, key): return _get_elem(self.get_options(), key)
+       def get_options(self): return self._options
 
        ##############################################
        # Access Opts
        ##############################################
-       def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
-       def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
-       def get_opts(self): return self._options[self.get_value()].get_opts()
+       def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
+       def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
+       def get_opts(self): return self.get_option(self.get_value()).get_opts()
 
        ##############################################
        ## Import/Export Methods
index 02d6d2319257e969c1b8b4f151b02556698df6ab..51a3b2f871eb824aea1fee2227201515a06e2dee 100644 (file)
@@ -146,7 +146,7 @@ class Platform(_Element):
 
        def is_platform(self): return True
 
-       def get_new_flow_graph(self): return self.FlowGraph(self)
+       def get_new_flow_graph(self): return self.FlowGraph(platform=self)
 
        def get_generator(self): return self._generator
 
@@ -171,6 +171,5 @@ class Platform(_Element):
        FlowGraph = _FlowGraph
        Connection = _Connection
        Block = _Block
-       Source = _Port
-       Sink = _Port
+       Port = _Port
        Param = _Param
index f4e8e5e1fb2a6f648aef6118b545b5a9e0d3354d..494ea894f7bdcf55551fc403845472b3aef1207d 100644 (file)
@@ -21,25 +21,20 @@ from Element import Element
 
 class Port(Element):
 
-       ##possible port types
-       TYPES = []
-
-       def __init__(self, block, n):
+       def __init__(self, block, n, dir):
                """
                Make a new port from nested data.
                @param block the parent element
                @param n the nested odict
-               @return a new port
+               @param dir the direction source or sink
                """
-               #grab the data
-               name = n['name']
-               key = n['key']
-               type = n['type']
                #build the port
                Element.__init__(self, block)
-               self._name = name
-               self._key = key
-               self._type = type
+               #grab the data
+               self._name = n['name']
+               self._key = n['key']
+               self._type = n['type']
+               self._dir = dir
 
        def validate(self):
                """
@@ -47,7 +42,7 @@ class Port(Element):
                The port must be non-empty and type must a possible type.
                """
                Element.validate(self)
-               try: assert self.get_type() in self.TYPES
+               try: assert self.get_type() in self.get_types()
                except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
 
        def __str__(self):
@@ -56,12 +51,19 @@ class Port(Element):
                if self.is_sink():
                        return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
 
+       def get_types(self):
+               """
+               Get a list of all possible port types.
+               @throw NotImplementedError
+               """
+               raise NotImplementedError
+
        def is_port(self): return True
        def get_color(self): return '#FFFFFF'
        def get_name(self): return self._name
        def get_key(self): return self._key
-       def is_sink(self): return self in self.get_parent().get_sinks()
-       def is_source(self): return self in self.get_parent().get_sources()
+       def is_sink(self): return self._dir == 'sink'
+       def is_source(self): return self._dir == 'source'
        def get_type(self): return self.get_parent().resolve_dependencies(self._type)
 
        def get_connections(self):
index caae6ce7540e7c8465a91c94d4feb23ce8ab8376..32ddc6567f3bbc6fbf4559262edd5e1c579b173b 100644 (file)
@@ -218,6 +218,8 @@ dist_ourdata_DATA = \
        variable_slider.xml \
        variable_static_text.xml \
        variable_text_box.xml \
+       virtual_sink.xml \
+       virtual_source.xml \
        wxgui_constellationsink2.xml \
        wxgui_fftsink2.xml \
        wxgui_histosink2.xml \
index e2e9acf4ebf9148fff3514ea0fdda93ba718bdd4..af083473d3a59f9a5fd3e76e6dc9b473973a5df1 100644 (file)
@@ -10,8 +10,8 @@
        <import>from gnuradio import gr</import>
        <import>from gnuradio.gr import firdes</import>
        <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.$(type.fcn)(
-       $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make>
-       <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback>
+       $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make>
+       <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback>
        <param>
                <name>FIR Type</name>
                <key>type</key>
        </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>
index 3b58f0b51431a1d555c650dcd0e6ddf9a2b6c7de..dd5e7a9d7664a814867dad3ab34b83b7aebabfa5 100644 (file)
@@ -10,8 +10,8 @@
        <import>from gnuradio import gr</import>
        <import>from gnuradio.gr import firdes</import>
        <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.band_reject(
-       $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make>
-       <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback>
+       $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make>
+       <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback>
        <param>
                <name>FIR Type</name>
                <key>type</key>
        </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>
index 5b45466f59289a25759b88bc5322debd24ca87e9..5a989cc018d6ba211360d693bac0711ae6d127d6 100644 (file)
@@ -22,6 +22,7 @@
                <block>gr_wavfile_source</block>
                <block>gr_message_source</block>
                <block>pad_source</block>
+               <block>virtual_source</block>
        </cat>
        <cat>
                <name>Sinks</name>
@@ -35,6 +36,7 @@
                <block>gr_wavfile_sink</block>
                <block>gr_message_sink</block>
                <block>pad_sink</block>
+               <block>virtual_sink</block>
        </cat>
        <cat>
                <name>Graphical Sinks</name>
index 4fcef5148d53e167627f2d76e5f892238d2426e5..4789b4400b8a71d3ca7b20ab74ebab56413e066b 100644 (file)
@@ -40,7 +40,7 @@
                <name>Noise Type</name>
                <key>noise_type</key>
                <value>gr.GR_GAUSSIAN</value>
-               <type>raw</type>
+               <type>int</type>
                <option>
                        <name>Uniform</name>
                        <key>gr.GR_UNIFORM</key>
index c329dba67fb0e34790fcc0fe93f44c4c5717f089..644cf52d0c7d50e4f5ea331e38584b190693c242 100644 (file)
@@ -53,7 +53,7 @@
                <name>Waveform</name>
                <key>waveform</key>
                <value>gr.GR_COS_WAVE</value>
-               <type>raw</type>
+               <type>int</type>
                <option>
                        <name>Constant</name>
                        <key>gr.GR_CONST_WAVE</key>
index 5be916fa97be3cfab26297f21926411d875d47fb..0e29cbb36f3a9ca8113786f5e5e80a5ac72e2061 100644 (file)
@@ -10,8 +10,8 @@
        <import>from gnuradio import gr</import>
        <import>from gnuradio.gr import firdes</import>
        <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.high_pass(
-       $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make>
-       <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback>
+       $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make>
+       <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback>
        <param>
                <name>FIR Type</name>
                <key>type</key>
        </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>
index 27120c0471d9120bea28748f3005c3a8563038f3..26435fd4d8f36dde9d6ae5f6f7b920fa5f766c85 100644 (file)
@@ -10,8 +10,8 @@
        <import>from gnuradio import gr</import>
        <import>from gnuradio.gr import firdes</import>
        <make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.low_pass(
-       $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make>
-       <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback>
+       $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make>
+       <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback>
        <param>
                <name>FIR Type</name>
                <key>type</key>
        </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>
index 18d6e2f0c99fc0818a5177950cc438672e6f55d0..1798a69f88a834c9dccd6ad7e878198b2d147372 100644 (file)
@@ -9,16 +9,17 @@
 <block>
        <name>Options</name>
        <key>options</key>
-       <import>from gnuradio import gr
-#if $generate_options() == 'wx_gui'
+       <import>from gnuradio import gr</import>
+       <import>from gnuradio.gr import firdes</import>
+       <import>#if $generate_options() == 'wx_gui'
 from grc_gnuradio import wxgui as grc_wxgui
 import wx
 #end if
 #if $generate_options() != 'hb'
 from optparse import OptionParser
 from gnuradio.eng_option import eng_option
-#end if
-</import>
+from gnuradio import eng_notation
+#end if</import>
        <make></make>
        <callback>if $run: self.start()
 else: self.stop(); self.wait()</callback>
index 477f2ad13a044a8911bd2e8db37488fdb522059a..734526793fae96b1c1ef890faf61feeab0c3167b 100644 (file)
                <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>
index b6ef2c55d1e2f2e6bbc3770ff066716d4da2b644..f44d9623879d77b1c35026b82eeddf745bdc3b3c 100644 (file)
                <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>
index 5d08c4b394662f8824877f13ea2153cd559e1c86..e35b8f4d1d8bc7c7ac9bd14a06acf6cb6a1eb0ae 100644 (file)
@@ -45,7 +45,7 @@
                </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>
index 639f96cf48bffd08bfcb4aeda0c09f46c0975fca..f2ee4d151f8b9834cc60d7a1691b1458ee8cf7c8 100644 (file)
@@ -2,6 +2,7 @@
 <!--
 ###################################################
 ##USRP2 Sink
+##  Note: the center freq must be set after the lo offset
 ###################################################
  -->
 <block>
@@ -16,14 +17,16 @@ usrp2.sink_$(type.fcn)($interface)
 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>
index 6c776d0ad37deaa54f32b3d7b570eb717a0caf37..02046e609a37b1f4ae2310e5362f0139e88d0db4 100644 (file)
@@ -2,6 +2,7 @@
 <!--
 ###################################################
 ##USRP2 Source
+##  Note: the center freq must be set after the lo offset
 ###################################################
  -->
 <block>
@@ -16,14 +17,16 @@ usrp2.source_$(type.fcn)($interface)
 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>
index 8f418becdba36e2db73eb4eded6e5827a62ceadd..4539b62f9527f1ef552022baa0f02a7c1e8d4a7b 100644 (file)
        <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
 ##################################################
@@ -39,8 +41,16 @@ self.$(id).set_enable_b(True)
 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>
index 740895d424697b8712c86c74a0ebba30cdb65f15..ad9a860ac3afd94ee2ca3424d61f335c47c24751 100644 (file)
 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>
index f3ccf1263c5671dfdb1da27ac3114f7eb1418dbf..b52cd4880913a2357c57227255e75bc1cc75c70e 100644 (file)
        <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>
index 1a777bd6302c7cf017703ce06556150a4e19e461..7fcc7a22cf37eeff7d924a95694c109718ba971b 100644 (file)
 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>
diff --git a/grc/blocks/virtual_sink.xml b/grc/blocks/virtual_sink.xml
new file mode 100644 (file)
index 0000000..35fb27e
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Virtual Sink
+###################################################
+ -->
+<block>
+       <name>Virtual Sink</name>
+       <key>virtual_sink</key>
+       <make></make>
+       <param>
+               <name>Stream ID</name>
+               <key>stream_id</key>
+               <value></value>
+               <type>stream_id</type>
+       </param>
+       <sink>
+               <name>in</name>
+               <type></type>
+       </sink>
+</block>
diff --git a/grc/blocks/virtual_source.xml b/grc/blocks/virtual_source.xml
new file mode 100644 (file)
index 0000000..e0c7754
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Virtual Source
+###################################################
+ -->
+<block>
+       <name>Virtual Source</name>
+       <key>virtual_source</key>
+       <make></make>
+       <param>
+               <name>Stream ID</name>
+               <key>stream_id</key>
+               <value></value>
+               <type>stream_id</type>
+       </param>
+       <source>
+               <name>out</name>
+               <type></type>
+       </source>
+</block>
index faeca37e3217bea7f8db5860e29ad5117693c1c5..6f19f1aa47d3e8c41725791a43da29db4d663006 100644 (file)
@@ -15,6 +15,7 @@ fftsink2.$(type.fcn)(
        y_per_div=$y_per_div,
        y_divs=$y_divs,
        ref_level=$ref_level,
+       ref_scale=$ref_scale,
        sample_rate=$samp_rate,
        fft_size=$fft_size,
        fft_rate=$fft_rate,
@@ -102,6 +103,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos()))))
                <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>
index 79ca356f704e6f92919c803b973f2a4d302bbeb0..35790f820b716b68de105d983bcf4b5521f213ba 100644 (file)
@@ -14,6 +14,7 @@ waterfallsink2.$(type.fcn)(
        baseband_freq=$baseband_freq,
        dynamic_range=$dynamic_range,
        ref_level=$ref_level,
+       ref_scale=$ref_scale,
        sample_rate=$samp_rate,
        fft_size=$fft_size,
        fft_rate=$fft_rate,
@@ -74,6 +75,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos()))))
                <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>
index 1ecf7c47fe4e980d2eba74d25f0ca5538236fc21..3692e17602148c9d674e648eb7a1a157f86e93a2 100644 (file)
@@ -53,22 +53,22 @@ class _dual_source(gr.hier_block2):
                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)
 
@@ -105,22 +105,22 @@ class _dual_sink(gr.hier_block2):
                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)
index 9065c7fe93ed2decbba24ee49484807b52b8acd1..fc4c75bf0618598dab80b60fc0df990a7e623c92 100644 (file)
@@ -56,8 +56,8 @@ class _simple_source(gr.hier_block2):
                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,
@@ -96,14 +96,14 @@ class _simple_sink(gr.hier_block2):
                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)
index ff137f6697074b657ece3f5ab2d90ce6a2db2c50..361be1cf8f095dba401f85649e624b01cdc0e5d0 100644 (file)
@@ -30,9 +30,8 @@ from threading import Thread
 import Messages
 from .. base import ParseXML
 import random
-from Platform import Platform
 from MainWindow import MainWindow
-from ParamsDialog import ParamsDialog
+from PropsDialog import PropsDialog
 import Dialogs
 from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog
 
@@ -53,11 +52,10 @@ class ActionHandler:
                @param platform platform module
                """
                self.clipboard = None
-               platform = Platform(platform)
-               for action in Actions.get_all_actions(): action.connect('activate', self._handle_actions)
+               for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
                #setup the main window
-               self.main_window = MainWindow(self.handle_states, platform)
-               self.main_window.connect('delete_event', self._quit)
+               self.main_window = MainWindow(platform)
+               self.main_window.connect('delete-event', self._quit)
                self.main_window.connect('key-press-event', self._handle_key_press)
                self.get_page = self.main_window.get_page
                self.get_flow_graph = self.main_window.get_flow_graph
@@ -67,7 +65,7 @@ class ActionHandler:
                Messages.send_init(platform)
                #initialize
                self.init_file_paths = file_paths
-               self.handle_states(Actions.APPLICATION_INITIALIZE)
+               Actions.APPLICATION_INITIALIZE()
                #enter the mainloop
                gtk.main()
 
@@ -81,17 +79,9 @@ class ActionHandler:
                When not in focus, gtk and the accelerators handle the the key press.
                @return false to let gtk handle the key action
                """
-               #dont allow key presses to queue up
-               if gtk.events_pending(): return True
-               #extract action name from this key press
-               key_name = gtk.gdk.keyval_name(event.keyval)
-               mod_mask = event.state
-               action_name = Actions.get_action_name_from_key_name(key_name, mod_mask)
-               #handle the action if flow graph is in focus
-               if action_name and self.get_focus_flag():
-                       self.handle_states(action_name)
-                       return True #handled by this method
-               return False #let gtk handle the key press
+               try: assert self.get_focus_flag()
+               except AssertionError: return False
+               return Actions.handle_key_press(event)
 
        def _quit(self, window, event):
                """
@@ -100,41 +90,24 @@ class ActionHandler:
                This method in turns calls the state handler to quit.
                @return true
                """
-               self.handle_states(Actions.APPLICATION_QUIT)
+               Actions.APPLICATION_QUIT()
                return True
 
-       def _handle_actions(self, event):
-               """
-               Handle all of the activate signals from the gtk actions.
-               The action signals derive from clicking on a toolbar or menu bar button.
-               Forward the action to the state handler.
-               """
-               self.handle_states(event.get_name())
-
-       def handle_states(self, state=''):
-               """
-               Handle the state changes in the GUI.
-               Handle all of the state changes that arise from the action handler or other gui and
-               inputs in the application. The state passed to the handle_states method is a string descriping
-               the change. A series of if/elif statements handle the state by greying out action buttons, causing
-               changes in the flow graph, saving/opening files... The handle_states method is passed to the
-               contructors of many of the classes used in this application enabling them to report any state change.
-               @param state a string describing the state change
-               """
-               #print state
+       def _handle_action(self, action):
+               #print action
                ##################################################
                # Initalize/Quit
                ##################################################
-               if state == Actions.APPLICATION_INITIALIZE:
+               if action == Actions.APPLICATION_INITIALIZE:
                        for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled
-                       # enable a select few actions
+                       #enable a select few actions
                        for action in (
                                Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
                                Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
                                Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
                                Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
-                               Actions.COLORS_WINDOW_DISPLAY,
-                       ): Actions.get_action_from_name(action).set_sensitive(True)
+                               Actions.TYPES_WINDOW_DISPLAY,
+                       ): action.set_sensitive(True)
                        if not self.init_file_paths:
                                self.init_file_paths = Preferences.files_open()
                        if not self.init_file_paths: self.init_file_paths = ['']
@@ -143,26 +116,26 @@ class ActionHandler:
                        if Preferences.file_open() in self.init_file_paths:
                                self.main_window.new_page(Preferences.file_open(), show=True)
                        if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists
-               elif state == Actions.APPLICATION_QUIT:
+               elif action == Actions.APPLICATION_QUIT:
                        if self.main_window.close_pages():
                                gtk.main_quit()
                                exit(0)
                ##################################################
                # Selections
                ##################################################
-               elif state == Actions.ELEMENT_SELECT:
+               elif action == Actions.ELEMENT_SELECT:
                        pass #do nothing, update routines below
-               elif state == Actions.NOTHING_SELECT:
+               elif action == Actions.NOTHING_SELECT:
                        self.get_flow_graph().unselect()
                ##################################################
                # Enable/Disable
                ##################################################
-               elif state == Actions.BLOCK_ENABLE:
+               elif action == Actions.BLOCK_ENABLE:
                        if self.get_flow_graph().enable_selected(True):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.BLOCK_DISABLE:
+               elif action == Actions.BLOCK_DISABLE:
                        if self.get_flow_graph().enable_selected(False):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
@@ -170,12 +143,12 @@ class ActionHandler:
                ##################################################
                # Cut/Copy/Paste
                ##################################################
-               elif state == Actions.BLOCK_CUT:
-                       self.handle_states(Actions.BLOCK_COPY)
-                       self.handle_states(Actions.ELEMENT_DELETE)
-               elif state == Actions.BLOCK_COPY:
+               elif action == Actions.BLOCK_CUT:
+                       Actions.BLOCK_COPY()
+                       Actions.ELEMENT_DELETE()
+               elif action == Actions.BLOCK_COPY:
                        self.clipboard = self.get_flow_graph().copy_to_clipboard()
-               elif state == Actions.BLOCK_PASTE:
+               elif action == Actions.BLOCK_PASTE:
                        if self.clipboard:
                                self.get_flow_graph().paste_from_clipboard(self.clipboard)
                                self.get_flow_graph().update()
@@ -184,81 +157,86 @@ class ActionHandler:
                ##################################################
                # Move/Rotate/Delete/Create
                ##################################################
-               elif state == Actions.BLOCK_MOVE:
+               elif action == Actions.BLOCK_MOVE:
                        self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                        self.get_page().set_saved(False)
-               elif state == Actions.BLOCK_ROTATE_CCW:
+               elif action == Actions.BLOCK_ROTATE_CCW:
                        if self.get_flow_graph().rotate_selected(90):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.BLOCK_ROTATE_CW:
+               elif action == Actions.BLOCK_ROTATE_CW:
                        if self.get_flow_graph().rotate_selected(-90):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.ELEMENT_DELETE:
+               elif action == Actions.ELEMENT_DELETE:
                        if self.get_flow_graph().remove_selected():
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
-                               self.handle_states(Actions.NOTHING_SELECT)
+                               Actions.NOTHING_SELECT()
                                self.get_page().set_saved(False)
-               elif state == Actions.ELEMENT_CREATE:
+               elif action == Actions.ELEMENT_CREATE:
                        self.get_flow_graph().update()
                        self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
-                       self.handle_states(Actions.NOTHING_SELECT)
+                       Actions.NOTHING_SELECT()
                        self.get_page().set_saved(False)
-               elif state == Actions.BLOCK_INC_TYPE:
+               elif action == Actions.BLOCK_INC_TYPE:
                        if self.get_flow_graph().type_controller_modify_selected(1):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.BLOCK_DEC_TYPE:
+               elif action == Actions.BLOCK_DEC_TYPE:
                        if self.get_flow_graph().type_controller_modify_selected(-1):
                                self.get_flow_graph().update()
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.PORT_CONTROLLER_INC:
+               elif action == Actions.PORT_CONTROLLER_INC:
                        if self.get_flow_graph().port_controller_modify_selected(1):
                                self.get_flow_graph().update()
-                               self.get_flow_graph().update() #2 times
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
-               elif state == Actions.PORT_CONTROLLER_DEC:
+               elif action == Actions.PORT_CONTROLLER_DEC:
                        if self.get_flow_graph().port_controller_modify_selected(-1):
                                self.get_flow_graph().update()
-                               self.get_flow_graph().update() #2 times
                                self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
                                self.get_page().set_saved(False)
                ##################################################
                # Window stuff
                ##################################################
-               elif state == Actions.ABOUT_WINDOW_DISPLAY:
+               elif action == Actions.ABOUT_WINDOW_DISPLAY:
                        Dialogs.AboutDialog(self.get_flow_graph().get_parent())
-               elif state == Actions.HELP_WINDOW_DISPLAY:
+               elif action == Actions.HELP_WINDOW_DISPLAY:
                        Dialogs.HelpDialog()
-               elif state == Actions.COLORS_WINDOW_DISPLAY:
-                       Dialogs.ColorsDialog(self.get_flow_graph().get_parent())
+               elif action == Actions.TYPES_WINDOW_DISPLAY:
+                       Dialogs.TypesDialog(self.get_flow_graph().get_parent())
                ##################################################
                # Param Modifications
                ##################################################
-               elif state == Actions.BLOCK_PARAM_MODIFY:
+               elif action == Actions.BLOCK_PARAM_MODIFY:
                        selected_block = self.get_flow_graph().get_selected_block()
-                       if selected_block and ParamsDialog(selected_block).run():
-                               self.get_flow_graph().update()
-                               self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
-                               self.get_page().set_saved(False)
+                       if selected_block:
+                               if PropsDialog(selected_block).run():
+                                       #save the new state
+                                       self.get_flow_graph().update()
+                                       self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+                                       self.get_page().set_saved(False)
+                               else:
+                                       #restore the current state
+                                       n = self.get_page().get_state_cache().get_current_state()
+                                       self.get_flow_graph().import_data(n)
+                                       self.get_flow_graph().update()
                ##################################################
                # Undo/Redo
                ##################################################
-               elif state == Actions.FLOW_GRAPH_UNDO:
+               elif action == Actions.FLOW_GRAPH_UNDO:
                        n = self.get_page().get_state_cache().get_prev_state()
                        if n:
                                self.get_flow_graph().unselect()
                                self.get_flow_graph().import_data(n)
                                self.get_flow_graph().update()
                                self.get_page().set_saved(False)
-               elif state == Actions.FLOW_GRAPH_REDO:
+               elif action == Actions.FLOW_GRAPH_REDO:
                        n = self.get_page().get_state_cache().get_next_state()
                        if n:
                                self.get_flow_graph().unselect()
@@ -268,19 +246,19 @@ class ActionHandler:
                ##################################################
                # New/Open/Save/Close
                ##################################################
-               elif state == Actions.FLOW_GRAPH_NEW:
+               elif action == Actions.FLOW_GRAPH_NEW:
                        self.main_window.new_page()
-               elif state == Actions.FLOW_GRAPH_OPEN:
+               elif action == Actions.FLOW_GRAPH_OPEN:
                        file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run()
                        if file_paths: #open a new page for each file, show only the first
                                for i,file_path in enumerate(file_paths):
                                        self.main_window.new_page(file_path, show=(i==0))
-               elif state == Actions.FLOW_GRAPH_CLOSE:
+               elif action == Actions.FLOW_GRAPH_CLOSE:
                        self.main_window.close_page()
-               elif state == Actions.FLOW_GRAPH_SAVE:
+               elif action == Actions.FLOW_GRAPH_SAVE:
                        #read-only or undefined file path, do save-as
                        if self.get_page().get_read_only() or not self.get_page().get_file_path():
-                               self.handle_states(Actions.FLOW_GRAPH_SAVE_AS)
+                               Actions.FLOW_GRAPH_SAVE_AS()
                        #otherwise try to save
                        else:
                                try:
@@ -289,12 +267,12 @@ class ActionHandler:
                                except IOError:
                                        Messages.send_fail_save(self.get_page().get_file_path())
                                        self.get_page().set_saved(False)
-               elif state == Actions.FLOW_GRAPH_SAVE_AS:
+               elif action == Actions.FLOW_GRAPH_SAVE_AS:
                        file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run()
                        if file_path is not None:
                                self.get_page().set_file_path(file_path)
-                               self.handle_states(Actions.FLOW_GRAPH_SAVE)
-               elif state == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
+                               Actions.FLOW_GRAPH_SAVE()
+               elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
                        file_path = SaveImageFileDialog(self.get_page().get_file_path()).run()
                        if file_path is not None:
                                pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf()
@@ -302,10 +280,10 @@ class ActionHandler:
                ##################################################
                # Gen/Exec/Stop
                ##################################################
-               elif state == Actions.FLOW_GRAPH_GEN:
+               elif action == Actions.FLOW_GRAPH_GEN:
                        if not self.get_page().get_pid():
                                if not self.get_page().get_saved() or not self.get_page().get_file_path():
-                                       self.handle_states(Actions.FLOW_GRAPH_SAVE) #only save if file path missing or not saved
+                                       Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved
                                if self.get_page().get_saved() and self.get_page().get_file_path():
                                        generator = self.get_page().get_generator()
                                        try:
@@ -313,37 +291,37 @@ class ActionHandler:
                                                generator.write()
                                        except Exception,e: Messages.send_fail_gen(e)
                                else: self.generator = None
-               elif state == Actions.FLOW_GRAPH_EXEC:
+               elif action == Actions.FLOW_GRAPH_EXEC:
                        if not self.get_page().get_pid():
-                               self.handle_states(Actions.FLOW_GRAPH_GEN)
+                               Actions.FLOW_GRAPH_GEN()
                                if self.get_page().get_saved() and self.get_page().get_file_path():
                                        ExecFlowGraphThread(self)
-               elif state == Actions.FLOW_GRAPH_KILL:
+               elif action == Actions.FLOW_GRAPH_KILL:
                        if self.get_page().get_pid():
                                try: os.kill(self.get_page().get_pid(), signal.SIGKILL)
                                except: print "could not kill pid: %s"%self.get_page().get_pid()
-               elif state == '': #pass and run the global actions
+               elif action == Actions.PAGE_CHANGE: #pass and run the global actions
                        pass
-               else: print '!!! State "%s" not handled !!!'%state
+               else: print '!!! Action "%s" not handled !!!'%action
                ##################################################
                # Global Actions for all States
                ##################################################
                #update general buttons
-               Actions.get_action_from_name(Actions.ELEMENT_DELETE).set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
-               Actions.get_action_from_name(Actions.BLOCK_PARAM_MODIFY).set_sensitive(bool(self.get_flow_graph().get_selected_block()))
-               Actions.get_action_from_name(Actions.BLOCK_ROTATE_CCW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-               Actions.get_action_from_name(Actions.BLOCK_ROTATE_CW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements()))
+               Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block()))
+               Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
                #update cut/copy/paste
-               Actions.get_action_from_name(Actions.BLOCK_CUT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-               Actions.get_action_from_name(Actions.BLOCK_COPY).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-               Actions.get_action_from_name(Actions.BLOCK_PASTE).set_sensitive(bool(self.clipboard))
+               Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
                #update enable/disable
-               Actions.get_action_from_name(Actions.BLOCK_ENABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
-               Actions.get_action_from_name(Actions.BLOCK_DISABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
+               Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks()))
                #set the exec and stop buttons
                self.update_exec_stop()
                #saved status
-               Actions.get_action_from_name(Actions.FLOW_GRAPH_SAVE).set_sensitive(not self.get_page().get_saved())
+               Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved())
                self.main_window.update()
                try: #set the size of the flow graph area (if changed)
                        new_size = self.get_flow_graph().get_option('window_size')
@@ -353,6 +331,7 @@ class ActionHandler:
                #draw the flow graph
                self.get_flow_graph().update_selected()
                self.get_flow_graph().queue_draw()
+               return True #action was handled
 
        def update_exec_stop(self):
                """
@@ -360,9 +339,9 @@ class ActionHandler:
                Lock and unlock the mutex for race conditions with exec flow graph threads.
                """
                sensitive = self.get_flow_graph().is_valid() and not self.get_page().get_pid()
-               Actions.get_action_from_name(Actions.FLOW_GRAPH_GEN).set_sensitive(sensitive)
-               Actions.get_action_from_name(Actions.FLOW_GRAPH_EXEC).set_sensitive(sensitive)
-               Actions.get_action_from_name(Actions.FLOW_GRAPH_KILL).set_sensitive(self.get_page().get_pid() != None)
+               Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
+               Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
+               Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_pid() != None)
 
 class ExecFlowGraphThread(Thread):
        """Execute the flow graph as a new process and wait on it to finish."""
index 3695e09ef3d7abdddc7b178d132099f83f46e92d..b22279c1da12892649562571a23a16007eb30db1 100644 (file)
@@ -21,149 +21,249 @@ import pygtk
 pygtk.require('2.0')
 import gtk
 
-######################################################################################################
-# Action Names
-######################################################################################################
-APPLICATION_INITIALIZE = 'app init'
-APPLICATION_QUIT = 'app quit'
-PARAM_MODIFY = 'param modify'
-BLOCK_MOVE = 'block move'
-BLOCK_ROTATE_CCW = 'block rotate ccw'
-BLOCK_ROTATE_CW = 'block rotate cw'
-BLOCK_PARAM_MODIFY = 'block param modify'
-BLOCK_INC_TYPE = 'block increment type'
-BLOCK_DEC_TYPE = 'block decrement type'
-BLOCK_ENABLE = 'block enable'
-BLOCK_DISABLE = 'block disable'
-BLOCK_CUT = 'block cut'
-BLOCK_COPY = 'block copy'
-BLOCK_PASTE = 'block paste'
-PORT_CONTROLLER_INC = 'port controller increment'
-PORT_CONTROLLER_DEC = 'port controller decrement'
-ELEMENT_CREATE = 'element create'
-ELEMENT_DELETE = 'element delete'
-ELEMENT_SELECT = 'element select'
-NOTHING_SELECT = 'nothing select'
-FLOW_GRAPH_OPEN = 'flow graph open'
-FLOW_GRAPH_UNDO = 'flow graph undo'
-FLOW_GRAPH_REDO = 'flow graph redo'
-FLOW_GRAPH_SAVE = 'flow graph save'
-FLOW_GRAPH_SAVE_AS = 'flow graph save as'
-FLOW_GRAPH_CLOSE = 'flow graph close'
-FLOW_GRAPH_NEW = 'flow graph new'
-FLOW_GRAPH_GEN = 'flow graph gen'
-FLOW_GRAPH_EXEC = 'flow graph exec'
-FLOW_GRAPH_KILL = 'flow graph kill'
-FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture'
-ABOUT_WINDOW_DISPLAY = 'about window display'
-HELP_WINDOW_DISPLAY = 'help window display'
-COLORS_WINDOW_DISPLAY = 'colors window display'
+NO_MODS_MASK = 0
 
-######################################################################################################
-# Action Key Map
-######################################################################################################
-_actions_key_list = (
-       #action name, key name, mod mask
-       (FLOW_GRAPH_NEW, 'n', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_OPEN, 'o', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_SAVE, 's', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_SAVE_AS, 's', gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK),
-       (FLOW_GRAPH_CLOSE, 'w', gtk.gdk.CONTROL_MASK),
-       (APPLICATION_QUIT, 'q', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_UNDO, 'z', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_REDO, 'y', gtk.gdk.CONTROL_MASK),
-       (ELEMENT_DELETE, 'Delete', 0),
-       (BLOCK_ROTATE_CCW, 'Left', 0),
-       (BLOCK_ROTATE_CW, 'Right', 0),
-       (BLOCK_DEC_TYPE, 'Up', 0),
-       (BLOCK_INC_TYPE, 'Down', 0),
-       (BLOCK_PARAM_MODIFY, 'Return', 0),
-       (BLOCK_ENABLE, 'e', 0),
-       (BLOCK_DISABLE, 'd', 0),
-       (BLOCK_CUT, 'x', gtk.gdk.CONTROL_MASK),
-       (BLOCK_COPY, 'c', gtk.gdk.CONTROL_MASK),
-       (BLOCK_PASTE, 'v', gtk.gdk.CONTROL_MASK),
-       (FLOW_GRAPH_GEN, 'F5', 0),
-       (FLOW_GRAPH_EXEC, 'F6', 0),
-       (FLOW_GRAPH_KILL, 'F7', 0),
-       (FLOW_GRAPH_SCREEN_CAPTURE, 'Print', 0),
-       (HELP_WINDOW_DISPLAY, 'F1', 0),
-       #the following have no associated gtk.Action
-       (PORT_CONTROLLER_INC, 'equal', 0),
-       (PORT_CONTROLLER_INC, 'plus', 0),
-       (PORT_CONTROLLER_INC, 'KP_Add', 0),
-       (PORT_CONTROLLER_DEC, 'minus', 0),
-       (PORT_CONTROLLER_DEC, 'KP_Subtract', 0),
-)
-
-_actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list)
-def get_action_name_from_key_name(key_name, mod_mask=0):
+########################################################################
+# Actions API
+########################################################################
+_actions_keypress_dict = dict()
+_keymap = gtk.gdk.keymap_get_default()
+_used_mods_mask = NO_MODS_MASK
+def handle_key_press(event):
        """
-       Get the action name associated with the key name and mask.
-       Both keyname and mask have to match.
-       @param key_name the name of the key
-       @param mod_mask the key press mask (shift, ctrl) 0 for none
-       @return the action name or blank string
+       Call the action associated with the key press event.
+       Both the key value and the mask must have a match.
+       @param event a gtk key press event
+       @return true if handled
        """
-       key_name_mod_mask = (key_name, mod_mask)
-       if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask]
-       return ''
+       _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK)
+       #extract the key value and the consumed modifiers
+       keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
+               event.hardware_keycode, event.state, event.group)
+       #get the modifier mask and ignore irrelevant modifiers
+       mod_mask = event.state & ~consumed & _used_mods_mask
+       #look up the keypress and call the action
+       try: _actions_keypress_dict[(keyval, mod_mask)]()
+       except KeyError: return False #not handled
+       return True #handled here
 
-######################################################################################################
-# Actions
-######################################################################################################
-_actions_list = (
-       gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', gtk.STOCK_NEW),
-       gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', gtk.STOCK_OPEN),
-       gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', gtk.STOCK_SAVE),
-       gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', gtk.STOCK_SAVE_AS),
-       gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', gtk.STOCK_CLOSE),
-       gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', gtk.STOCK_QUIT),
-       gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', gtk.STOCK_UNDO),
-       gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', gtk.STOCK_REDO),
-       gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', gtk.STOCK_DELETE),
-       gtk.Action(BLOCK_ROTATE_CCW, 'Rotate Counterclockwise', 'Rotate the selected blocks 90 degrees to the left', gtk.STOCK_GO_BACK),
-       gtk.Action(BLOCK_ROTATE_CW, 'Rotate Clockwise', 'Rotate the selected blocks 90 degrees to the right', gtk.STOCK_GO_FORWARD),
-       gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', gtk.STOCK_PROPERTIES),
-       gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', gtk.STOCK_CONNECT),
-       gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', gtk.STOCK_DISCONNECT),
-       gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', gtk.STOCK_CUT),
-       gtk.Action(BLOCK_COPY, '_Copy', 'Copy', gtk.STOCK_COPY),
-       gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE),
-       gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT),
-       gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP),
-       gtk.Action(COLORS_WINDOW_DISPLAY, '_Colors', 'Color Mapping', gtk.STOCK_DIALOG_INFO),
-       gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT),
-       gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE),
-       gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP),
-       gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', gtk.STOCK_PRINT),
-)
-def get_all_actions(): return _actions_list
+_all_actions_list = list()
+def get_all_actions(): return _all_actions_list
+
+_accel_group = gtk.AccelGroup()
+def get_accel_group(): return _accel_group
 
-_actions_dict = dict((action.get_name(), action) for action in _actions_list)
-def get_action_from_name(action_name):
+class Action(gtk.Action):
        """
-       Retrieve the action from the action list.
-       Search the list and find an action with said name.
-       @param action_name the action name(string)
-       @throw KeyError bad action name
-       @return a gtk action object
+       A custom Action class based on gtk.Action.
+       Pass additional arguments such as keypresses.
+       Register actions and keypresses with this module.
        """
-       if action_name in _actions_dict: return _actions_dict[action_name]
-       raise KeyError('Action Name: "%s" does not exist'%action_name)
 
-######################################################################################################
-# Accelerators
-######################################################################################################
-_accel_group = gtk.AccelGroup()
-def get_accel_group(): return _accel_group
+       def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None):
+               """
+               Create a new Action instance.
+               @param key_presses a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
+               @param the regular gtk.Action parameters (defaults to None)
+               """
+               if name is None: name = label
+               gtk.Action.__init__(self,
+                       name=name, label=label,
+                       tooltip=tooltip, stock_id=stock_id,
+               )
+               #register this action
+               _all_actions_list.append(self)
+               for i in range(len(keypresses)/2):
+                       keyval, mod_mask = keypresses[i*2:(i+1)*2]
+                       #register this keypress
+                       assert not _actions_keypress_dict.has_key((keyval, mod_mask))
+                       _actions_keypress_dict[(keyval, mod_mask)] = self
+                       #set the accelerator group, and accelerator path
+                       #register the key name and mod mask with the accelerator path
+                       if label is None: continue #dont register accel
+                       accel_path = '<main>/'+self.get_name()
+                       self.set_accel_group(get_accel_group())
+                       self.set_accel_path(accel_path)
+                       gtk.accel_map_add_entry(accel_path, keyval, mod_mask)
+
+       def __str__(self):
+               """
+               The string representation should be the name of the action id.
+               Try to find the action id for this action by searching this module.
+               """
+               try:
+                       import Actions
+                       return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0]
+               except: return self.get_name()
+
+       def __repr__(self): return str(self)
 
-#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),
+)
index e0c547eba5348af90130848d0c4b737aff961cdf..fff5ebc08d1b51f55ed2beab5c55b4cc609da328 100644 (file)
@@ -88,7 +88,7 @@ MENU_BAR_LIST = (
        ]),
        (gtk.Action('Help', '_Help', None, None), [
                Actions.HELP_WINDOW_DISPLAY,
-               Actions.COLORS_WINDOW_DISPLAY,
+               Actions.TYPES_WINDOW_DISPLAY,
                None,
                Actions.ABOUT_WINDOW_DISPLAY,
        ]),
@@ -104,9 +104,8 @@ class Toolbar(gtk.Toolbar):
                """
                gtk.Toolbar.__init__(self)
                self.set_style(gtk.TOOLBAR_ICONS)
-               for action_name in TOOLBAR_LIST:
-                       if action_name: #add a tool item
-                               action = Actions.get_action_from_name(action_name)
+               for action in TOOLBAR_LIST:
+                       if action: #add a tool item
                                self.add(action.create_tool_item())
                                #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show
                                action.set_property('tooltip', action.get_property('tooltip'))
@@ -123,16 +122,15 @@ class MenuBar(gtk.MenuBar):
                Add the submenu to the menu bar.
                """
                gtk.MenuBar.__init__(self)
-               for main_action,action_names in MENU_BAR_LIST:
+               for main_action, actions in MENU_BAR_LIST:
                        #create the main menu item
                        main_menu_item = main_action.create_menu_item()
                        self.append(main_menu_item)
                        #create the menu
                        main_menu = gtk.Menu()
                        main_menu_item.set_submenu(main_menu)
-                       for action_name in action_names:
-                               if action_name: #append a menu item
-                                       action = Actions.get_action_from_name(action_name)
+                       for action in actions:
+                               if action: #append a menu item
                                        main_menu.append(action.create_menu_item())
                                else: main_menu.append(gtk.SeparatorMenuItem())
                        main_menu.show_all() #this show all is required for the separators to show
index 4add3aa195f9db8d34cd46c09104fd7bf78d2467..8c65bf06f104a2dd347856460d347775c813ff9f 100644 (file)
@@ -37,15 +37,15 @@ BLOCK_MARKUP_TMPL="""\
 class Block(Element):
        """The graphical signal block."""
 
-       def __init__(self, *args, **kwargs):
+       def __init__(self):
                """
                Block contructor.
                Add graphics related params to the block.
                """
                #add the position param
                self.get_params().append(self.get_parent().get_parent().Param(
-                       self,
-                       odict({
+                       block=self,
+                       n=odict({
                                'name': 'GUI Coordinate',
                                'key': '_coordinate',
                                'type': 'raw',
@@ -54,8 +54,8 @@ class Block(Element):
                        })
                ))
                self.get_params().append(self.get_parent().get_parent().Param(
-                       self,
-                       odict({
+                       block=self,
+                       n=odict({
                                'name': 'GUI Rotation',
                                'key': '_rotation',
                                'type': 'raw',
@@ -113,23 +113,16 @@ class Block(Element):
                """
                self.get_param('_rotation').set_value(str(rot))
 
-       def update(self):
+       def create_shapes(self):
                """Update the block, parameters, and ports when a change occurs."""
-               self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
-               self.clear()
-               self._create_labels()
-               self.W = self.label_width + 2*BLOCK_LABEL_PADDING
-               self.H = max(*(
-                       [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
-                       sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
-                       for ports in (self.get_sources(), self.get_sinks())]
-               ))
+               Element.create_shapes(self)
                if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H))
                elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W))
-               map(lambda p: p.update(), self.get_ports())
 
-       def _create_labels(self):
+       def create_labels(self):
                """Create the labels for the signal block."""
+               Element.create_labels(self)
+               self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
                layouts = list()
                #create the main layout
                layout = gtk.DrawingArea().create_pango_layout('')
@@ -142,7 +135,7 @@ class Block(Element):
                        layouts.append(layout)
                        w,h = layout.get_pixel_size()
                        self.label_width = max(w, self.label_width)
-                       self.label_height = self.label_height + h + LABEL_SEPARATION
+                       self.label_height += h + LABEL_SEPARATION
                width = self.label_width
                height = self.label_height
                #setup the pixmap
@@ -164,7 +157,13 @@ class Block(Element):
                        self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width)
                        for i in range(width):
                                for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j))
-               map(lambda p: p._create_labels(), self.get_ports())
+               #calculate width and height needed
+               self.W = self.label_width + 2*BLOCK_LABEL_PADDING
+               self.H = max(*(
+                       [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
+                       sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
+                       for ports in (self.get_sources(), self.get_sinks())]
+               ))
 
        def draw(self, gc, window):
                """
index 379c4a6a25e04b0d2ca6db6431efa250cb1e4fab..07b8ea7e0f63f5451d6a182f9d7ae7e7f7a11273 100644 (file)
@@ -28,6 +28,15 @@ NAME_INDEX = 0
 KEY_INDEX = 1
 DOC_INDEX = 2
 
+DOC_MARKUP_TMPL="""\
+#if $doc
+$encode($doc)#slurp
+#else
+undocumented#slurp
+#end if"""
+
+CAT_MARKUP_TMPL="""Category: $cat"""
+
 class BlockTreeWindow(gtk.VBox):
        """The block selection panel."""
 
@@ -48,7 +57,7 @@ class BlockTreeWindow(gtk.VBox):
                self.treeview = gtk.TreeView(self.treestore)
                self.treeview.set_enable_search(False) #disable pop up search box
                self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
-               self.treeview.connect('button_press_event', self._handle_mouse_button_press)
+               self.treeview.connect('button-press-event', self._handle_mouse_button_press)
                selection = self.treeview.get_selection()
                selection.set_mode('single')
                selection.connect('changed', self._handle_selection_change)
@@ -97,14 +106,14 @@ class BlockTreeWindow(gtk.VBox):
                                iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None)
                                self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name)
                                self.treestore.set_value(iter, KEY_INDEX, '')
-                               self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode('Category: %s'%cat_name))
+                               self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name))
                                self._categories[sub_category] = iter
                #add block
                if block is None: return
                iter = self.treestore.insert_before(self._categories[category], None)
                self.treestore.set_value(iter, NAME_INDEX, block.get_name())
                self.treestore.set_value(iter, KEY_INDEX, block.get_key())
-               self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode(block.get_doc() or 'undocumented'))
+               self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc()))
 
        ############################################################
        ## Helper Methods
index 013bcb00f81556c469ca48f610154e334c423664..fabf34ee727c75bdb70320bbc8e9ef91a6732bac 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2007, 2008 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -32,6 +32,8 @@ class Connection(Element):
        The arrow coloring exposes the enabled and valid states.
        """
 
+       def __init__(self): Element.__init__(self)
+
        def get_coordinate(self):
                """
                Get the 0,0 coordinate.
@@ -48,8 +50,9 @@ class Connection(Element):
                """
                return 0
 
-       def update(self):
+       def create_shapes(self):
                """Precalculate relative coordinates."""
+               Element.create_shapes(self)
                self._sink_rot = None
                self._source_rot = None
                self._sink_coor = None
@@ -72,7 +75,7 @@ class Connection(Element):
 
        def _update_after_move(self):
                """Calculate coordinates."""
-               self.clear()
+               self.clear() #FIXME do i want this here?
                #source connector
                source = self.get_source()
                X, Y = source.get_connector_coordinate()
@@ -123,7 +126,7 @@ class Connection(Element):
                sink = self.get_sink()
                source = self.get_source()
                #check for changes
-               if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.update()
+               if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes()
                elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move()
                #cache values
                self._sink_rot = sink.get_rotation()
index 8d764e28e38e8584302026ccae4fbde33133495d..3cf617b92c8e03b1a06fdd6d6e457dd8a450f613 100644 (file)
@@ -98,8 +98,8 @@ COLORS_DIALOG_MARKUP_TMPL = """\
 #end if
 """
 
-def ColorsDialog(platform): MessageDialogHelper(
+def TypesDialog(platform): MessageDialogHelper(
        type=gtk.MESSAGE_INFO,
        buttons=gtk.BUTTONS_CLOSE,
-       title='Colors',
+       title='Types',
        markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors()))
index 3151917237785ad299ac0cc7b756e74ba8d2d2a8..f0518ee12ba56883debd666ede1a8e31c12bc8fe 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,11 +17,9 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import Colors
 import pygtk
 pygtk.require('2.0')
 import gtk
-import pango
 from Constants import LINE_SELECT_SENSITIVITY
 from Constants import POSSIBLE_ROTATIONS
 
@@ -32,7 +30,7 @@ class Element(object):
        and methods to detect selection of those areas.
        """
 
-       def __init__(self, *args, **kwargs):
+       def __init__(self):
                """
                Make a new list of rectangular areas and lines, and set the coordinate and the rotation.
                """
@@ -61,6 +59,21 @@ class Element(object):
                rotation = rotation or self.get_rotation()
                return rotation in (90, 270)
 
+       def create_labels(self):
+               """
+               Create labels (if applicable) and call on all children.
+               Call this base method before creating labels in the element.
+               """
+               for child in self.get_children(): child.create_labels()
+
+       def create_shapes(self):
+               """
+               Create shapes (if applicable) and call on all children.
+               Call this base method before creating shapes in the element.
+               """
+               self.clear()
+               for child in self.get_children(): child.create_shapes()
+
        def draw(self, gc, window, border_color, bg_color):
                """
                Draw in the given window.
@@ -70,14 +83,14 @@ class Element(object):
                @param bg_color the color for the inside of the rectangle
                """
                X,Y = self.get_coordinate()
-               for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]:
+               for (rX,rY),(W,H) in self._areas_list:
                        aX = X + rX
                        aY = Y + rY
                        gc.set_foreground(bg_color)
                        window.draw_rectangle(gc, True, aX, aY, W, H)
                        gc.set_foreground(border_color)
                        window.draw_rectangle(gc, False, aX, aY, W, H)
-               for (x1, y1),(x2, y2) in self.lines_dict[self.get_rotation()]:
+               for (x1, y1),(x2, y2) in self._lines_list:
                        gc.set_foreground(border_color)
                        window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2)
 
@@ -90,8 +103,8 @@ class Element(object):
 
        def clear(self):
                """Empty the lines and areas."""
-               self.areas_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS)
-               self.lines_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS)
+               self._areas_list = list()
+               self._lines_list = list()
 
        def set_coordinate(self, coor):
                """
@@ -136,7 +149,7 @@ class Element(object):
                X, Y = self.get_coordinate()
                self.set_coordinate((X+deltaX, Y+deltaY))
 
-       def add_area(self, rel_coor, area, rotation=None):
+       def add_area(self, rel_coor, area):
                """
                Add an area to the area list.
                An area is actually a coordinate relative to the main coordinate
@@ -144,25 +157,21 @@ class Element(object):
                A positive width is to the right of the coordinate.
                A positive height is above the coordinate.
                The area is associated with a rotation.
-               If rotation is not specified, the element's current rotation is used.
                @param rel_coor (x,y) offset from this element's coordinate
                @param area (width,height) tuple
-               @param rotation rotation in degrees
                """
-               self.areas_dict[rotation or self.get_rotation()].append((rel_coor, area))
+               self._areas_list.append((rel_coor, area))
 
-       def add_line(self, rel_coor1, rel_coor2, rotation=None):
+       def add_line(self, rel_coor1, rel_coor2):
                """
                Add a line to the line list.
                A line is defined by 2 relative coordinates.
                Lines must be horizontal or vertical.
                The line is associated with a rotation.
-               If rotation is not specified, the element's current rotation is used.
                @param rel_coor1 relative (x1,y1) tuple
                @param rel_coor2 relative (x2,y2) tuple
-               @param rotation rotation in degrees
                """
-               self.lines_dict[rotation or self.get_rotation()].append((rel_coor1, rel_coor2))
+               self._lines_list.append((rel_coor1, rel_coor2))
 
        def what_is_selected(self, coor, coor_m=None):
                """
@@ -183,24 +192,24 @@ class Element(object):
                if coor_m:
                        x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())]
                        #handle rectangular areas
-                       for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]:
+                       for (x1,y1), (w,h) in self._areas_list:
                                if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
                                        in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \
                                        in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \
                                        in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m):
                                        return self
                        #handle horizontal or vertical lines
-                       for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]:
+                       for (x1, y1), (x2, y2) in self._lines_list:
                                if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \
                                        in_between(x2, x, x_m) and in_between(y2, y, y_m):
                                        return self
                        return None
                else:
                        #handle rectangular areas
-                       for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]:
+                       for (x1,y1), (w,h) in self._areas_list:
                                if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self
                        #handle horizontal or vertical lines
-                       for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]:
+                       for (x1, y1), (x2, y2) in self._lines_list:
                                if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY
                                if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY
                                if in_between(x, x1, x2) and in_between(y, y1, y2): return self
@@ -220,7 +229,3 @@ class Element(object):
                if rotation not in POSSIBLE_ROTATIONS:
                        raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS))
                self.rotation = rotation
-
-       def update(self):
-               """Do nothing for the update. Dummy method."""
-               pass
index f8028f199add9ca85120ea7ab19f53dbc93a8352..8feb171f1fd15e1a25c1f24013f56d8a6dd1f768 100644 (file)
@@ -18,10 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 from Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
-from Actions import \
-       ELEMENT_CREATE, ELEMENT_SELECT, \
-       BLOCK_PARAM_MODIFY, BLOCK_MOVE, \
-       ELEMENT_DELETE
+import Actions
 import Colors
 import Utils
 from Element import Element
@@ -39,7 +36,7 @@ class FlowGraph(Element):
        and the connections between inputs and outputs.
        """
 
-       def __init__(self, *args, **kwargs):
+       def __init__(self):
                """
                FlowGraph contructor.
                Create a list for signal blocks and connections. Connect mouse handlers.
@@ -86,7 +83,7 @@ class FlowGraph(Element):
                block.set_coordinate(coor)
                block.set_rotation(0)
                block.get_param('id').set_value(id)
-               self.handle_states(ELEMENT_CREATE)
+               Actions.ELEMENT_CREATE()
 
        ###########################################################################
        # Copy Paste
@@ -291,10 +288,13 @@ class FlowGraph(Element):
 
        def update(self):
                """
-               Call update on all elements.
+               Call the top level rewrite and validate.
+               Call the top level create labels and shapes.
                """
+               self.rewrite()
                self.validate()
-               for element in self.get_elements(): element.update()
+               self.create_labels()
+               self.create_shapes()
 
        ##########################################################################
        ## Get Selected
@@ -406,7 +406,7 @@ class FlowGraph(Element):
                        self._old_selected_port is not self._new_selected_port:
                        try:
                                self.connect(self._old_selected_port, self._new_selected_port)
-                               self.handle_states(ELEMENT_CREATE)
+                               Actions.ELEMENT_CREATE()
                        except: Messages.send_fail_connection()
                        self._old_selected_port = None
                        self._new_selected_port = None
@@ -421,7 +421,7 @@ class FlowGraph(Element):
                        self._selected_elements = list(
                                set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements)
                        )
-               self.handle_states(ELEMENT_SELECT)
+               Actions.ELEMENT_SELECT()
 
        ##########################################################################
        ## Event Handlers
@@ -443,7 +443,7 @@ class FlowGraph(Element):
                #double click detected, bring up params dialog if possible
                if double_click and self.get_selected_block():
                        self.mouse_pressed = False
-                       self.handle_states(BLOCK_PARAM_MODIFY)
+                       Actions.BLOCK_PARAM_MODIFY()
 
        def handle_mouse_button_release(self, left_click, coordinate):
                """
@@ -454,7 +454,7 @@ class FlowGraph(Element):
                self.time = 0
                self.mouse_pressed = False
                if self.element_moved:
-                       self.handle_states(BLOCK_MOVE)
+                       Actions.BLOCK_MOVE()
                        self.element_moved = False
                self.update_selected_elements()
 
@@ -484,7 +484,7 @@ class FlowGraph(Element):
                                adj.emit('changed')
                #remove the connection if selected in drag event
                if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection():
-                       self.handle_states(ELEMENT_DELETE)
+                       Actions.ELEMENT_DELETE()
                #move the selected elements and record the new coordinate
                X, Y = self.get_coordinate()
                if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y)))
index 6d36f4cf70dcc8d79615bef50f7615458d747ebe..9fcbe2a6cb95304fba5a28b3c22a18a897ed8022 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -19,9 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 from Constants import \
        NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH
-from Actions import \
-       APPLICATION_QUIT, FLOW_GRAPH_KILL, \
-       FLOW_GRAPH_SAVE, get_accel_group
+import Actions
 import pygtk
 pygtk.require('2.0')
 import gtk
@@ -67,20 +65,19 @@ PAGE_TITLE_MARKUP_TMPL = """\
 class MainWindow(gtk.Window):
        """The topmost window with menus, the tool bar, and other major windows."""
 
-       def __init__(self, handle_states, platform):
+       def __init__(self, platform):
                """
-               MainWindow contructor.
-               @param handle_states the callback function
+               MainWindow contructor
+               Setup the menu, toolbar, flowgraph editor notebook, block selection window...
                """
                self._platform = platform
                #setup window
-               self.handle_states = handle_states
                gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
                vbox = gtk.VBox()
                self.hpaned = gtk.HPaned()
                self.add(vbox)
                #create the menu bar and toolbar
-               self.add_accel_group(get_accel_group())
+               self.add_accel_group(Actions.get_accel_group())
                vbox.pack_start(Bars.MenuBar(), False)
                vbox.pack_start(Bars.Toolbar(), False)
                vbox.pack_start(self.hpaned)
@@ -123,7 +120,7 @@ class MainWindow(gtk.Window):
                This method in turns calls the state handler to quit.
                @return true
                """
-               self.handle_states(APPLICATION_QUIT)
+               Actions.APPLICATION_QUIT()
                return True
 
        def _handle_page_change(self, notebook, page, page_num):
@@ -137,7 +134,7 @@ class MainWindow(gtk.Window):
                """
                self.current_page = self.notebook.get_nth_page(page_num)
                Messages.send_page_switch(self.current_page.get_file_path())
-               self.handle_states()
+               Actions.PAGE_CHANGE()
 
        ############################################################
        # Report Window
@@ -223,12 +220,12 @@ class MainWindow(gtk.Window):
                        self._set_page(self.page_to_be_closed)
                #unsaved? ask the user
                if not self.page_to_be_closed.get_saved() and self._save_changes():
-                       self.handle_states(FLOW_GRAPH_SAVE) #try to save
+                       Actions.FLOW_GRAPH_SAVE() #try to save
                        if not self.page_to_be_closed.get_saved(): #still unsaved?
                                self.page_to_be_closed = None #set the page to be closed back to None
                                return
                #stop the flow graph if executing
-               if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL)
+               if self.page_to_be_closed.get_pid(): Actions.FLOW_GRAPH_KILL()
                #remove the page
                self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
                if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one
index cb45d535992e208b4e2144e913b83d7be8a5fe7f..b14817d04e0d9e891544a99736a99ad3ccbe358a 100644 (file)
@@ -43,7 +43,7 @@ ourpython_PYTHON = \
        MainWindow.py \
        Messages.py \
        NotebookPage.py \
-       ParamsDialog.py \
+       PropsDialog.py \
        Preferences.py \
        StateCache.py \
        __init__.py
index cb6b7ed3079d7b1df77d207d20b18ab6eef2cde1..fddfeaf5f1cf7b07d2708d602ea99bb3164ae70b 100644 (file)
@@ -17,10 +17,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from Actions import FLOW_GRAPH_CLOSE
 import pygtk
 pygtk.require('2.0')
 import gtk
+import Actions
 from StateCache import StateCache
 from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT
 from DrawingArea import DrawingArea
@@ -80,9 +80,8 @@ class NotebookPage(gtk.HBox):
                self.drawing_area = DrawingArea(self.get_flow_graph())
                self.scrolled_window.add_with_viewport(self.get_drawing_area())
                self.pack_start(self.scrolled_window)
-               #inject drawing area and handle states into flow graph
+               #inject drawing area into flow graph
                self.get_flow_graph().drawing_area = self.get_drawing_area()
-               self.get_flow_graph().handle_states = main_window.handle_states
                self.show_all()
 
        def get_drawing_area(self): return self.drawing_area
@@ -104,7 +103,7 @@ class NotebookPage(gtk.HBox):
                @param the button
                """
                self.main_window.page_to_be_closed = self
-               self.main_window.handle_states(FLOW_GRAPH_CLOSE)
+               Actions.FLOW_GRAPH_CLOSE()
 
        def set_markup(self, markup):
                """
index a11fd906591c02870701c8599a2b090bec9f2bea..4464a57ab77505f006b06a3731d1120248d891bb 100644 (file)
@@ -23,6 +23,106 @@ import pygtk
 pygtk.require('2.0')
 import gtk
 
+class InputParam(gtk.HBox):
+       """The base class for an input parameter inside the input parameters dialog."""
+
+       def __init__(self, param, callback=None):
+               gtk.HBox.__init__(self)
+               self.param = param
+               self._callback = callback
+               self.label = gtk.Label() #no label, markup is added by set_markup
+               self.label.set_size_request(150, -1)
+               self.pack_start(self.label, False)
+               self.set_markup = lambda m: self.label.set_markup(m)
+               self.tp = None
+               #connect events
+               self.connect('show', self._update_gui)
+       def set_color(self, color): pass
+
+       def _update_gui(self, *args):
+               """
+               Set the markup, color, tooltip, show/hide.
+               """
+               #set the markup
+               has_cb = \
+                       hasattr(self.param.get_parent(), 'get_callbacks') and \
+                       filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks)
+               self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb))
+               #set the color
+               self.set_color(self.param.get_color())
+               #set the tooltip
+               if self.tp: self.tp.set_tip(
+                       self.entry,
+                       Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(),
+               )
+               #show/hide
+               if self.param.get_hide() == 'all': self.hide_all()
+               else: self.show_all()
+
+       def _handle_changed(self, *args):
+               """
+               Handle a gui change by setting the new param value,
+               calling the callback (if applicable), and updating.
+               """
+               #set the new value
+               self.param.set_value(self.get_text())
+               #call the callback
+               if self._callback: self._callback(*args)
+               else: self.param.validate()
+               #gui update
+               self._update_gui()
+
+class EntryParam(InputParam):
+       """Provide an entry box for strings and numbers."""
+
+       def __init__(self, *args, **kwargs):
+               InputParam.__init__(self, *args, **kwargs)
+               self.entry = input = gtk.Entry()
+               input.set_text(self.param.get_value())
+               input.connect('changed', self._handle_changed)
+               self.pack_start(input, True)
+               self.get_text = input.get_text
+               #tool tip
+               self.tp = gtk.Tooltips()
+               self.tp.set_tip(self.entry, '')
+               self.tp.enable()
+       def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+
+class EnumParam(InputParam):
+       """Provide an entry box for Enum types with a drop down menu."""
+
+       def __init__(self, *args, **kwargs):
+               InputParam.__init__(self, *args, **kwargs)
+               self._input = gtk.combo_box_new_text()
+               for option in self.param.get_options(): self._input.append_text(option.get_name())
+               self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+               self._input.connect('changed', self._handle_changed)
+               self.pack_start(self._input, False)
+       def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
+
+class EnumEntryParam(InputParam):
+       """Provide an entry box and drop down menu for Raw Enum types."""
+
+       def __init__(self, *args, **kwargs):
+               InputParam.__init__(self, *args, **kwargs)
+               self._input = gtk.combo_box_entry_new_text()
+               for option in self.param.get_options(): self._input.append_text(option.get_name())
+               try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+               except:
+                       self._input.set_active(-1)
+                       self._input.get_child().set_text(self.param.get_value())
+               self._input.connect('changed', self._handle_changed)
+               self._input.get_child().connect('changed', self._handle_changed)
+               self.pack_start(self._input, False)
+       def get_text(self):
+               if self._input.get_active() == -1: return self._input.get_child().get_text()
+               return self.param.get_option_keys()[self._input.get_active()]
+       def set_color(self, color):
+               if self._input.get_active() == -1: #custom entry, use color
+                       self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+               else: #from enum, make white background
+                       self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
+
 PARAM_MARKUP_TMPL="""\
 #set $foreground = $param.is_valid() and 'black' or 'red'
 <span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode(repr($param))</span>"""
@@ -49,49 +149,19 @@ Error:
 class Param(Element):
        """The graphical parameter."""
 
-       def update(self):
-               """
-               Called when an external change occurs.
-               Update the graphical input by calling the change handler.
-               """
-               if hasattr(self, '_input'): self._handle_changed()
-
-       def get_input_object(self, callback=None):
-               """
-               Get the graphical gtk object to represent this parameter.
-               Create the input object with this data type and the handle changed method.
-               @param callback a function of one argument(this param) to be called from the change handler
-               @return gtk input object
-               """
-               self._callback = callback
-               self._input = self.get_input_class()(self, self._handle_changed)
-               if not self._callback: self.update()
-               return self._input
+       def __init__(self): Element.__init__(self)
 
-       def _handle_changed(self, widget=None):
+       def get_input(self, *args, **kwargs):
                """
-               When the input changes, write the inputs to the data type.
-               Finish by calling the exteral callback.
+               Get the graphical gtk class to represent this parameter.
+               An enum requires and combo parameter.
+               A non-enum with options gets a combined entry/combo parameter.
+               All others get a standard entry parameter.
+               @return gtk input class
                """
-               self.set_value(self._input.get_text())
-               self.validate()
-               #is param is involved in a callback? #FIXME: messy
-               has_cb = \
-                       hasattr(self.get_parent(), 'get_callbacks') and \
-                       filter(lambda c: self.get_key() in c, self.get_parent()._callbacks)
-               self._input.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self, has_cb=has_cb))
-               #hide/show
-               if self.get_hide() == 'all': self._input.hide_all()
-               else: self._input.show_all()
-               #set the color
-               self._input.set_color(self.get_color())
-               #set the tooltip
-               if self._input.tp: self._input.tp.set_tip(
-                       self._input.entry,
-                       Utils.parse_template(TIP_MARKUP_TMPL, param=self).strip(),
-               )
-               #execute the external callback
-               if self._callback: self._callback(self)
+               if self.is_enum(): return EnumParam(self, *args, **kwargs)
+               if self.get_options(): return EnumEntryParam(self, *args, **kwargs)
+               return EntryParam(self, *args, **kwargs)
 
        def get_layout(self):
                """
diff --git a/grc/gui/ParamsDialog.py b/grc/gui/ParamsDialog.py
deleted file mode 100644 (file)
index ccf19d1..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-"""
-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
index a32b0209ffb2815c2e769a673dac58af1239b26a..8bbfaca2322a5a0a7528733bc83777f2e4e2cd5e 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,32 +17,7 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from FlowGraph import FlowGraph
-from Connection import Connection
-from Block import Block
-from Port import Port
-from Param import Param
+from Element import Element
 
-def conjoin_classes(name, c1, c2):
-       exec("""
-class %s(c1, c2):
-       def __init__(self, *args, **kwargs):
-               c1.__init__(self, *args, **kwargs)
-               c2.__init__(self, *args, **kwargs)
-"""%name, locals())
-       return locals()[name]
-
-def Platform(platform):
-       #combine with gui class
-       for attr, value in (
-               ('FlowGraph', FlowGraph),
-               ('Connection', Connection),
-               ('Block', Block),
-               ('Source', Port),
-               ('Sink', Port),
-               ('Param', Param),
-       ):
-               old_value = getattr(platform, attr)
-               c = conjoin_classes(attr, old_value, value)
-               setattr(platform, attr, c)
-       return platform
+class Platform(Element):
+       def __init__(self): Element.__init__(self)
index d1f36f8b963659aea5d5e8130c8def7ffb3bd965..6763f6cbd553f61ab7673095f247687000e06dc4 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@ PORT_MARKUP_TMPL="""\
 class Port(Element):
        """The graphical port."""
 
-       def __init__(self, *args, **kwargs):
+       def __init__(self):
                """
                Port contructor.
                Create list of connector coordinates.
@@ -42,9 +42,9 @@ class Port(Element):
                Element.__init__(self)
                self.connector_coordinates = dict()
 
-       def update(self):
+       def create_shapes(self):
                """Create new areas and labels for the port."""
-               self.clear()
+               Element.create_shapes(self)
                #get current rotation
                rotation = self.get_rotation()
                #get all sibling ports
@@ -82,8 +82,9 @@ class Port(Element):
                #the connector length
                self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index
 
-       def _create_labels(self):
+       def create_labels(self):
                """Create the labels for the socket."""
+               Element.create_labels(self)
                self._bg_color = Colors.get_color(self.get_color())
                #create the layout
                layout = gtk.DrawingArea().create_pango_layout('')
@@ -114,7 +115,7 @@ class Port(Element):
                        border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
                )
                X,Y = self.get_coordinate()
-               (x,y),(w,h) = self.areas_dict[self.get_rotation()][0] #use the first area's sizes to place the labels
+               (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels
                if self.is_horizontal():
                        window.draw_image(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1)
                elif self.is_vertical():
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
new file mode 100644 (file)
index 0000000..a7822b2
--- /dev/null
@@ -0,0 +1,171 @@
+"""
+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
index 04b18b18aa676013b0f09a49122d035cf948c0d2..3f6b7922405da7364653476c28f64c865c20a85e 100644 (file)
@@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO, get_action_from_name
+import Actions
 from Constants import STATE_CACHE_SIZE
 
 class StateCache(object):
@@ -88,5 +88,5 @@ class StateCache(object):
                """
                Update the undo and redo actions based on the number of next and prev states.
                """
-               get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(self.num_next_states != 0)
-               get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(self.num_prev_states != 0)
+               Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0)
+               Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0)
index ee6dc6cdc4aa2a62cddc7bc5d6a1ecce71bba496..83036a4b858c0c4eb5460738be7eb2f3e4002e6d 100644 (file)
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 from Constants import POSSIBLE_ROTATIONS
 from Cheetah.Template import Template
+import gobject
 
 def get_rotated_coordinate(coor, rotation):
        """
@@ -54,23 +55,6 @@ def get_angle_from_coordinates((x1,y1), (x2,y2)):
                if y2 > y1: return 270
                else: return 90
 
-def xml_encode(string):
-       """
-       Encode a string into an xml safe string by replacing special characters.
-       Needed for gtk pango markup in labels.
-       @param string the input string
-       @return output string with safe characters
-       """
-       string = str(string)
-       for char, safe in (
-                       ('&', '&amp;'),
-                       ('<', '&lt;'),
-                       ('>', '&gt;'),
-                       ('"', '&quot;'),
-                       ("'", '&apos;'),
-       ): string = string.replace(char, safe)
-       return string
-
 def parse_template(tmpl_str, **kwargs):
        """
        Parse the template string with the given args.
@@ -78,5 +62,5 @@ def parse_template(tmpl_str, **kwargs):
        @param tmpl_str the template as a string
        @return a string of the parsed template
        """
-       kwargs['encode'] = xml_encode
+       kwargs['encode'] = gobject.markup_escape_text
        return str(Template(tmpl_str, kwargs))
index 47fe13a3cc11ee6c87d81d605e5d2e7317eda4c2..dd39b095de5a0c14920ee1db2bed655c43e5ae1a 100644 (file)
@@ -18,10 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 from .. base.Block import Block as _Block
+from .. gui.Block import Block as _GUIBlock
 import extract_docs
 import extract_category
 
-class Block(_Block):
+class Block(_Block, _GUIBlock):
+
+       def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
+       def is_virtual_source(self): return self.get_key() == 'virtual_source'
 
        ##for make source to keep track of indexes
        _source_count = 0
@@ -48,13 +52,13 @@ class Block(_Block):
                        flow_graph=flow_graph,
                        n=n,
                )
+               _GUIBlock.__init__(self)
 
        def validate(self):
                """
                Validate this block.
                Call the base class validate.
                Evaluate the checks: each check must evaluate to True.
-               Adjust the nports.
                """
                _Block.validate(self)
                #evaluate the checks
@@ -65,6 +69,12 @@ class Block(_Block):
                                try: assert check_eval
                                except AssertionError: self.add_error_message('Check "%s" failed.'%check)
                        except: self.add_error_message('Check "%s" did not evaluate.'%check)
+
+       def rewrite(self):
+               """
+               Add and remove ports to adjust for the nports.
+               """
+               _Block.rewrite(self)
                #adjust nports
                for get_ports, get_port in (
                        (self.get_sources, self.get_source),
index 5eba9f24dd839ed0b6bbf65427bc4f5a2cd02475..edc18841a00b7844d6c203bf6af1ca19263115d4 100644 (file)
@@ -1,5 +1,5 @@
 """
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -18,8 +18,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 from .. base.Connection import Connection as _Connection
+from .. gui.Connection import Connection as _GUIConnection
 
-class Connection(_Connection):
+class Connection(_Connection, _GUIConnection):
+
+       def __init__(self, **kwargs):
+               _Connection.__init__(self, **kwargs)
+               _GUIConnection.__init__(self)
 
        def is_msg(self):
                return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
index 8cad8be492216d46c86884750f0badfb9e6b83fa..4dd18a81f4cd230dbec042dfb77a2068129ed859 100644 (file)
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 import expr_utils
 from .. base.FlowGraph import FlowGraph as _FlowGraph
+from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
 from Block import Block
 from Connection import Connection
 import re
@@ -26,9 +27,13 @@ import re
 _variable_matcher = re.compile('^(variable\w*)$')
 _parameter_matcher = re.compile('^(parameter)$')
 
-class FlowGraph(_FlowGraph):
+class FlowGraph(_FlowGraph, _GUIFlowGraph):
+
+       def __init__(self, **kwargs):
+               _FlowGraph.__init__(self, **kwargs)
+               _GUIFlowGraph.__init__(self)
+               self._eval_cache = dict()
 
-       _eval_cache = dict()
        def _eval(self, code, namespace, namespace_hash):
                """
                Evaluate the code with the given namespace.
@@ -37,6 +42,7 @@ class FlowGraph(_FlowGraph):
                @param namespace_hash a unique hash for the namespace
                @return the resultant object
                """
+               if not code: raise Exception, 'Cannot evaluate empty statement.'
                my_hash = hash(code) ^ namespace_hash
                #cache if does not exist
                if not self._eval_cache.has_key(my_hash):
@@ -109,6 +115,13 @@ class FlowGraph(_FlowGraph):
                parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks())
                return parameters
 
+       def rewrite(self):
+               """
+               Flag the namespace to be renewed.
+               """
+               self._renew_eval_ns = True
+               _FlowGraph.rewrite(self)
+
        def evaluate(self, expr):
                """
                Evaluate the expression.
@@ -116,8 +129,8 @@ class FlowGraph(_FlowGraph):
                @throw Exception bad expression
                @return the evaluated data
                """
-               if self.is_flagged():
-                       self.deflag()
+               if self._renew_eval_ns:
+                       self._renew_eval_ns = False
                        #reload namespace
                        n = dict()
                        #load imports
index f971d0c3fb6330ca7b06d24f5863e777334d6399..387fab5481af81c27692cd20169023a7deba58c9 100644 (file)
@@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 import expr_utils
-from .. base.Param import Param as _Param, EntryParam
+from .. base.Param import Param as _Param
+from .. gui.Param import Param as _GUIParam
+from .. gui.Param import EntryParam
 import Constants
 import numpy
 import os
@@ -83,21 +85,24 @@ COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
 REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
 INT_TYPES = tuple(INT_TYPES)
 
-class Param(_Param):
+class Param(_Param, _GUIParam):
 
-       _init = False
-       _hostage_cells = list()
+       def __init__(self, **kwargs):
+               _Param.__init__(self, **kwargs)
+               _GUIParam.__init__(self)
+               self._init = False
+               self._hostage_cells = list()
 
-       ##possible param types
-       TYPES = _Param.TYPES + [
+       def get_types(self): return (
+               'raw', 'enum',
                'complex', 'real', 'int',
                'complex_vector', 'real_vector', 'int_vector',
                'hex', 'string', 'bool',
                'file_open', 'file_save',
-               'id',
+               'id', 'stream_id',
                'grid_pos', 'notebook',
                'import',
-       ]
+       )
 
        def __repr__(self):
                """
@@ -148,9 +153,9 @@ class Param(_Param):
                                dt_str = dt_str[:max_len-3] + '...'
                return dt_str
 
-       def get_input_class(self):
-               if self.get_type() in ('file_open', 'file_save'): return FileParam
-               return _Param.get_input_class(self)
+       def get_input(self, *args, **kwargs):
+               if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs)
+               return _GUIParam.get_input(self, *args, **kwargs)
 
        def get_color(self):
                """
@@ -172,6 +177,7 @@ class Param(_Param):
                                'hex': Constants.INT_COLOR_SPEC,
                                'string': Constants.BYTE_VECTOR_COLOR_SPEC,
                                'id': Constants.ID_COLOR_SPEC,
+                               'stream_id': Constants.ID_COLOR_SPEC,
                                'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
                                'notebook': Constants.INT_VECTOR_COLOR_SPEC,
                                'raw': Constants.WILDCARD_COLOR_SPEC,
@@ -310,14 +316,31 @@ class Param(_Param):
                        #can python use this as a variable?
                        try: assert _check_id_matcher.match(v)
                        except AssertionError: raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
-                       params = self.get_all_params('id')
-                       keys = [param.get_value() for param in params]
-                       try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled
+                       ids = [param.get_value() for param in self.get_all_params(t)]
+                       try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled
                        except: raise Exception, 'ID "%s" is not unique.'%v
                        try: assert v not in ID_BLACKLIST
                        except: raise Exception, 'ID "%s" is blacklisted.'%v
                        return v
                #########################
+               # Stream ID Type
+               #########################
+               elif t == 'stream_id':
+                       #get a list of all stream ids used in the virtual sinks 
+                       ids = [param.get_value() for param in filter(
+                               lambda p: p.get_parent().is_virtual_sink(),
+                               self.get_all_params(t),
+                       )]
+                       #check that the virtual sink's stream id is unique
+                       if self.get_parent().is_virtual_sink():
+                               try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled
+                               except: raise Exception, 'Stream ID "%s" is not unique.'%v
+                       #check that the virtual source's steam id is found
+                       if self.get_parent().is_virtual_source():
+                               try: assert v in ids
+                               except: raise Exception, 'Stream ID "%s" is not found.'%v
+                       return v
+               #########################
                # Grid Position Type
                #########################
                elif t == 'grid_pos':
@@ -380,17 +403,18 @@ class Param(_Param):
        def to_code(self):
                """
                Convert the value to code.
+               For string and list types, check the init flag, call evaluate().
+               This ensures that evaluate() was called to set the xxxify_flags.
                @return a string representing the code
                """
-               #run init tasks in evaluate
-               #such as setting flags
-               if not self._init: self.evaluate()
                v = self.get_value()
                t = self.get_type()
                if t in ('string', 'file_open', 'file_save'): #string types
+                       if not self._init: self.evaluate()
                        if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
                        else: return v
                elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
+                       if not self._init: self.evaluate()
                        if self._lisitify_flag: return '(%s, )'%v
                        else: return '(%s)'%v
                else: return v
index d55dbf4ce71a224fa89fd710a396f466db7c2391..bb56d361b5296406c9186086b05f4f6c39a32837 100644 (file)
@@ -20,10 +20,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 import os
 from gnuradio import gr
 from .. base.Platform import Platform as _Platform
+from .. gui.Platform import Platform as _GUIPlatform
 from FlowGraph import FlowGraph as _FlowGraph
 from Connection import Connection as _Connection
 from Block import Block as _Block
-from Port import Source,Sink
+from Port import Port as _Port
 from Param import Param as _Param
 from Generator import Generator
 from Constants import \
@@ -46,7 +47,7 @@ COLORS = (#title, #color spec
        ('Message', Constants.MSG_COLOR_SPEC),
 )
 
-class Platform(_Platform):
+class Platform(_Platform, _GUIPlatform):
 
        def __init__(self):
                """
@@ -70,6 +71,7 @@ class Platform(_Platform):
                        generator=Generator,
                        colors=COLORS,
                )
+               _GUIPlatform.__init__(self)
 
        ##############################################
        # Constructors
@@ -77,6 +79,5 @@ class Platform(_Platform):
        FlowGraph = _FlowGraph
        Connection = _Connection
        Block = _Block
-       Source = Source
-       Sink = Sink
+       Port = _Port
        Param = _Param
index daf8f9ca34c1f687fffc3e54dac26af3dc35b6e3..6965371df8a9e922dbeb808d78da53bf93c81a59 100644 (file)
@@ -18,41 +18,100 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 from .. base.Port import Port as _Port
+from .. gui.Port import Port as _GUIPort
 import Constants
 
-class Port(_Port):
-
-       ##possible port types
-       TYPES = ['complex', 'float', 'int', 'short', 'byte', 'msg']
-
-       def __init__(self, block, n):
+def _get_source_from_virtual_sink_port(vsp):
+       """
+       Resolve the source port that is connected to the given virtual sink port.
+       Use the get source from virtual source to recursively resolve subsequent ports. 
+       """
+       try: return _get_source_from_virtual_source_port(
+               vsp.get_enabled_connections()[0].get_source())
+       except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
+
+def _get_source_from_virtual_source_port(vsp, traversed=[]):
+       """
+       Recursively resolve source ports over the virtual connections.
+       Keep track of traversed sources to avoid recursive loops.
+       """
+       if not vsp.get_parent().is_virtual_source(): return vsp
+       if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp
+       try: return _get_source_from_virtual_source_port(
+               _get_source_from_virtual_sink_port(
+                       filter(#get all virtual sinks with a matching stream id
+                               lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
+                               filter(#get all enabled blocks that are also virtual sinks
+                                       lambda b: b.is_virtual_sink(),
+                                       vsp.get_parent().get_parent().get_enabled_blocks(),
+                               ),
+                       )[0].get_sinks()[0]
+               ), traversed + [vsp],
+       )
+       except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
+
+class Port(_Port, _GUIPort):
+
+       def __init__(self, block, n, dir):
                """
                Make a new port from nested data.
                @param block the parent element
                @param n the nested odict
+               @param dir the direction
                """
+               self._n = n
+               if n['type'] == 'msg': n['key'] = 'msg'
+               if dir == 'source' and not n.find('key'):
+                       n['key'] = str(block._source_count)
+                       block._source_count += 1
+               if dir == 'sink' and not n.find('key'):
+                       n['key'] = str(block._sink_count)
+                       block._sink_count += 1
                #build the port
                _Port.__init__(
                        self,
                        block=block,
                        n=n,
+                       dir=dir,
                )
+               _GUIPort.__init__(self)
                self._nports = n.find('nports') or ''
                self._vlen = n.find('vlen') or ''
                self._optional = bool(n.find('optional'))
 
+       def get_types(self): return ('complex', 'float', 'int', 'short', 'byte', 'msg', '')
+
        def validate(self):
                _Port.validate(self)
                try: assert self.get_enabled_connections() or self.get_optional()
                except AssertionError: self.add_error_message('Port is not connected.')
                try: assert self.is_source() or len(self.get_enabled_connections()) <= 1
                except AssertionError: self.add_error_message('Port has too many connections.')
+               #message port logic
                if self.get_type() == 'msg':
                        try: assert not self.get_nports()
                        except AssertionError: self.add_error_message('A port of type "msg" cannot have "nports" set.')
                        try: assert self.get_vlen() == 1
                        except AssertionError: self.add_error_message('A port of type "msg" must have a "vlen" of 1.')
 
+       def rewrite(self):
+               """
+               Handle the port cloning for virtual blocks.
+               """
+               _Port.rewrite(self)
+               if self.get_parent().is_virtual_sink() or self.get_parent().is_virtual_source():
+                       try: #clone type and vlen
+                               source = self.resolve_virtual_source()
+                               self._type = str(source.get_type())
+                               self._vlen = str(source.get_vlen())
+                       except: #reset type and vlen
+                               self._type = ''
+                               self._vlen = ''
+
+       def resolve_virtual_source(self):
+               if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self)
+               if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self)
+
        def get_vlen(self):
                """
                Get the vector length.
@@ -109,24 +168,4 @@ class Port(_Port):
        def copy(self, new_key=None):
                n = self._n.copy()
                if new_key: n['key'] = new_key
-               return self.__class__(self.get_parent(), n)
-
-class Source(Port):
-
-       def __init__(self, block, n):
-               self._n = n #save n
-               if n['type'] == 'msg': n['key'] = 'msg'
-               if not n.find('key'):
-                       n['key'] = str(block._source_count)
-                       block._source_count = block._source_count + 1
-               Port.__init__(self, block, n)
-
-class Sink(Port):
-
-       def __init__(self, block, n):
-               self._n = n #save n
-               if n['type'] == 'msg': n['key'] = 'msg'
-               if not n.find('key'):
-                       n['key'] = str(block._sink_count)
-                       block._sink_count = block._sink_count + 1
-               Port.__init__(self, block, n)
+               return self.__class__(self.get_parent(), n, self._dir)
index df346dd165567002a34fcfbcd2787818ef43cbea..dce4037d58a4a9cde77cf99ca7bd10120f81b279 100644 (file)
@@ -154,6 +154,13 @@ class $(class_name)(gr.hier_block2):
 ##     The port name should be the id of the parent block.
 ##     However, port names for IO pads should be self.
 ########################################################
+#def make_port_name($port)
+       #if $port.get_parent().get_key().startswith('pad_')
+self#slurp
+       #else
+self.$port.get_parent().get_id()#slurp
+       #end if
+#end def
 #if $connections
 
                $DIVIDER
@@ -163,17 +170,14 @@ class $(class_name)(gr.hier_block2):
 #for $con in $connections
        #set $source = $con.get_source()
        #set $sink = $con.get_sink()
-       #if $source.get_parent().get_key() == 'pad_source'
-               #set $source_name = 'self'
-       #else
-               #set $source_name = 'self.' + $source.get_parent().get_id()
+       ##resolve virtual sources to the actual sources
+       #if $source.get_parent().is_virtual_source()
+               #set $source = $source.resolve_virtual_source()
        #end if
-       #if $sink.get_parent().get_key() == 'pad_sink'
-               #set $sink_name = 'self'
-       #else
-               #set $sink_name = 'self.' + $sink.get_parent().get_id()
+       ##do not generate connections with virtual sinks
+       #if not $sink.get_parent().is_virtual_sink()
+               self.connect(($make_port_name($source), $source.get_key()), ($make_port_name($sink), $sink.get_key()))
        #end if
-               self.connect(($source_name, $source.get_key()), ($sink_name, $sink.get_key()))
 #end for
 
 ########################################################
@@ -194,6 +198,20 @@ class $(class_name)(gr.hier_block2):
 ##     For top block code, generate a main routine.
 ##     Instantiate the top block and run as gui or cli.
 ########################################################
+#def make_default($type, $param)
+       #if $type == 'eng_float'
+eng_notation.num_to_str($param.get_make())#slurp
+       #else
+$param.get_make()#slurp
+       #end if
+#end def
+#def make_short_id($param)
+       #set $short_id = $param.get_param('short_id').get_evaluated()
+       #if $short_id
+               #set $short_id = '-' + $short_id
+       #end if
+$short_id#slurp
+#end def
 #if $generate_options != 'hb'
 if __name__ == '__main__':
        parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
@@ -202,12 +220,8 @@ if __name__ == '__main__':
                #set $type = $param.get_param('type').get_value()
                #if $type
                        #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
-                       #set $short_id = $param.get_param('short_id').get_evaluated()
-                       #if $short_id
-                               #set $short_id = '-' + $short_id
-                       #end if
-       parser.add_option("$short_id", "--$param.get_id()", dest="$param.get_id()", type="$type", default=$param.get_make(),
-               help="Set $($param.get_param('label').evaluate() or $param.get_id()) [default=%default]")
+       parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
+               help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
                #end if
        #end for
        (options, args) = parser.parse_args()
index 00d4366ddfc2c24fc3d9c0094077b96e6ac3d3e1..38c8f655ce854b350e4f0d3b693b91e325061f85 100755 (executable)
@@ -32,9 +32,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay
 from gnuradio.grc.python.Platform import Platform
 platform = Platform()
 
-from gnuradio.grc.gui.Platform import Platform
-platform = Platform(platform)
-
 flow_graph = platform.get_new_flow_graph()
 block = flow_graph.get_new_block('usrp2_probe')
 
@@ -42,6 +39,11 @@ block = flow_graph.get_new_block('usrp2_probe')
 usrp_interface_param = block.get_param('interface')
 usrp_type_param = block.get_param('type')
 
+def get_input(param):
+       param.validate()
+       input = param.get_input()
+       return input
+
 class USRP2ProbeWindow(gtk.Window):
        """
        The main window for USRP Dignostics.
@@ -69,8 +71,8 @@ class USRP2ProbeWindow(gtk.Window):
                #create vbox for storage
                vbox = gtk.VBox()
                frame.add(vbox)
-               vbox.pack_start(usrp_interface_param.get_input_object(), False)
-               vbox.pack_start(usrp_type_param.get_input_object(), False)
+               vbox.pack_start(get_input(usrp_interface_param), False)
+               vbox.pack_start(get_input(usrp_type_param), False)
                #make the tree model for holding mac addrs
                self.treestore = gtk.TreeStore(gobject.TYPE_STRING)
                self.treeview = gtk.TreeView(self.treestore)
index 6565612c16e87980e5d4e64d2ec6597358827d4b..d2e92e7530ab10dff1b46062ac13840d7209b544 100755 (executable)
@@ -30,9 +30,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay
 from gnuradio.grc.python.Platform import Platform
 platform = Platform()
 
-from gnuradio.grc.gui.Platform import Platform
-platform = Platform(platform)
-
 flow_graph = platform.get_new_flow_graph()
 block = flow_graph.get_new_block('usrp_probe')
 
@@ -40,6 +37,11 @@ block = flow_graph.get_new_block('usrp_probe')
 usrp_which_param = block.get_param('which')
 usrp_dboard_param = block.get_param('dboard')
 
+def get_input(param):
+       param.validate()
+       input = param.get_input()
+       return input
+
 class USRPProbeWindow(gtk.Window):
        """
        The main window for USRP Dignostics.
@@ -66,8 +68,8 @@ class USRPProbeWindow(gtk.Window):
                #create vbox for storage
                vbox = gtk.VBox()
                frame.add(vbox)
-               vbox.pack_start(usrp_which_param.get_input_object(), False)
-               vbox.pack_start(usrp_dboard_param.get_input_object(), False)
+               vbox.pack_start(get_input(usrp_which_param), False)
+               vbox.pack_start(get_input(usrp_dboard_param), False)
                self.probe_button = gtk.Button('Probe')
                self.probe_button.connect('clicked', self._probe_usrp)
                vbox.pack_start(self.probe_button, False)
index bb40e1f160fe4009dec974596cefed2ca38f0284..7fa68e523aae4af0a2ad254a9d42edc83d4f5aae 100644 (file)
@@ -25,8 +25,7 @@
 * size params for the graphical sinks
 * callbacks for set average on fft, waterfall, number sinks
 * add units to params: Sps, Hz, dB...
-* command line options should replace _ with - for the --option
-  * add bool type to command line option store_true or store_false
+* add bool type to command line option store_true or store_false
 
 ##################################################
 # Features
@@ -59,6 +58,8 @@
 ##################################################
 # Problems
 ##################################################
+* msg ports dont work with virtual connections
+  * dont fix this until pmts are used?
 * hier block generation
   * auto generate hier library on changes
   * auto clean hier library when block removed
 * 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
index 89a768d4685c43bdde8e820017ffc185bf80257f..165e179d677f6f00f8f71d3285da72d240113daa 100644 (file)
@@ -2,3 +2,4 @@
 /Makefile.in
 /.libs
 /.deps
+test_gruel
index a8f4684b57244cf0d0ba9cd6cb4e7cba79fb20b2..2d2bfabbb262cb21b16cfd4b5dde51aa0db46e5d 100644 (file)
@@ -668,7 +668,7 @@ _2400_common::freq_min()
 double
 _2400_common::freq_max()
 {
-  return 2700e6;
+  return 2900e6;
 }
 
 //----------------------------------------------------------------------
@@ -700,7 +700,7 @@ _1200_common::freq_min()
 double 
 _1200_common::freq_max()
 {
-  return 1350e6;
+  return 1450e6;
 }
 
 //-------------------------------------------------------------------------
@@ -726,13 +726,13 @@ _1800_common::_1800_common()
 double 
 _1800_common::freq_min()
 {
-  return 1600e6;
+  return 1500e6;
 }
 
 double 
 _1800_common::freq_max()
 {
-  return 2000e6;
+  return 2100e6;
 }
 
 //-------------------------------------------------------------------------
@@ -758,13 +758,13 @@ _900_common::_900_common()
 double
 _900_common::freq_min()
 {
-  return 800e6;
+  return 750e6;
 }
 
 double
 _900_common::freq_max()
 {
-  return 1000e6;
+  return 1050e6;
 }
 
 //-------------------------------------------------------------------------
index 62b2d5bad25873e4ca4e48681c91b4be25e149bd..c75136de1cc16481704b99e1af10da3dbbc12aed 100644 (file)
@@ -22,8 +22,8 @@ include $(top_srcdir)/Makefile.common
 EXTRA_DIST = \
        bootstrap \
        configure \
-       configure.gnu
-
+       configure.gnu \
+       u2_flash_tool
 
 SUBDIRS = config 
 
index 2f950016fb2304e3bef4ef5d779965cf38b2a497..ff12f9e32b1d02eb71612934cb71d96a58c2fff7 100644 (file)
@@ -200,8 +200,8 @@ struct db_rfx_900_rx db_rfx_900_rx = {
   .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),
@@ -231,8 +231,8 @@ struct db_rfx_900_tx db_rfx_900_tx = {
   .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),
@@ -262,7 +262,7 @@ struct db_rfx_1200_rx db_rfx_1200_rx = {
   .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),
@@ -293,7 +293,7 @@ struct db_rfx_1200_tx db_rfx_1200_tx = {
   .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),
@@ -322,8 +322,8 @@ struct db_rfx_1800_rx db_rfx_1800_rx = {
   .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),
@@ -353,8 +353,8 @@ struct db_rfx_1800_tx db_rfx_1800_tx = {
   .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),
@@ -385,7 +385,7 @@ struct db_rfx_2400_rx db_rfx_2400_rx = {
   .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),
@@ -416,7 +416,7 @@ struct db_rfx_2400_tx db_rfx_2400_tx = {
   .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),
index 4b8597c6003a15983d0c12fe3e28e18e68978ca5..bb71f79c27002bfadbecb305c0eae28a54495497 100644 (file)
 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();
   }
   
index 9adc1618f8ce251b270374c4cde9ec5a5cf3cd1c..8769e4522f2e7dcfe38cba6170eef5065c0b1c36 100644 (file)
@@ -118,10 +118,13 @@ namespace usrp2 {
   {
   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:  
     /*!
@@ -140,12 +143,12 @@ namespace usrp2 {
      * 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
index 1ecfd7348e65a5bf79b521591b69f49ff8e725fc..3d030432429c42d270743697840161552f4db43f 100644 (file)
@@ -133,7 +133,7 @@ namespace usrp2 {
       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");
@@ -298,22 +298,35 @@ namespace usrp2 {
     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;
   }
@@ -373,6 +386,10 @@ namespace usrp2 {
       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);
     }
 
@@ -404,7 +421,7 @@ namespace usrp2 {
     
       // 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;
     }
@@ -485,7 +502,7 @@ namespace usrp2 {
     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);
@@ -512,7 +529,7 @@ namespace usrp2 {
     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);
@@ -532,7 +549,7 @@ namespace usrp2 {
     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);
@@ -569,7 +586,7 @@ namespace usrp2 {
     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);
@@ -589,7 +606,7 @@ namespace usrp2 {
     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);
@@ -634,14 +651,18 @@ namespace usrp2 {
       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;
     }
   }
@@ -661,6 +682,9 @@ namespace usrp2 {
       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;
 
@@ -677,9 +701,10 @@ namespace usrp2 {
     
       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;
     }
   }
@@ -732,6 +757,36 @@ namespace usrp2 {
     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
   // ----------------------------------------------------------------
@@ -747,7 +802,7 @@ namespace usrp2 {
     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);
@@ -774,7 +829,7 @@ namespace usrp2 {
     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);
@@ -794,7 +849,7 @@ namespace usrp2 {
     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);
@@ -831,7 +886,7 @@ namespace usrp2 {
     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);
@@ -882,7 +937,7 @@ namespace usrp2 {
     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);
@@ -1010,7 +1065,7 @@ namespace usrp2 {
     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;
@@ -1069,7 +1124,7 @@ namespace usrp2 {
       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);
@@ -1108,7 +1163,7 @@ namespace usrp2 {
     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);
@@ -1135,7 +1190,7 @@ namespace usrp2 {
     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;
@@ -1157,7 +1212,7 @@ namespace usrp2 {
     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;
@@ -1197,7 +1252,7 @@ namespace usrp2 {
 
     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++)
@@ -1264,7 +1319,7 @@ namespace usrp2 {
     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);
@@ -1286,7 +1341,7 @@ namespace usrp2 {
     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);
@@ -1315,7 +1370,7 @@ namespace usrp2 {
     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);
@@ -1348,7 +1403,7 @@ namespace usrp2 {
     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);
@@ -1377,7 +1432,7 @@ namespace usrp2 {
     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);
@@ -1406,7 +1461,7 @@ namespace usrp2 {
     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);
@@ -1443,7 +1498,7 @@ namespace usrp2 {
     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);
index ec96f3a7095d8692c0c9c8ec4ff73d33072d227c..ed71a6ba33903c09589b342ea75cdccb8c1fcf34 100644 (file)
@@ -87,6 +87,8 @@ namespace usrp2 {
     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++;
@@ -105,7 +107,8 @@ namespace usrp2 {
     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);
@@ -141,6 +144,7 @@ namespace usrp2 {
     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; }