summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/grc_gr_uhd.m446
-rw-r--r--configure.ac8
-rw-r--r--docs/doxygen/Doxyfile.in6
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am15
-rw-r--r--gnuradio-core/src/lib/general/general.i6
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_1to1.cc107
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_1to1.h74
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_1to1.i36
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_alltoall.cc110
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_alltoall.h75
-rw-r--r--gnuradio-core/src/lib/general/gr_annotator_alltoall.i36
-rw-r--r--gnuradio-core/src/lib/general/gr_burst_tagger.cc83
-rw-r--r--gnuradio-core/src/lib/general/gr_burst_tagger.h56
-rw-r--r--gnuradio-core/src/lib/general/gr_burst_tagger.i31
-rw-r--r--gnuradio-core/src/lib/general/gr_keep_one_in_n.cc5
-rw-r--r--gnuradio-core/src/lib/io/Makefile.am9
-rw-r--r--gnuradio-core/src/lib/io/gr_tagged_file_sink.cc212
-rw-r--r--gnuradio-core/src/lib/io/gr_tagged_file_sink.h70
-rw-r--r--gnuradio-core/src/lib/io/gr_tagged_file_sink.i35
-rw-r--r--gnuradio-core/src/lib/io/io.i3
-rw-r--r--gnuradio-core/src/lib/runtime/Makefile.am8
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.cc68
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.h85
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block.i5
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_detail.cc92
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_detail.h73
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.cc87
-rw-r--r--gnuradio-core/src/lib/runtime/gr_block_executor.h3
-rw-r--r--gnuradio-core/src/lib/runtime/gr_buffer.cc71
-rw-r--r--gnuradio-core/src/lib/runtime/gr_buffer.h50
-rw-r--r--gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc7
-rw-r--r--gnuradio-core/src/lib/runtime/gr_tag_info.cc38
-rw-r--r--gnuradio-core/src/lib/runtime/gr_tag_info.h87
-rw-r--r--gnuradio-core/src/lib/runtime/qa_block_tags.cc450
-rw-r--r--gnuradio-core/src/lib/runtime/qa_block_tags.h52
-rw-r--r--gnuradio-core/src/lib/runtime/qa_runtime.cc2
-rwxr-xr-xgnuradio-examples/python/tags/test_file_tags.py29
-rwxr-xr-xgnuradio-examples/python/tags/uhd_burst_detector.py98
-rw-r--r--gr-howto-write-a-block/version.sh4
-rw-r--r--gr-uhd/.gitignore2
-rw-r--r--gr-uhd/Makefile.am29
-rw-r--r--gr-uhd/apps/.gitignore2
-rw-r--r--gr-uhd/apps/Makefile.am22
-rw-r--r--gr-uhd/grc/.gitignore4
-rw-r--r--gr-uhd/grc/Makefile.am55
-rwxr-xr-xgr-uhd/grc/gen_uhd_multi_usrp_blocks_xml.py293
-rwxr-xr-xgr-uhd/grc/gen_uhd_single_usrp_blocks_xml.py269
-rw-r--r--gr-uhd/grc/uhd_block_tree.xml16
-rw-r--r--gr-uhd/lib/.gitignore2
-rw-r--r--gr-uhd/lib/Makefile.am49
-rw-r--r--gr-uhd/lib/uhd_multi_usrp_sink.cc188
-rw-r--r--gr-uhd/lib/uhd_multi_usrp_sink.h175
-rw-r--r--gr-uhd/lib/uhd_multi_usrp_source.cc187
-rw-r--r--gr-uhd/lib/uhd_multi_usrp_source.h175
-rw-r--r--gr-uhd/lib/uhd_single_usrp_sink.cc183
-rw-r--r--gr-uhd/lib/uhd_single_usrp_sink.h173
-rw-r--r--gr-uhd/lib/uhd_single_usrp_source.cc182
-rw-r--r--gr-uhd/lib/uhd_single_usrp_source.h177
-rw-r--r--gr-uhd/swig/.gitignore4
-rw-r--r--gr-uhd/swig/Makefile.am65
-rw-r--r--gr-uhd/swig/Makefile.swig.gen259
-rw-r--r--gr-uhd/swig/__init__.py40
-rw-r--r--gr-uhd/swig/uhd_swig.i106
-rwxr-xr-xgr-utils/src/python/gr_plot_psd.py17
-rw-r--r--grc/base/Param.py2
-rw-r--r--grc/python/Generator.py2
-rw-r--r--usrp/host/include/usrp/usrp_basic.h2
-rw-r--r--version.sh6
-rw-r--r--vrt/README10
69 files changed, 4976 insertions, 52 deletions
diff --git a/config/grc_gr_uhd.m4 b/config/grc_gr_uhd.m4
new file mode 100644
index 0000000000..00892867dd
--- /dev/null
+++ b/config/grc_gr_uhd.m4
@@ -0,0 +1,46 @@
+dnl Copyright 2010 Free Software Foundation, Inc.
+dnl
+dnl This file is part of GNU Radio
+dnl
+dnl GNU Radio is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl GNU Radio is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Radio; see the file COPYING. If not, write to
+dnl the Free Software Foundation, Inc., 51 Franklin Street,
+dnl Boston, MA 02110-1301, USA.
+
+AC_DEFUN([GRC_GR_UHD],[
+ GRC_ENABLE(gr-uhd)
+
+ dnl Dont do gr-uhd if gnuradio-core skipped
+ GRC_CHECK_DEPENDENCY(gr-uhd, gnuradio-core)
+
+ if test $passed = yes; then
+ dnl Don't do gr-uhd if the 'uhd' package is not installed
+ PKG_CHECK_MODULES(
+ [UHD], [uhd >= 1.0.0 uhd < 2.0.0], [],
+ [passed=no; AC_MSG_RESULT([gr-uhd requires libuhd 1.x.x])]
+ )
+ UHD_CPPFLAGS="${UHD_CPPFLAGS} -I\${abs_top_srcdir}/gr-uhd/lib"
+ AC_SUBST(UHD_CPPFLAGS)
+ AC_SUBST(UHD_LIBS)
+ fi
+
+ AC_CONFIG_FILES([ \
+ gr-uhd/Makefile \
+ gr-uhd/apps/Makefile \
+ gr-uhd/grc/Makefile \
+ gr-uhd/lib/Makefile \
+ gr-uhd/swig/Makefile \
+ ])
+
+ GRC_BUILD_CONDITIONAL(gr-uhd)
+])
diff --git a/configure.ac b/configure.ac
index 19d1931721..91bbe755a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,13 @@ dnl Boston, MA 02110-1301, USA.
AC_INIT
AC_PREREQ(2.57)
+
+dnl Set the prefix to the default when --prefix is not specified.
+dnl This is critical for variable substitutions in the configure.
+if test "${prefix}" = "NONE"; then
+ prefix=${ac_default_prefix}
+fi
+
AM_CONFIG_HEADER(config.h)
AC_CONFIG_SRCDIR([gnuradio-core/src/lib/runtime/gr_vmcircbuf.cc])
@@ -367,6 +374,7 @@ GRC_GR_SOUNDER dnl this must come after GRC_USRP
GRC_GR_UTILS dnl this must come after GRC_GR_WXGUI
GRC_GNURADIO_EXAMPLES dnl must come after all GRC_GR_*
GRC_GRC
+GRC_GR_UHD
GRC_DOCS dnl must be last
# Each component is now either to be built, was skipped, will be
diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in
index 243fa00bfd..f12dd61b76 100644
--- a/docs/doxygen/Doxyfile.in
+++ b/docs/doxygen/Doxyfile.in
@@ -587,7 +587,7 @@ EXCLUDE = @abs_top_builddir@/docs/doxygen/html \
@abs_top_builddir@/docs/doxygen/xml-swig \
@abs_top_builddir@/docs/doxygen/other/doxypy.py \
@abs_top_builddir@/dtools \
- @abs_top_builddir@/gcell/ibm \
+ @abs_top_srcdir@/gcell/ibm \
@abs_top_builddir@/gnuradio-core/src/lib/bug_work_around_6.cc \
@abs_top_builddir@/gnuradio-core/src/lib/filter/assembly.h \
@abs_top_builddir@/gnuradio-core/src/lib/filter/generate_all.py \
@@ -666,7 +666,9 @@ EXCLUDE = @abs_top_builddir@/docs/doxygen/html \
@abs_top_builddir@/usrp/host/misc \
@abs_top_builddir@/usrp/host/swig \
@abs_top_builddir@/usrp2/firmware \
- @abs_top_builddir@/usrp2/fpga
+ @abs_top_srcdir@/usrp2/firmware \
+ @abs_top_builddir@/usrp2/fpga \
+ @abs_top_srcdir@/usrp2/fpga
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index 3d8a42805c..0e9109d6c7 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -175,7 +175,10 @@ libgeneral_la_SOURCES = \
gr_descrambler_bb.cc \
gr_scrambler_bb.cc \
gr_probe_mpsk_snr_c.cc \
- gr_probe_density_b.cc
+ gr_probe_density_b.cc \
+ gr_annotator_alltoall.cc \
+ gr_annotator_1to1.cc \
+ gr_burst_tagger.cc
libgeneral_qa_la_SOURCES = \
qa_general.cc \
@@ -344,7 +347,10 @@ grinclude_HEADERS = \
gr_descrambler_bb.h \
gr_scrambler_bb.h \
gr_probe_mpsk_snr_c.h \
- gr_probe_density_b.h
+ gr_probe_density_b.h \
+ gr_annotator_alltoall.h \
+ gr_annotator_1to1.h \
+ gr_burst_tagger.h
noinst_HEADERS = \
qa_general.h \
@@ -484,5 +490,8 @@ swiginclude_HEADERS = \
gr_descrambler_bb.i \
gr_scrambler_bb.i \
gr_probe_mpsk_snr_c.i \
- gr_probe_density_b.i
+ gr_probe_density_b.i \
+ gr_annotator_alltoall.i \
+ gr_annotator_1to1.i \
+ gr_burst_tagger.i
endif
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index 68cafce2e6..0f8b57a44b 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -141,6 +141,9 @@
#include <gr_copy.h>
#include <gr_fll_band_edge_cc.h>
#include <gr_additive_scrambler_bb.h>
+#include <gr_annotator_alltoall.h>
+#include <gr_annotator_1to1.h>
+#include <gr_burst_tagger.h>
%}
%include "gr_nop.i"
@@ -262,3 +265,6 @@
%include "gr_copy.i"
%include "gr_fll_band_edge_cc.i"
%include "gr_additive_scrambler_bb.i"
+%include "gr_annotator_alltoall.i"
+%include "gr_annotator_1to1.i"
+%include "gr_burst_tagger.i"
diff --git a/gnuradio-core/src/lib/general/gr_annotator_1to1.cc b/gnuradio-core/src/lib/general/gr_annotator_1to1.cc
new file mode 100644
index 0000000000..511b356e56
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_1to1.cc
@@ -0,0 +1,107 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gr_annotator_1to1.h>
+#include <gr_io_signature.h>
+#include <string.h>
+#include <iostream>
+#include <iomanip>
+
+gr_annotator_1to1_sptr
+gr_make_annotator_1to1 (int when, size_t sizeof_stream_item)
+{
+ return gnuradio::get_initial_sptr (new gr_annotator_1to1
+ (when, sizeof_stream_item));
+}
+
+gr_annotator_1to1::gr_annotator_1to1 (int when, size_t sizeof_stream_item)
+ : gr_sync_block ("annotator_1to1",
+ gr_make_io_signature (1, -1, sizeof_stream_item),
+ gr_make_io_signature (1, -1, sizeof_stream_item)),
+ d_itemsize(sizeof_stream_item), d_when((uint64_t)when)
+{
+ set_tag_propagation_policy(TPP_ONE_TO_ONE);
+
+ d_tag_counter = 0;
+ set_relative_rate(1.0);
+}
+
+gr_annotator_1to1::~gr_annotator_1to1 ()
+{
+}
+
+int
+gr_annotator_1to1::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float*)input_items[0];
+ float *out = (float*)output_items[0];
+
+ std::stringstream str;
+ str << name() << unique_id();
+
+ uint64_t abs_N = 0;
+ int ninputs = input_items.size();
+ for(int i = 0; i < ninputs; i++) {
+ abs_N = nitems_read(i);
+
+ std::vector<pmt::pmt_t> all_tags;
+ get_tags_in_range(all_tags, i, abs_N, abs_N + noutput_items);
+
+ std::vector<pmt::pmt_t>::iterator itr;
+ for(itr = all_tags.begin(); itr != all_tags.end(); itr++) {
+ d_stored_tags.push_back(*itr);
+ }
+ }
+
+ // Storing the current noutput_items as the value to the "noutput_items" key
+ pmt::pmt_t srcid = pmt::pmt_string_to_symbol(str.str());
+ pmt::pmt_t key = pmt::pmt_string_to_symbol("seq");
+
+ // Work does nothing to the data stream; just copy all inputs to outputs
+ // Adds a new tag when the number of items read is a multiple of d_when
+ abs_N = nitems_read(0);
+ int noutputs = output_items.size();
+ for(int j = 0; j < noutput_items; j++) {
+ // the min() is a hack to make sure this doesn't segfault if there are a
+ // different number of ins and outs. This is specifically designed to test
+ // the 1-to-1 propagation policy.
+ for(int i = 0; i < std::min(noutputs, ninputs); i++) {
+ if(abs_N % d_when == 0) {
+ pmt::pmt_t value = pmt::pmt_from_uint64(d_tag_counter++);
+ add_item_tag(i, abs_N, key, value, srcid);
+ }
+
+ in = (const float*)input_items[i];
+ out = (float*)output_items[i];
+ out[j] = in[j];
+ }
+ abs_N++;
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/general/gr_annotator_1to1.h b/gnuradio-core/src/lib/general/gr_annotator_1to1.h
new file mode 100644
index 0000000000..4abc5b0516
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_1to1.h
@@ -0,0 +1,74 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_ANNOTATOR_1TO1_H
+#define INCLUDED_GR_ANNOTATOR_1TO1_H
+
+#include <gr_sync_block.h>
+
+class gr_annotator_1to1;
+typedef boost::shared_ptr<gr_annotator_1to1> gr_annotator_1to1_sptr;
+
+// public constructor
+gr_annotator_1to1_sptr
+gr_make_annotator_1to1 (int when, size_t sizeof_stream_item);
+
+/*!
+ * \brief 1-to-1 stream annotator testing block. FOR TESTING PURPOSES ONLY.
+ *
+ * This block creates tags to be sent downstream every 10,000 items it sees. The
+ * tags contain the name and ID of the instantiated block, use "seq" as a key,
+ * and have a counter that increments by 1 for every tag produced that is used
+ * as the tag's value. The tags are propagated using the 1-to-1 policy.
+ *
+ * It also stores a copy of all tags it sees flow past it. These tags can be
+ * recalled externally with the data() member.
+ *
+ * This block is only meant for testing and showing how to use the tags.
+ */
+class gr_annotator_1to1 : public gr_sync_block
+{
+ public:
+ ~gr_annotator_1to1 ();
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ std::vector<pmt::pmt_t> data() const
+ {
+ return d_stored_tags;
+ }
+
+protected:
+ gr_annotator_1to1 (int when, size_t sizeof_stream_item);
+
+ private:
+ size_t d_itemsize;
+ uint64_t d_when;
+ uint64_t d_tag_counter;
+ std::vector<pmt::pmt_t> d_stored_tags;
+
+ friend gr_annotator_1to1_sptr
+ gr_make_annotator_1to1 (int when, size_t sizeof_stream_item);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_annotator_1to1.i b/gnuradio-core/src/lib/general/gr_annotator_1to1.i
new file mode 100644
index 0000000000..f29ecbf536
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_1to1.i
@@ -0,0 +1,36 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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,annotator_1to1);
+
+gr_annotator_1to1_sptr gr_make_annotator_1to1 (int when,
+ size_t sizeof_stream_item);
+
+class gr_annotator_1to1 : public gr_sync_block
+{
+public:
+ std::vector<pmt::pmt_t> data() const;
+
+private:
+ gr_annotator_1to1 (int when, size_t sizeof_stream_item);
+};
+
diff --git a/gnuradio-core/src/lib/general/gr_annotator_alltoall.cc b/gnuradio-core/src/lib/general/gr_annotator_alltoall.cc
new file mode 100644
index 0000000000..344fd088b8
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_alltoall.cc
@@ -0,0 +1,110 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gr_annotator_alltoall.h>
+#include <gr_io_signature.h>
+#include <string.h>
+#include <iostream>
+#include <iomanip>
+
+gr_annotator_alltoall_sptr
+gr_make_annotator_alltoall (int when, size_t sizeof_stream_item)
+{
+ return gnuradio::get_initial_sptr (new gr_annotator_alltoall
+ (when, sizeof_stream_item));
+}
+
+gr_annotator_alltoall::gr_annotator_alltoall (int when,
+ size_t sizeof_stream_item)
+ : gr_sync_block ("annotator_alltoall",
+ gr_make_io_signature (1, -1, sizeof_stream_item),
+ gr_make_io_signature (1, -1, sizeof_stream_item)),
+ d_itemsize(sizeof_stream_item), d_when((uint64_t)when)
+{
+ set_tag_propagation_policy(TPP_ALL_TO_ALL);
+
+ d_tag_counter = 0;
+}
+
+gr_annotator_alltoall::~gr_annotator_alltoall ()
+{
+}
+
+int
+gr_annotator_alltoall::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ float *out = (float *) output_items[0];
+
+ std::stringstream str;
+ str << name() << unique_id();
+
+ uint64_t abs_N = 0, end_N;
+ int ninputs = input_items.size();
+ for(int i = 0; i < ninputs; i++) {
+ abs_N = nitems_read(i);
+ end_N = abs_N + (uint64_t)(noutput_items);
+
+ std::vector<pmt::pmt_t> all_tags;
+ get_tags_in_range(all_tags, i, abs_N, end_N);
+
+ std::vector<pmt::pmt_t>::iterator itr;
+ for(itr = all_tags.begin(); itr != all_tags.end(); itr++) {
+ d_stored_tags.push_back(*itr);
+ }
+ }
+
+ // Source ID and key for any tag that might get applied from this block
+ pmt::pmt_t srcid = pmt::pmt_string_to_symbol(str.str());
+ pmt::pmt_t key = pmt::pmt_string_to_symbol("seq");
+
+ // Work does nothing to the data stream; just copy all inputs to outputs
+ // Adds a new tag when the number of items read is a multiple of d_when
+ abs_N = nitems_written(0);
+ int noutputs = output_items.size();
+
+ for(int j = 0; j < noutput_items; j++) {
+ for(int i = 0; i < noutputs; i++) {
+ if(abs_N % d_when == 0) {
+ pmt::pmt_t value = pmt::pmt_from_uint64(d_tag_counter++);
+ add_item_tag(i, abs_N, key, value, srcid);
+ }
+
+ // Sum all of the inputs together for each output. Just 'cause.
+ out = (float*)output_items[i];
+ out[j] = 0;
+ for(int ins = 0; ins < ninputs; ins++) {
+ in = (const float*)input_items[ins];
+ out[j] += in[j];
+ }
+ }
+ abs_N++;
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/general/gr_annotator_alltoall.h b/gnuradio-core/src/lib/general/gr_annotator_alltoall.h
new file mode 100644
index 0000000000..e1e51ebf37
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_alltoall.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_ANNOTATOR_ALLTOALL_H
+#define INCLUDED_GR_ANNOTATOR_ALLTOALL_H
+
+#include <gr_sync_block.h>
+
+class gr_annotator_alltoall;
+typedef boost::shared_ptr<gr_annotator_alltoall> gr_annotator_alltoall_sptr;
+
+// public constructor
+gr_annotator_alltoall_sptr
+gr_make_annotator_alltoall (int when, size_t sizeof_stream_item);
+
+/*!
+ * \brief All-to-all stream annotator testing block. FOR TESTING PURPOSES ONLY.
+ *
+ * This block creates tags to be sent downstream every 10,000 items it sees. The
+ * tags contain the name and ID of the instantiated block, use "seq" as a key,
+ * and have a counter that increments by 1 for every tag produced that is used
+ * as the tag's value. The tags are propagated using the all-to-all policy.
+ *
+ * It also stores a copy of all tags it sees flow past it. These tags can be
+ * recalled externally with the data() member.
+ *
+ * This block is only meant for testing and showing how to use the tags.
+ */
+class gr_annotator_alltoall : public gr_sync_block
+{
+ public:
+ ~gr_annotator_alltoall ();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ std::vector<pmt::pmt_t> data() const
+ {
+ return d_stored_tags;
+ }
+
+protected:
+ gr_annotator_alltoall (int when, size_t sizeof_stream_item);
+
+ private:
+ size_t d_itemsize;
+ uint64_t d_when;
+ uint64_t d_tag_counter;
+ std::vector<pmt::pmt_t> d_stored_tags;
+
+ friend gr_annotator_alltoall_sptr
+ gr_make_annotator_alltoall (int when, size_t sizeof_stream_item);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_annotator_alltoall.i b/gnuradio-core/src/lib/general/gr_annotator_alltoall.i
new file mode 100644
index 0000000000..f9bf6dd9ae
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_annotator_alltoall.i
@@ -0,0 +1,36 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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,annotator_alltoall);
+
+gr_annotator_alltoall_sptr gr_make_annotator_alltoall (int when,
+ size_t sizeof_stream_item);
+
+class gr_annotator_alltoall : public gr_sync_block
+{
+public:
+ std::vector<pmt::pmt_t> data() const;
+
+private:
+ gr_annotator_alltoall (int when, size_t sizeof_stream_item);
+};
+
diff --git a/gnuradio-core/src/lib/general/gr_burst_tagger.cc b/gnuradio-core/src/lib/general/gr_burst_tagger.cc
new file mode 100644
index 0000000000..4b3847b084
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_burst_tagger.cc
@@ -0,0 +1,83 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gr_burst_tagger.h>
+#include <gr_io_signature.h>
+#include <string.h>
+
+gr_burst_tagger_sptr
+gr_make_burst_tagger(size_t itemsize)
+{
+ return gnuradio::get_initial_sptr(new gr_burst_tagger(itemsize));
+}
+
+gr_burst_tagger::gr_burst_tagger(size_t itemsize)
+ : gr_sync_block ("burst_tagger",
+ gr_make_io_signature2 (2, 2, itemsize, sizeof(short)),
+ gr_make_io_signature (1, 1, itemsize)),
+ d_itemsize(itemsize), d_state(false)
+{
+ std::stringstream str;
+ str << name() << unique_id();
+
+ d_key = pmt::pmt_string_to_symbol("burst");
+ d_id = pmt::pmt_string_to_symbol(str.str());
+}
+
+gr_burst_tagger::~gr_burst_tagger()
+{
+}
+
+int
+gr_burst_tagger::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const char *signal = (const char*)input_items[0];
+ const short *trigger = (const short*)input_items[1];
+ char *out = (char*)output_items[0];
+
+ memcpy(out, signal, noutput_items * d_itemsize);
+
+ for(int i = 0; i < noutput_items; i++) {
+ if(trigger[i] > 0) {
+ if(d_state == false) {
+ d_state = true;
+ pmt::pmt_t value = pmt::PMT_T;
+ add_item_tag(0, nitems_written(0)+i, d_key, value, d_id);
+ }
+ }
+ else {
+ if(d_state == true) {
+ d_state = false;
+ pmt::pmt_t value = pmt::PMT_F;
+ add_item_tag(0, nitems_written(0)+i, d_key, value, d_id);
+ }
+ }
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/general/gr_burst_tagger.h b/gnuradio-core/src/lib/general/gr_burst_tagger.h
new file mode 100644
index 0000000000..8f814bea09
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_burst_tagger.h
@@ -0,0 +1,56 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_BURST_TAGGER_H
+#define INCLUDED_GR_BURST_TAGGER_H
+
+#include <gr_sync_block.h>
+
+class gr_burst_tagger;
+typedef boost::shared_ptr<gr_burst_tagger> gr_burst_tagger_sptr;
+
+gr_burst_tagger_sptr gr_make_burst_tagger(size_t itemsize);
+
+/*!
+ * \brief output[i] = input[i]
+ * \ingroup misc_blk
+ *
+ */
+class gr_burst_tagger : public gr_sync_block
+{
+ size_t d_itemsize;
+ bool d_state;
+ pmt::pmt_t d_key;
+ pmt::pmt_t d_id;
+
+ friend gr_burst_tagger_sptr gr_make_burst_tagger(size_t itemsize);
+ gr_burst_tagger(size_t itemsize);
+
+ public:
+ ~gr_burst_tagger();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_burst_tagger.i b/gnuradio-core/src/lib/general/gr_burst_tagger.i
new file mode 100644
index 0000000000..ebf1eea8c7
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_burst_tagger.i
@@ -0,0 +1,31 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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,burst_tagger)
+
+gr_burst_tagger_sptr gr_make_burst_tagger(size_t itemsize);
+
+class gr_burst_tagger : public gr_sync_block
+{
+ private:
+ gr_burst_tagger(size_t itemsize);
+};
diff --git a/gnuradio-core/src/lib/general/gr_keep_one_in_n.cc b/gnuradio-core/src/lib/general/gr_keep_one_in_n.cc
index c07e177fe2..85495e2775 100644
--- a/gnuradio-core/src/lib/general/gr_keep_one_in_n.cc
+++ b/gnuradio-core/src/lib/general/gr_keep_one_in_n.cc
@@ -38,8 +38,9 @@ gr_keep_one_in_n::gr_keep_one_in_n (size_t item_size, int n)
: gr_block ("keep_one_in_n",
gr_make_io_signature (1, 1, item_size),
gr_make_io_signature (1, 1, item_size)),
- d_n (n), d_count(n)
+ d_count(n)
{
+ set_n(n);
}
void
@@ -50,6 +51,8 @@ gr_keep_one_in_n::set_n(int n)
d_n = n;
d_count = n;
+
+ set_relative_rate(1.0 / (float)n);
}
int
diff --git a/gnuradio-core/src/lib/io/Makefile.am b/gnuradio-core/src/lib/io/Makefile.am
index c525546457..8ce740afd0 100644
--- a/gnuradio-core/src/lib/io/Makefile.am
+++ b/gnuradio-core/src/lib/io/Makefile.am
@@ -56,7 +56,8 @@ libio_la_SOURCES = \
gr_udp_source.cc \
gr_wavfile_sink.cc \
gr_wavfile_source.cc \
- gri_wavfile.cc
+ gri_wavfile.cc \
+ gr_tagged_file_sink.cc
grinclude_HEADERS = \
gr_file_sink.h \
@@ -89,7 +90,8 @@ grinclude_HEADERS = \
gr_udp_source.h \
gr_wavfile_source.h \
gr_wavfile_sink.h \
- gri_wavfile.h
+ gri_wavfile.h \
+ gr_tagged_file_sink.h
if PYTHON
swiginclude_HEADERS = \
@@ -111,5 +113,6 @@ swiginclude_HEADERS = \
gr_udp_sink.i \
gr_udp_source.i \
gr_wavfile_source.i \
- gr_wavfile_sink.i
+ gr_wavfile_sink.i \
+ gr_tagged_file_sink.i
endif
diff --git a/gnuradio-core/src/lib/io/gr_tagged_file_sink.cc b/gnuradio-core/src/lib/io/gr_tagged_file_sink.cc
new file mode 100644
index 0000000000..c76ede5429
--- /dev/null
+++ b/gnuradio-core/src/lib/io/gr_tagged_file_sink.cc
@@ -0,0 +1,212 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gr_tagged_file_sink.h>
+#include <gr_io_signature.h>
+#include <cstdio>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdexcept>
+#include <iostream>
+#include <gr_tag_info.h>
+
+#ifdef O_BINARY
+#define OUR_O_BINARY O_BINARY
+#else
+#define OUR_O_BINARY 0
+#endif
+
+// should be handled via configure
+#ifdef O_LARGEFILE
+#define OUR_O_LARGEFILE O_LARGEFILE
+#else
+#define OUR_O_LARGEFILE 0
+#endif
+
+
+gr_tagged_file_sink::gr_tagged_file_sink (size_t itemsize, double samp_rate)
+ : gr_sync_block ("tagged_file_sink",
+ gr_make_io_signature (1, 1, itemsize),
+ gr_make_io_signature (0, 0, 0)),
+ d_itemsize (itemsize), d_n(0), d_sample_rate(samp_rate)
+{
+ d_state = NOT_IN_BURST;
+ d_last_N = 0;
+ d_timeval = 0;
+}
+
+gr_tagged_file_sink_sptr
+gr_make_tagged_file_sink (size_t itemsize, double samp_rate)
+{
+ return gnuradio::get_initial_sptr(new gr_tagged_file_sink (itemsize, samp_rate));
+}
+
+gr_tagged_file_sink::~gr_tagged_file_sink ()
+{
+}
+
+int
+gr_tagged_file_sink::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ char *inbuf = (char *) input_items[0];
+
+ uint64_t start_N = nitems_read(0);
+ uint64_t end_N = start_N + (uint64_t)(noutput_items);
+ pmt::pmt_t bkey = pmt::pmt_string_to_symbol("burst");
+ //pmt::pmt_t tkey = pmt::pmt_string_to_symbol("time"); // use gr_tags::key_time
+
+ std::vector<pmt::pmt_t> all_tags;
+ get_tags_in_range(all_tags, 0, start_N, end_N);
+
+ std::sort(all_tags.begin(), all_tags.end(), gr_tags::nitems_compare);
+
+ std::vector<pmt::pmt_t>::iterator vitr = all_tags.begin();
+
+ int idx = 0, idx_stop = 0;
+ while(idx < noutput_items) {
+ if(d_state == NOT_IN_BURST) {
+ while(vitr != all_tags.end()) {
+ if((pmt::pmt_eqv(gr_tags::get_key(*vitr), bkey)) &&
+ pmt::pmt_is_true(gr_tags::get_value(*vitr))) {
+
+ uint64_t N = gr_tags::get_nitems(*vitr);
+ idx = (int)(N - start_N);
+
+ //std::cout << std::endl << "Found start of burst: "
+ // << idx << ", " << N << std::endl;
+
+ // Find time burst occurred by getting latest time tag and extrapolating
+ // to new time based on sample rate of this block.
+ std::vector<pmt::pmt_t> time_tags;
+ //get_tags_in_range(time_tags, 0, d_last_N, N, gr_tags::key_time);
+ get_tags_in_range(time_tags, 0, d_last_N, N,
+ pmt::pmt_string_to_symbol("time"));
+ if(time_tags.size() > 0) {
+ pmt::pmt_t tag = time_tags[time_tags.size()-1];
+
+ uint64_t time_nitems = gr_tags::get_nitems(tag);
+
+ // Get time based on last time tag from USRP
+ pmt::pmt_t time = gr_tags::get_value(tag);
+ int tsecs = pmt::pmt_to_long(pmt::pmt_tuple_ref(time, 0));
+ double tfrac = pmt::pmt_to_double(pmt::pmt_tuple_ref(time, 1));
+
+ // Get new time from last time tag + difference in time to when
+ // burst tag occured based on the sample rate
+ double delta = (double)(N - time_nitems) / d_sample_rate;
+ d_timeval = (double)tsecs + tfrac + delta;
+
+ //std::cout.setf(std::ios::fixed, std::ios::floatfield);
+ //std::cout.precision(8);
+ //std::cout << "Time found: " << (double)tsecs + tfrac << std::endl;
+ //std::cout << " time: " << d_timeval << std::endl;
+ //std::cout << " time at N = " << time_nitems << " burst N = " << N << std::endl;
+ }
+ else {
+ // if no time tag, use last seen tag and update time based on
+ // sample rate of the block
+ d_timeval += (double)(N - d_last_N) / d_sample_rate;
+ //std::cout << "Time not found" << std::endl;
+ //std::cout << " time: " << d_timeval << std::endl;
+ }
+ d_last_N = N;
+
+ std::stringstream filename;
+ filename.setf(std::ios::fixed, std::ios::floatfield);
+ filename.precision(8);
+ filename << "file" << d_n << "_" << d_timeval << ".dat";
+ d_n++;
+
+ int fd;
+ if ((fd = ::open (filename.str().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC|OUR_O_LARGEFILE|OUR_O_BINARY,
+ 0664)) < 0){
+ perror (filename.str().c_str());
+ return -1;
+ }
+
+ // FIXME:
+ //if ((d_handle = fdopen (fd, d_is_binary ? "wb" : "w")) == NULL){
+ if ((d_handle = fdopen (fd, "wb")) == NULL){
+ perror (filename.str().c_str());
+ ::close(fd); // don't leak file descriptor if fdopen fails.
+ }
+
+ //std::cout << "Created new file: " << filename.str() << std::endl;
+
+ d_state = IN_BURST;
+ break;
+ }
+
+ vitr++;
+ }
+ if(d_state == NOT_IN_BURST)
+ return noutput_items;
+ }
+ else { // In burst
+ while(vitr != all_tags.end()) {
+ if((pmt::pmt_eqv(gr_tags::get_key(*vitr), bkey)) &&
+ pmt::pmt_is_false(gr_tags::get_value(*vitr))) {
+ uint64_t N = gr_tags::get_nitems(*vitr);
+ idx_stop = (int)N - start_N;
+
+ //std::cout << "Found end of burst: "
+ // << idx_stop << ", " << N << std::endl;
+
+ int count = fwrite (&inbuf[d_itemsize*idx], d_itemsize, idx_stop-idx, d_handle);
+ if (count == 0) {
+ if(ferror(d_handle)) {
+ perror("gr_tagged_file_sink: error writing file");
+ }
+ }
+ idx = idx_stop;
+ d_state = NOT_IN_BURST;
+ vitr++;
+ fclose(d_handle);
+ break;
+ }
+ else {
+ vitr++;
+ }
+ }
+ if(d_state == IN_BURST) {
+ int count = fwrite (&inbuf[idx], d_itemsize, noutput_items-idx, d_handle);
+ if (count == 0) {
+ if(ferror(d_handle)) {
+ perror("gr_tagged_file_sink: error writing file");
+ }
+ }
+ idx = noutput_items;
+ }
+ }
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/io/gr_tagged_file_sink.h b/gnuradio-core/src/lib/io/gr_tagged_file_sink.h
new file mode 100644
index 0000000000..956340f8db
--- /dev/null
+++ b/gnuradio-core/src/lib/io/gr_tagged_file_sink.h
@@ -0,0 +1,70 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_TAGGED_FILE_SINK_H
+#define INCLUDED_GR_TAGGED_FILE_SINK_H
+
+#include <gr_sync_block.h>
+
+class gr_tagged_file_sink;
+typedef boost::shared_ptr<gr_tagged_file_sink> gr_tagged_file_sink_sptr;
+
+gr_tagged_file_sink_sptr gr_make_tagged_file_sink (size_t itemsize,
+ double samp_rate);
+
+/*!
+ * \brief Write stream to file descriptor.
+ * \ingroup sink_blk
+ */
+
+class gr_tagged_file_sink : public gr_sync_block
+{
+ friend gr_tagged_file_sink_sptr gr_make_tagged_file_sink (size_t itemsize,
+ double samp_rate);
+
+ private:
+ enum {
+ NOT_IN_BURST = 0,
+ IN_BURST
+ };
+
+ size_t d_itemsize;
+ int d_state;
+ FILE *d_handle;
+ int d_n;
+ double d_sample_rate;
+ uint64_t d_last_N;
+ double d_timeval;
+
+ protected:
+ gr_tagged_file_sink (size_t itemsize, double samp_rate);
+
+ public:
+ ~gr_tagged_file_sink ();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+
+#endif /* INCLUDED_GR_TAGGED_FILE_SINK_H */
diff --git a/gnuradio-core/src/lib/io/gr_tagged_file_sink.i b/gnuradio-core/src/lib/io/gr_tagged_file_sink.i
new file mode 100644
index 0000000000..1408adfc18
--- /dev/null
+++ b/gnuradio-core/src/lib/io/gr_tagged_file_sink.i
@@ -0,0 +1,35 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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,tagged_file_sink)
+
+gr_tagged_file_sink_sptr
+gr_make_tagged_file_sink (size_t itemsize, double samp_rate);
+
+class gr_tagged_file_sink : public gr_sync_block
+{
+ protected:
+ gr_tagged_file_sink (size_t itemsize, double samp_rate);
+
+ public:
+ ~gr_tagged_file_sink ();
+};
diff --git a/gnuradio-core/src/lib/io/io.i b/gnuradio-core/src/lib/io/io.i
index 3538942ca4..365577cd47 100644
--- a/gnuradio-core/src/lib/io/io.i
+++ b/gnuradio-core/src/lib/io/io.i
@@ -43,7 +43,7 @@
#include <gr_udp_source.h>
#include <gr_wavfile_sink.h>
#include <gr_wavfile_source.h>
-
+#include <gr_tagged_file_sink.h>
%}
%include "gr_file_sink_base.i"
@@ -64,4 +64,5 @@
%include "gr_udp_source.i"
%include "gr_wavfile_sink.i"
%include "gr_wavfile_source.i"
+%include "gr_tagged_file_sink.i"
diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am
index f67e8843d1..dd9a8ea647 100644
--- a/gnuradio-core/src/lib/runtime/Makefile.am
+++ b/gnuradio-core/src/lib/runtime/Makefile.am
@@ -68,7 +68,8 @@ libruntime_la_SOURCES = \
gr_vmcircbuf_mmap_tmpfile.cc \
gr_vmcircbuf_createfilemapping.cc \
gr_vmcircbuf_sysv_shm.cc \
- gr_select_handler.cc
+ gr_select_handler.cc \
+ gr_tag_info.cc
libruntime_qa_la_SOURCES = \
qa_gr_block.cc \
@@ -79,6 +80,7 @@ libruntime_qa_la_SOURCES = \
qa_gr_top_block.cc \
qa_gr_io_signature.cc \
qa_gr_vmcircbuf.cc \
+ qa_block_tags.cc \
qa_runtime.cc
grinclude_HEADERS = \
@@ -121,7 +123,8 @@ grinclude_HEADERS = \
gr_tmp_path.h \
gr_types.h \
gr_unittests.h \
- gr_vmcircbuf.h
+ gr_vmcircbuf.h \
+ gr_tag_info.h
noinst_HEADERS = \
gr_vmcircbuf_mmap_shm_open.h \
@@ -136,6 +139,7 @@ noinst_HEADERS = \
qa_gr_io_signature.h \
qa_gr_top_block.h \
qa_gr_vmcircbuf.h \
+ qa_block_tags.h \
qa_runtime.h
if PYTHON
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
index 8915f3360f..81a55af9d1 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -36,7 +36,8 @@ gr_block::gr_block (const std::string &name,
d_output_multiple (1),
d_relative_rate (1.0),
d_history(1),
- d_fixed_rate(false)
+ d_fixed_rate(false),
+ d_tag_propagation_policy(TPP_ALL_TO_ALL)
{
}
@@ -117,6 +118,69 @@ gr_block::fixed_rate_noutput_to_ninput(int noutput)
throw std::runtime_error("Unimplemented");
}
+uint64_t
+gr_block::nitems_read(unsigned int which_input)
+{
+ if(d_detail) {
+ return d_detail->nitems_read(which_input);
+ }
+ else {
+ //throw std::runtime_error("No block_detail associated with block yet");
+ return 0;
+ }
+}
+
+uint64_t
+gr_block::nitems_written(unsigned int which_output)
+{
+ if(d_detail) {
+ return d_detail->nitems_written(which_output);
+ }
+ else {
+ //throw std::runtime_error("No block_detail associated with block yet");
+ return 0;
+ }
+}
+
+void
+gr_block::add_item_tag(unsigned int which_output,
+ uint64_t offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid)
+{
+ d_detail->add_item_tag(which_output, offset, key, value, srcid);
+}
+
+void
+gr_block::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_output,
+ uint64_t start, uint64_t end)
+{
+ d_detail->get_tags_in_range(v, which_output, start, end);
+}
+
+void
+gr_block::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_output,
+ uint64_t start, uint64_t end,
+ const pmt::pmt_t &key)
+{
+ d_detail->get_tags_in_range(v, which_output, start, end, key);
+}
+
+gr_block::tag_propagation_policy_t
+gr_block::tag_propagation_policy()
+{
+ return d_tag_propagation_policy;
+}
+
+void
+gr_block::set_tag_propagation_policy(tag_propagation_policy_t p)
+{
+ d_tag_propagation_policy = p;
+}
+
std::ostream&
operator << (std::ostream& os, const gr_block *m)
{
diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h
index b6f724dde0..ad7fa9555f 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_block.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2007,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2007,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -63,6 +63,12 @@ class gr_block : public gr_basic_block {
WORK_DONE = -1
};
+ enum tag_propagation_policy_t {
+ TPP_DONT = 0,
+ TPP_ALL_TO_ALL = 1,
+ TPP_ONE_TO_ONE = 2
+ };
+
virtual ~gr_block ();
/*!
@@ -198,6 +204,26 @@ class gr_block : public gr_basic_block {
*/
virtual int fixed_rate_noutput_to_ninput(int noutput);
+ /*!
+ * \brief Return the number of items read on input stream which_input
+ */
+ uint64_t nitems_read(unsigned int which_input);
+
+ /*!
+ * \brief Return the number of items written on output stream which_output
+ */
+ uint64_t nitems_written(unsigned int which_output);
+
+ /*!
+ * \brief Asks for the policy used by the scheduler to moved tags downstream.
+ */
+ tag_propagation_policy_t tag_propagation_policy();
+
+ /*!
+ * \brief Set the policy by the scheduler to determine how tags are moved downstream.
+ */
+ void set_tag_propagation_policy(tag_propagation_policy_t p);
+
// ----------------------------------------------------------------------------
private:
@@ -207,6 +233,7 @@ class gr_block : public gr_basic_block {
gr_block_detail_sptr d_detail; // implementation details
unsigned d_history;
bool d_fixed_rate;
+ tag_propagation_policy_t d_tag_propagation_policy; // policy for moving tags downstream
protected:
@@ -216,6 +243,62 @@ class gr_block : public gr_basic_block {
void set_fixed_rate(bool fixed_rate){ d_fixed_rate = fixed_rate; }
+
+ /*!
+ * \brief Adds a new tag onto the given output buffer.
+ *
+ * \param which_output an integer of which output stream to attach the tag
+ * \param abs_offset a uint64 number of the absolute item number
+ * assicated with the tag. Can get from nitems_written.
+ * \param key the tag key as a PMT symbol
+ * \param value any PMT holding any value for the given key
+ * \param srcid optional source ID specifier; defaults to PMT_F
+ */
+ void add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid=pmt::PMT_F);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range.
+ *
+ * Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range
+ * with a given key.
+ *
+ * Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ * \param key a PMT symbol key to filter only tags of this key
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt::pmt_t &key);
+
// These are really only for internal use, but leaving them public avoids
// having to work up an ever-varying list of friends
diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i
index c2e2aa4b8b..2de354878f 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -49,6 +49,9 @@ class gr_block : public gr_basic_block {
bool start();
bool stop();
+ uint64_t nitems_read(unsigned int which_input);
+ uint64_t nitems_written(unsigned int which_output);
+
// internal use
gr_block_detail_sptr detail () const { return d_detail; }
void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
index 38d4a13ca5..a360240c0a 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -27,6 +27,8 @@
#include <gr_block_detail.h>
#include <gr_buffer.h>
+using namespace pmt;
+
static long s_ncurrently_allocated = 0;
long
@@ -88,16 +90,20 @@ gr_block_detail::set_done (bool done)
void
gr_block_detail::consume (int which_input, int how_many_items)
{
- if (how_many_items > 0)
+ if (how_many_items > 0) {
input (which_input)->update_read_pointer (how_many_items);
+ }
}
+
void
gr_block_detail::consume_each (int how_many_items)
{
- if (how_many_items > 0)
- for (int i = 0; i < ninputs (); i++)
+ if (how_many_items > 0) {
+ for (int i = 0; i < ninputs (); i++) {
d_input[i]->update_read_pointer (how_many_items);
+ }
+ }
}
void
@@ -112,16 +118,88 @@ gr_block_detail::produce (int which_output, int how_many_items)
void
gr_block_detail::produce_each (int how_many_items)
{
- if (how_many_items > 0){
- for (int i = 0; i < noutputs (); i++)
+ if (how_many_items > 0) {
+ for (int i = 0; i < noutputs (); i++) {
d_output[i]->update_write_pointer (how_many_items);
+ }
d_produce_or |= how_many_items;
}
}
void
-gr_block_detail::_post(pmt::pmt_t msg)
+gr_block_detail::_post(pmt_t msg)
{
d_tpb.insert_tail(msg);
}
+
+uint64_t
+gr_block_detail::nitems_read(unsigned int which_input)
+{
+ if(which_input >= d_ninputs)
+ throw std::invalid_argument ("gr_block_detail::n_input_items");
+ return d_input[which_input]->nitems_read();
+}
+
+uint64_t
+gr_block_detail::nitems_written(unsigned int which_output)
+{
+ if(which_output >= d_noutputs)
+ throw std::invalid_argument ("gr_block_detail::n_output_items");
+ return d_output[which_output]->nitems_written();
+}
+
+void
+gr_block_detail::add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt_t &key,
+ const pmt_t &value,
+ const pmt_t &srcid)
+{
+ if(!pmt_is_symbol(key)) {
+ throw pmt_wrong_type("gr_block_detail::add_item_tag key", key);
+ }
+ else {
+ // build tag tuple
+ pmt_t nitem = pmt_from_uint64(abs_offset);
+ pmt_t tuple = pmt_make_tuple(nitem, srcid, key, value);
+
+ // Add tag to gr_buffer's deque tags
+ d_output[which_output]->add_item_tag(tuple);
+ }
+}
+
+void
+gr_block_detail::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end)
+{
+ // get from gr_buffer_reader's deque of tags
+ d_input[which_input]->get_tags_in_range(v, abs_start, abs_end);
+}
+
+void
+gr_block_detail::get_tags_in_range(std::vector<pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt_t &key)
+{
+ std::vector<pmt_t> found_items;
+
+ v.resize(0);
+
+ // get from gr_buffer_reader's deque of tags
+ d_input[which_input]->get_tags_in_range(found_items, abs_start, abs_end);
+
+ // Filter further by key name
+ pmt_t itemkey;
+ std::vector<pmt_t>::iterator itr;
+ for(itr = found_items.begin(); itr != found_items.end(); itr++) {
+ itemkey = pmt_tuple_ref(*itr, 2);
+ if(pmt_eqv(key, itemkey)) {
+ v.push_back(*itr);
+ }
+ }
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h
index c5787a5ad0..d7ec3b1368 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -25,6 +25,7 @@
#include <gr_runtime_types.h>
#include <gr_tpb_detail.h>
+#include <gr_tag_info.h>
#include <stdexcept>
/*!
@@ -88,6 +89,75 @@ class gr_block_detail {
*/
void _post(pmt::pmt_t msg);
+ // Return the number of items read on input stream which_input
+ uint64_t nitems_read(unsigned int which_input);
+
+ // Return the number of items written on output stream which_output
+ uint64_t nitems_written(unsigned int which_output);
+
+
+ /*!
+ * \brief Adds a new tag to the given output stream.
+ *
+ * This takes the input parameters and builds a PMT tuple
+ * from it. It then calls gr_buffer::add_item_tag(pmt::pmt_t t),
+ * which appends the tag onto its deque.
+ *
+ * \param which_output an integer of which output stream to attach the tag
+ * \param abs_offset a uint64 number of the absolute item number
+ * assicated with the tag. Can get from nitems_written.
+ * \param key the tag key as a PMT symbol
+ * \param value any PMT holding any value for the given key
+ * \param srcid a PMT source ID specifier
+ */
+ void add_item_tag(unsigned int which_output,
+ uint64_t abs_offset,
+ const pmt::pmt_t &key,
+ const pmt::pmt_t &value,
+ const pmt::pmt_t &srcid);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range.
+ *
+ * Pass-through function to gr_buffer_reader to get a vector of tags
+ * in given range. Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
+ /*!
+ * \brief Given a [start,end), returns a vector of all tags in the range
+ * with a given key.
+ *
+ * Calls get_tags_in_range(which_input, abs_start, abs_end) to get a vector of
+ * tags from the buffers. This function then provides a secondary filter to
+ * the tags to extract only tags with the given 'key'.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param which_input an integer of which input stream to pull from
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ * \param key a PMT symbol to select only tags of this key
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ unsigned int which_input,
+ uint64_t abs_start,
+ uint64_t abs_end,
+ const pmt::pmt_t &key);
+
gr_tpb_detail d_tpb; // used by thread-per-block scheduler
int d_produce_or;
@@ -100,7 +170,6 @@ class gr_block_detail {
std::vector<gr_buffer_sptr> d_output;
bool d_done;
-
gr_block_detail (unsigned int ninputs, unsigned int noutputs);
friend class gr_tpb_detail;
diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.cc b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
index 2c21a0b0f2..1121502355 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_executor.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_executor.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -87,7 +87,80 @@ min_available_space (gr_block_detail *d, int output_multiple)
return min_space;
}
+static bool
+propagate_tags(gr_block::tag_propagation_policy_t policy, gr_block_detail *d,
+ const std::vector<uint64_t> &start_nitems_read, double rrate,
+ std::vector<pmt::pmt_t> &rtags)
+{
+ // Move tags downstream
+ // if a sink, we don't need to move downstream;
+ // and do not bother if block uses TAGS_NONE attribute
+ if(d->sink_p()) {
+ return true;
+ }
+ switch(policy) {
+ case gr_block::TPP_DONT:
+ return true;
+ break;
+ case gr_block::TPP_ALL_TO_ALL:
+ // every tag on every input propogates to everyone downstream
+ for(int i = 0; i < d->ninputs(); i++) {
+ d->get_tags_in_range(rtags, i, start_nitems_read[i],
+ d->nitems_read(i));
+
+ std::vector<pmt::pmt_t>::iterator t;
+ if(rrate == 1.0) {
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ for(int o = 0; o < d->noutputs(); o++)
+ d->output(o)->add_item_tag(*t);
+ }
+ }
+ else {
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ uint64_t newcount = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*t, 0));
+ pmt::pmt_t newtup = pmt::mp(pmt::pmt_from_uint64(newcount * rrate),
+ pmt::pmt_tuple_ref(*t, 1),
+ pmt::pmt_tuple_ref(*t, 2),
+ pmt::pmt_tuple_ref(*t, 3));
+
+ for(int o = 0; o < d->noutputs(); o++)
+ d->output(o)->add_item_tag(newtup);
+ }
+ }
+ }
+ break;
+ case gr_block::TPP_ONE_TO_ONE:
+ // tags from input i only go to output i
+ // this requires d->ninputs() == d->noutputs; this is checked when this
+ // type of tag-propagation system is selected in gr_block_detail
+ if(d->ninputs() == d->noutputs()) {
+ for(int i = 0; i < d->ninputs(); i++) {
+ d->get_tags_in_range(rtags, i, start_nitems_read[i],
+ d->nitems_read(i));
+
+ std::vector<pmt::pmt_t>::iterator t;
+ for(t = rtags.begin(); t != rtags.end(); t++) {
+ uint64_t newcount = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*t, 0));
+ pmt::pmt_t newtup = pmt::mp(pmt::pmt_from_uint64(newcount * rrate),
+ pmt::pmt_tuple_ref(*t, 1),
+ pmt::pmt_tuple_ref(*t, 2),
+ pmt::pmt_tuple_ref(*t, 3));
+ d->output(i)->add_item_tag(newtup);
+ }
+ }
+ }
+ else {
+ std::cerr << "Error: gr_block_executor: propagation_policy 'ONE-TO-ONE' requires ninputs == noutputs" << std::endl;
+ return false;
+ }
+
+ break;
+ default:
+ return true;
+ }
+ return true;
+}
gr_block_executor::gr_block_executor (gr_block_sptr block)
: d_block(block), d_log(0)
@@ -134,6 +207,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (0);
d_input_done.resize(0);
d_output_items.resize (d->noutputs ());
+ d_start_nitems_read.resize(0);
// determine the minimum available output space
noutput_items = min_available_space (d, m->output_multiple ());
@@ -155,6 +229,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (d->ninputs ());
d_input_done.resize(d->ninputs());
d_output_items.resize (0);
+ d_start_nitems_read.resize(d->ninputs());
LOG(*d_log << " sink\n");
max_items_avail = 0;
@@ -198,6 +273,7 @@ gr_block_executor::run_one_iteration()
d_input_items.resize (d->ninputs ());
d_input_done.resize(d->ninputs());
d_output_items.resize (d->noutputs ());
+ d_start_nitems_read.resize(d->ninputs());
max_items_avail = 0;
for (int i = 0; i < d->ninputs (); i++){
@@ -294,12 +370,21 @@ gr_block_executor::run_one_iteration()
for (int i = 0; i < d->noutputs (); i++)
d_output_items[i] = d->output(i)->write_pointer();
+ // determine where to start looking for new tags
+ for (int i = 0; i < d->ninputs(); i++)
+ d_start_nitems_read[i] = d->nitems_read(i);
+
// Do the actual work of the block
int n = m->general_work (noutput_items, d_ninput_items,
d_input_items, d_output_items);
LOG(*d_log << " general_work: noutput_items = " << noutput_items
<< " result = " << n << std::endl);
+ if(!propagate_tags(m->tag_propagation_policy(), d,
+ d_start_nitems_read, m->relative_rate(),
+ d_returned_tags))
+ goto were_done;
+
if (n == gr_block::WORK_DONE)
goto were_done;
diff --git a/gnuradio-core/src/lib/runtime/gr_block_executor.h b/gnuradio-core/src/lib/runtime/gr_block_executor.h
index 41b5ede7c8..77ace55229 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_executor.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_executor.h
@@ -25,6 +25,7 @@
#include <gr_runtime_types.h>
#include <fstream>
+#include <gruel/pmt.h>
//class gr_block_executor;
//typedef boost::shared_ptr<gr_block_executor> gr_block_executor_sptr;
@@ -47,6 +48,8 @@ protected:
gr_vector_const_void_star d_input_items;
std::vector<bool> d_input_done;
gr_vector_void_star d_output_items;
+ std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work
+ std::vector<pmt::pmt_t> d_returned_tags;
public:
gr_block_executor(gr_block_sptr block);
diff --git a/gnuradio-core/src/lib/runtime/gr_buffer.cc b/gnuradio-core/src/lib/runtime/gr_buffer.cc
index db2db5d6d7..0b2eb52a0d 100644
--- a/gnuradio-core/src/lib/runtime/gr_buffer.cc
+++ b/gnuradio-core/src/lib/runtime/gr_buffer.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -80,7 +80,7 @@ minimum_buffer_items (long type_size, long page_size)
gr_buffer::gr_buffer (int nitems, size_t sizeof_item, gr_block_sptr link)
: d_base (0), d_bufsize (0), d_vmcircbuf (0),
d_sizeof_item (sizeof_item), d_link(link),
- d_write_index (0), d_done (false)
+ d_write_index (0), d_abs_write_offset(0), d_done (false)
{
if (!allocate_buffer (nitems, sizeof_item))
throw std::bad_alloc ();
@@ -156,8 +156,13 @@ gr_buffer::space_available ()
// Find out the maximum amount of data available to our readers
int most_data = d_readers[0]->items_available ();
- for (unsigned int i = 1; i < d_readers.size (); i++)
+ uint64_t min_items_read = d_readers[0]->nitems_read();
+ for (size_t i = 1; i < d_readers.size (); i++) {
most_data = std::max (most_data, d_readers[i]->items_available ());
+ min_items_read = std::min(min_items_read, d_readers[i]->nitems_read());
+ }
+
+ prune_tags(min_items_read);
// The -1 ensures that the case d_write_index == d_read_index is
// unambiguous. It indicates that there is no data for the reader
@@ -177,6 +182,7 @@ gr_buffer::update_write_pointer (int nitems)
{
gruel::scoped_lock guard(*mutex());
d_write_index = index_add (d_write_index, nitems);
+ d_abs_write_offset += nitems;
}
void
@@ -215,6 +221,40 @@ gr_buffer::drop_reader (gr_buffer_reader *reader)
d_readers.erase (result);
}
+void
+gr_buffer::add_item_tag(const pmt::pmt_t &tag)
+{
+ gruel::scoped_lock guard(*mutex());
+ d_item_tags.push_back(tag);
+}
+
+void
+gr_buffer::prune_tags(uint64_t max_time)
+{
+ /* NOTE: this function _should_ lock the mutex before editing
+ d_item_tags. In practice, this function is only called at
+ runtime by min_available_space in gr_block_executor.cc,
+ which locks the mutex itself.
+
+ If this function is used elsewhere, remember to lock the
+ buffer's mutex al la the scoped_lock line below.
+ */
+ //gruel::scoped_lock guard(*mutex());
+
+ int n = 0;
+ uint64_t item_time;
+ std::deque<pmt::pmt_t>::iterator itr = d_item_tags.begin();
+
+ while(itr != d_item_tags.end()) {
+ item_time = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*itr, 0));
+ if(item_time < max_time) {
+ d_item_tags.pop_front();
+ n++;
+ }
+ itr++;
+ }
+}
+
long
gr_buffer_ncurrently_allocated ()
{
@@ -225,7 +265,7 @@ gr_buffer_ncurrently_allocated ()
gr_buffer_reader::gr_buffer_reader(gr_buffer_sptr buffer, unsigned int read_index,
gr_block_sptr link)
- : d_buffer(buffer), d_read_index(read_index), d_link(link)
+ : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link)
{
s_buffer_reader_count++;
}
@@ -253,6 +293,29 @@ gr_buffer_reader::update_read_pointer (int nitems)
{
gruel::scoped_lock guard(*mutex());
d_read_index = d_buffer->index_add (d_read_index, nitems);
+ d_abs_read_offset += nitems;
+}
+
+void
+gr_buffer_reader::get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ uint64_t abs_start,
+ uint64_t abs_end)
+{
+ gruel::scoped_lock guard(*mutex());
+
+ v.resize(0);
+ std::deque<pmt::pmt_t>::iterator itr = d_buffer->get_tags_begin();
+
+ uint64_t item_time;
+ while(itr != d_buffer->get_tags_end()) {
+ item_time = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*itr, 0));
+
+ if((item_time >= abs_start) && (item_time <= abs_end)) {
+ v.push_back(*itr);
+ }
+
+ itr++;
+ }
}
long
diff --git a/gnuradio-core/src/lib/runtime/gr_buffer.h b/gnuradio-core/src/lib/runtime/gr_buffer.h
index 207bfe7c58..fe0e7585dc 100644
--- a/gnuradio-core/src/lib/runtime/gr_buffer.h
+++ b/gnuradio-core/src/lib/runtime/gr_buffer.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2009 Free Software Foundation, Inc.
+ * Copyright 2004,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,6 +26,7 @@
#include <gr_runtime_types.h>
#include <boost/weak_ptr.hpp>
#include <gruel/thread.h>
+#include <gruel/pmt.h>
class gr_vmcircbuf;
@@ -88,6 +89,26 @@ class gr_buffer {
gruel::mutex *mutex() { return &d_mutex; }
+ uint64_t nitems_written() { return d_abs_write_offset; }
+
+
+ /*!
+ * \brief Adds a new tag to the buffer.
+ *
+ * \param tag a PMT tuple containing the new tag
+ */
+ void add_item_tag(const pmt::pmt_t &tag);
+
+ /*!
+ * \brief Removes all tags before \p max_time from buffer
+ *
+ * \param max_time the time (item number) to trim up until.
+ */
+ void prune_tags(uint64_t max_time);
+
+ std::deque<pmt::pmt_t>::iterator get_tags_begin() { return d_item_tags.begin(); }
+ std::deque<pmt::pmt_t>::iterator get_tags_end() { return d_item_tags.end(); }
+
// -------------------------------------------------------------------------
private:
@@ -106,11 +127,15 @@ class gr_buffer {
boost::weak_ptr<gr_block> d_link; // block that writes to this buffer
//
- // The mutex protects d_write_index, d_done and the d_read_index's in the buffer readers.
+ // The mutex protects d_write_index, d_abs_write_offset, d_done, d_item_tags
+ // and the d_read_index's and d_abs_read_offset's in the buffer readers.
//
gruel::mutex d_mutex;
unsigned int d_write_index; // in items [0,d_bufsize)
+ uint64_t d_abs_write_offset; // num items written since the start
bool d_done;
+ std::deque<pmt::pmt_t> d_item_tags;
+
unsigned
index_add (unsigned a, unsigned b)
@@ -220,11 +245,31 @@ class gr_buffer_reader {
gruel::mutex *mutex() { return d_buffer->mutex(); }
+ uint64_t nitems_read() { return d_abs_read_offset; }
+
/*!
* \brief Return the block that reads via this reader.
+ *
*/
gr_block_sptr link() { return gr_block_sptr(d_link); }
+
+ /*!
+ * \brief Given a [start,end), returns a vector all tags in the range.
+ *
+ * Get a vector of tags in given range. Range of counts is from start to end-1.
+ *
+ * Tags are tuples of:
+ * (item count, source id, key, value)
+ *
+ * \param v a vector reference to return tags into
+ * \param abs_start a uint64 count of the start of the range of interest
+ * \param abs_end a uint64 count of the end of the range of interest
+ */
+ void get_tags_in_range(std::vector<pmt::pmt_t> &v,
+ uint64_t abs_start,
+ uint64_t abs_end);
+
// -------------------------------------------------------------------------
private:
@@ -236,6 +281,7 @@ class gr_buffer_reader {
gr_buffer_sptr d_buffer;
unsigned int d_read_index; // in items [0,d->buffer.d_bufsize)
+ uint64_t d_abs_read_offset; // num items seen since the start
boost::weak_ptr<gr_block> d_link; // block that reads via this buffer reader
//! constructor is private. Use gr_buffer::add_reader to create instances
diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
index 031eb6dfd5..5d1057e0fe 100644
--- a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
+++ b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
@@ -264,16 +264,13 @@ void gr_flat_flowgraph::dump()
int no = detail->noutputs();
for (int i = 0; i < no; i++) {
gr_buffer_sptr buffer = detail->output(i);
- std::cout << " output " << i << ": " << buffer
- << " space=" << buffer->space_available() << std::endl;
+ std::cout << " output " << i << ": " << buffer << std::endl;
}
for (int i = 0; i < ni; i++) {
gr_buffer_reader_sptr reader = detail->input(i);
std::cout << " reader " << i << ": " << reader
- << " reading from buffer=" << reader->buffer()
- << " avail=" << reader->items_available() << " items"
- << std::endl;
+ << " reading from buffer=" << reader->buffer() << std::endl;
}
}
diff --git a/gnuradio-core/src/lib/runtime/gr_tag_info.cc b/gnuradio-core/src/lib/runtime/gr_tag_info.cc
new file mode 100644
index 0000000000..f15329f9be
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_tag_info.cc
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gr_tag_info.h>
+#include <gruel/pmt.h>
+
+namespace gr_tags {
+/*
+ const pmt::pmt_t key_time = pmt::pmt_string_to_symbol("time");
+ const pmt::pmt_t key_sample_rate = pmt::pmt_string_to_symbol("sample_rate");
+ const pmt::pmt_t key_frequency = pmt::pmt_string_to_symbol("frequency");
+ const pmt::pmt_t key_rssi = pmt::pmt_string_to_symbol("rssi");
+ const pmt::pmt_t key_rx_gain = pmt::pmt_string_to_symbol("gain");
+*/
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_tag_info.h b/gnuradio-core/src/lib/runtime/gr_tag_info.h
new file mode 100644
index 0000000000..5a1e1555aa
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_tag_info.h
@@ -0,0 +1,87 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_TAG_INFO_H
+#define INCLUDED_GR_TAG_INFO_H
+
+#include <gruel/pmt.h>
+
+namespace gr_tags {
+
+ enum {
+ TAG_NITEM_REF = 0,
+ TAG_SRCID_REF,
+ TAG_KEY_REF,
+ TAG_VALUE_REF
+ };
+
+ /*
+ extern const pmt::pmt_t key_time;
+ extern const pmt::pmt_t key_sample_rate;
+ extern const pmt::pmt_t key_frequency;
+ extern const pmt::pmt_t key_rssi;
+ extern const pmt::pmt_t key_gain;
+ */
+
+ /*!
+ * \brief Returns the item \p tag occurred at (as a uint64_t)
+ */
+ static inline uint64_t
+ get_nitems(const pmt::pmt_t &tag) {
+ return pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tag, TAG_NITEM_REF));
+ }
+
+ /*!
+ * \brief Returns the source ID of \p tag (as a PMT)
+ */
+ static inline pmt::pmt_t
+ get_srcid(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_SRCID_REF);
+ }
+
+ /*!
+ * \brief Returns the key of \p tag (as a PMT symbol)
+ */
+ static inline pmt::pmt_t
+ get_key(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_KEY_REF);
+ }
+
+ /*!
+ * \brief Returns the value of \p tag (as a PMT)
+ */
+ static inline pmt::pmt_t
+ get_value(const pmt::pmt_t &tag) {
+ return pmt::pmt_tuple_ref(tag, TAG_VALUE_REF);
+ }
+
+ /*!
+ * \brief Comparison function to test which tag, \p x or \p y, came first in time
+ */
+ static inline bool
+ nitems_compare(pmt::pmt_t x, pmt::pmt_t y) {
+ return get_nitems(x) < get_nitems(y);
+ }
+
+}; /* namespace tags */
+
+#endif /* GR_TAG_INFO */
diff --git a/gnuradio-core/src/lib/runtime/qa_block_tags.cc b/gnuradio-core/src/lib/runtime/qa_block_tags.cc
new file mode 100644
index 0000000000..07ce5c276e
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_block_tags.cc
@@ -0,0 +1,450 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <qa_block_tags.h>
+#include <gr_block.h>
+#include <gr_top_block.h>
+#include <gr_null_source.h>
+#include <gr_null_sink.h>
+#include <gr_head.h>
+#include <gr_annotator_alltoall.h>
+#include <gr_annotator_1to1.h>
+#include <gr_keep_one_in_n.h>
+#include <gr_firdes.h>
+#include <gruel/pmt.h>
+
+
+// ----------------------------------------------------------------
+
+using namespace pmt;
+
+// set to 1 to turn on debug output
+// The debug output fully checks that the tags seen are what are expected. While
+// this behavior currently works with our implementation, there is no guarentee
+// that the tags will be coming in this specific order, so it's dangerous to
+// rely on this as a test of the tag system working. We would really want to
+// tags we know we should see and then test that they all occur once, but in no
+// particular order.
+#define QA_TAGS_DEBUG 0
+
+void
+qa_block_tags::t0 ()
+{
+ unsigned int N = 1000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_block_sptr snk (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, snk, 0);
+
+ //CPPUNIT_ASSERT_THROW(src->nitems_read(0), std::runtime_error);
+ //CPPUNIT_ASSERT_THROW(src->nitems_written(0), std::runtime_error);
+ CPPUNIT_ASSERT_EQUAL(src->nitems_read(0), (uint64_t)0);
+ CPPUNIT_ASSERT_EQUAL(src->nitems_written(0), (uint64_t)0);
+
+ tb->run();
+
+ CPPUNIT_ASSERT_THROW(src->nitems_read(0), std::invalid_argument);
+ CPPUNIT_ASSERT(src->nitems_written(0) >= N);
+ CPPUNIT_ASSERT_EQUAL(snk->nitems_read(0), (uint64_t)1000);
+ CPPUNIT_ASSERT_THROW(snk->nitems_written(0), std::invalid_argument);
+}
+
+
+void
+qa_block_tags::t1 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann3 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann4 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, ann3, 0);
+ tb->connect(ann2, 0, ann4, 0);
+
+ tb->connect(ann3, 0, snk0, 0);
+ tb->connect(ann4, 0, snk1, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags3 = ann3->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)8);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)8);
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags3[8];
+ expected_tags3[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags3[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags3[2] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags3[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags3[4] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags3[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags3[6] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags3[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+
+ pmt_t expected_tags4[8];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str2.str()), mp("seq"), mp(0));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[2] = mp(pmt_from_uint64(10000), mp(str2.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[4] = mp(pmt_from_uint64(20000), mp(str2.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[6] = mp(pmt_from_uint64(30000), mp(str2.str()), mp("seq"), mp(3));
+ expected_tags4[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t1" << std::endl;
+
+ // For annotator 3, we know it gets tags from ann0 and ann1, test this
+ for(size_t i = 0; i < tags3.size(); i++) {
+ std::cout << "tags3[" << i << "] = " << tags3[i] << "\t\t" << expected_tags3[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags3[i]), pmt_write_string(expected_tags3[i]));
+ }
+
+ // For annotator 4, we know it gets tags from ann0 and ann2, test this
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags4[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+void
+qa_block_tags::t2 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann3 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann4 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk2 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann1, 1);
+ tb->connect(ann1, 0, ann2, 0);
+ tb->connect(ann1, 1, ann3, 0);
+ tb->connect(ann1, 2, ann4, 0);
+
+ tb->connect(ann2, 0, snk0, 0);
+ tb->connect(ann3, 0, snk1, 0);
+ tb->connect(ann4, 0, snk2, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags1 = ann1->data();
+ std::vector<pmt::pmt_t> tags2 = ann2->data();
+ std::vector<pmt::pmt_t> tags3 = ann4->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags1.size(), (size_t)8);
+
+ // Make sure the rest all have 12 tags
+ CPPUNIT_ASSERT_EQUAL(tags2.size(), (size_t)12);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)12);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)12);
+
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+
+ pmt_t expected_tags2[12];
+ expected_tags2[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags2[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags2[2] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags2[3] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags2[4] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags2[5] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags2[6] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(6));
+ expected_tags2[7] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags2[8] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags2[9] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(9));
+ expected_tags2[10] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+ expected_tags2[11] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ pmt_t expected_tags4[12];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags4[2] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(5));
+ expected_tags4[4] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[6] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(8));
+ expected_tags4[7] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags4[8] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[9] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(11));
+ expected_tags4[10] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+ expected_tags4[11] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t2" << std::endl;
+
+ // For annotator[2-4], we know it gets tags from ann0 and ann1
+ // but the tags from the different outputs of ann1 are different for each.
+ // Just testing ann2 and ann4; if they are correct it would be
+ // inconceivable for ann3 to have it wrong.
+ for(size_t i = 0; i < tags2.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags2[i] << "\t\t" << expected_tags2[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags2[i]), pmt_write_string(expected_tags2[i]));
+ }
+
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+
+void
+qa_block_tags::t3 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_1to1_sptr ann0 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann3 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann4 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(head, 0, ann0, 1);
+
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, ann3, 0);
+ tb->connect(ann2, 0, ann4, 0);
+
+ tb->connect(ann3, 0, snk0, 0);
+ tb->connect(ann4, 0, snk1, 0);
+
+ tb->run();
+
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags3 = ann3->data();
+ std::vector<pmt::pmt_t> tags4 = ann4->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags3.size(), (size_t)8);
+ CPPUNIT_ASSERT_EQUAL(tags4.size(), (size_t)8);
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags3[8];
+ expected_tags3[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags3[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags3[2] = mp(pmt_from_uint64(10000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags3[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags3[4] = mp(pmt_from_uint64(20000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags3[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(4));
+ expected_tags3[6] = mp(pmt_from_uint64(30000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags3[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(6));
+
+ pmt_t expected_tags4[8];
+ expected_tags4[0] = mp(pmt_from_uint64(0), mp(str2.str()), mp("seq"), mp(0));
+ expected_tags4[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags4[2] = mp(pmt_from_uint64(10000), mp(str2.str()), mp("seq"), mp(1));
+ expected_tags4[3] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags4[4] = mp(pmt_from_uint64(20000), mp(str2.str()), mp("seq"), mp(2));
+ expected_tags4[5] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(5));
+ expected_tags4[6] = mp(pmt_from_uint64(30000), mp(str2.str()), mp("seq"), mp(3));
+ expected_tags4[7] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(7));
+
+ std::cout << std::endl << "qa_block_tags::t3" << std::endl;
+
+ // For annotator 3, we know it gets tags from ann0 and ann1, test this
+ for(size_t i = 0; i < tags3.size(); i++) {
+ std::cout << "tags3[" << i << "] = " << tags3[i] << "\t\t" << expected_tags3[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags3[i]), pmt_write_string(expected_tags3[i]));
+ }
+
+ // For annotator 4, we know it gets tags from ann0 and ann2, test this
+ std::cout << std::endl;
+ for(size_t i = 0; i < tags4.size(); i++) {
+ std::cout << "tags4[" << i << "] = " << tags4[i] << "\t\t" << expected_tags4[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags4[i]), pmt_write_string(expected_tags4[i]));
+ }
+#endif
+}
+
+
+void
+qa_block_tags::t4 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(int)));
+ gr_block_sptr head (gr_make_head(sizeof(int), N));
+ gr_annotator_1to1_sptr ann0 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann1 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_annotator_1to1_sptr ann2 (gr_make_annotator_1to1(10000, sizeof(int)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(int)));
+ gr_block_sptr snk1 (gr_make_null_sink(sizeof(int)));
+
+ // using 1-to-1 tag propagation without having equal number of
+ // ins and outs. Make sure this works; will just exit run early.
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann0, 1, ann2, 0);
+ tb->connect(ann1, 0, snk0, 0);
+ tb->connect(ann2, 0, snk1, 0);
+
+ std::cerr << std::endl
+ << "NOTE: This is supposed to produce an error from gr_block_executor"
+ << std::endl;
+ tb->run();
+}
+
+
+void
+qa_block_tags::t5 ()
+{
+ int N = 40000;
+ gr_top_block_sptr tb = gr_make_top_block("top");
+ gr_block_sptr src (gr_make_null_source(sizeof(float)));
+ gr_block_sptr head (gr_make_head(sizeof(float), N));
+ gr_annotator_alltoall_sptr ann0 (gr_make_annotator_alltoall(10000, sizeof(float)));
+ gr_annotator_alltoall_sptr ann1 (gr_make_annotator_alltoall(10000, sizeof(float)));
+ gr_annotator_alltoall_sptr ann2 (gr_make_annotator_alltoall(1000, sizeof(float)));
+ gr_block_sptr snk0 (gr_make_null_sink(sizeof(float)));
+
+ // Rate change blocks
+ gr_keep_one_in_n_sptr dec10 (gr_make_keep_one_in_n(sizeof(float), 10));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, ann0, 0);
+ tb->connect(ann0, 0, ann1, 0);
+ tb->connect(ann1, 0, dec10, 0);
+ tb->connect(dec10, 0, ann2, 0);
+ tb->connect(ann2, 0, snk0, 0);
+
+ tb->run();
+
+ std::vector<pmt::pmt_t> tags0 = ann0->data();
+ std::vector<pmt::pmt_t> tags1 = ann1->data();
+ std::vector<pmt::pmt_t> tags2 = ann2->data();
+
+ // The first annotator does not receive any tags from the null sink upstream
+ CPPUNIT_ASSERT_EQUAL(tags0.size(), (size_t)0);
+ CPPUNIT_ASSERT_EQUAL(tags1.size(), (size_t)4);
+ CPPUNIT_ASSERT_EQUAL(tags2.size(), (size_t)8);
+
+
+#if QA_TAGS_DEBUG
+ // Kludge together the tags that we know should result from the above graph
+ std::stringstream str0, str1, str2;
+ str0 << ann0->name() << ann0->unique_id();
+ str1 << ann1->name() << ann1->unique_id();
+ str2 << ann2->name() << ann2->unique_id();
+
+ pmt_t expected_tags1[5];
+ expected_tags1[0] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags1[1] = mp(pmt_from_uint64(10000), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags1[2] = mp(pmt_from_uint64(20000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags1[3] = mp(pmt_from_uint64(30000), mp(str0.str()), mp("seq"), mp(3));
+
+ pmt_t expected_tags2[10];
+ expected_tags2[0] = mp(pmt_from_uint64(0), mp(str1.str()), mp("seq"), mp(0));
+ expected_tags2[1] = mp(pmt_from_uint64(0), mp(str0.str()), mp("seq"), mp(0));
+ expected_tags2[2] = mp(pmt_from_uint64(1000), mp(str1.str()), mp("seq"), mp(1));
+ expected_tags2[3] = mp(pmt_from_uint64(1000), mp(str0.str()), mp("seq"), mp(1));
+ expected_tags2[4] = mp(pmt_from_uint64(2000), mp(str1.str()), mp("seq"), mp(2));
+ expected_tags2[5] = mp(pmt_from_uint64(2000), mp(str0.str()), mp("seq"), mp(2));
+ expected_tags2[6] = mp(pmt_from_uint64(3000), mp(str1.str()), mp("seq"), mp(3));
+ expected_tags2[7] = mp(pmt_from_uint64(3000), mp(str0.str()), mp("seq"), mp(3));
+ expected_tags2[8] = mp(pmt_from_uint64(4000), mp(str1.str()), mp("seq"), mp(4));
+ expected_tags2[9] = mp(pmt_from_uint64(4000), mp(str0.str()), mp("seq"), mp(4));
+
+ std::cout << std::endl << "qa_block_tags::t5" << std::endl;
+
+ // annotator 1 gets tags from annotator 0
+ std::cout << "tags1.size(): " << tags1.size() << std::endl;
+ for(size_t i = 0; i < tags1.size(); i++) {
+ std::cout << "tags1[" << i << "] = " << tags1[i] << "\t\t" << expected_tags1[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags1[i]), pmt_write_string(expected_tags1[i]));
+ }
+
+ // annotator 2 gets tags from annotators 0 and 1
+ std::cout << std::endl;
+ std::cout << "tags2.size(): " << tags2.size() << std::endl;
+ for(size_t i = 0; i < tags2.size(); i++) {
+ std::cout << "tags2[" << i << "] = " << tags2[i] << "\t\t" << expected_tags2[i] << std::endl;
+ CPPUNIT_ASSERT_EQUAL(pmt_write_string(tags2[i]), pmt_write_string(expected_tags2[i]));
+ }
+#endif
+}
+
diff --git a/gnuradio-core/src/lib/runtime/qa_block_tags.h b/gnuradio-core/src/lib/runtime/qa_block_tags.h
new file mode 100644
index 0000000000..b0d2113909
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_block_tags.h
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_QA_BLOCK_TAGS_H
+#define INCLUDED_QA_BLOCK_TAGS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+#include <stdexcept>
+
+class qa_block_tags : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE (qa_block_tags);
+ CPPUNIT_TEST (t0);
+ CPPUNIT_TEST (t1);
+ CPPUNIT_TEST (t2);
+ CPPUNIT_TEST (t3);
+ CPPUNIT_TEST (t4);
+ CPPUNIT_TEST (t5);
+ CPPUNIT_TEST_SUITE_END ();
+
+ private:
+ void t0 ();
+ void t1 ();
+ void t2 ();
+ void t3 ();
+ void t4 ();
+ void t5 ();
+
+};
+
+
+#endif /* INCLUDED_QA_BLOCK_TAGS_H */
diff --git a/gnuradio-core/src/lib/runtime/qa_runtime.cc b/gnuradio-core/src/lib/runtime/qa_runtime.cc
index 31e3a82d67..967d4bfa8a 100644
--- a/gnuradio-core/src/lib/runtime/qa_runtime.cc
+++ b/gnuradio-core/src/lib/runtime/qa_runtime.cc
@@ -38,6 +38,7 @@
#include <qa_gr_hier_block2.h>
#include <qa_gr_hier_block2_derived.h>
#include <qa_gr_buffer.h>
+#include <qa_block_tags.h>
CppUnit::TestSuite *
qa_runtime::suite ()
@@ -52,6 +53,7 @@ qa_runtime::suite ()
s->addTest (qa_gr_hier_block2::suite ());
s->addTest (qa_gr_hier_block2_derived::suite ());
s->addTest (qa_gr_buffer::suite ());
+ s->addTest (qa_block_tags::suite ());
return s;
}
diff --git a/gnuradio-examples/python/tags/test_file_tags.py b/gnuradio-examples/python/tags/test_file_tags.py
new file mode 100755
index 0000000000..4ff4549ef9
--- /dev/null
+++ b/gnuradio-examples/python/tags/test_file_tags.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from gnuradio import gr
+import scipy
+
+def main():
+ data = scipy.arange(0, 32000, 1).tolist()
+ trig = 100*[0,] + 100*[1,]
+
+ src = gr.vector_source_s(data, True)
+ trigger = gr.vector_source_s(trig, True)
+
+ thr = gr.throttle(gr.sizeof_short, 10e3)
+ ann = gr.annotator_alltoall(1000000, gr.sizeof_short)
+ tagger = gr.burst_tagger(gr.sizeof_short)
+
+ fsnk = gr.tagged_file_sink(gr.sizeof_short, 1)
+
+ tb = gr.top_block()
+ tb.connect(src, thr, (tagger, 0))
+ tb.connect(trigger, (tagger, 1))
+ tb.connect(tagger, fsnk)
+
+ tb.run()
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/gnuradio-examples/python/tags/uhd_burst_detector.py b/gnuradio-examples/python/tags/uhd_burst_detector.py
new file mode 100755
index 0000000000..f8ebbe66a6
--- /dev/null
+++ b/gnuradio-examples/python/tags/uhd_burst_detector.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+from gnuradio import eng_notation
+from gnuradio import gr
+from gnuradio import uhd
+from gnuradio import window
+from gnuradio.eng_option import eng_option
+from gnuradio.gr import firdes
+from optparse import OptionParser
+
+class uhd_burst_detector(gr.top_block):
+ def __init__(self, frequency, sample_rate,
+ uhd_address="192.168.10.2", trigger=False):
+
+ gr.top_block.__init__(self)
+
+ self.freq = frequency
+ self.samp_rate = sample_rate
+ self.uhd_addr = uhd_address
+ self.gain = 32
+ self.trigger = trigger
+
+ self.uhd_src = uhd.single_usrp_source(
+ device_addr=self.uhd_addr,
+ io_type=uhd.io_type_t.COMPLEX_FLOAT32,
+ num_channels=1,
+ )
+
+ self.uhd_src.set_samp_rate(self.samp_rate)
+ self.uhd_src.set_center_freq(self.freq, 0)
+ self.uhd_src.set_gain(self.gain, 0)
+
+ taps = firdes.low_pass_2(1, 1, 0.4, 0.1, 60)
+ self.chanfilt = gr.fir_filter_ccc(10, taps)
+ self.ann0 = gr.annotator_alltoall(100000, gr.sizeof_gr_complex)
+ self.tagger = gr.burst_tagger(gr.sizeof_gr_complex)
+
+ # Dummy signaler to collect a burst on known periods
+ data = 1000*[0,] + 1000*[1,]
+ self.signal = gr.vector_source_s(data, True)
+
+ # Energy detector to get signal burst
+ self.c2m = gr.complex_to_mag_squared()
+ self.iir = gr.single_pole_iir_filter_ff(0.0001)
+ self.sub = gr.sub_ff()
+ self.mult = gr.multiply_const_ff(32768)
+ self.f2s = gr.float_to_short()
+ self.fsnk = gr.tagged_file_sink(gr.sizeof_gr_complex, self.samp_rate)
+
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.uhd_src, 0), (self.tagger, 0))
+ self.connect((self.tagger, 0), (self.fsnk, 0))
+
+ if self.trigger:
+ # Connect a dummy signaler to the burst tagger
+ self.connect((self.signal, 0), (self.tagger, 1))
+
+ else:
+ # Connect an energy detector signaler to the burst tagger
+ self.connect((self.uhd_src, 0), (self.c2m, 0))
+ self.connect((self.c2m, 0), (self.sub, 0))
+ self.connect((self.c2m, 0), (self.iir, 0))
+ self.connect((self.iir, 0), (self.sub, 1))
+ self.connect((self.sub, 0), (self.mult,0))
+ self.connect((self.mult, 0), (self.f2s, 0))
+ self.connect((self.f2s, 0), (self.tagger, 1))
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+ self.wxgui_fftsink2_0.set_sample_rate(self.samp_rate/10)
+ self.uhd_src_0.set_samp_rate(self.samp_rate)
+
+if __name__ == '__main__':
+ parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+ parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+ help="select address of the device [default=%default]")
+ #parser.add_option("-A", "--antenna", default=None,
+ # help="select Rx Antenna (only on RFX-series boards)")
+ parser.add_option("-f", "--freq", type="eng_float", default=450e6,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=0,
+ help="set gain in dB [default=%default]")
+ parser.add_option("-R", "--rate", type="eng_float", default=200000,
+ help="set USRP sample rate [default=%default]")
+ parser.add_option("-T", "--trigger", action="store_true", default=False,
+ help="Use internal trigger instead of detector [default=%default]")
+ (options, args) = parser.parse_args()
+
+ frequency = options.freq
+ samp_rate = samp_rate = options.rate
+ uhd_addr = options.address
+ trigger = options.trigger
+
+ tb = uhd_burst_detector(frequency, samp_rate, uhd_addr, trigger)
+ tb.run()
diff --git a/gr-howto-write-a-block/version.sh b/gr-howto-write-a-block/version.sh
index 01a47b5d92..0d6cc96f0d 100644
--- a/gr-howto-write-a-block/version.sh
+++ b/gr-howto-write-a-block/version.sh
@@ -1,4 +1,4 @@
MAJOR_VERSION=3
-API_COMPAT=3
-MINOR_VERSION=0
+API_COMPAT=4
+MINOR_VERSION=git
MAINT_VERSION=0
diff --git a/gr-uhd/.gitignore b/gr-uhd/.gitignore
new file mode 100644
index 0000000000..b336cc7cec
--- /dev/null
+++ b/gr-uhd/.gitignore
@@ -0,0 +1,2 @@
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/Makefile.am b/gr-uhd/Makefile.am
new file mode 100644
index 0000000000..83190a1d06
--- /dev/null
+++ b/gr-uhd/Makefile.am
@@ -0,0 +1,29 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = lib apps
+
+if PYTHON
+SUBDIRS += swig grc
+endif
+
diff --git a/gr-uhd/apps/.gitignore b/gr-uhd/apps/.gitignore
new file mode 100644
index 0000000000..b336cc7cec
--- /dev/null
+++ b/gr-uhd/apps/.gitignore
@@ -0,0 +1,2 @@
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/apps/Makefile.am b/gr-uhd/apps/Makefile.am
new file mode 100644
index 0000000000..b78d07ee82
--- /dev/null
+++ b/gr-uhd/apps/Makefile.am
@@ -0,0 +1,22 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
diff --git a/gr-uhd/grc/.gitignore b/gr-uhd/grc/.gitignore
new file mode 100644
index 0000000000..d8ab9bd0c3
--- /dev/null
+++ b/gr-uhd/grc/.gitignore
@@ -0,0 +1,4 @@
+/uhd_multi*.xml
+/uhd_single*.xml
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/grc/Makefile.am b/gr-uhd/grc/Makefile.am
new file mode 100644
index 0000000000..1106bdd23a
--- /dev/null
+++ b/gr-uhd/grc/Makefile.am
@@ -0,0 +1,55 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+grcblocksdir = $(grc_blocksdir)
+
+generated_uhd_multi_usrp_blocks = \
+ uhd_multi_usrp_source.xml \
+ uhd_multi_usrp_sink.xml
+
+generated_uhd_single_usrp_blocks = \
+ uhd_single_usrp_source.xml \
+ uhd_single_usrp_sink.xml
+
+BUILT_SOURCES = \
+ $(generated_uhd_multi_usrp_blocks) \
+ $(generated_uhd_single_usrp_blocks)
+
+dist_grcblocks_DATA = \
+ uhd_block_tree.xml \
+ $(BUILT_SOURCES)
+
+########################################################################
+# Rules for generating the source and sink xml wrappers
+########################################################################
+EXTRA_DIST = \
+ $(srcdir)/gen_uhd_multi_usrp_blocks_xml.py \
+ $(srcdir)/gen_uhd_single_usrp_blocks_xml.py
+
+$(generated_uhd_multi_usrp_blocks): $(srcdir)/gen_uhd_multi_usrp_blocks_xml.py
+ @echo "generating $@..."
+ $(PYTHON) $< $@
+
+$(generated_uhd_single_usrp_blocks): $(srcdir)/gen_uhd_single_usrp_blocks_xml.py
+ @echo "generating $@..."
+ $(PYTHON) $< $@
diff --git a/gr-uhd/grc/gen_uhd_multi_usrp_blocks_xml.py b/gr-uhd/grc/gen_uhd_multi_usrp_blocks_xml.py
new file mode 100755
index 0000000000..112d881599
--- /dev/null
+++ b/gr-uhd/grc/gen_uhd_multi_usrp_blocks_xml.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python
+"""
+Copyright 2010 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
+"""
+
+MAIN_TMPL = """\
+<?xml version="1.0"?>
+<block>
+ <name>UHD: Multi USRP $sourk.title()</name>
+ <key>uhd_multi_usrp_$(sourk)</key>
+ <import>from gnuradio import uhd</import>
+ <make>uhd.multi_usrp_$(sourk)(
+ device_addr=\$dev_addr,
+ io_type=uhd.io_type_t.\$type.type,
+ num_channels=\$nchan,
+)
+\#if \$sync()
+_clk_cfg = uhd.clock_config_t()
+_clk_cfg.ref_source = uhd.clock_config_t.REF_SMA
+_clk_cfg.pps_source = uhd.clock_config_t.PPS_SMA
+_clk_cfg.pps_polarity = uhd.clock_config_t.PPS_POS
+self.\$(id).set_clock_config(_clk_cfg, uhd.ALL_MBOARDS);
+self.\$(id).set_time_unknown_pps(uhd.time_spec_t())
+\#end if
+#for $m in range($max_mboards)
+\#if \$num_mboards() > $m and \$sd_spec$(m)()
+self.\$(id).set_subdev_spec(\$sd_spec$(m), $m)
+\#end if
+#end for
+self.\$(id).set_samp_rate(\$samp_rate)
+#for $n in range($max_nchan)
+\#if \$nchan() > $n
+self.\$(id).set_center_freq(\$center_freq$(n), $n)
+self.\$(id).set_gain(\$gain$(n), $n)
+ \#if \$ant$(n)()
+self.\$(id).set_antenna(\$ant$(n), $n)
+ \#end if
+ \#if \$bw$(n)()
+self.\$(id).set_bandwidth(\$bw$(n), $n)
+ \#end if
+\#end if
+#end for
+</make>
+ <callback>set_samp_rate(\$samp_rate)</callback>
+ #for $n in range($max_nchan)
+ <callback>set_center_freq(\$center_freq$(n), $n)</callback>
+ <callback>set_gain(\$gain$(n), $n)</callback>
+ <callback>set_antenna(\$ant$(n), $n)</callback>
+ <callback>set_bandwidth(\$bw$(n), $n)</callback>
+ #end for
+ <param>
+ <name>Input Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Complex</name>
+ <key>complex</key>
+ <opt>type:COMPLEX_FLOAT32</opt>
+ <opt>vlen:1</opt>
+ </option>
+ <option>
+ <name>Short</name>
+ <key>short</key>
+ <opt>type:COMPLEX_INT16</opt>
+ <opt>vlen:2</opt>
+ </option>
+ </param>
+ <param>
+ <name>Device Addr</name>
+ <key>dev_addr</key>
+ <value>addr=192.168.10.2</value>
+ <type>string</type>
+ <hide>
+ \#if \$dev_addr()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
+ <name>Sync</name>
+ <key>sync</key>
+ <value>sync</value>
+ <type>enum</type>
+ <hide>\#if \$sync() then 'none' else 'part'#</hide>
+ <option>
+ <name>unknown PPS</name>
+ <key>sync</key>
+ </option>
+ <option>
+ <name>don't sync</name>
+ <key></key>
+ </option>
+ </param>
+ <param>
+ <name>Num Mboards</name>
+ <key>num_mboards</key>
+ <value>2</value>
+ <type>int</type>
+ #for $m in range(1, $max_mboards+1)
+ <option>
+ <name>$(m)</name>
+ <key>$m</key>
+ </option>
+ #end for
+ </param>
+ #for $m in range($max_mboards)
+ <param>
+ <name>Mb$(m): Subdev Spec</name>
+ <key>sd_spec$(m)</key>
+ <value></value>
+ <type>string</type>
+ <hide>
+ \#if not \$num_mboards() > $m
+ all
+ \#elif \$sd_spec$(m)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ #end for
+ <param>
+ <name>Num Channels</name>
+ <key>nchan</key>
+ <value>2</value>
+ <type>int</type>
+ #for $n in range(1, $max_nchan+1)
+ <option>
+ <name>$(n)</name>
+ <key>$n</key>
+ </option>
+ #end for
+ </param>
+ <param>
+ <name>Samp Rate (Sps)</name>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ <type>real</type>
+ </param>
+ $params
+ <check>$max_nchan >= \$nchan</check>
+ <check>\$nchan > 0</check>
+ <check>$max_mboards >= \$num_mboards</check>
+ <check>\$num_mboards > 0</check>
+ <check>\$nchan >= \$num_mboards</check>
+ <$sourk>
+ <name>$direction</name>
+ <type>\$type</type>
+ <vlen>\$type.vlen</vlen>
+ <nports>\$nchan</nports>
+ </$sourk>
+ <doc>
+The UHD Multi USRP $sourk.title() Block:
+
+Device Address:
+The device address is a delimited string used to locate UHD devices on your system. \\
+If left blank, the first UHD device found will be used. \\
+Used args to specify a specfic device.
+USRP2 Example: addr=192.168.10.2 192.168.10.3
+
+Num Motherboards:
+Selects the number of USRP motherboards in this multi-USRP configuration.
+
+Subdevice specification:
+Each motherboard should have its own subdevice specification \\
+and all subdevice specifications should be the same length. \\
+Select the subdevice or subdevices for each channel using a markup string. \\
+The markup string consists of a list of dboard_slot:subdev_name pairs (one pair per channel). \\
+If left blank, the UHD will try to select the first subdevice on your system. \\
+See the application notes for further details.
+Single channel example: :AB
+Dual channel example: :A :B
+
+Num Channels:
+Selects the total number of channels in this multi-USRP configuration.
+Ex: 4 motherboards with 2 channels per board = 8 channels total
+
+Sample rate:
+The sample rate is the number of samples per second input by this block. \\
+The UHD device driver will try its best to match the requested sample rate. \\
+If the requested rate is not possible, the UHD block will print an error at runtime.
+
+Center frequency:
+The center frequency is the overall frequency of the RF chain. \\
+For greater control of how the UHD tunes elements in the RF chain, \\
+pass a tune_request_t object rather than a simple target frequency.
+Tuning with an LO offset example: uhd.tune_request_t(freq, lo_off)
+
+Antenna:
+For subdevices with only one antenna, this may be left blank. \\
+Otherwise, the user should specify one of the possible antenna choices. \\
+See the daughterboard application notes for the possible antenna choices.
+
+Bandwidth:
+To use the default bandwidth filter setting, this should be zero. \\
+Only certain subdevices have configurable bandwidth filters. \\
+See the daughterboard application notes for possible configurations.
+ </doc>
+</block>
+"""
+
+PARAMS_TMPL = """
+ <param>
+ <name>Ch$(n): Center Freq (Hz)</name>
+ <key>center_freq$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
+ </param>
+ <param>
+ <name>Ch$(n): Gain (dB)</name>
+ <key>gain$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
+ </param>
+ <param>
+ <name>Ch$(n): Antenna</name>
+ <key>ant$(n)</key>
+ <value></value>
+ <type>string</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$ant$(n)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
+ <name>Ch$(n): Bandwidth (Hz)</name>
+ <key>bw$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$bw$(n)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+"""
+
+def parse_tmpl(_tmpl, **kwargs):
+ from Cheetah import Template
+ return str(Template.Template(_tmpl, kwargs))
+
+max_num_mboards = 4
+max_num_channels = max_num_mboards*4
+
+if __name__ == '__main__':
+ import sys
+ for file in sys.argv[1:]:
+ if 'source' in file:
+ sourk = 'source'
+ direction = 'out'
+ elif 'sink' in file:
+ sourk = 'sink'
+ direction = 'in'
+ else: raise Exception, 'is %s a source or sink?'%file
+
+ params = ''.join([parse_tmpl(PARAMS_TMPL, n=n) for n in range(max_num_channels)])
+ open(file, 'w').write(parse_tmpl(MAIN_TMPL,
+ max_nchan=max_num_channels,
+ max_mboards=max_num_mboards,
+ params=params,
+ sourk=sourk,
+ direction=direction,
+ ))
diff --git a/gr-uhd/grc/gen_uhd_single_usrp_blocks_xml.py b/gr-uhd/grc/gen_uhd_single_usrp_blocks_xml.py
new file mode 100755
index 0000000000..7337c71d7b
--- /dev/null
+++ b/gr-uhd/grc/gen_uhd_single_usrp_blocks_xml.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+"""
+Copyright 2010 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
+"""
+
+MAIN_TMPL = """\
+<?xml version="1.0"?>
+<block>
+ <name>UHD: Single USRP $sourk.title()</name>
+ <key>uhd_single_usrp_$(sourk)</key>
+ <import>from gnuradio import uhd</import>
+ <make>uhd.single_usrp_$(sourk)(
+ device_addr=\$dev_addr,
+ io_type=uhd.io_type_t.\$type.type,
+ num_channels=\$nchan,
+)
+\#if \$ref_clk()
+_clk_cfg = uhd.clock_config_t()
+_clk_cfg.ref_source = uhd.clock_config_t.REF_SMA
+_clk_cfg.pps_source = uhd.clock_config_t.PPS_SMA
+_clk_cfg.pps_polarity = uhd.clock_config_t.PPS_POS
+self.\$(id).set_clock_config(_clk_cfg);
+\#end if
+\#if \$sd_spec()
+self.\$(id).set_subdev_spec(\$sd_spec)
+\#end if
+self.\$(id).set_samp_rate(\$samp_rate)
+#for $n in range($max_nchan)
+\#if \$nchan() > $n
+self.\$(id).set_center_freq(\$center_freq$(n), $n)
+self.\$(id).set_gain(\$gain$(n), $n)
+ \#if \$ant$(n)()
+self.\$(id).set_antenna(\$ant$(n), $n)
+ \#end if
+ \#if \$bw$(n)()
+self.\$(id).set_bandwidth(\$bw$(n), $n)
+ \#end if
+\#end if
+#end for
+</make>
+ <callback>set_samp_rate(\$samp_rate)</callback>
+ #for $n in range($max_nchan)
+ <callback>set_center_freq(\$center_freq$(n), $n)</callback>
+ <callback>set_gain(\$gain$(n), $n)</callback>
+ <callback>set_antenna(\$ant$(n), $n)</callback>
+ <callback>set_bandwidth(\$bw$(n), $n)</callback>
+ #end for
+ <param>
+ <name>Input Type</name>
+ <key>type</key>
+ <type>enum</type>
+ <option>
+ <name>Complex</name>
+ <key>complex</key>
+ <opt>type:COMPLEX_FLOAT32</opt>
+ <opt>vlen:1</opt>
+ </option>
+ <option>
+ <name>Short</name>
+ <key>short</key>
+ <opt>type:COMPLEX_INT16</opt>
+ <opt>vlen:2</opt>
+ </option>
+ </param>
+ <param>
+ <name>Num Channels</name>
+ <key>nchan</key>
+ <value>1</value>
+ <type>int</type>
+ <hide>part</hide>
+ <option>
+ <name>Single Channel</name>
+ <key>1</key>
+ </option>
+ <option>
+ <name>Dual Channel</name>
+ <key>2</key>
+ </option>
+ <option>
+ <name>Quad Channel</name>
+ <key>4</key>
+ </option>
+ </param>
+ <param>
+ <name>Device Addr</name>
+ <key>dev_addr</key>
+ <value>addr=192.168.10.2</value>
+ <type>string</type>
+ <hide>
+ \#if \$dev_addr()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
+ <name>Ref Clock</name>
+ <key>ref_clk</key>
+ <value></value>
+ <type>enum</type>
+ <hide>\#if \$ref_clk() then 'none' else 'part'#</hide>
+ <option>
+ <name>External</name>
+ <key>ext</key>
+ </option>
+ <option>
+ <name>Internal</name>
+ <key></key>
+ </option>
+ </param>
+ <param>
+ <name>Subdev Spec</name>
+ <key>sd_spec</key>
+ <value></value>
+ <type>string</type>
+ <hide>
+ \#if \$sd_spec()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
+ <name>Samp Rate (Sps)</name>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ <type>real</type>
+ </param>
+ $params
+ <check>$max_nchan >= \$nchan</check>
+ <check>\$nchan > 0</check>
+ <check>(len((\$sd_spec).split()) or 1) == \$nchan</check>
+ <$sourk>
+ <name>$direction</name>
+ <type>\$type</type>
+ <vlen>\$type.vlen</vlen>
+ <nports>\$nchan</nports>
+ </$sourk>
+ <doc>
+The UHD Single USRP $sourk.title() Block:
+
+Device Address:
+The device address is a delimited string used to locate UHD devices on your system. \\
+If left blank, the first UHD device found will be used. \\
+Used args to specify a specfic device.
+USRP2 Example: addr=192.168.10.2
+USRP1 Example: serial=12345678
+
+Subdevice specification:
+Select the subdevice or subdevices for each channel using a markup string. \\
+The markup string consists of a list of dboard_slot:subdev_name pairs (one pair per channel). \\
+If left blank, the UHD will try to select the first subdevice on your system. \\
+See the application notes for further details.
+Single channel example: A:AB
+Dual channel example: A:AB B:0
+
+Sample rate:
+The sample rate is the number of samples per second input by this block. \\
+The UHD device driver will try its best to match the requested sample rate. \\
+If the requested rate is not possible, the UHD block will print an error at runtime.
+
+Center frequency:
+The center frequency is the overall frequency of the RF chain. \\
+For greater control of how the UHD tunes elements in the RF chain, \\
+pass a tune_request_t object rather than a simple target frequency.
+Tuning with an LO offset example: uhd.tune_request_t(freq, lo_off)
+
+Antenna:
+For subdevices with only one antenna, this may be left blank. \\
+Otherwise, the user should specify one of the possible antenna choices. \\
+See the daughterboard application notes for the possible antenna choices.
+
+Bandwidth:
+To use the default bandwidth filter setting, this should be zero. \\
+Only certain subdevices have configurable bandwidth filters. \\
+See the daughterboard application notes for possible configurations.
+ </doc>
+</block>
+"""
+
+PARAMS_TMPL = """
+ <param>
+ <name>Ch$(n): Center Freq (Hz)</name>
+ <key>center_freq$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
+ </param>
+ <param>
+ <name>Ch$(n): Gain (dB)</name>
+ <key>gain$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
+ </param>
+ <param>
+ <name>Ch$(n): Antenna</name>
+ <key>ant$(n)</key>
+ <value></value>
+ <type>string</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$ant$(n)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+ <param>
+ <name>Ch$(n): Bandwidth (Hz)</name>
+ <key>bw$(n)</key>
+ <value>0</value>
+ <type>real</type>
+ <hide>
+ \#if not \$nchan() > $n
+ all
+ \#elif \$bw$(n)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ </param>
+"""
+
+def parse_tmpl(_tmpl, **kwargs):
+ from Cheetah import Template
+ return str(Template.Template(_tmpl, kwargs))
+
+max_num_channels = 4
+
+if __name__ == '__main__':
+ import sys
+ for file in sys.argv[1:]:
+ if 'source' in file:
+ sourk = 'source'
+ direction = 'out'
+ elif 'sink' in file:
+ sourk = 'sink'
+ direction = 'in'
+ else: raise Exception, 'is %s a source or sink?'%file
+
+ params = ''.join([parse_tmpl(PARAMS_TMPL, n=n) for n in range(max_num_channels)])
+ open(file, 'w').write(parse_tmpl(MAIN_TMPL,
+ max_nchan=max_num_channels,
+ params=params,
+ sourk=sourk,
+ direction=direction,
+ ))
diff --git a/gr-uhd/grc/uhd_block_tree.xml b/gr-uhd/grc/uhd_block_tree.xml
new file mode 100644
index 0000000000..f5d42b567d
--- /dev/null
+++ b/gr-uhd/grc/uhd_block_tree.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Block Tree for uhd blocks.
+###################################################
+ -->
+<cat>
+ <name></name> <!-- Blank for Root Name -->
+ <cat>
+ <name>UHD</name>
+ <block>uhd_single_usrp_source</block>
+ <block>uhd_single_usrp_sink</block>
+ <block>uhd_multi_usrp_source</block>
+ <block>uhd_multi_usrp_sink</block>
+ </cat>
+</cat>
diff --git a/gr-uhd/lib/.gitignore b/gr-uhd/lib/.gitignore
new file mode 100644
index 0000000000..b336cc7cec
--- /dev/null
+++ b/gr-uhd/lib/.gitignore
@@ -0,0 +1,2 @@
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/lib/Makefile.am b/gr-uhd/lib/Makefile.am
new file mode 100644
index 0000000000..1bcfbbbdc4
--- /dev/null
+++ b/gr-uhd/lib/Makefile.am
@@ -0,0 +1,49 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = \
+ $(STD_DEFINES_AND_INCLUDES) \
+ $(WITH_INCLUDES) \
+ $(UHD_CPPFLAGS)
+
+lib_LTLIBRARIES = libgnuradio-uhd.la
+
+libgnuradio_uhd_la_SOURCES = \
+ uhd_multi_usrp_source.cc \
+ uhd_multi_usrp_sink.cc \
+ uhd_single_usrp_source.cc \
+ uhd_single_usrp_sink.cc
+
+libgnuradio_uhd_la_LIBADD = \
+ $(GNURADIO_CORE_LA) \
+ $(UHD_LIBS)
+
+libgnuradio_uhd_la_LDFLAGS = $(LTVERSIONFLAGS)
+
+grinclude_HEADERS = \
+ uhd_multi_usrp_source.h \
+ uhd_multi_usrp_sink.h \
+ uhd_single_usrp_source.h \
+ uhd_single_usrp_sink.h
+
+noinst_HEADERS =
diff --git a/gr-uhd/lib/uhd_multi_usrp_sink.cc b/gr-uhd/lib/uhd_multi_usrp_sink.cc
new file mode 100644
index 0000000000..ee16e2928d
--- /dev/null
+++ b/gr-uhd/lib/uhd_multi_usrp_sink.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <uhd_multi_usrp_sink.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+
+/***********************************************************************
+ * UHD Multi USRP Sink
+ **********************************************************************/
+uhd_multi_usrp_sink::uhd_multi_usrp_sink(gr_io_signature_sptr sig)
+:gr_sync_block("uhd multi usrp sink", sig, gr_make_io_signature(0, 0, 0)){
+ /* NOP */
+}
+
+/***********************************************************************
+ * UHD Multi USRP Sink Impl
+ **********************************************************************/
+class uhd_multi_usrp_sink_impl : public uhd_multi_usrp_sink{
+public:
+ uhd_multi_usrp_sink_impl(
+ const std::string &device_addr,
+ const uhd::io_type_t &io_type,
+ size_t num_channels
+ ):
+ uhd_multi_usrp_sink(gr_make_io_signature(
+ num_channels, num_channels, io_type.size
+ )),
+ _type(io_type),
+ _nchan(num_channels)
+ {
+ _dev = uhd::usrp::multi_usrp::make(device_addr);
+ }
+
+ void set_subdev_spec(const std::string &spec, size_t mboard){
+ return _dev->set_tx_subdev_spec(spec, mboard);
+ }
+
+ void set_samp_rate(double rate){
+ _dev->set_tx_rate(rate);
+ }
+
+ double get_samp_rate(void){
+ return _dev->get_tx_rate();
+ }
+
+ uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ){
+ return _dev->set_tx_freq(tune_request, chan);
+ }
+
+ uhd::freq_range_t get_freq_range(size_t chan){
+ return _dev->get_tx_freq_range(chan);
+ }
+
+ void set_gain(float gain, size_t chan){
+ return _dev->set_tx_gain(gain, chan);
+ }
+
+ float get_gain(size_t chan){
+ return _dev->get_tx_gain(chan);
+ }
+
+ uhd::gain_range_t get_gain_range(size_t chan){
+ return _dev->get_tx_gain_range(chan);
+ }
+
+ void set_antenna(const std::string &ant, size_t chan){
+ return _dev->set_tx_antenna(ant, chan);
+ }
+
+ std::string get_antenna(size_t chan){
+ return _dev->get_tx_antenna(chan);
+ }
+
+ std::vector<std::string> get_antennas(size_t chan){
+ return _dev->get_tx_antennas(chan);
+ }
+
+ void set_bandwidth(double bandwidth, size_t chan){
+ return _dev->set_tx_bandwidth(bandwidth, chan);
+ }
+
+ void set_clock_config(const uhd::clock_config_t &clock_config, size_t mboard){
+ return _dev->set_clock_config(clock_config, mboard);
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ return _dev->get_time_now();
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_next_pps(time_spec);
+ }
+
+ void set_time_unknown_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_unknown_pps(time_spec);
+ }
+
+ uhd::usrp::multi_usrp::sptr get_device(void){
+ return _dev;
+ }
+
+/***********************************************************************
+ * Work
+ **********************************************************************/
+ int work(
+ int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ uhd::tx_metadata_t metadata;
+ metadata.start_of_burst = true;
+
+ return _dev->get_device()->send(
+ input_items, noutput_items, metadata,
+ _type, uhd::device::SEND_MODE_FULL_BUFF, 1.0
+ );
+ }
+
+ //Send an empty start-of-burst packet to begin streaming.
+ //Set at a time in the near future so data will be sync'd.
+ bool start(void){
+ uhd::tx_metadata_t metadata;
+ metadata.start_of_burst = true;
+ metadata.has_time_spec = true;
+ //TODO: Time in the near future, must be less than source time in future
+ //because ethernet pause frames with throttle stream commands.
+ //It will be fixed with the invention of host-based flow control.
+ metadata.time_spec = get_time_now() + uhd::time_spec_t(0.05);
+
+ _dev->get_device()->send(
+ gr_vector_const_void_star(_nchan), 0, metadata,
+ _type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
+ );
+ return true;
+ }
+
+ //Send an empty end-of-burst packet to end streaming.
+ //Ending the burst avoids an underflow error on stop.
+ bool stop(void){
+ uhd::tx_metadata_t metadata;
+ metadata.end_of_burst = true;
+
+ _dev->get_device()->send(
+ gr_vector_const_void_star(_nchan), 0, metadata,
+ _type, uhd::device::SEND_MODE_ONE_PACKET, 1.0
+ );
+ return true;
+ }
+
+protected:
+ uhd::usrp::multi_usrp::sptr _dev;
+ const uhd::io_type_t _type;
+ size_t _nchan;
+};
+
+/***********************************************************************
+ * Make UHD Multi USRP Sink
+ **********************************************************************/
+boost::shared_ptr<uhd_multi_usrp_sink> uhd_make_multi_usrp_sink(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+){
+ return boost::shared_ptr<uhd_multi_usrp_sink>(
+ new uhd_multi_usrp_sink_impl(device_addr, io_type, num_channels)
+ );
+}
diff --git a/gr-uhd/lib/uhd_multi_usrp_sink.h b/gr-uhd/lib/uhd_multi_usrp_sink.h
new file mode 100644
index 0000000000..370e59d0e1
--- /dev/null
+++ b/gr-uhd/lib/uhd_multi_usrp_sink.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2010 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_UHD_MULTI_USRP_SINK_H
+#define INCLUDED_UHD_MULTI_USRP_SINK_H
+
+#include <gr_sync_block.h>
+#include <uhd/usrp/multi_usrp.hpp>
+
+class uhd_multi_usrp_sink;
+
+boost::shared_ptr<uhd_multi_usrp_sink> uhd_make_multi_usrp_sink(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+);
+
+class uhd_multi_usrp_sink : public gr_sync_block{
+public:
+
+ /*!
+ * Set the IO signature for this block.
+ * \param sig the input signature
+ */
+ uhd_multi_usrp_sink(gr_io_signature_sptr sig);
+
+ /*!
+ * Set the subdevice specification.
+ * \param spec the subdev spec markup string
+ * \param mboard the motherboard index 0 to M-1
+ */
+ virtual void set_subdev_spec(const std::string &spec, size_t mboard) = 0;
+
+ /*!
+ * Set the sample rate for the usrp device.
+ * \param rate a new rate in Sps
+ */
+ virtual void set_samp_rate(double rate) = 0;
+
+ /*!
+ * Get the sample rate for the usrp device.
+ * This is the actual sample rate and may differ from the rate set.
+ * \return the actual rate in Sps
+ */
+ virtual double get_samp_rate(void) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * \param tune_request the tune request instructions
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ virtual uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * This is a wrapper around set center freq so that in this case,
+ * the user can pass a single frequency in the call through swig.
+ * \param freq the desired frequency in Hz
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ uhd::tune_result_t set_center_freq(double freq, size_t chan){
+ return set_center_freq(uhd::tune_request_t(freq), chan);
+ }
+
+ /*!
+ * Get the tunable frequency range.
+ * \param chan the channel index 0 to N-1
+ * \return the frequency range in Hz
+ */
+ virtual uhd::freq_range_t get_freq_range(size_t chan) = 0;
+
+ /*!
+ * Set the gain for the dboard.
+ * \param gain the gain in dB
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(float gain, size_t chan) = 0;
+
+ /*!
+ * Get the actual dboard gain setting.
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual float get_gain(size_t chan) = 0;
+
+ /*!
+ * Get the settable gain range.
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(size_t chan) = 0;
+
+ /*!
+ * Set the antenna to use.
+ * \param ant the antenna string
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_antenna(const std::string &ant, size_t chan) = 0;
+
+ /*!
+ * Get the antenna in use.
+ * \param chan the channel index 0 to N-1
+ * \return the antenna string
+ */
+ virtual std::string get_antenna(size_t chan) = 0;
+
+ /*!
+ * Get a list of possible antennas.
+ * \param chan the channel index 0 to N-1
+ * \return a vector of antenna strings
+ */
+ virtual std::vector<std::string> get_antennas(size_t chan) = 0;
+
+ /*!
+ * Set the subdevice bandpass filter.
+ * \param chan the channel index 0 to N-1
+ * \param bandwidth the filter bandwidth in Hz
+ */
+ virtual void set_bandwidth(double bandwidth, size_t chan) = 0;
+
+ /*!
+ * Set the clock configuration.
+ * \param clock_config the new configuration
+ * \param mboard the motherboard index 0 to M-1
+ */
+ virtual void set_clock_config(const uhd::clock_config_t &clock_config, size_t mboard) = 0;
+
+ /*!
+ * Get the current time registers.
+ * \return the current usrp time
+ */
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ /*!
+ * Set the time registers at the next pps.
+ * \param time_spec the new time
+ */
+ virtual void set_time_next_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Sync the time registers with an unknown pps edge.
+ * \param time_spec the new time
+ */
+ virtual void set_time_unknown_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Get access to the underlying uhd device object.
+ * \return the multi usrp device object
+ */
+ virtual uhd::usrp::multi_usrp::sptr get_device(void) = 0;
+};
+
+#endif /* INCLUDED_UHD_MULTI_USRP_SINK_H */
diff --git a/gr-uhd/lib/uhd_multi_usrp_source.cc b/gr-uhd/lib/uhd_multi_usrp_source.cc
new file mode 100644
index 0000000000..029a763e33
--- /dev/null
+++ b/gr-uhd/lib/uhd_multi_usrp_source.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <uhd_multi_usrp_source.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <iostream>
+#include <boost/format.hpp>
+
+/***********************************************************************
+ * UHD Multi USRP Source
+ **********************************************************************/
+uhd_multi_usrp_source::uhd_multi_usrp_source(gr_io_signature_sptr sig)
+:gr_sync_block("uhd multi_usrp source", gr_make_io_signature(0, 0, 0), sig){
+ /* NOP */
+}
+
+/***********************************************************************
+ * UHD Multi USRP Source Impl
+ **********************************************************************/
+class uhd_multi_usrp_source_impl : public uhd_multi_usrp_source{
+public:
+ uhd_multi_usrp_source_impl(
+ const std::string &device_addr,
+ const uhd::io_type_t &io_type,
+ size_t num_channels
+ ):
+ uhd_multi_usrp_source(gr_make_io_signature(
+ num_channels, num_channels, io_type.size
+ )),
+ _type(io_type)
+ {
+ _dev = uhd::usrp::multi_usrp::make(device_addr);
+ }
+
+ void set_subdev_spec(const std::string &spec, size_t mboard){
+ return _dev->set_rx_subdev_spec(spec, mboard);
+ }
+
+ void set_samp_rate(double rate){
+ _dev->set_rx_rate(rate);
+ }
+
+ double get_samp_rate(void){
+ return _dev->get_rx_rate();
+ }
+
+ uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ){
+ return _dev->set_rx_freq(tune_request, chan);
+ }
+
+ uhd::freq_range_t get_freq_range(size_t chan){
+ return _dev->get_rx_freq_range(chan);
+ }
+
+ void set_gain(float gain, size_t chan){
+ return _dev->set_rx_gain(gain, chan);
+ }
+
+ float get_gain(size_t chan){
+ return _dev->get_rx_gain(chan);
+ }
+
+ uhd::gain_range_t get_gain_range(size_t chan){
+ return _dev->get_rx_gain_range(chan);
+ }
+
+ void set_antenna(const std::string &ant, size_t chan){
+ return _dev->set_rx_antenna(ant, chan);
+ }
+
+ std::string get_antenna(size_t chan){
+ return _dev->get_rx_antenna(chan);
+ }
+
+ std::vector<std::string> get_antennas(size_t chan){
+ return _dev->get_rx_antennas(chan);
+ }
+
+ void set_bandwidth(double bandwidth, size_t chan){
+ return _dev->set_rx_bandwidth(bandwidth, chan);
+ }
+
+ void set_clock_config(const uhd::clock_config_t &clock_config, size_t mboard){
+ return _dev->set_clock_config(clock_config, mboard);
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ return _dev->get_time_now();
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_next_pps(time_spec);
+ }
+
+ void set_time_unknown_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_unknown_pps(time_spec);
+ }
+
+ uhd::usrp::multi_usrp::sptr get_device(void){
+ return _dev;
+ }
+
+/***********************************************************************
+ * Work
+ **********************************************************************/
+ int work(
+ int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ uhd::rx_metadata_t metadata; //not passed out of this block
+
+ size_t num_samps = _dev->get_device()->recv(
+ output_items, noutput_items, metadata,
+ _type, uhd::device::RECV_MODE_FULL_BUFF, 1.0
+ );
+
+ switch(metadata.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_NONE:
+ return num_samps;
+
+ case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
+ //ignore overflows and try work again
+ return work(noutput_items, input_items, output_items);
+
+ default:
+ std::cout << boost::format(
+ "UHD source block got error code 0x%x"
+ ) % metadata.error_code << std::endl;
+ return num_samps;
+ }
+ }
+
+ bool start(void){
+ //setup a stream command that starts streaming slightly in the future
+ static const double reasonable_delay = 0.1; //order of magnitude over RTT
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ stream_cmd.stream_now = false;
+ stream_cmd.time_spec = get_time_now() + uhd::time_spec_t(reasonable_delay);
+ _dev->issue_stream_cmd(stream_cmd);
+ return true;
+ }
+
+ bool stop(void){
+ _dev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ return true;
+ }
+
+private:
+ uhd::usrp::multi_usrp::sptr _dev;
+ const uhd::io_type_t _type;
+};
+
+
+/***********************************************************************
+ * Make UHD Multi USRP Source
+ **********************************************************************/
+boost::shared_ptr<uhd_multi_usrp_source> uhd_make_multi_usrp_source(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+){
+ return boost::shared_ptr<uhd_multi_usrp_source>(
+ new uhd_multi_usrp_source_impl(device_addr, io_type, num_channels)
+ );
+}
diff --git a/gr-uhd/lib/uhd_multi_usrp_source.h b/gr-uhd/lib/uhd_multi_usrp_source.h
new file mode 100644
index 0000000000..b3cbdae1f6
--- /dev/null
+++ b/gr-uhd/lib/uhd_multi_usrp_source.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2010 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_UHD_MULTI_USRP_SOURCE_H
+#define INCLUDED_UHD_MULTI_USRP_SOURCE_H
+
+#include <gr_sync_block.h>
+#include <uhd/usrp/multi_usrp.hpp>
+
+class uhd_multi_usrp_source;
+
+boost::shared_ptr<uhd_multi_usrp_source> uhd_make_multi_usrp_source(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+);
+
+class uhd_multi_usrp_source : public gr_sync_block{
+public:
+
+ /*!
+ * Set the IO signature for this block.
+ * \param sig the output signature
+ */
+ uhd_multi_usrp_source(gr_io_signature_sptr sig);
+
+ /*!
+ * Set the subdevice specification.
+ * \param spec the subdev spec markup string
+ * \param mboard the motherboard index 0 to M-1
+ */
+ virtual void set_subdev_spec(const std::string &spec, size_t mboard) = 0;
+
+ /*!
+ * Set the sample rate for the usrp device.
+ * \param rate a new rate in Sps
+ */
+ virtual void set_samp_rate(double rate) = 0;
+
+ /*!
+ * Get the sample rate for the usrp device.
+ * This is the actual sample rate and may differ from the rate set.
+ * \return the actual rate in Sps
+ */
+ virtual double get_samp_rate(void) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * \param tune_request the tune request instructions
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ virtual uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * This is a wrapper around set center freq so that in this case,
+ * the user can pass a single frequency in the call through swig.
+ * \param freq the desired frequency in Hz
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ uhd::tune_result_t set_center_freq(double freq, size_t chan){
+ return set_center_freq(uhd::tune_request_t(freq), chan);
+ }
+
+ /*!
+ * Get the tunable frequency range.
+ * \param chan the channel index 0 to N-1
+ * \return the frequency range in Hz
+ */
+ virtual uhd::freq_range_t get_freq_range(size_t chan) = 0;
+
+ /*!
+ * Set the gain for the dboard.
+ * \param gain the gain in dB
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(float gain, size_t chan) = 0;
+
+ /*!
+ * Get the actual dboard gain setting.
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual float get_gain(size_t chan) = 0;
+
+ /*!
+ * Get the settable gain range.
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(size_t chan) = 0;
+
+ /*!
+ * Set the antenna to use.
+ * \param ant the antenna string
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_antenna(const std::string &ant, size_t chan) = 0;
+
+ /*!
+ * Get the antenna in use.
+ * \param chan the channel index 0 to N-1
+ * \return the antenna string
+ */
+ virtual std::string get_antenna(size_t chan) = 0;
+
+ /*!
+ * Get a list of possible antennas.
+ * \param chan the channel index 0 to N-1
+ * \return a vector of antenna strings
+ */
+ virtual std::vector<std::string> get_antennas(size_t chan) = 0;
+
+ /*!
+ * Set the subdevice bandpass filter.
+ * \param bandwidth the filter bandwidth in Hz
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_bandwidth(double bandwidth, size_t chan) = 0;
+
+ /*!
+ * Set the clock configuration.
+ * \param clock_config the new configuration
+ * \param mboard the motherboard index 0 to M-1
+ */
+ virtual void set_clock_config(const uhd::clock_config_t &clock_config, size_t mboard) = 0;
+
+ /*!
+ * Get the current time registers.
+ * \return the current usrp time
+ */
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ /*!
+ * Set the time registers at the next pps.
+ * \param time_spec the new time
+ */
+ virtual void set_time_next_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Sync the time registers with an unknown pps edge.
+ * \param time_spec the new time
+ */
+ virtual void set_time_unknown_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Get access to the underlying uhd device object.
+ * \return the multi usrp device object
+ */
+ virtual uhd::usrp::multi_usrp::sptr get_device(void) = 0;
+};
+
+#endif /* INCLUDED_UHD_MULTI_USRP_SOURCE_H */
diff --git a/gr-uhd/lib/uhd_single_usrp_sink.cc b/gr-uhd/lib/uhd_single_usrp_sink.cc
new file mode 100644
index 0000000000..622f506b55
--- /dev/null
+++ b/gr-uhd/lib/uhd_single_usrp_sink.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <uhd_single_usrp_sink.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+
+/***********************************************************************
+ * UHD Single USRP Sink
+ **********************************************************************/
+uhd_single_usrp_sink::uhd_single_usrp_sink(gr_io_signature_sptr sig)
+:gr_sync_block("uhd single usrp sink", sig, gr_make_io_signature(0, 0, 0)){
+ /* NOP */
+}
+
+/***********************************************************************
+ * UHD Single USRP Sink Impl
+ **********************************************************************/
+class uhd_single_usrp_sink_impl : public uhd_single_usrp_sink{
+public:
+ uhd_single_usrp_sink_impl(
+ const std::string &device_addr,
+ const uhd::io_type_t &io_type,
+ size_t num_channels
+ ):
+ uhd_single_usrp_sink(gr_make_io_signature(
+ num_channels, num_channels, io_type.size
+ )),
+ _type(io_type),
+ _nchan(num_channels)
+ {
+ _dev = uhd::usrp::single_usrp::make(device_addr);
+ }
+
+ void set_subdev_spec(const std::string &spec){
+ return _dev->set_tx_subdev_spec(spec);
+ }
+
+ void set_samp_rate(double rate){
+ _dev->set_tx_rate(rate);
+ }
+
+ double get_samp_rate(void){
+ return _dev->get_tx_rate();
+ }
+
+ uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ){
+ return _dev->set_tx_freq(tune_request, chan);
+ }
+
+ uhd::freq_range_t get_freq_range(size_t chan){
+ return _dev->get_tx_freq_range(chan);
+ }
+
+ void set_gain(float gain, size_t chan){
+ return _dev->set_tx_gain(gain, chan);
+ }
+
+ float get_gain(size_t chan){
+ return _dev->get_tx_gain(chan);
+ }
+
+ uhd::gain_range_t get_gain_range(size_t chan){
+ return _dev->get_tx_gain_range(chan);
+ }
+
+ void set_antenna(const std::string &ant, size_t chan){
+ return _dev->set_tx_antenna(ant, chan);
+ }
+
+ std::string get_antenna(size_t chan){
+ return _dev->get_tx_antenna(chan);
+ }
+
+ std::vector<std::string> get_antennas(size_t chan){
+ return _dev->get_tx_antennas(chan);
+ }
+
+ void set_bandwidth(double bandwidth, size_t chan){
+ return _dev->set_tx_bandwidth(bandwidth, chan);
+ }
+
+ void set_clock_config(const uhd::clock_config_t &clock_config){
+ return _dev->set_clock_config(clock_config);
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ return _dev->get_time_now();
+ }
+
+ void set_time_now(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_now(time_spec);
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_next_pps(time_spec);
+ }
+
+ uhd::usrp::single_usrp::sptr get_device(void){
+ return _dev;
+ }
+
+/***********************************************************************
+ * Work
+ **********************************************************************/
+ int work(
+ int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ uhd::tx_metadata_t metadata;
+ metadata.start_of_burst = true;
+
+ return _dev->get_device()->send(
+ input_items, noutput_items, metadata,
+ _type, uhd::device::SEND_MODE_FULL_BUFF
+ );
+ }
+
+ //Send an empty start-of-burst packet to begin streaming.
+ //This is not necessary since all packets are marked SOB.
+ bool start(void){
+ uhd::tx_metadata_t metadata;
+ metadata.start_of_burst = true;
+
+ _dev->get_device()->send(
+ gr_vector_const_void_star(_nchan), 0, metadata,
+ _type, uhd::device::SEND_MODE_ONE_PACKET
+ );
+ return true;
+ }
+
+ //Send an empty end-of-burst packet to end streaming.
+ //Ending the burst avoids an underflow error on stop.
+ bool stop(void){
+ uhd::tx_metadata_t metadata;
+ metadata.end_of_burst = true;
+
+ _dev->get_device()->send(
+ gr_vector_const_void_star(_nchan), 0, metadata,
+ _type, uhd::device::SEND_MODE_ONE_PACKET
+ );
+ return true;
+ }
+
+protected:
+ uhd::usrp::single_usrp::sptr _dev;
+ const uhd::io_type_t _type;
+ size_t _nchan;
+};
+
+/***********************************************************************
+ * Make UHD Single USRP Sink
+ **********************************************************************/
+boost::shared_ptr<uhd_single_usrp_sink> uhd_make_single_usrp_sink(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+){
+ return boost::shared_ptr<uhd_single_usrp_sink>(
+ new uhd_single_usrp_sink_impl(device_addr, io_type, num_channels)
+ );
+}
diff --git a/gr-uhd/lib/uhd_single_usrp_sink.h b/gr-uhd/lib/uhd_single_usrp_sink.h
new file mode 100644
index 0000000000..a4c4e6452e
--- /dev/null
+++ b/gr-uhd/lib/uhd_single_usrp_sink.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2010 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_UHD_SINGLE_USRP_SINK_H
+#define INCLUDED_UHD_SINGLE_USRP_SINK_H
+
+#include <gr_sync_block.h>
+#include <uhd/usrp/single_usrp.hpp>
+
+class uhd_single_usrp_sink;
+
+boost::shared_ptr<uhd_single_usrp_sink> uhd_make_single_usrp_sink(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels = 1
+);
+
+class uhd_single_usrp_sink : public gr_sync_block{
+public:
+
+ /*!
+ * Set the IO signature for this block.
+ * \param sig the input signature
+ */
+ uhd_single_usrp_sink(gr_io_signature_sptr sig);
+
+ /*!
+ * Set the subdevice specification.
+ * \param spec the subdev spec markup string
+ */
+ virtual void set_subdev_spec(const std::string &spec) = 0;
+
+ /*!
+ * Set the sample rate for the usrp device.
+ * \param rate a new rate in Sps
+ */
+ virtual void set_samp_rate(double rate) = 0;
+
+ /*!
+ * Get the sample rate for the usrp device.
+ * This is the actual sample rate and may differ from the rate set.
+ * \return the actual rate in Sps
+ */
+ virtual double get_samp_rate(void) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * \param tune_request the tune request instructions
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ virtual uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * This is a wrapper around set center freq so that in this case,
+ * the user can pass a single frequency in the call through swig.
+ * \param freq the desired frequency in Hz
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ uhd::tune_result_t set_center_freq(double freq, size_t chan){
+ return set_center_freq(uhd::tune_request_t(freq), chan);
+ }
+
+ /*!
+ * Get the tunable frequency range.
+ * \param chan the channel index 0 to N-1
+ * \return the frequency range in Hz
+ */
+ virtual uhd::freq_range_t get_freq_range(size_t chan = 0) = 0;
+
+ /*!
+ * Set the gain for the dboard.
+ * \param gain the gain in dB
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(float gain, size_t chan = 0) = 0;
+
+ /*!
+ * Get the actual dboard gain setting.
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual float get_gain(size_t chan = 0) = 0;
+
+ /*!
+ * Get the settable gain range.
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0;
+
+ /*!
+ * Set the antenna to use.
+ * \param ant the antenna string
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_antenna(const std::string &ant, size_t chan = 0) = 0;
+
+ /*!
+ * Get the antenna in use.
+ * \param chan the channel index 0 to N-1
+ * \return the antenna string
+ */
+ virtual std::string get_antenna(size_t chan = 0) = 0;
+
+ /*!
+ * Get a list of possible antennas.
+ * \param chan the channel index 0 to N-1
+ * \return a vector of antenna strings
+ */
+ virtual std::vector<std::string> get_antennas(size_t chan = 0) = 0;
+
+ /*!
+ * Set the subdevice bandpass filter.
+ * \param bandwidth the filter bandwidth in Hz
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_bandwidth(double bandwidth, size_t chan = 0) = 0;
+
+ /*!
+ * Set the clock configuration.
+ * \param clock_config the new configuration
+ */
+ virtual void set_clock_config(const uhd::clock_config_t &clock_config) = 0;
+
+ /*!
+ * Get the current time registers.
+ * \return the current usrp time
+ */
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ /*!
+ * Set the time registers asap.
+ * \param time_spec the new time
+ */
+ virtual void set_time_now(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Set the time registers at the next pps.
+ * \param time_spec the new time
+ */
+ virtual void set_time_next_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Get access to the underlying uhd device object.
+ * \return the single usrp device object
+ */
+ virtual uhd::usrp::single_usrp::sptr get_device(void) = 0;
+};
+
+#endif /* INCLUDED_UHD_SINGLE_USRP_SINK_H */
diff --git a/gr-uhd/lib/uhd_single_usrp_source.cc b/gr-uhd/lib/uhd_single_usrp_source.cc
new file mode 100644
index 0000000000..907e8be542
--- /dev/null
+++ b/gr-uhd/lib/uhd_single_usrp_source.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <uhd_single_usrp_source.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <iostream>
+#include <boost/format.hpp>
+
+/***********************************************************************
+ * UHD Single USRP Source
+ **********************************************************************/
+uhd_single_usrp_source::uhd_single_usrp_source(gr_io_signature_sptr sig)
+:gr_sync_block("uhd single_usrp source", gr_make_io_signature(0, 0, 0), sig){
+ /* NOP */
+}
+
+/***********************************************************************
+ * UHD Single USRP Source Impl
+ **********************************************************************/
+class uhd_single_usrp_source_impl : public uhd_single_usrp_source{
+public:
+ uhd_single_usrp_source_impl(
+ const std::string &device_addr,
+ const uhd::io_type_t &io_type,
+ size_t num_channels
+ ):
+ uhd_single_usrp_source(gr_make_io_signature(
+ num_channels, num_channels, io_type.size
+ )),
+ _type(io_type)
+ {
+ _dev = uhd::usrp::single_usrp::make(device_addr);
+ }
+
+ void set_subdev_spec(const std::string &spec){
+ return _dev->set_rx_subdev_spec(spec);
+ }
+
+ void set_samp_rate(double rate){
+ _dev->set_rx_rate(rate);
+ }
+
+ double get_samp_rate(void){
+ return _dev->get_rx_rate();
+ }
+
+ uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ){
+ return _dev->set_rx_freq(tune_request, chan);
+ }
+
+ uhd::freq_range_t get_freq_range(size_t chan){
+ return _dev->get_rx_freq_range(chan);
+ }
+
+ void set_gain(float gain, size_t chan){
+ return _dev->set_rx_gain(gain, chan);
+ }
+
+ float get_gain(size_t chan){
+ return _dev->get_rx_gain(chan);
+ }
+
+ uhd::gain_range_t get_gain_range(size_t chan){
+ return _dev->get_rx_gain_range(chan);
+ }
+
+ void set_antenna(const std::string &ant, size_t chan){
+ return _dev->set_rx_antenna(ant, chan);
+ }
+
+ std::string get_antenna(size_t chan){
+ return _dev->get_rx_antenna(chan);
+ }
+
+ std::vector<std::string> get_antennas(size_t chan){
+ return _dev->get_rx_antennas(chan);
+ }
+
+ void set_bandwidth(double bandwidth, size_t chan){
+ return _dev->set_rx_bandwidth(bandwidth, chan);
+ }
+
+ void set_clock_config(const uhd::clock_config_t &clock_config){
+ return _dev->set_clock_config(clock_config);
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ return _dev->get_time_now();
+ }
+
+ void set_time_now(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_now(time_spec);
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time_spec){
+ return _dev->set_time_next_pps(time_spec);
+ }
+
+ uhd::usrp::single_usrp::sptr get_device(void){
+ return _dev;
+ }
+
+/***********************************************************************
+ * Work
+ **********************************************************************/
+ int work(
+ int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items
+ ){
+ uhd::rx_metadata_t metadata; //not passed out of this block
+
+ size_t num_samps = _dev->get_device()->recv(
+ output_items, noutput_items, metadata,
+ _type, uhd::device::RECV_MODE_FULL_BUFF
+ );
+
+ switch(metadata.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_NONE:
+ return num_samps;
+
+ case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
+ //ignore overflows and try work again
+ return work(noutput_items, input_items, output_items);
+
+ default:
+ std::cout << boost::format(
+ "UHD source block got error code 0x%x"
+ ) % metadata.error_code << std::endl;
+ return num_samps;
+ }
+ }
+
+ bool start(void){
+ _dev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ return true;
+ }
+
+ bool stop(void){
+ _dev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ return true;
+ }
+
+private:
+ uhd::usrp::single_usrp::sptr _dev;
+ const uhd::io_type_t _type;
+};
+
+
+/***********************************************************************
+ * Make UHD Single USRP Source
+ **********************************************************************/
+boost::shared_ptr<uhd_single_usrp_source> uhd_make_single_usrp_source(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels
+){
+ return boost::shared_ptr<uhd_single_usrp_source>(
+ new uhd_single_usrp_source_impl(device_addr, io_type, num_channels)
+ );
+}
diff --git a/gr-uhd/lib/uhd_single_usrp_source.h b/gr-uhd/lib/uhd_single_usrp_source.h
new file mode 100644
index 0000000000..2a011b2b3a
--- /dev/null
+++ b/gr-uhd/lib/uhd_single_usrp_source.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010 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_UHD_SINGLE_USRP_SOURCE_H
+#define INCLUDED_UHD_SINGLE_USRP_SOURCE_H
+
+#include <gr_sync_block.h>
+#include <uhd/usrp/single_usrp.hpp>
+
+class uhd_single_usrp_source;
+
+boost::shared_ptr<uhd_single_usrp_source> uhd_make_single_usrp_source(
+ const std::string &device_addr,
+ const uhd::io_type_t::tid_t &io_type,
+ size_t num_channels = 1
+);
+
+class uhd_single_usrp_source : public gr_sync_block{
+public:
+
+ /*!
+ * Set the IO signature for this block.
+ * \param sig the output signature
+ */
+ uhd_single_usrp_source(gr_io_signature_sptr sig);
+
+ /*!
+ * Set the subdevice specification.
+ * \param spec the subdev spec markup string
+ */
+ virtual void set_subdev_spec(const std::string &spec) = 0;
+
+ /*!
+ * Set the sample rate for the usrp device.
+ * \param rate a new rate in Sps
+ */
+ virtual void set_samp_rate(double rate) = 0;
+
+ /*!
+ * Get the sample rate for the usrp device.
+ * This is the actual sample rate and may differ from the rate set.
+ * \return the actual rate in Sps
+ */
+ virtual double get_samp_rate(void) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * \param tune_request the tune request instructions
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ virtual uhd::tune_result_t set_center_freq(
+ const uhd::tune_request_t tune_request, size_t chan
+ ) = 0;
+
+ /*!
+ * Tune the usrp device to the desired center frequency.
+ * This is a wrapper around set center freq so that in this case,
+ * the user can pass a single frequency in the call through swig.
+ * \param freq the desired frequency in Hz
+ * \param chan the channel index 0 to N-1
+ * \return a tune result with the actual frequencies
+ */
+ uhd::tune_result_t set_center_freq(double freq, size_t chan){
+ return set_center_freq(uhd::tune_request_t(freq), chan);
+ }
+
+ /*!
+ * Get the tunable frequency range.
+ * \param chan the channel index 0 to N-1
+ * \return the frequency range in Hz
+ */
+ virtual uhd::freq_range_t get_freq_range(size_t chan = 0) = 0;
+
+ /*!
+ * Set the gain for the dboard.
+ * \param gain the gain in dB
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(float gain, size_t chan = 0) = 0;
+
+ /*!
+ * Get the actual dboard gain setting.
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual float get_gain(size_t chan = 0) = 0;
+
+ /*!
+ * Get the settable gain range.
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0;
+
+ /*!
+ * Set the antenna to use.
+ * \param ant the antenna string
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_antenna(const std::string &ant, size_t chan = 0) = 0;
+
+ /*!
+ * Get the antenna in use.
+ * \param chan the channel index 0 to N-1
+ * \return the antenna string
+ */
+ virtual std::string get_antenna(size_t chan = 0) = 0;
+
+ /*!
+ * Get a list of possible antennas.
+ * \param chan the channel index 0 to N-1
+ * \return a vector of antenna strings
+ */
+ virtual std::vector<std::string> get_antennas(size_t chan = 0) = 0;
+
+ /*!
+ * Set the subdevice bandpass filter.
+ * \param bandwidth the filter bandwidth in Hz
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_bandwidth(double bandwidth, size_t chan = 0) = 0;
+
+ /*!
+ * Set the clock configuration.
+ * \param clock_config the new configuration
+ */
+ virtual void set_clock_config(const uhd::clock_config_t &clock_config) = 0;
+
+ /*!
+ * Get the current time registers.
+ * \return the current usrp time
+ */
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ /*!
+ * Set the time registers asap.
+ * \param time_spec the new time
+ */
+ virtual void set_time_now(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Set the time registers at the next pps.
+ * \param time_spec the new time
+ */
+ virtual void set_time_next_pps(const uhd::time_spec_t &time_spec) = 0;
+
+ /*!
+ * Get access to the underlying uhd device object.
+ * \return the single usrp device object
+ */
+ virtual uhd::usrp::single_usrp::sptr get_device(void) = 0;
+
+ protected:
+ size_t d_num_packet_samps;
+ pmt::pmt_t d_tstamp_pair;
+};
+
+#endif /* INCLUDED_UHD_SINGLE_USRP_SOURCE_H */
diff --git a/gr-uhd/swig/.gitignore b/gr-uhd/swig/.gitignore
new file mode 100644
index 0000000000..02d25cc00d
--- /dev/null
+++ b/gr-uhd/swig/.gitignore
@@ -0,0 +1,4 @@
+/uhd_swig.cc
+/uhd_swig.py
+/Makefile
+/Makefile.in
diff --git a/gr-uhd/swig/Makefile.am b/gr-uhd/swig/Makefile.am
new file mode 100644
index 0000000000..b201f676b4
--- /dev/null
+++ b/gr-uhd/swig/Makefile.am
@@ -0,0 +1,65 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+AM_CPPFLAGS = \
+ $(STD_DEFINES_AND_INCLUDES) \
+ $(PYTHON_CPPFLAGS) \
+ $(UHD_CPPFLAGS) \
+ $(WITH_INCLUDES)
+
+uhd_swig_swig_args = $(UHD_CPPFLAGS)
+
+if PYTHON
+# ----------------------------------------------------------------
+# The SWIG library
+# TESTS = run_tests
+
+TOP_SWIG_IFILES = \
+ uhd_swig.i
+
+# Install so that they end up available as:
+# import gnuradio.uhd
+# This ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio/uhd
+uhd_swig_pythondir_category = \
+ gnuradio/uhd
+
+# additional libraries for linking with the SWIG-generated library
+uhd_swig_la_swig_libadd = \
+ $(top_builddir)/gr-uhd/lib/libgnuradio-uhd.la
+
+# additional Python files to be installed along with the SWIG-generated one
+uhd_swig_python = \
+ __init__.py
+
+# additional SWIG files to be installed
+uhd_swig_swiginclude_headers =
+
+include $(top_srcdir)/Makefile.swig
+
+# add some of the variables generated inside the Makefile.swig.gen
+BUILT_SOURCES = $(swig_built_sources)
+
+# Do not distribute the output of SWIG
+no_dist_files = $(swig_built_sources)
+endif
diff --git a/gr-uhd/swig/Makefile.swig.gen b/gr-uhd/swig/Makefile.swig.gen
new file mode 100644
index 0000000000..3804461a4e
--- /dev/null
+++ b/gr-uhd/swig/Makefile.swig.gen
@@ -0,0 +1,259 @@
+# -*- Makefile -*-
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# Makefile.swig.gen for uhd_swig.i
+
+## Default install locations for these files:
+##
+## Default location for the Python directory is:
+## ${prefix}/lib/python${python_version}/site-packages/[category]/uhd_swig
+## Default location for the Python exec directory is:
+## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/uhd_swig
+##
+## The following can be overloaded to change the install location, but
+## this has to be done in the including Makefile.am -before-
+## Makefile.swig is included.
+
+uhd_swig_pythondir_category ?= gnuradio/uhd_swig
+uhd_swig_pylibdir_category ?= $(uhd_swig_pythondir_category)
+uhd_swig_pythondir = $(pythondir)/$(uhd_swig_pythondir_category)
+uhd_swig_pylibdir = $(pyexecdir)/$(uhd_swig_pylibdir_category)
+
+## SWIG headers are always installed into the same directory.
+
+uhd_swig_swigincludedir = $(swigincludedir)
+
+## This is a template file for a "generated" Makefile addition (in
+## this case, "Makefile.swig.gen"). By including the top-level
+## Makefile.swig, this file will be used to generate the SWIG
+## dependencies. Assign the variable TOP_SWIG_FILES to be the list of
+## SWIG .i files to generated wrappings for; there can be more than 1
+## so long as the names are unique (no sorting is done on the
+## TOP_SWIG_FILES list). This file explicitly assumes that a SWIG .i
+## file will generate .cc, .py, and possibly .h files -- meaning that
+## all of these files will have the same base name (that provided for
+## the SWIG .i file).
+##
+## This code is setup to ensure parallel MAKE ("-j" or "-jN") does the
+## right thing. For more info, see <
+## http://sources.redhat.com/automake/automake.html#Multiple-Outputs >
+
+## Stamps used to ensure parallel make does the right thing. These
+## are removed by "make clean", but otherwise unused except during the
+## parallel built. These will not be included in a tarball, because
+## the SWIG-generated files will be removed from the distribution.
+
+STAMPS += $(DEPDIR)/uhd_swig-generate-*
+
+## Other cleaned files: dependency files generated by SWIG or this Makefile
+
+MOSTLYCLEANFILES += $(DEPDIR)/*.S*
+
+## Add the .py and .cc files to the list of SWIG built sources. The
+## .h file is sometimes built, but not always ... so that one has to
+## be added manually by the including Makefile.am .
+
+swig_built_sources += uhd_swig.py uhd_swig.cc
+
+## Various SWIG variables. These can be overloaded in the including
+## Makefile.am by setting the variable value there, then including
+## Makefile.swig .
+
+uhd_swig_swiginclude_HEADERS = \
+ uhd_swig.i \
+ $(uhd_swig_swiginclude_headers)
+
+uhd_swig_pylib_LTLIBRARIES = \
+ _uhd_swig.la
+
+_uhd_swig_la_SOURCES = \
+ uhd_swig.cc \
+ $(uhd_swig_la_swig_sources)
+
+_uhd_swig_la_LIBADD = \
+ $(STD_SWIG_LA_LIB_ADD) \
+ $(uhd_swig_la_swig_libadd)
+
+_uhd_swig_la_LDFLAGS = \
+ $(STD_SWIG_LA_LD_FLAGS) \
+ $(uhd_swig_la_swig_ldflags)
+
+_uhd_swig_la_CXXFLAGS = \
+ $(STD_SWIG_CXX_FLAGS) \
+ $(uhd_swig_la_swig_cxxflags)
+
+uhd_swig_python_PYTHON = \
+ uhd_swig.py \
+ $(uhd_swig_python)
+
+## Entry rule for running SWIG
+
+uhd_swig.h uhd_swig.py uhd_swig.cc: uhd_swig.i
+## This rule will get called only when MAKE decides that one of the
+## targets needs to be created or re-created, because:
+##
+## * The .i file is newer than any or all of the generated files;
+##
+## * Any or all of the .cc, .h, or .py files does not exist and is
+## needed (in the case this file is not needed, the rule for it is
+## ignored); or
+##
+## * Some SWIG-based dependecy of the .cc file isn't met and hence the
+## .cc file needs be be regenerated. Explanation: Because MAKE
+## knows how to handle dependencies for .cc files (regardless of
+## their name or extension), then the .cc file is used as a target
+## instead of the .i file -- but with the dependencies of the .i
+## file. It is this last reason why the line:
+##
+## if test -f $@; then :; else
+##
+## cannot be used in this case: If a .i file dependecy is not met,
+## then the .cc file needs to be rebuilt. But if the stamp is newer
+## than the .cc file, and the .cc file exists, then in the original
+## version (with the 'test' above) the internal MAKE call will not
+## be issued and hence the .cc file will not be rebuilt.
+##
+## Once execution gets to here, it should always proceed no matter the
+## state of a stamp (as discussed in link above). The
+## $(DEPDIR)/uhd_swig-generate stuff is used to allow for parallel
+## builds to "do the right thing". The stamp has no relationship with
+## either the target files or dependency file; it is used solely for
+## the protection of multiple builds during a given call to MAKE.
+##
+## Catch signals SIGHUP (1), SIGINT (2), SIGPIPE (13), and SIGTERM
+## (15). At a caught signal, the quoted command will be issued before
+## exiting. In this case, remove any stamp, whether temporary of not.
+## The trap is valid until the process exits; the process includes all
+## commands appended via "\"s.
+##
+ trap 'rm -rf $(DEPDIR)/uhd_swig-generate-*' 1 2 13 15; \
+##
+## Create a temporary directory, which acts as a lock. The first
+## process to create the directory will succeed and issue the MAKE
+## command to do the actual work, while all subsequent processes will
+## fail -- leading them to wait for the first process to finish.
+##
+ if mkdir $(DEPDIR)/uhd_swig-generate-lock 2>/dev/null; then \
+##
+## This code is being executed by the first process to succeed in
+## creating the directory lock.
+##
+## Remove the stamp associated with this filename.
+##
+ rm -f $(DEPDIR)/uhd_swig-generate-stamp; \
+##
+## Tell MAKE to run the rule for creating this stamp.
+##
+ $(MAKE) $(AM_MAKEFLAGS) $(DEPDIR)/uhd_swig-generate-stamp WHAT=$<; \
+##
+## Now that the .cc, .h, and .py files have been (re)created from the
+## .i file, future checking of this rule during the same MAKE
+## execution will come back that the rule doesn't need to be executed
+## because none of the conditions mentioned at the start of this rule
+## will be positive. Remove the the directory lock, which frees up
+## any waiting process(es) to continue.
+##
+ rmdir $(DEPDIR)/uhd_swig-generate-lock; \
+ else \
+##
+## This code is being executed by any follower processes while the
+## directory lock is in place.
+##
+## Wait until the first process is done, testing once per second.
+##
+ while test -d $(DEPDIR)/uhd_swig-generate-lock; do \
+ sleep 1; \
+ done; \
+##
+## Succeed if and only if the first process succeeded; exit this
+## process returning the status of the generated stamp.
+##
+ test -f $(DEPDIR)/uhd_swig-generate-stamp; \
+ exit $$?; \
+ fi;
+
+$(DEPDIR)/uhd_swig-generate-stamp:
+## This rule will be called only by the first process issuing the
+## above rule to succeed in creating the lock directory, after
+## removing the actual stamp file in order to guarantee that MAKE will
+## execute this rule.
+##
+## Call SWIG to generate the various output files; special
+## post-processing on 'mingw32' host OS for the dependency file.
+##
+ if $(SWIG) $(STD_SWIG_PYTHON_ARGS) $(uhd_swig_swig_args) \
+ -MD -MF $(DEPDIR)/uhd_swig.Std \
+ -module uhd_swig -o uhd_swig.cc $(WHAT); then \
+ if test $(host_os) = mingw32; then \
+ $(RM) $(DEPDIR)/uhd_swig.Sd; \
+ $(SED) 's,\\\\,/,g' < $(DEPDIR)/uhd_swig.Std \
+ > $(DEPDIR)/uhd_swig.Sd; \
+ $(RM) $(DEPDIR)/uhd_swig.Std; \
+ $(MV) $(DEPDIR)/uhd_swig.Sd $(DEPDIR)/uhd_swig.Std; \
+ fi; \
+ else \
+ $(RM) $(DEPDIR)/uhd_swig.S*; exit 1; \
+ fi;
+##
+## Mess with the SWIG output .Std dependency file, to create a
+## dependecy file valid for the input .i file: Basically, simulate the
+## dependency file created for libraries by GNU's libtool for C++,
+## where all of the dependencies for the target are first listed, then
+## each individual dependency is listed as a target with no further
+## dependencies.
+##
+## (1) remove the current dependency file
+##
+ $(RM) $(DEPDIR)/uhd_swig.d
+##
+## (2) Copy the whole SWIG file:
+##
+ cp $(DEPDIR)/uhd_swig.Std $(DEPDIR)/uhd_swig.d
+##
+## (3) all a carriage return to the end of the dependency file.
+##
+ echo "" >> $(DEPDIR)/uhd_swig.d
+##
+## (4) from the SWIG file, remove the first line (the target); remove
+## trailing " \" and " " from each line. Append ":" to each line,
+## followed by 2 carriage returns, then append this to the end of
+## the dependency file.
+##
+ $(SED) -e '1d;s, \\,,g;s, ,,g' < $(DEPDIR)/uhd_swig.Std | \
+ awk '{ printf "%s:\n\n", $$0 }' >> $(DEPDIR)/uhd_swig.d
+##
+## (5) remove the SWIG-generated file
+##
+ $(RM) $(DEPDIR)/uhd_swig.Std
+##
+## Create the stamp for this filename generation, to signal success in
+## executing this rule; allows other threads waiting on this process
+## to continue.
+##
+ touch $(DEPDIR)/uhd_swig-generate-stamp
+
+# KLUDGE: Force runtime include of a SWIG dependency file. This is
+# not guaranteed to be portable, but will probably work. If it works,
+# we have accurate dependencies for our swig stuff, which is good.
+
+@am__include@ @am__quote@./$(DEPDIR)/uhd_swig.d@am__quote@
+
diff --git a/gr-uhd/swig/__init__.py b/gr-uhd/swig/__init__.py
new file mode 100644
index 0000000000..0fdacb796c
--- /dev/null
+++ b/gr-uhd/swig/__init__.py
@@ -0,0 +1,40 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# The presence of this file turns this directory into a Python package
+
+########################################################################
+# Add SWIG generated code to this namespace
+########################################################################
+from uhd_swig import *
+
+########################################################################
+# Add other content from pure-Python modules here
+########################################################################
+
+class tune_request_t(tune_request_t, float):
+ """
+ Make the python tune request object inherit from float
+ so that it can be passed in GRC as a frequency parameter.
+ The type checking in GRC will accept the tune request.
+ """
+ def __new__(self, *args): return float.__new__(self)
+ def __float__(self): return self.target_freq
diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i
new file mode 100644
index 0000000000..695cf1cd21
--- /dev/null
+++ b/gr-uhd/swig/uhd_swig.i
@@ -0,0 +1,106 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+////////////////////////////////////////////////////////////////////////
+// Language independent exception handler
+////////////////////////////////////////////////////////////////////////
+%include exception.i
+
+%exception {
+ try {
+ $action
+ }
+ catch(std::exception &e) {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+ catch(...) {
+ SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+ }
+
+}
+
+////////////////////////////////////////////////////////////////////////
+// standard includes
+////////////////////////////////////////////////////////////////////////
+%include "gnuradio.i"
+%include "std_string.i"
+%include "std_vector.i"
+
+namespace std {
+ %template(StringVector) vector<string>;
+}
+
+////////////////////////////////////////////////////////////////////////
+// block headers
+////////////////////////////////////////////////////////////////////////
+%{
+#include <uhd_multi_usrp_source.h>
+#include <uhd_multi_usrp_sink.h>
+#include <uhd_single_usrp_source.h>
+#include <uhd_single_usrp_sink.h>
+%}
+
+////////////////////////////////////////////////////////////////////////
+// used types
+////////////////////////////////////////////////////////////////////////
+%include <uhd/config.hpp>
+%include <uhd/utils/pimpl.hpp>
+%include <uhd/types/ranges.hpp>
+%include <uhd/types/tune_request.hpp>
+%include <uhd/types/tune_result.hpp>
+%include <uhd/types/io_type.hpp>
+%include <uhd/types/time_spec.hpp>
+%include <uhd/types/clock_config.hpp>
+
+//Re-create range typedefs here with %template as they are not imported.
+//Replicate all the levels of templated inheritance so swig understands.
+
+%template(float_range_t) uhd::range_t<float>;
+%template(_float_range_vector_t) std::vector<uhd::range_t<float> >;
+%template(gain_range_t) uhd::meta_range_t<float>;
+
+%template(double_range_t) uhd::range_t<double>;
+%template(_double_range_vector_t) std::vector<uhd::range_t<double> >;
+%template(freq_range_t) uhd::meta_range_t<double>;
+
+////////////////////////////////////////////////////////////////////////
+// block magic
+////////////////////////////////////////////////////////////////////////
+GR_SWIG_BLOCK_MAGIC(uhd,multi_usrp_source)
+%include <uhd_multi_usrp_source.h>
+
+GR_SWIG_BLOCK_MAGIC(uhd,multi_usrp_sink)
+%include <uhd_multi_usrp_sink.h>
+
+GR_SWIG_BLOCK_MAGIC(uhd,single_usrp_source)
+%include <uhd_single_usrp_source.h>
+
+GR_SWIG_BLOCK_MAGIC(uhd,single_usrp_sink)
+%include <uhd_single_usrp_sink.h>
+
+////////////////////////////////////////////////////////////////////////
+// helpful constants
+////////////////////////////////////////////////////////////////////////
+%{
+static const size_t ALL_MBOARDS = uhd::usrp::multi_usrp::ALL_MBOARDS;
+%}
+static const size_t ALL_MBOARDS;
diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py
index 0e3dbecd94..f3535d321d 100755
--- a/gr-utils/src/python/gr_plot_psd.py
+++ b/gr-utils/src/python/gr_plot_psd.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2007,2008 Free Software Foundation, Inc.
+# Copyright 2007,2008,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -35,6 +35,7 @@ except ImportError:
from optparse import OptionParser
from scipy import log10
+from gnuradio.eng_option import eng_option
class gr_plot_psd:
def __init__(self, datatype, filename, options):
@@ -100,10 +101,10 @@ class gr_plot_psd:
''' Need to do this here and plot later so we can do the fftshift '''
overlap = self.psdfftsize/4
winfunc = scipy.blackman
- psd,freq = self.sp_psd.psd(iq, self.psdfftsize, self.sample_rate,
- window = lambda d: d*winfunc(self.psdfftsize),
- noverlap = overlap, visible=False)
- psd = 10.0*log10(abs(fftpack.fftshift(psd)))
+ psd,freq = mlab.psd(iq, self.psdfftsize, self.sample_rate,
+ window = lambda d: d*winfunc(self.psdfftsize),
+ noverlap = overlap)
+ psd = 10.0*log10(abs(psd))
return (psd, freq)
def make_plots(self):
@@ -159,6 +160,7 @@ class gr_plot_psd:
def draw_psd(self):
self.plot_psd[0].set_data([self.freq, self.iq_psd])
self.sp_psd.set_ylim([min(self.iq_psd)-10, max(self.iq_psd)+10])
+ self.sp_psd.set_xlim([min(self.freq), max(self.freq)])
def draw_spec(self):
overlap = self.specfftsize/4
@@ -236,14 +238,15 @@ def setup_options():
usage="%prog: [options] input_filename"
description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec."
- parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve",
+ usage=usage, description=description)
parser.add_option("-d", "--data-type", type="string", default="complex64",
help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]")
parser.add_option("-B", "--block", type="int", default=8192,
help="Specify the block size [default=%default]")
parser.add_option("-s", "--start", type="int", default=0,
help="Specify where to start in the file [default=%default]")
- parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+ parser.add_option("-R", "--sample-rate", type="eng_float", default=1.0,
help="Set the sampler rate of the data [default=%default]")
parser.add_option("", "--psd-size", type="int", default=1024,
help="Set the size of the PSD FFT [default=%default]")
diff --git a/grc/base/Param.py b/grc/base/Param.py
index e56eac36e1..5cd0f9d6d8 100644
--- a/grc/base/Param.py
+++ b/grc/base/Param.py
@@ -94,7 +94,7 @@ class Param(Element):
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
- self._value = value or self.get_option_keys()[0]
+ self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0]
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 ''
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
index acd98ef841..d53802bef8 100644
--- a/grc/python/Generator.py
+++ b/grc/python/Generator.py
@@ -58,7 +58,7 @@ class Generator(object):
def write(self):
#do throttle warning
all_keys = ' '.join(map(lambda b: b.get_key(), self._flow_graph.get_enabled_blocks()))
- if ('usrp' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys) and self._generate_options != 'hb':
+ if ('usrp' not in all_keys) and ('uhd' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys) and self._generate_options != 'hb':
Messages.send_warning('''\
This flow graph may not have flow control: no audio or usrp blocks found. \
Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''')
diff --git a/usrp/host/include/usrp/usrp_basic.h b/usrp/host/include/usrp/usrp_basic.h
index c24630eb6f..b76493ea4e 100644
--- a/usrp/host/include/usrp/usrp_basic.h
+++ b/usrp/host/include/usrp/usrp_basic.h
@@ -88,7 +88,7 @@ protected:
*/
std::vector< std::vector<db_base_sptr> > d_db;
- //! One time call, made only only from usrp_standard_*::make after shared_ptr is created.
+ // One time call, made only only from usrp_standard_*::make after shared_ptr is created.
void init_db(usrp_basic_sptr u);
diff --git a/version.sh b/version.sh
index 70d6d74f92..0ae0409824 100644
--- a/version.sh
+++ b/version.sh
@@ -1,4 +1,4 @@
MAJOR_VERSION=3
-API_COMPAT=3
-MINOR_VERSION=1
-MAINT_VERSION=git
+API_COMPAT=4
+MINOR_VERSION=git
+MAINT_VERSION=
diff --git a/vrt/README b/vrt/README
new file mode 100644
index 0000000000..97719d412f
--- /dev/null
+++ b/vrt/README
@@ -0,0 +1,10 @@
+The vrt code has been temporarily moved to Eric's Out-of-Tree repository,
+pending the "Grand Build System Reorganization".
+
+To grab the code and build it:
+
+ $ git clone git://gnuradio.org/eb-oot
+
+ $ cd eb-oot/vrt
+ $ ./bootstrap && ./configure
+ $ make && make check && make install