summaryrefslogtreecommitdiff
path: root/gr-uhd
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd')
-rw-r--r--gr-uhd/.gitignore1
-rw-r--r--gr-uhd/Makefile.am4
-rw-r--r--gr-uhd/apps/.gitignore3
-rw-r--r--gr-uhd/apps/Makefile.am32
-rwxr-xr-xgr-uhd/apps/uhd_fft.py267
-rwxr-xr-xgr-uhd/apps/uhd_rx_cfile.py149
-rw-r--r--gr-uhd/gnuradio-uhd.pc.in11
-rw-r--r--gr-uhd/grc/gen_uhd_usrp_blocks.py67
-rw-r--r--gr-uhd/include/gr_uhd_usrp_sink.h32
-rw-r--r--gr-uhd/include/gr_uhd_usrp_source.h32
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_sink.cc16
-rw-r--r--gr-uhd/lib/gr_uhd_usrp_source.cc50
-rw-r--r--gr-uhd/swig/uhd_swig.i3
13 files changed, 629 insertions, 38 deletions
diff --git a/gr-uhd/.gitignore b/gr-uhd/.gitignore
index b336cc7ce..a37fc0c1a 100644
--- a/gr-uhd/.gitignore
+++ b/gr-uhd/.gitignore
@@ -1,2 +1,3 @@
/Makefile
/Makefile.in
+/*.pc
diff --git a/gr-uhd/Makefile.am b/gr-uhd/Makefile.am
index 2e2d0fbe9..ea16c863c 100644
--- a/gr-uhd/Makefile.am
+++ b/gr-uhd/Makefile.am
@@ -21,9 +21,11 @@
include $(top_srcdir)/Makefile.common
-SUBDIRS = include lib
+SUBDIRS = include lib apps
if PYTHON
SUBDIRS += swig grc
endif
+pkgconfigdir = $(libdir)/pkgconfig
+dist_pkgconfig_DATA = gnuradio-uhd.pc
diff --git a/gr-uhd/apps/.gitignore b/gr-uhd/apps/.gitignore
new file mode 100644
index 000000000..22a4e7292
--- /dev/null
+++ b/gr-uhd/apps/.gitignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+
diff --git a/gr-uhd/apps/Makefile.am b/gr-uhd/apps/Makefile.am
new file mode 100644
index 000000000..9bb9b6cdd
--- /dev/null
+++ b/gr-uhd/apps/Makefile.am
@@ -0,0 +1,32 @@
+#
+# 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 $(top_srcdir)/Makefile.common
+
+EXTRA_DIST += \
+ $(bin_SCRIPTS)
+
+ourpythondir = $(grpythondir)
+
+bin_SCRIPTS = \
+ uhd_fft.py \
+ uhd_rx_cfile.py
+
diff --git a/gr-uhd/apps/uhd_fft.py b/gr-uhd/apps/uhd_fft.py
new file mode 100755
index 000000000..87952ef3a
--- /dev/null
+++ b/gr-uhd/apps/uhd_fft.py
@@ -0,0 +1,267 @@
+#!/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, gru
+from gnuradio import uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider
+from optparse import OptionParser
+import wx
+import sys
+import numpy
+
+class app_top_block(stdgui2.std_top_block):
+ def __init__(self, frame, panel, vbox, argv):
+ stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
+
+ self.frame = frame
+ self.panel = panel
+
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
+ help="set sample rate (bandwidth) [default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=None,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("-W", "--waterfall", action="store_true", default=False,
+ help="Enable waterfall display")
+ parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
+ help="Enable oscilloscope display")
+ parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1,
+ help="Set fftsink averaging factor, default=[%default]")
+ parser.add_option("", "--ref-scale", type="eng_float", default=1.0,
+ help="Set dBFS=0dB input value, default=[%default]")
+ parser.add_option("--fft-size", type="int", default=1024,
+ help="Set number of FFT bins [default=%default]")
+ (options, args) = parser.parse_args()
+ if len(args) != 0:
+ parser.print_help()
+ sys.exit(1)
+ self.options = options
+ self.show_debug_info = True
+
+ self.u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ self.u.set_samp_rate(options.samp_rate)
+ input_rate = self.u.get_samp_rate()
+
+ if options.waterfall:
+ self.scope = \
+ waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate)
+ self.frame.SetMinSize((800, 420))
+ elif options.oscilloscope:
+ self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
+ self.frame.SetMinSize((800, 600))
+ else:
+ self.scope = fftsink2.fft_sink_c (panel,
+ fft_size=options.fft_size,
+ sample_rate=input_rate,
+ ref_scale=options.ref_scale,
+ ref_level=20.0,
+ y_divs = 12,
+ avg_alpha=options.avg_alpha)
+ self.frame.SetMinSize((800, 420))
+
+ self.connect(self.u, self.scope)
+
+ self._build_gui(vbox)
+ self._setup_events()
+
+
+ # set initial values
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2
+
+ if options.freq is None:
+ # if no freq was specified, use the mid-point
+ r = self.u.get_freq_range()
+ options.freq = float(r.start()+r.stop())/2
+
+ self.set_gain(options.gain)
+
+ if(options.antenna):
+ self.u.set_antenna(options.antenna, 0)
+
+ if self.show_debug_info:
+ self.myform['samprate'].set_value(self.u.get_samp_rate())
+ self.myform['fs@gbe'].set_value(input_rate)
+ self.myform['baseband'].set_value(0)
+ self.myform['ddc'].set_value(0)
+
+ if not(self.set_freq(options.freq)):
+ self._set_status_msg("Failed to set initial frequency")
+
+ def _set_status_msg(self, msg):
+ self.frame.GetStatusBar().SetStatusText(msg, 0)
+
+ def _build_gui(self, vbox):
+
+ def _form_set_freq(kv):
+ return self.set_freq(kv['freq'])
+
+ vbox.Add(self.scope.win, 10, wx.EXPAND)
+
+ # add control area at the bottom
+ self.myform = myform = form.form()
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add((5,0), 0, 0)
+ myform['freq'] = form.float_field(
+ parent=self.panel, sizer=hbox, label="Center freq", weight=1,
+ callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
+
+ hbox.Add((5,0), 0, 0)
+ g = self.u.get_gain_range()
+
+ # some configurations don't have gain control
+ if g.stop() > g.start():
+ myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain",
+ weight=3,
+ min=int(g.start()), max=int(g.stop()),
+ callback=self.set_gain)
+
+ hbox.Add((5,0), 0, 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ self._build_subpanel(vbox)
+
+ def _build_subpanel(self, vbox_arg):
+ # build a secondary information panel (sometimes hidden)
+
+ # FIXME figure out how to have this be a subpanel that is always
+ # created, but has its visibility controlled by foo.Show(True/False)
+
+ def _form_set_samp_rate(kv):
+ return self.set_samp_rate(kv['samprate'])
+
+ if not(self.show_debug_info):
+ return
+
+ panel = self.panel
+ vbox = vbox_arg
+ myform = self.myform
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+
+ hbox.Add((5,0), 0)
+ myform['samprate'] = form.float_field(
+ parent=panel, sizer=hbox, label="Sample Rate",
+ callback=myform.check_input_and_call(_form_set_samp_rate, self._set_status_msg))
+
+ hbox.Add((5,0), 1)
+ myform['fs@gbe'] = form.static_float_field(
+ parent=panel, sizer=hbox, label="Fs@GbE")
+
+ hbox.Add((5,0), 1)
+ myform['baseband'] = form.static_float_field(
+ parent=panel, sizer=hbox, label="Analog BB")
+
+ hbox.Add((5,0), 1)
+ myform['ddc'] = form.static_float_field(
+ parent=panel, sizer=hbox, label="DDC")
+
+ hbox.Add((5,0), 0)
+ vbox.Add(hbox, 0, wx.EXPAND)
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+
+ Tuning is a two step process. First we ask the front-end to
+ tune as close to the desired frequency as it can. Then we use
+ the result of that operation and our target_frequency to
+ determine the value for the digital down converter.
+ """
+ r = self.u.set_center_freq(target_freq, 0)
+
+ if r:
+ self.myform['freq'].set_value(target_freq) # update displayed value
+ if self.show_debug_info:
+ self.myform['baseband'].set_value(r.actual_rf_freq)
+ self.myform['ddc'].set_value(r.actual_dsp_freq)
+ if not self.options.oscilloscope:
+ self.scope.set_baseband_freq(target_freq)
+ return True
+
+ return False
+
+ def set_gain(self, gain):
+ if self.myform.has_key('gain'):
+ self.myform['gain'].set_value(gain) # update displayed value
+ self.u.set_gain(gain, 0)
+
+ def set_samp_rate(self, samp_rate):
+ ok = self.u.set_samp_rate(samp_rate)
+ input_rate = self.u.get_samp_rate()
+ self.scope.set_sample_rate(input_rate)
+ if self.show_debug_info: # update displayed values
+ self.myform['samprate'].set_value(self.u.get_samp_rate())
+ self.myform['fs@gbe'].set_value(input_rate)
+
+ # uhd set_samp_rate never fails; always falls back to closest requested.
+ return True
+
+ def _setup_events(self):
+ if not self.options.waterfall and not self.options.oscilloscope:
+ self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick)
+
+ def evt_left_dclick(self, event):
+ (ux, uy) = self.scope.win.GetXY(event)
+ if event.CmdDown():
+ # Re-center on maximum power
+ points = self.scope.win._points
+ if self.scope.win.peak_hold:
+ if self.scope.win.peak_vals is not None:
+ ind = numpy.argmax(self.scope.win.peak_vals)
+ else:
+ ind = int(points.shape()[0]/2)
+ else:
+ ind = numpy.argmax(points[:,1])
+ (freq, pwr) = points[ind]
+ target_freq = freq/self.scope.win._scale_factor
+ print ind, freq, pwr
+ self.set_freq(target_freq)
+ else:
+ # Re-center on clicked frequency
+ target_freq = ux/self.scope.win._scale_factor
+ self.set_freq(target_freq)
+
+
+def main ():
+ app = stdgui2.stdapp(app_top_block, "UHD FFT", nstatus=1)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main ()
diff --git a/gr-uhd/apps/uhd_rx_cfile.py b/gr-uhd/apps/uhd_rx_cfile.py
new file mode 100755
index 000000000..f49052d9c
--- /dev/null
+++ b/gr-uhd/apps/uhd_rx_cfile.py
@@ -0,0 +1,149 @@
+#!/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.
+#
+
+"""
+Read samples from a UHD device and write to file formatted as binary
+outputs single precision complex float values or complex short values
+(interleaved 16 bit signed short integers).
+"""
+
+from gnuradio import gr, eng_notation
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+n2s = eng_notation.num_to_str
+
+class rx_cfile_block(gr.top_block):
+
+ def __init__(self, options, filename):
+ gr.top_block.__init__(self)
+
+ # Create a UHD device source
+ if options.output_shorts:
+ self._u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_INT16,
+ num_channels=1)
+ self._sink = gr.file_sink(gr.sizeof_short*2, filename)
+ else:
+ self._u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+ self._sink = gr.file_sink(gr.sizeof_gr_complex, filename)
+
+ # Set receiver sample rate
+ self._u.set_samp_rate(options.samp_rate)
+
+ # Set receive daughterboard gain
+ if options.gain is None:
+ g = self._u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2
+ print "Using mid-point gain of", options.gain, "(", g.start(), "-", g.stop(), ")"
+ self._u.set_gain(options.gain)
+
+ # Set the antenna
+ if(options.antenna):
+ self._u.set_antenna(options.antenna, 0)
+
+ # Set frequency (tune request takes lo_offset)
+ if(options.lo_offset is not None):
+ treq = uhd.tune_request(options.freq, options.lo_offset)
+ else:
+ treq = uhd.tune_request(options.freq)
+ tr = self._u.set_center_freq(treq)
+ if tr == None:
+ sys.stderr.write('Failed to set center frequency\n')
+ raise SystemExit, 1
+
+ # Create head block if needed and wire it up
+ if options.nsamples is None:
+ self.connect(self._u, self._sink)
+ else:
+ if options.output_shorts:
+ self._head = gr.head(gr.sizeof_short*2, int(options.nsamples))
+ else:
+ self._head = gr.head(gr.sizeof_gr_complex, int(options.nsamples))
+
+ self.connect(self._u, self._head, self._sink)
+
+ input_rate = self._u.get_samp_rate()
+
+ if options.verbose:
+ print "Address:", options.address
+ print "Rx gain:", options.gain
+ print "Rx baseband frequency:", n2s(tr.actual_rf_freq)
+ print "Rx DDC frequency:", n2s(tr.actual_dsp_freq)
+ print "Rx Sample Rate:", n2s(input_rate)
+ if options.nsamples is None:
+ print "Receiving samples until Ctrl-C"
+ else:
+ print "Receving", n2s(options.nsamples), "samples"
+ if options.output_shorts:
+ print "Writing 16-bit complex shorts"
+ else:
+ print "Writing 32-bit complex floats"
+ print "Output filename:", filename
+
+def get_options():
+ usage="%prog: [options] output_filename"
+ parser = OptionParser(option_class=eng_option, usage=usage)
+ parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ parser.add_option("", "--samp-rate", type="eng_float", default=1e6,
+ help="set sample rate (bandwidth) [default=%default]")
+ parser.add_option("-f", "--freq", type="eng_float", default=None,
+ help="set frequency to FREQ", metavar="FREQ")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option( "-s","--output-shorts", action="store_true", default=False,
+ help="output interleaved shorts instead of complex floats")
+ parser.add_option("-N", "--nsamples", type="eng_float", default=None,
+ help="number of samples to collect [default=+inf]")
+ parser.add_option("-v", "--verbose", action="store_true", default=False,
+ help="verbose output")
+ parser.add_option("", "--lo-offset", type="eng_float", default=None,
+ help="set daughterboard LO offset to OFFSET [default=hw default]")
+
+ (options, args) = parser.parse_args ()
+ if len(args) != 1:
+ parser.print_help()
+ raise SystemExit, 1
+
+ if options.freq is None:
+ parser.print_help()
+ sys.stderr.write('You must specify the frequency with -f FREQ\n');
+ raise SystemExit, 1
+
+ return (options, args[0])
+
+
+if __name__ == '__main__':
+ (options, filename) = get_options()
+ tb = rx_cfile_block(options, filename)
+
+ try:
+ tb.run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/gnuradio-uhd.pc.in b/gr-uhd/gnuradio-uhd.pc.in
new file mode 100644
index 000000000..383ad6011
--- /dev/null
+++ b/gr-uhd/gnuradio-uhd.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gnuradio-qtgui
+Description: GNU Radio blocks for UHD
+Requires: gnuradio-core
+Version: @LIBVER@
+Libs: -L${libdir} -lgnuradio-uhd
+Cflags: -I${includedir}
diff --git a/gr-uhd/grc/gen_uhd_usrp_blocks.py b/gr-uhd/grc/gen_uhd_usrp_blocks.py
index 8596e14a6..c77df6c97 100644
--- a/gr-uhd/grc/gen_uhd_usrp_blocks.py
+++ b/gr-uhd/grc/gen_uhd_usrp_blocks.py
@@ -29,20 +29,34 @@ MAIN_TMPL = """\
io_type=uhd.io_type.\$type.type,
num_channels=\$nchan,
)
-\#if \$ref_clk()
-self.\$(id).set_clock_config(uhd.clock_config.external(), uhd.ALL_MBOARDS)
-\#end if
-\#if \$sync()
-self.\$(id).set_time_unknown_pps(uhd.time_spec())
-\#end if
\#if \$clock_rate()
self.\$(id).set_clock_rate(\$clock_rate, uhd.ALL_MBOARDS)
\#end if
#for $m in range($max_mboards)
+########################################################################
+\#if \$num_mboards() > $m and \$ref_source$(m)() == 'external'
+self.\$(id).set_clock_config(uhd.clock_config.external(), $m)
+\#end if
+########################################################################
+\#if \$num_mboards() > $m and \$ref_source$(m)() == 'internal'
+self.\$(id).set_clock_config(uhd.clock_config.internal(), $m)
+\#end if
+########################################################################
+\#if \$num_mboards() > $m and \$ref_source$(m)() == 'mimo'
+_config = uhd.clock_config()
+_config.ref_source = uhd.clock_config.REF_MIMO
+_config.pps_source = uhd.clock_config.PPS_MIMO
+self.\$(id).set_clock_config(_config, $m)
+\#end if
+########################################################################
\#if \$num_mboards() > $m and \$sd_spec$(m)()
self.\$(id).set_subdev_spec(\$sd_spec$(m), $m)
\#end if
+########################################################################
#end for
+\#if \$sync()
+self.\$(id).set_time_unknown_pps(uhd.time_spec())
+\#end if
self.\$(id).set_samp_rate(\$samp_rate)
#for $n in range($max_nchan)
\#if \$nchan() > $n
@@ -95,21 +109,6 @@ self.\$(id).set_bandwidth(\$bw$(n), $n)
</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>Sync</name>
<key>sync</key>
<value></value>
@@ -150,6 +149,25 @@ self.\$(id).set_bandwidth(\$bw$(n), $n)
</param>
#for $m in range($max_mboards)
<param>
+ <name>Mb$(m): Ref Source</name>
+ <key>ref_source$(m)</key>
+ <value></value>
+ <type>enum</type>
+ <hide>
+ \#if not \$num_mboards() > $m
+ all
+ \#elif \$ref_source$(m)()
+ none
+ \#else
+ part
+ \#end if
+ </hide>
+ <option><name>Default</name><key></key></option>
+ <option><name>Internal</name><key>internal</key></option>
+ <option><name>External</name><key>external</key></option>
+ <option><name>MIMO Cable</name><key>mimo</key></option>
+ </param>
+ <param>
<name>Mb$(m): Subdev Spec</name>
<key>sd_spec$(m)</key>
<value></value>
@@ -209,6 +227,11 @@ USRP2 Example: addr0=192.168.10.2, addr1=192.168.10.3
Num Motherboards:
Selects the number of USRP motherboards in this device configuration.
+Reference Source:
+Where the motherboard should sync its time and clock references.
+If source and sink blocks reference the same device,
+it is only necessary to set the reference source on one of the blocks.
+
Subdevice specification:
Each motherboard should have its own subdevice specification \\
and all subdevice specifications should be the same length. \\
@@ -298,7 +321,7 @@ def parse_tmpl(_tmpl, **kwargs):
from Cheetah import Template
return str(Template.Template(_tmpl, kwargs))
-max_num_mboards = 4
+max_num_mboards = 8
max_num_channels = max_num_mboards*4
if __name__ == '__main__':
diff --git a/gr-uhd/include/gr_uhd_usrp_sink.h b/gr-uhd/include/gr_uhd_usrp_sink.h
index 0475957de..320d07d41 100644
--- a/gr-uhd/include/gr_uhd_usrp_sink.h
+++ b/gr-uhd/include/gr_uhd_usrp_sink.h
@@ -101,6 +101,14 @@ public:
virtual void set_gain(double gain, size_t chan = 0) = 0;
/*!
+ * Set the named gain on the dboard.
+ * \param gain the gain in dB
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(double gain, const std::string &name, 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
@@ -108,6 +116,22 @@ public:
virtual double get_gain(size_t chan = 0) = 0;
/*!
+ * Get the actual dboard gain setting of named stage.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual double get_gain(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the actual dboard gain setting of named stage.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual std::vector<std::string> get_gain_names(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
@@ -115,6 +139,14 @@ public:
virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0;
/*!
+ * Get the settable gain range.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
* Set the antenna to use.
* \param ant the antenna string
* \param chan the channel index 0 to N-1
diff --git a/gr-uhd/include/gr_uhd_usrp_source.h b/gr-uhd/include/gr_uhd_usrp_source.h
index 038f9a91e..36331f782 100644
--- a/gr-uhd/include/gr_uhd_usrp_source.h
+++ b/gr-uhd/include/gr_uhd_usrp_source.h
@@ -101,6 +101,14 @@ public:
virtual void set_gain(double gain, size_t chan = 0) = 0;
/*!
+ * Set the named gain on the dboard.
+ * \param gain the gain in dB
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_gain(double gain, const std::string &name, 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
@@ -108,6 +116,22 @@ public:
virtual double get_gain(size_t chan = 0) = 0;
/*!
+ * Get the actual dboard gain setting of named stage.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual double get_gain(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
+ * Get the actual dboard gain setting of named stage.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the actual gain in dB
+ */
+ virtual std::vector<std::string> get_gain_names(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
@@ -115,6 +139,14 @@ public:
virtual uhd::gain_range_t get_gain_range(size_t chan = 0) = 0;
/*!
+ * Get the settable gain range.
+ * \param name the name of the gain stage
+ * \param chan the channel index 0 to N-1
+ * \return the gain range in dB
+ */
+ virtual uhd::gain_range_t get_gain_range(const std::string &name, size_t chan = 0) = 0;
+
+ /*!
* Set the antenna to use.
* \param ant the antenna string
* \param chan the channel index 0 to N-1
diff --git a/gr-uhd/lib/gr_uhd_usrp_sink.cc b/gr-uhd/lib/gr_uhd_usrp_sink.cc
index d44af25ab..ce9d89d8d 100644
--- a/gr-uhd/lib/gr_uhd_usrp_sink.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_sink.cc
@@ -76,14 +76,30 @@ public:
return _dev->set_tx_gain(gain, chan);
}
+ void set_gain(double gain, const std::string &name, size_t chan){
+ return _dev->set_tx_gain(gain, name, chan);
+ }
+
double get_gain(size_t chan){
return _dev->get_tx_gain(chan);
}
+ double get_gain(const std::string &name, size_t chan){
+ return _dev->get_tx_gain(name, chan);
+ }
+
+ std::vector<std::string> get_gain_names(size_t chan){
+ return _dev->get_tx_gain_names(chan);
+ }
+
uhd::gain_range_t get_gain_range(size_t chan){
return _dev->get_tx_gain_range(chan);
}
+ uhd::gain_range_t get_gain_range(const std::string &name, size_t chan){
+ return _dev->get_tx_gain_range(name, chan);
+ }
+
void set_antenna(const std::string &ant, size_t chan){
return _dev->set_tx_antenna(ant, chan);
}
diff --git a/gr-uhd/lib/gr_uhd_usrp_source.cc b/gr-uhd/lib/gr_uhd_usrp_source.cc
index fed8e6624..669f890ea 100644
--- a/gr-uhd/lib/gr_uhd_usrp_source.cc
+++ b/gr-uhd/lib/gr_uhd_usrp_source.cc
@@ -78,14 +78,30 @@ public:
return _dev->set_rx_gain(gain, chan);
}
+ void set_gain(double gain, const std::string &name, size_t chan){
+ return _dev->set_rx_gain(gain, name, chan);
+ }
+
double get_gain(size_t chan){
return _dev->get_rx_gain(chan);
}
+ double get_gain(const std::string &name, size_t chan){
+ return _dev->get_rx_gain(name, chan);
+ }
+
+ std::vector<std::string> get_gain_names(size_t chan){
+ return _dev->get_rx_gain_names(chan);
+ }
+
uhd::gain_range_t get_gain_range(size_t chan){
return _dev->get_rx_gain_range(chan);
}
+ uhd::gain_range_t get_gain_range(const std::string &name, size_t chan){
+ return _dev->get_rx_gain_range(name, chan);
+ }
+
void set_antenna(const std::string &ant, size_t chan){
return _dev->set_rx_antenna(ant, chan);
}
@@ -166,19 +182,37 @@ public:
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
){
- //wait for a packet to become available
+ //In order to allow for low-latency:
+ //We receive all available packets without timeout.
+ //This call can timeout under regular operation...
size_t num_samps = _dev->get_device()->recv(
output_items, noutput_items, _metadata,
- _type, uhd::device::RECV_MODE_ONE_PACKET, 1.0
+ _type, uhd::device::RECV_MODE_FULL_BUFF, 0.0
);
+ //If receive resulted in a timeout condition:
+ //We now receive a single packet with a large timeout.
+ if (_metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT){
+ num_samps = _dev->get_device()->recv(
+ output_items, noutput_items, _metadata,
+ _type, uhd::device::RECV_MODE_ONE_PACKET, 1.0
+ );
+ }
+
//handle possible errors conditions
switch(_metadata.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
+ //TODO insert tag for time stamp
break;
+ case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+ //Assume that the user called stop() on the flow graph.
+ //However, a timeout can occur under error conditions.
+ return WORK_DONE;
+
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
//ignore overflows and try work again
+ //TODO insert tag for overflow
return work(noutput_items, input_items, output_items);
default:
@@ -188,18 +222,6 @@ public:
return num_samps;
}
- //advance the pointers and count by num_samps
- noutput_items -= num_samps;
- for (size_t i = 0; i < _nchan; i++){
- _tmp_buffs[i] = static_cast<char *>(output_items[i]) + num_samps*_type.size;
- }
-
- //receive all available packets without timeout
- num_samps += _dev->get_device()->recv(
- _tmp_buffs, noutput_items, _metadata,
- _type, uhd::device::RECV_MODE_FULL_BUFF, 0.0
- );
-
return num_samps;
}
diff --git a/gr-uhd/swig/uhd_swig.i b/gr-uhd/swig/uhd_swig.i
index 3ffcc7aea..9bdb962c9 100644
--- a/gr-uhd/swig/uhd_swig.i
+++ b/gr-uhd/swig/uhd_swig.i
@@ -100,6 +100,7 @@
////////////////////////////////////////////////////////////////////////
%include stdint.i
%include <uhd/types/serial.hpp>
+%template(byte_vector_t) std::vector<uint8_t>;
%include <uhd/usrp/dboard_iface.hpp>
%template(dboard_iface_sptr) boost::shared_ptr<uhd::usrp::dboard_iface>;
@@ -129,6 +130,6 @@ static const size_t ALL_MBOARDS;
%goops %{
(use-modules (gnuradio gnuradio_core_runtime))
%}
-#endif /* SWIGGUILE */
+#endif /* SWIGGUILE */
#endif /* GR_HAVE_UHD */