diff options
30 files changed, 888 insertions, 82 deletions
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 85495e277..8bccefa95 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 @@ -40,6 +40,12 @@ gr_keep_one_in_n::gr_keep_one_in_n (size_t item_size, int n) gr_make_io_signature (1, 1, item_size)), d_count(n) { + // To avoid bad behavior with using set_relative_rate in this block with + // VERY large values of n, we will keep track of things ourselves. Using + // this to turn off automatic tag propagation, which will be handled + // locally in general_work(). + set_tag_propagation_policy(TPP_DONT); + set_n(n); } @@ -52,7 +58,10 @@ gr_keep_one_in_n::set_n(int n) d_n = n; d_count = n; - set_relative_rate(1.0 / (float)n); + // keep our internal understanding of the relative rate of this block + // don't set the relative rate, though, and we will handle our own + // tag propagation. + d_decim_rate = 1.0/(float)d_n; } int @@ -80,6 +89,19 @@ gr_keep_one_in_n::general_work (int noutput_items, ni++; } + // Because we have set TPP_DONT, we have to propagate the tags here manually. + // Adjustment of the tag sample value is done using the float d_decim_rate. + std::vector<pmt::pmt_t> tags; + std::vector<pmt::pmt_t>::iterator t; + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+ni); + for(t = tags.begin(); t != tags.end(); t++) { + uint64_t newcount = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(*t, 0)); + add_item_tag(0, newcount * d_decim_rate, + pmt::pmt_tuple_ref(*t, 1), + pmt::pmt_tuple_ref(*t, 2), + pmt::pmt_tuple_ref(*t, 3)); + } + consume_each (ni); return no; } diff --git a/gnuradio-core/src/lib/general/gr_keep_one_in_n.h b/gnuradio-core/src/lib/general/gr_keep_one_in_n.h index f12a7a0f1..c32ed2a26 100644 --- a/gnuradio-core/src/lib/general/gr_keep_one_in_n.h +++ b/gnuradio-core/src/lib/general/gr_keep_one_in_n.h @@ -44,6 +44,7 @@ class GR_CORE_API gr_keep_one_in_n : public gr_block int d_n; int d_count; + float d_decim_rate; protected: gr_keep_one_in_n (size_t item_size, int n); diff --git a/gnuradio-examples/python/ofdm/gr_plot_ofdm.py b/gnuradio-examples/python/ofdm/gr_plot_ofdm.py index e3b347189..b24855148 100755 --- a/gnuradio-examples/python/ofdm/gr_plot_ofdm.py +++ b/gnuradio-examples/python/ofdm/gr_plot_ofdm.py @@ -20,14 +20,24 @@ # Boston, MA 02110-1301, USA. # -import scipy, pylab, math -import struct, sys -from pylab import * -from matplotlib.font_manager import fontManager, FontProperties +import math, struct, sys from optparse import OptionParser -from scipy import fftpack from math import log10 +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + from pylab import * + from matplotlib.font_manager import fontManager, FontProperties +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) + matplotlib.interactive(True) matplotlib.use('TkAgg') diff --git a/gnuradio-examples/python/pfb/channelize.py b/gnuradio-examples/python/pfb/channelize.py index f845c05c6..999e5d20e 100755 --- a/gnuradio-examples/python/pfb/channelize.py +++ b/gnuradio-examples/python/pfb/channelize.py @@ -21,10 +21,21 @@ # from gnuradio import gr, blks2 -import os, time -import scipy, pylab -from scipy import fftpack -from pylab import mlab +import sys, time + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab + from pylab import mlab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) class pfb_top_block(gr.top_block): def __init__(self): diff --git a/gnuradio-examples/python/pfb/chirp_channelize.py b/gnuradio-examples/python/pfb/chirp_channelize.py index edebf5f59..951255d3b 100755 --- a/gnuradio-examples/python/pfb/chirp_channelize.py +++ b/gnuradio-examples/python/pfb/chirp_channelize.py @@ -21,10 +21,21 @@ # from gnuradio import gr, blks2 -import os, time -import scipy, pylab -from scipy import fftpack -from pylab import mlab +import sys, time + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab + from pylab import mlab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) class pfb_top_block(gr.top_block): def __init__(self): diff --git a/gnuradio-examples/python/pfb/decimate.py b/gnuradio-examples/python/pfb/decimate.py index cb5d61b72..643a2c241 100755 --- a/gnuradio-examples/python/pfb/decimate.py +++ b/gnuradio-examples/python/pfb/decimate.py @@ -21,14 +21,21 @@ # from gnuradio import gr, blks2 -import os -import scipy, pylab -from scipy import fftpack -from pylab import mlab -import time - -#print os.getpid() -#raw_input() +import sys, time + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab + from pylab import mlab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) class pfb_top_block(gr.top_block): def __init__(self): diff --git a/gnuradio-examples/python/pfb/fmtest.py b/gnuradio-examples/python/pfb/fmtest.py index 97df0e0f5..635ee4e9e 100755 --- a/gnuradio-examples/python/pfb/fmtest.py +++ b/gnuradio-examples/python/pfb/fmtest.py @@ -1,14 +1,42 @@ #!/usr/bin/env python # +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, blks2 +import sys, math, time + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) -from gnuradio import gr, eng_notation -from gnuradio import blks2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import math, time, sys, scipy, pylab -from scipy import fftpack - class fmtx(gr.hier_block2): def __init__(self, lo_freq, audio_rate, if_rate): diff --git a/gnuradio-examples/python/pfb/interpolate.py b/gnuradio-examples/python/pfb/interpolate.py index a7a2522f8..370cf26a7 100755 --- a/gnuradio-examples/python/pfb/interpolate.py +++ b/gnuradio-examples/python/pfb/interpolate.py @@ -21,14 +21,21 @@ # from gnuradio import gr, blks2 -import os -import scipy, pylab -from scipy import fftpack -from pylab import mlab -import time - -#print os.getpid() -#raw_input() +import sys, time + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab + from pylab import mlab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) class pfb_top_block(gr.top_block): def __init__(self): diff --git a/gnuradio-examples/python/pfb/resampler.py b/gnuradio-examples/python/pfb/resampler.py index 6be7cf14e..7b296ca71 100755 --- a/gnuradio-examples/python/pfb/resampler.py +++ b/gnuradio-examples/python/pfb/resampler.py @@ -1,7 +1,39 @@ #!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr, blks2 -import scipy, pylab +import sys + +try: + import scipy +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) class mytb(gr.top_block): def __init__(self, fs_in, fs_out, fc, N=10000): diff --git a/gnuradio-examples/python/pfb/synth_filter.py b/gnuradio-examples/python/pfb/synth_filter.py index a1562f9ea..074d9cb2c 100755 --- a/gnuradio-examples/python/pfb/synth_filter.py +++ b/gnuradio-examples/python/pfb/synth_filter.py @@ -21,7 +21,19 @@ # from gnuradio import gr, blks2 -import scipy, pylab +import sys + +try: + import scipy +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) def main(): N = 1000000 diff --git a/gnuradio-examples/python/pfb/synth_to_chan.py b/gnuradio-examples/python/pfb/synth_to_chan.py index 1beda1a54..7e454d903 100755 --- a/gnuradio-examples/python/pfb/synth_to_chan.py +++ b/gnuradio-examples/python/pfb/synth_to_chan.py @@ -21,7 +21,19 @@ # from gnuradio import gr, blks2 -import scipy, pylab +import sys + +try: + import scipy +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + +try: + import pylab +except ImportError: + print "Error: Program requires matplotlib (see: matplotlib.sourceforge.net)." + sys.exit(1) def main(): N = 1000000 diff --git a/gnuradio-examples/python/tags/test_file_tags.py b/gnuradio-examples/python/tags/test_file_tags.py index 4ff4549ef..446986cd7 100755 --- a/gnuradio-examples/python/tags/test_file_tags.py +++ b/gnuradio-examples/python/tags/test_file_tags.py @@ -1,7 +1,33 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr -import scipy +import sys + +try: + import scipy +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) def main(): data = scipy.arange(0, 32000, 1).tolist() diff --git a/gr-noaa/lib/noaa_hrpt_pll_cf.cc b/gr-noaa/lib/noaa_hrpt_pll_cf.cc index 08ab1d15f..ba2ce98d5 100644 --- a/gr-noaa/lib/noaa_hrpt_pll_cf.cc +++ b/gr-noaa/lib/noaa_hrpt_pll_cf.cc @@ -67,15 +67,16 @@ noaa_hrpt_pll_cf::work(int noutput_items, for (int i = 0; i < noutput_items; i++) { + // Generate and mix out carrier + float re, im; + gr_sincosf(d_phase, &im, &re); + out[i] = (in[i]*gr_complex(re, -im)).imag(); + // Adjust PLL phase/frequency float error = phase_wrap(gr_fast_atan2f(in[i].imag(), in[i].real()) - d_phase); d_freq = gr_branchless_clip(d_freq + error*d_beta, d_max_offset); d_phase = phase_wrap(d_phase + error*d_alpha + d_freq); - // Generate and mix out carrier - float re, im; - gr_sincosf(d_phase, &im, &re); - out[i] = (in[i]*gr_complex(re, -im)).imag(); } return noutput_items; diff --git a/gr-qtgui/apps/qt_digital.py b/gr-qtgui/apps/qt_digital.py index 99c799f2a..2bc039a31 100755 --- a/gr-qtgui/apps/qt_digital.py +++ b/gr-qtgui/apps/qt_digital.py @@ -1,11 +1,42 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr, blks2 -from gnuradio import qtgui from gnuradio import eng_notation -from PyQt4 import QtGui, QtCore -import sys, sip -import scipy +import sys + +try: + from gnuradio import qtgui + from PyQt4 import QtGui, QtCore + import sip +except ImportError: + print "Error: Program requires PyQt4 and gr-qtgui." + sys.exit(1) + +try: + import scipy +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) try: from qt_digital_window import Ui_DigitalWindow diff --git a/gr-qtgui/apps/uhd_display.py b/gr-qtgui/apps/uhd_display.py index 1d69586ef..806914797 100755 --- a/gr-qtgui/apps/uhd_display.py +++ b/gr-qtgui/apps/uhd_display.py @@ -33,7 +33,7 @@ try: from PyQt4 import QtGui, QtCore import sip except ImportError: - print "Please install gr-qtgui." + print "Error: Program requires PyQt4 and gr-qtgui." sys.exit(1) try: diff --git a/gr-qtgui/examples/pyqt_example_c.py b/gr-qtgui/examples/pyqt_example_c.py index 607ab12ee..553d346c9 100755 --- a/gr-qtgui/examples/pyqt_example_c.py +++ b/gr-qtgui/examples/pyqt_example_c.py @@ -1,9 +1,35 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr -from gnuradio import qtgui -from PyQt4 import QtGui, QtCore -import sys, sip +import sys + +try: + from gnuradio import qtgui + from PyQt4 import QtGui, QtCore + import sip +except ImportError: + print "Error: Program requires PyQt4 and gr-qtgui." + sys.exit(1) class dialog_box(QtGui.QWidget): def __init__(self, display, control): diff --git a/gr-qtgui/examples/pyqt_example_f.py b/gr-qtgui/examples/pyqt_example_f.py index 2d957c85a..5e432fe78 100755 --- a/gr-qtgui/examples/pyqt_example_f.py +++ b/gr-qtgui/examples/pyqt_example_f.py @@ -1,9 +1,35 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr -from gnuradio import qtgui -from PyQt4 import QtGui, QtCore -import sys, sip +import sys + +try: + from gnuradio import qtgui + from PyQt4 import QtGui, QtCore + import sip +except ImportError: + print "Error: Program requires PyQt4 and gr-qtgui." + sys.exit(1) class dialog_box(QtGui.QWidget): def __init__(self, display, control): diff --git a/gr-qtgui/examples/pyqt_time_c.py b/gr-qtgui/examples/pyqt_time_c.py index fa7d60e81..a47302d19 100755 --- a/gr-qtgui/examples/pyqt_time_c.py +++ b/gr-qtgui/examples/pyqt_time_c.py @@ -1,9 +1,35 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr -from gnuradio import qtgui -from PyQt4 import QtGui, QtCore -import sys, sip +import sys + +try: + from gnuradio import qtgui + from PyQt4 import QtGui, QtCore + import sip +except ImportError: + print "Error: Program requires PyQt4 and gr-qtgui." + sys.exit(1) class dialog_box(QtGui.QWidget): def __init__(self, display, control): diff --git a/gr-qtgui/examples/pyqt_time_f.py b/gr-qtgui/examples/pyqt_time_f.py index 1b9efa10d..835b42a75 100755 --- a/gr-qtgui/examples/pyqt_time_f.py +++ b/gr-qtgui/examples/pyqt_time_f.py @@ -1,9 +1,35 @@ #!/usr/bin/env python +# +# Copyright 2011 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# from gnuradio import gr -from gnuradio import qtgui -from PyQt4 import QtGui, QtCore -import sys, sip +import sys + +try: + from gnuradio import qtgui + from PyQt4 import QtGui, QtCore + import sip +except ImportError: + print "Error: Program requires PyQt4 and gr-qtgui." + sys.exit(1) class dialog_box(QtGui.QWidget): def __init__(self, display, control): diff --git a/gr-trellis/src/examples/fsm_utils.py b/gr-trellis/src/examples/fsm_utils.py index e3426637c..e9243f899 100755 --- a/gr-trellis/src/examples/fsm_utils.py +++ b/gr-trellis/src/examples/fsm_utils.py @@ -26,10 +26,15 @@ import math import sys import operator import numpy -import scipy.linalg from gnuradio import trellis +try: + import scipy.linalg +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + ###################################################################### diff --git a/gr-trellis/src/examples/test_cpm.py b/gr-trellis/src/examples/test_cpm.py index ec432d4ff..b5bdaae44 100755 --- a/gr-trellis/src/examples/test_cpm.py +++ b/gr-trellis/src/examples/test_cpm.py @@ -13,10 +13,15 @@ from gnuradio.gr import firdes from grc_gnuradio import blks2 as grc_blks2 import math import numpy -import scipy.stats import fsm_utils from gnuradio import trellis +try: + import scipy.stats +except ImportError: + print "Error: Program requires scipy (see: www.scipy.org)." + sys.exit(1) + def run_test(seed,blocksize): tb = gr.top_block() @@ -83,7 +88,7 @@ def run_test(seed,blocksize): ################################################## # Blocks ################################################## - random_source_x_0 = gr.vector_source_b(data, False) + random_source_x_0 = gr.vector_source_b(data.tolist(), False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) @@ -96,9 +101,9 @@ def run_test(seed,blocksize): # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) - gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, N) - gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, N*(1+0)) - viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, N, constellation, trellis.TRELLIS_EUCLIDEAN) + gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, int(N)) + gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, int(N*(1+0))) + viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, int(N), constellation, trellis.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() diff --git a/gr-uhd/examples/tag_sink_demo.h b/gr-uhd/examples/tag_sink_demo.h new file mode 100644 index 000000000..84baf0a9c --- /dev/null +++ b/gr-uhd/examples/tag_sink_demo.h @@ -0,0 +1,66 @@ +/* + * Copyright 2011 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 <gr_sync_block.h> +#include <gr_io_signature.h> +#include <gr_tag_info.h> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +class tag_sink_demo : public gr_sync_block{ +public: + + tag_sink_demo(void): + gr_sync_block( + "uhd tag sink demo", + gr_make_io_signature(1, 1, sizeof(std::complex<float>)), + gr_make_io_signature(0, 0, 0) + ) + { + //NOP + } + + int work( + int ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ){ + //grab all "rx time" tags in this work call + const uint64_t samp0_count = this->nitems_read(0); + std::vector<pmt::pmt_t> rx_time_tags; + get_tags_in_range(rx_time_tags, 0, samp0_count, samp0_count + ninput_items, pmt::pmt_string_to_symbol("rx_time")); + + //print all tags + BOOST_FOREACH(const pmt::pmt_t &rx_time_tag, rx_time_tags){ + const uint64_t count = gr_tags::get_nitems(rx_time_tag); + const pmt::pmt_t &value = gr_tags::get_value(rx_time_tag); + + std::cout << boost::format("Full seconds %u, Frac seconds %f") + % pmt::pmt_to_uint64(pmt_tuple_ref(value, 0)) + % pmt::pmt_to_double(pmt_tuple_ref(value, 1)) + << std::endl; + } + + return ninput_items; + } +}; diff --git a/gr-uhd/examples/tag_source_demo.h b/gr-uhd/examples/tag_source_demo.h new file mode 100644 index 000000000..c7c0884d3 --- /dev/null +++ b/gr-uhd/examples/tag_source_demo.h @@ -0,0 +1,129 @@ +/* + * Copyright 2011 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 <gr_sync_block.h> +#include <gr_io_signature.h> +#include <gr_tag_info.h> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +class tag_source_demo : public gr_sync_block{ +public: + + tag_source_demo( + const uint64_t start_secs, + const double start_fracs, + const double samp_rate, + const double idle_duration, + const double burst_duration + ): + gr_sync_block( + "uhd tag source demo", + gr_make_io_signature(0, 0, 0), + gr_make_io_signature(1, 1, sizeof(std::complex<float>)) + ), + _time_secs(start_secs), + _time_fracs(start_fracs), + _samp_rate(samp_rate), + _samps_per_burst(samp_rate*burst_duration), + _cycle_duration(idle_duration + burst_duration), + _samps_left_in_burst(1), //immediate EOB + _do_new_burst(false) + { + //NOP + } + + void make_time_tag(const uint64_t tag_count){; + const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_time"); + const pmt::pmt_t value = pmt::pmt_make_tuple( + pmt::pmt_from_uint64(_time_secs), + pmt::pmt_from_double(_time_fracs) + ); + const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name()); + this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid); + } + + void make_sob_tag(const uint64_t tag_count){ + const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_sob"); + const pmt::pmt_t value = pmt::PMT_T; + const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name()); + this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid); + } + + void make_eob_tag(const uint64_t tag_count){; + const pmt::pmt_t key = pmt::pmt_string_to_symbol("tx_eob"); + const pmt::pmt_t value = pmt::PMT_T; + const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(this->name()); + this->add_item_tag(0/*chan0*/, tag_count, key, value, srcid); + } + + int work( + int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ){ + //load the output with a constant + std::complex<float> *output = reinterpret_cast<std::complex<float> *>(output_items[0]); + for (size_t i = 0; i < size_t(noutput_items); i++){ + output[i] = std::complex<float>(0.7, 0.7); + } + + //Handle the start of burst condition. + //Tag a start of burst and timestamp. + //Increment the time for the next burst. + if (_do_new_burst){ + _do_new_burst = false; + _samps_left_in_burst = _samps_per_burst; + + this->make_sob_tag(this->nitems_written(0)); + this->make_time_tag(this->nitems_written(0)); + + _time_fracs += _cycle_duration; + double intpart; //normalize + _time_fracs = std::modf(_time_fracs, &intpart); + _time_secs += uint64_t(intpart); + } + + //Handle the end of burst condition. + //Tag an end of burst and return early. + //the next work call will be a start of burst. + if (_samps_left_in_burst < size_t(noutput_items)){ + this->make_eob_tag(this->nitems_written(0) + _samps_left_in_burst - 1); + _do_new_burst = true; + noutput_items = _samps_left_in_burst; + } + + _samps_left_in_burst -= noutput_items; + return noutput_items; + } + +private: + uint64_t _time_secs; + double _time_fracs; + const double _samp_rate; + const uint64_t _samps_per_burst; + const double _cycle_duration; + bool _do_new_burst; + uint64_t _samps_left_in_burst; + +}; diff --git a/gr-uhd/examples/tags_demo.cc b/gr-uhd/examples/tags_demo.cc new file mode 100644 index 000000000..b40518f34 --- /dev/null +++ b/gr-uhd/examples/tags_demo.cc @@ -0,0 +1,139 @@ +/* + * Copyright 2011 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 <gr_top_block.h> +#include <gr_uhd_usrp_source.h> +#include <gr_uhd_usrp_sink.h> +#include <tag_source_demo.h> +#include <tag_sink_demo.h> +#include <boost/make_shared.hpp> +#include <boost/thread/thread.hpp> //sleep +#include <boost/program_options.hpp> +#include <csignal> +#include <iostream> + +namespace po = boost::program_options; + +/*********************************************************************** + * Signal handlers + **********************************************************************/ +static bool stop_signal_called = false; +void sig_int_handler(int){stop_signal_called = true;} + +/*********************************************************************** + * Main w/ program options + **********************************************************************/ +int main(int argc, char *argv[]){ + + std::string device_addr; + double center_freq, samp_rate, burst_dur, idle_dur; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("addr", po::value<std::string>(&device_addr)->default_value(""), "the device address in string format") + ("rate", po::value<double>(&samp_rate)->default_value(1e6), "the sample rate in samples per second") + ("freq", po::value<double>(¢er_freq)->default_value(10e6), "the center frequency in Hz") + ("burst", po::value<double>(&burst_dur)->default_value(0.1), "the duration of each burst in seconds") + ("idle", po::value<double>(&idle_dur)->default_value(0.05), "idle time between bursts in seconds") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout + << boost::format("UHD Tags Demo %s") % desc << std::endl + << "The tags sink demo block will print USRP source time stamps." << std::endl + << "The tags source demo block will send bursts to the USRP sink." << std::endl + << "Look at the USRP output on a scope to see the timed bursts." << std::endl + << std::endl; + return ~0; + } + + //------------------------------------------------------------------ + //-- make a top block + //------------------------------------------------------------------ + gr_top_block_sptr tb = gr_make_top_block("tags_demo"); + + //------------------------------------------------------------------ + //-- make the usrp source test blocks + //------------------------------------------------------------------ + boost::shared_ptr<uhd_usrp_source> usrp_source = uhd_make_usrp_source( + device_addr, uhd::io_type_t::COMPLEX_FLOAT32, 1 + ); + usrp_source->set_samp_rate(samp_rate); + usrp_source->set_center_freq(center_freq); + + boost::shared_ptr<tag_sink_demo> tag_sink = boost::make_shared<tag_sink_demo>(); + + //------------------------------------------------------------------ + //-- connect the usrp source test blocks + //------------------------------------------------------------------ + tb->connect(usrp_source, 0, tag_sink, 0); + + //------------------------------------------------------------------ + //-- make the usrp sink test blocks + //------------------------------------------------------------------ + boost::shared_ptr<uhd_usrp_sink> usrp_sink = uhd_make_usrp_sink( + device_addr, uhd::io_type_t::COMPLEX_FLOAT32, 1 + ); + usrp_sink->set_samp_rate(samp_rate); + usrp_sink->set_center_freq(center_freq); + const uhd::time_spec_t time_now = usrp_sink->get_time_now(); + + boost::shared_ptr<tag_source_demo> tag_source = boost::make_shared<tag_source_demo>( + time_now.get_full_secs() + 1, time_now.get_frac_secs(), //time now + 1 second + samp_rate, idle_dur, burst_dur + ); + + //------------------------------------------------------------------ + //-- connect the usrp sink test blocks + //------------------------------------------------------------------ + tb->connect(tag_source, 0, usrp_sink, 0); + + //------------------------------------------------------------------ + //-- start flow graph execution + //------------------------------------------------------------------ + std::cout << "starting flow graph" << std::endl; + tb->start(); + + //------------------------------------------------------------------ + //-- poll the exit signal while running + //------------------------------------------------------------------ + std::signal(SIGINT, &sig_int_handler); + std::cout << "press ctrl + c to exit" << std::endl; + while (not stop_signal_called){ + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + + //------------------------------------------------------------------ + //-- stop flow graph execution + //------------------------------------------------------------------ + std::cout << "stopping flow graph" << std::endl; + tb->stop(); + tb->wait(); + + std::cout << "done!" << std::endl; + return 0; +} diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py index c77df6c97..b6bc5fb79 100644 --- a/gr-uhd/grc/gen_uhd_usrp_blocks.py +++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py @@ -256,6 +256,8 @@ 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 object rather than a simple target frequency. Tuning with an LO offset example: uhd.tune_request(freq, lo_off) +Tuning without DSP: uhd.tune_request(target_freq, dsp_freq=0, \\ +dsp_freq_policy=uhd.tune_request.POLICY_MANUAL) Antenna: For subdevices with only one antenna, this may be left blank. \\ @@ -266,6 +268,9 @@ 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. + +See the UHD manual for more detailed documentation: +http://code.ettus.com/redmine/ettus/projects/uhd/wiki </doc> </block> """ diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h index 2adc5f1bf..c1fc3b09e 100644 --- a/gr-uhd/include/gr_uhd_usrp_sink.h +++ b/gr-uhd/include/gr_uhd_usrp_sink.h @@ -28,6 +28,33 @@ class uhd_usrp_sink; +/*! + * \brief Make a new USRP sink block. + * + * The USRP sink block reads a stream and transmits the samples. + * The sink block also provides API calls for transmitter settings. + * + * TX Stream tagging: + * + * The following tag keys will be consumed by the work function: + * - pmt::pmt_string_to_symbol("tx_sob") + * - pmt::pmt_string_to_symbol("tx_eob") + * - pmt::pmt_string_to_symbol("tx_time") + * + * The sob and eob (start and end of burst) tag values are pmt booleans. + * When present, burst tags should be set to true (pmt::PMT_T). + * + * The timstamp tag value is a pmt tuple of the following: + * (uint64 seconds, and double fractional seconds). + * + * See the UHD manual for more detailed documentation: + * http://code.ettus.com/redmine/ettus/projects/uhd/wiki + * + * \param device_addr the address to identify the hardware + * \param io_type the desired input data type + * \param num_channels number of stream from the device + * \return a new USRP sink block object + */ GR_UHD_API boost::shared_ptr<uhd_usrp_sink> uhd_make_usrp_sink( const uhd::device_addr_t &device_addr, const uhd::io_type_t &io_type, diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h index 6e51a1423..f8ac9361e 100644 --- a/gr-uhd/include/gr_uhd_usrp_source.h +++ b/gr-uhd/include/gr_uhd_usrp_source.h @@ -28,6 +28,29 @@ class uhd_usrp_source; +/*! + * \brief Make a new USRP source block. + * + * The USRP source block receives samples and writes to a stream. + * The source block also provides API calls for receiver settings. + * + * RX Stream tagging: + * + * The following tag keys will be produced by the work function: + * - pmt::pmt_string_to_symbol("rx_time") + * + * The timstamp tag value is a pmt tuple of the following: + * (uint64 seconds, and double fractional seconds). + * A timestamp tag is produced at start() and after overflows. + * + * See the UHD manual for more detailed documentation: + * http://code.ettus.com/redmine/ettus/projects/uhd/wiki + * + * \param device_addr the address to identify the hardware + * \param io_type the desired output data type + * \param num_channels number of stream from the device + * \return a new USRP source block object + */ GR_UHD_API boost::shared_ptr<uhd_usrp_source> uhd_make_usrp_source( const uhd::device_addr_t &device_addr, const uhd::io_type_t &io_type, diff --git a/gr-uhd/lib/gr_uhd_usrp_sink.cc b/gr-uhd/lib/gr_uhd_usrp_sink.cc index ce9d89d8d..a780f0551 100644 --- a/gr-uhd/lib/gr_uhd_usrp_sink.cc +++ b/gr-uhd/lib/gr_uhd_usrp_sink.cc @@ -21,8 +21,13 @@ #include <gr_uhd_usrp_sink.h> #include <gr_io_signature.h> +#include <gr_tag_info.h> #include <stdexcept> +static const pmt::pmt_t SOB_KEY = pmt::pmt_string_to_symbol("tx_sob"); +static const pmt::pmt_t EOB_KEY = pmt::pmt_string_to_symbol("tx_eob"); +static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("tx_time"); + /*********************************************************************** * UHD Multi USRP Sink Impl **********************************************************************/ @@ -39,8 +44,7 @@ public: gr_make_io_signature(0, 0, 0) ), _type(io_type), - _nchan(num_channels), - _has_time_spec(_nchan > 1) + _nchan(num_channels) { _dev = uhd::usrp::multi_usrp::make(device_addr); } @@ -180,13 +184,20 @@ public: gr_vector_const_void_star &input_items, gr_vector_void_star &output_items ){ + int ninput_items = noutput_items; //cuz its a sync block + //send a mid-burst packet with time spec _metadata.start_of_burst = false; _metadata.end_of_burst = false; - _metadata.has_time_spec = _has_time_spec; - size_t num_sent = _dev->get_device()->send( - input_items, noutput_items, _metadata, + //collect tags in this work() + const uint64_t samp0_count = nitems_read(0); + get_tags_in_range(_tags, 0, samp0_count, samp0_count + ninput_items); + if (not _tags.empty()) this->tag_work(ninput_items); + + //send all ninput_items with metadata + const size_t num_sent = _dev->get_device()->send( + input_items, ninput_items, _metadata, _type, uhd::device::SEND_MODE_FULL_BUFF, 1.0 ); @@ -195,12 +206,70 @@ public: return num_sent; } +/*********************************************************************** + * Tag Work + **********************************************************************/ + inline void tag_work(int &ninput_items){ + //the for loop below assumes tags sorted by count low -> high + std::sort(_tags.begin(), _tags.end(), gr_tags::nitems_compare); + + //extract absolute sample counts + const pmt::pmt_t &tag0 = _tags.front(); + const uint64_t tag0_count = gr_tags::get_nitems(tag0); + const uint64_t samp0_count = this->nitems_read(0); + + //only transmit nsamples from 0 to the first tag + //this ensures that the next work starts on a tag + if (samp0_count != tag0_count){ + ninput_items = tag0_count - samp0_count; + return; + } + + //time will not be set unless a time tag is found + _metadata.has_time_spec = false; + + //process all of the tags found with the same count as tag0 + BOOST_FOREACH(const pmt::pmt_t &my_tag, _tags){ + const uint64_t my_tag_count = gr_tags::get_nitems(my_tag); + const pmt::pmt_t &key = gr_tags::get_key(my_tag); + const pmt::pmt_t &value = gr_tags::get_value(my_tag); + + //determine how many samples to send... + //from zero until the next tag or end of work + if (my_tag_count != tag0_count){ + ninput_items = my_tag_count - samp0_count; + break; + } + + //handle end of burst with a mini end of burst packet + else if (pmt::pmt_equal(key, EOB_KEY)){ + _metadata.end_of_burst = pmt::pmt_to_bool(value); + ninput_items = 1; + return; + } + + //set the start of burst flag in the metadata + else if (pmt::pmt_equal(key, SOB_KEY)){ + _metadata.start_of_burst = pmt::pmt_to_bool(value); + } + + //set the time specification in the metadata + else if (pmt::pmt_equal(key, TIME_KEY)){ + _metadata.has_time_spec = true; + _metadata.time_spec = uhd::time_spec_t( + pmt::pmt_to_uint64(pmt_tuple_ref(value, 0)), + pmt::pmt_to_double(pmt_tuple_ref(value, 1)) + ); + } + } + } + //Send an empty start-of-burst packet to begin streaming. //Set at a time in the near future to avoid late packets. bool start(void){ _metadata.start_of_burst = true; _metadata.end_of_burst = false; - _metadata.has_time_spec = _has_time_spec; + _metadata.has_time_spec = _nchan > 1; _metadata.time_spec = get_time_now() + uhd::time_spec_t(0.01); _dev->get_device()->send( @@ -224,13 +293,15 @@ public: return true; } -protected: +private: uhd::usrp::multi_usrp::sptr _dev; const uhd::io_type_t _type; size_t _nchan; - bool _has_time_spec; uhd::tx_metadata_t _metadata; double _sample_rate; + + //stream tags related stuff + std::vector<pmt::pmt_t> _tags; }; /*********************************************************************** diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc index 669f890ea..62da83d96 100644 --- a/gr-uhd/lib/gr_uhd_usrp_source.cc +++ b/gr-uhd/lib/gr_uhd_usrp_source.cc @@ -25,6 +25,8 @@ #include <iostream> #include <boost/format.hpp> +static const pmt::pmt_t TIME_KEY = pmt::pmt_string_to_symbol("rx_time"); + /*********************************************************************** * UHD Multi USRP Source Impl **********************************************************************/ @@ -43,8 +45,11 @@ public: _type(io_type), _nchan(num_channels), _stream_now(_nchan == 1), - _tmp_buffs(_nchan) + _tag_now(false) { + std::stringstream str; + str << name() << unique_id(); + _id = pmt::pmt_string_to_symbol(str.str()); _dev = uhd::usrp::multi_usrp::make(device_addr); } @@ -202,7 +207,18 @@ public: //handle possible errors conditions switch(_metadata.error_code){ case uhd::rx_metadata_t::ERROR_CODE_NONE: - //TODO insert tag for time stamp + if (_tag_now){ + _tag_now = false; + //create a timestamp pmt for the first sample + const pmt::pmt_t val = pmt::pmt_make_tuple( + pmt::pmt_from_uint64(_metadata.time_spec.get_full_secs()), + pmt::pmt_from_double(_metadata.time_spec.get_frac_secs()) + ); + //create a timestamp tag for each channel + for (size_t i = 0; i < _nchan; i++){ + this->add_item_tag(i, nitems_written(0), TIME_KEY, val, _id); + } + } break; case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT: @@ -211,8 +227,8 @@ public: return WORK_DONE; case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW: + _tag_now = true; //ignore overflows and try work again - //TODO insert tag for overflow return work(noutput_items, input_items, output_items); default: @@ -232,6 +248,7 @@ public: stream_cmd.stream_now = _stream_now; stream_cmd.time_spec = get_time_now() + uhd::time_spec_t(reasonable_delay); _dev->issue_stream_cmd(stream_cmd); + _tag_now = true; return true; } @@ -244,9 +261,9 @@ private: uhd::usrp::multi_usrp::sptr _dev; const uhd::io_type_t _type; size_t _nchan; - bool _stream_now; - gr_vector_void_star _tmp_buffs; + bool _stream_now, _tag_now; uhd::rx_metadata_t _metadata; + pmt::pmt_t _id; }; diff --git a/gr-uhd/swig/__init__.py b/gr-uhd/swig/__init__.py index 5c0c011b7..1f82b4a26 100644 --- a/gr-uhd/swig/__init__.py +++ b/gr-uhd/swig/__init__.py @@ -32,9 +32,13 @@ def _prepare_uhd_swig(): #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. + #Also use kwargs to construct individual struct elements. class tune_request_t(uhd_swig.tune_request_t, float): - def __new__(self, *args): return float.__new__(self) + def __new__(self, *args, **kwargs): return float.__new__(self) def __float__(self): return self.target_freq + def __init__(self, *args, **kwargs): + super(tune_request_t, self).__init__(*args) + for key, val in kwargs.iteritems(): setattr(self, key, val) setattr(uhd_swig, 'tune_request_t', tune_request_t) #Make the python tune request object inherit from string |