diff options
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 |