diff options
author | Martin Braun <martin.braun@ettus.com> | 2015-06-28 00:23:16 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-09-24 15:51:44 -0700 |
commit | 5fe360c6ad5e6b50b00380962a1fbe0b5eaeca34 (patch) | |
tree | 997e54a313108fb4d8a6fc97d5f8d5af13ad320b | |
parent | 2e7800ff6f8dbf16775b8682c5297417e460fa67 (diff) |
uhd: Updated uhd_siggen_gui (uses QT), added GRC siggen example
- Added uhd_app.py base class for example apps
- uhd_siggen and uhd_siggen_gui now both use uhd_app
- siggen now also multi-channel capabilities
- siggen_gui fully QT, no more WX
-rw-r--r-- | gr-uhd/apps/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-uhd/apps/uhd_app.py | 292 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_siggen | 34 | ||||
-rw-r--r-- | gr-uhd/apps/uhd_siggen_base.py | 351 | ||||
-rwxr-xr-x | gr-uhd/apps/uhd_siggen_gui | 689 | ||||
-rw-r--r-- | gr-uhd/examples/grc/uhd_siggen_gui.grc | 2154 |
6 files changed, 2994 insertions, 527 deletions
diff --git a/gr-uhd/apps/CMakeLists.txt b/gr-uhd/apps/CMakeLists.txt index 1d68c00ac7..ebcaf6e9f8 100644 --- a/gr-uhd/apps/CMakeLists.txt +++ b/gr-uhd/apps/CMakeLists.txt @@ -25,6 +25,7 @@ include(GrPython) GR_PYTHON_INSTALL( FILES uhd_siggen_base.py + uhd_app.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/uhd COMPONENT "uhd_python" ) diff --git a/gr-uhd/apps/uhd_app.py b/gr-uhd/apps/uhd_app.py new file mode 100644 index 0000000000..5af01adaaa --- /dev/null +++ b/gr-uhd/apps/uhd_app.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python +# +# Copyright 2015 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. +# +""" +USRP Helper Module: Common tasks for uhd-based apps. +""" + +from __future__ import print_function +import sys +import time +import argparse +from gnuradio import eng_arg +from gnuradio import uhd +from gnuradio import gr +from gnuradio import gru + +COMMAND_DELAY = .2 # Seconds + +COMPACT_TPL = "{mb_id} ({mb_serial}), {db_subdev} ({subdev}, {ant}{db_serial})" +LONG_TPL = """{prefix} Motherboard: {mb_id} ({mb_serial}) +{prefix} Daughterboard: {db_subdev}{db_serial} +{prefix} Subdev: {subdev} +{prefix} Antenna: {ant} +""" + +class UHDApp(object): + def __init__(self, prefix=None, args=None): + self.prefix = prefix + self.args = args + self.verbose = args.verbose or 0 + if self.args.sync == 'auto' and len(self.args.channels) > 1: + self.args.sync = 'pps' + + def vprint(self, *args): + """ + Print 'string' with 'prefix' prepended if self.verbose is True + """ + if self.verbose: + print("[{prefix}]".format(prefix=self.prefix), *args) + + def get_usrp_info_string(self, + compact=False, + tx_or_rx='rx', + chan=0, + mboard=0, + ): + """ + Return a nice textual description of the USRP we're using. + """ + assert tx_or_rx == 'rx' or tx_or_rx == 'tx' + try: + info_pp = {} + if self.prefix is None: + info_pp['prefix'] = "" + else: + info_pp['prefix'] = "[{prefix}] ".format(prefix=self.prefix) + usrp_info = self.usrp.get_usrp_info(chan) + info_pp['mb_id'] = usrp_info['mboard_id'] + info_pp['mb_serial'] = usrp_info['mboard_serial'] + if info_pp['mb_serial'] == "": + info_pp['mb_serial'] = "no serial" + info_pp['db_subdev'] = usrp_info["{xx}_subdev_name".format(xx=tx_or_rx)] + info_pp['db_serial'] = ", " + usrp_info["{xx}_serial".format(xx=tx_or_rx)] + if info_pp['db_serial'] == "": + info_pp['db_serial'] = "no serial" + info_pp['subdev'] = self.usrp.get_subdev_spec(mboard) + info_pp['ant'] = self.usrp.get_antenna(chan) + if info_pp['mb_id'] in ("B200", "B210", "E310"): + # In this case, this is meaningless + info_pp['db_serial'] = "" + tpl = LONG_TPL + if compact: + tpl = COMPACT_TPL + return tpl.format(**info_pp) + except: + return "Can't establish USRP info." + + def normalize_antenna_sel(self, args): + """ + Make sure the --antenna option matches the --channels option. + """ + if args.antenna is None: + return None + antennas = [x.strip() for x in args.antenna.split(",")] + if len(antennas) != 1 and len(antennas) != len(args.channels): + raise ValueError("Invalid antenna setting for {n} channels: {a}".format( + n=len(self.channels), a=args.antenna, + )) + if len(antennas) == 1: + antennas = [antennas[0],] * len(args.channels) + return antennas + + def async_callback(self, msg): + """ + Call this when USRP async metadata needs printing. + """ + md = self.async_src.msg_to_async_metadata_t(msg) + print("[{prefix}] Channel: {chan} Time: {t} Event: {e}".format( + prefix=self.prefix, + chan=md.channel, + t=md.time_spec.get_real_secs(), + e=md.event_code, + )) + + def setup_usrp(self, ctor, args, cpu_format='fc32'): + """ + Instantiate a USRP object; takes care of all kinds of corner cases and settings. + Pop it and some args onto the class that calls this. + """ + self.channels = args.channels + self.cpu_format = cpu_format + # Create a UHD device object: + self.usrp = ctor( + device_addr=args.args, + stream_args=uhd.stream_args( + cpu_format, + args.otw_format, + args=args.stream_args, + channels=self.channels, + ) + ) + # Set the subdevice spec: + if args.spec: + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.set_subdev_spec(args.spec, mb_idx) + # Sampling rate: + self.usrp.set_samp_rate(args.samp_rate) + self.samp_rate = self.usrp.get_samp_rate() + self.vprint("Using sampling rate: {rate}".format(rate=self.samp_rate)) + # Set the antenna: + self.antenna = self.normalize_antenna_sel(args) + if self.antenna is not None: + for i, chan in enumerate(self.channels): + self.usrp.set_antenna(self.antenna[i], chan) + self.vprint("[{prefix}] Channel {chan}: Using antenna {ant}.".format( + prefix=self.prefix, chan=chan, ant=self.usrp.get_antenna(chan) + )) + self.antenna = self.usrp.get_antenna(self.channels[0]) + # Set receive daughterboard gain: + self.set_gain(args.gain) + # Set frequency (tune request takes lo_offset): + if hasattr(args, 'lo_offset') and args.lo_offset is not None: + treq = uhd.tune_request(args.freq, args.lo_offset) + else: + treq = uhd.tune_request(args.freq) + # Make sure tuning is synched: + if len(self.channels) > 1: + if args.sync == 'pps': + self.usrp.set_time_unknown_pps(uhd.time_spec()) + cmd_time = self.usrp.get_time_now() + uhd.time_spec(COMMAND_DELAY) + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.set_command_time(cmd_time, mb_idx) + for chan in self.channels: + self.tr = self.usrp.set_center_freq(treq, chan) + if self.tr == None: + sys.stderr.write('[{prefix}] [ERROR] Failed to set center frequency on channel {chan}\n'.format( + prefix=self.prefix, chan=chan + )) + exit(1) + if len(self.channels) > 1: + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.clear_command_time(mb_idx) + print("[{prefix}] Syncing channels...".format(prefix=self.prefix)) + time.sleep(COMMAND_DELAY) + self.freq = self.usrp.get_center_freq(self.channels[0]) + if args.show_async_msg: + self.async_msgq = gr.msg_queue(0) + self.async_src = uhd.amsg_source("", self.async_msgq) + self.async_rcv = gru.msgq_runner(self.async_msgq, self.async_callback) + + def set_gain(self, gain): + """ + Safe gain-setter. Catches some special cases: + - If gain is None, set to mid-point in dB. + - If the USRP is multi-channel, set it on all channels. + """ + if gain is None: + if self.args.verbose: + self.vprint("Defaulting to mid-point gains:".format(prefix=self.prefix)) + for chan in self.channels: + self.usrp.set_normalized_gain(.5, chan) + if self.args.verbose: + self.vprint("Channel {chan} gain: {g} dB".format( + prefix=self.prefix, chan=chan, g=self.usrp.get_gain(chan) + )) + else: + self.vprint("Setting gain to {g} dB.".format(g=gain)) + for chan in self.channels: + self.usrp.set_gain(gain, chan) + self.gain = self.usrp.get_gain(self.channels[0]) + + def set_freq(self, freq, skip_sync=False): + """ + Safely tune all channels to freq. + """ + self.vprint("Tuning all channels to {freq} MHz.".format(freq=freq/1e6)) + # Set frequency (tune request takes lo_offset): + if hasattr(self.args, 'lo_offset') and self.args.lo_offset is not None: + treq = uhd.tune_request(self.args.freq, self.args.lo_offset) + else: + treq = uhd.tune_request(self.args.freq) + # Make sure tuning is synched: + if len(self.channels) > 1 and not skip_sync: + cmd_time = self.usrp.get_time_now() + uhd.time_spec(COMMAND_DELAY) + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.set_command_time(cmd_time, mb_idx) + for chan in self.channels: + self.tr = self.usrp.set_center_freq(treq, chan) + if self.tr == None: + sys.stderr.write('[{prefix}] [ERROR] Failed to set center frequency on channel {chan}\n'.format( + prefix=self.prefix, chan=chan + )) + exit(1) + if len(self.channels) > 1 and not skip_sync: + for mb_idx in xrange(self.usrp.get_num_mboards()): + self.usrp.clear_command_time(mb_idx) + self.vprint("Syncing channels...".format(prefix=self.prefix)) + time.sleep(COMMAND_DELAY) + + @staticmethod + def setup_argparser( + parser=None, + description='USRP App', + allow_mimo=True, + tx_or_rx="", + skip_freq=False, + ): + """ + Create or amend an argument parser with typical USRP options. + """ + def cslist(string): + """ + For ArgParser: Turn a comma separated list into an actual list. + """ + try: + return [int(x.strip()) for x in string.split(",")] + except: + raise argparse.ArgumentTypeError("Not a comma-separated list: {string}".format(string=string)) + if parser is None: + parser = argparse.ArgumentParser( + description=description, + ) + tx_or_rx = tx_or_rx.strip() + " " + group = parser.add_argument_group('USRP Arguments') + group.add_argument("-a", "--args", default="", help="UHD device address args") + group.add_argument("--spec", help="Subdevice of UHD device where appropriate") + group.add_argument("-A", "--antenna", help="Select {xx}Antenna(s) where appropriate".format(xx=tx_or_rx)) + group.add_argument("-s", "--samp-rate", type=eng_arg.eng_float, default=1e6, + help="Sample rate") + group.add_argument("-g", "--gain", type=eng_arg.eng_float, default=None, + help="Gain (default is midpoint)") + group.add_argument("--gain-type", choices=('db', 'normalized'), default='db', + help="Gain Type (applies to -g)") + if not skip_freq: + group.add_argument("-f", "--freq", type=eng_arg.eng_float, default=None, required=True, + help="Set carrier frequency to FREQ", + metavar="FREQ") + group.add_argument("--lo-offset", type=eng_arg.eng_float, default=0.0, + help="Set daughterboard LO offset to OFFSET [default=hw default]") + if allow_mimo: + group.add_argument("-c", "--channels", default=[0,], type=cslist, + help="Select {xx} Channels".format(xx=tx_or_rx)) + group.add_argument("--otw-format", choices=['sc16', 'sc12', 'sc8'], default='sc16', + help="Choose over-the-wire data format") + group.add_argument("--stream-args", default="", help="Set additional stream arguments") + group.add_argument("-m", "--amplitude", type=eng_arg.eng_float, default=0.15, + help="Set output amplitude to AMPL (0.0-1.0)", metavar="AMPL") + group.add_argument("-v", "--verbose", action="count", help="Use verbose console output") + group.add_argument("--show-async-msg", action="store_true", + help="Show asynchronous message notifications from UHD") + group.add_argument("--sync", choices=('default', 'pps', 'auto'), + default='auto', help="Set to 'pps' to sync devices to PPS") + return parser + diff --git a/gr-uhd/apps/uhd_siggen b/gr-uhd/apps/uhd_siggen index 52fc24922f..6e5d46506f 100755 --- a/gr-uhd/apps/uhd_siggen +++ b/gr-uhd/apps/uhd_siggen @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc. +# Copyright 2008,2009,2011,2012,2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,32 +20,10 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr -from gnuradio.uhd import uhd_siggen_base as uhd_siggen -import sys +try: + import uhd_siggen_base as uhd_siggen +except ImportError: + from gnuradio.uhd import uhd_siggen_base as uhd_siggen -def main(): - if gr.enable_realtime_scheduling() != gr.RT_OK: - print "Note: failed to enable realtime scheduling, continuing" - - # Grab command line options and create top block - try: - (options, args) = uhd_siggen.get_options() - tb = uhd_siggen.top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - - tb.start() - raw_input('Press Enter to quit: ') - tb.stop() - tb.wait() - -# Make sure to create the top block (tb) within a function: -# That code in main will allow tb to go out of scope on return, -# which will call the decontructor on usrp and stop transmit. -# Whats odd is that grc works fine with tb in the __main__, -# perhaps its because the try/except clauses around tb. if __name__ == "__main__": - main() + uhd_siggen.main() diff --git a/gr-uhd/apps/uhd_siggen_base.py b/gr-uhd/apps/uhd_siggen_base.py index 503f49b481..31415dac41 100644 --- a/gr-uhd/apps/uhd_siggen_base.py +++ b/gr-uhd/apps/uhd_siggen_base.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # -# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc. +# Copyright 2008,2009,2011,2012,2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,6 +19,9 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # +""" +Provide a base flow graph for USRP signal generators. +""" DESC_KEY = 'desc' SAMP_RATE_KEY = 'samp_rate' @@ -36,44 +39,69 @@ FREQ_RANGE_KEY = 'freq_range' GAIN_RANGE_KEY = 'gain_range' TYPE_KEY = 'type' -def setter(ps, key, val): ps[key] = val +# FIXME figure out if this can be deleted +#def setter(ps, key, val): ps[key] = val -from gnuradio import gr, gru, uhd, eng_notation +import sys +import math +import argparse +try: + from uhd_app import UHDApp +except ImportError: + from gnuradio.uhd.uhd_app import UHDApp +from gnuradio import gr, gru, uhd, eng_notation, eng_arg from gnuradio import analog from gnuradio import blocks from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option from optparse import OptionParser -import sys -import math n2s = eng_notation.num_to_str -waveforms = { analog.GR_SIN_WAVE : "Complex Sinusoid", - analog.GR_CONST_WAVE : "Constant", - analog.GR_GAUSSIAN : "Gaussian Noise", - analog.GR_UNIFORM : "Uniform Noise", - "2tone" : "Two Tone", - "sweep" : "Sweep" } - -# -# GUI-unaware GNU Radio flowgraph. This may be used either with command -# line applications or GUI applications. -# -class top_block(gr.top_block, pubsub): - def __init__(self, options, args): +waveforms = { + analog.GR_CONST_WAVE : "Constant", + analog.GR_SIN_WAVE : "Complex Sinusoid", + analog.GR_GAUSSIAN : "Gaussian Noise", + analog.GR_UNIFORM : "Uniform Noise", + "2tone" : "Two Tone", + "sweep" : "Sweep", +} + +class USRPSiggen(gr.top_block, pubsub, UHDApp): + """ + GUI-unaware GNU Radio flowgraph. This may be used either with command + line applications or GUI applications. + """ + def __init__(self, args): gr.top_block.__init__(self) pubsub.__init__(self) - self._verbose = options.verbose - - #initialize values from options - self._setup_usrpx(options) - self[SAMP_RATE_KEY] = options.samp_rate - self[TX_FREQ_KEY] = options.tx_freq - self[AMPLITUDE_KEY] = options.amplitude - self[WAVEFORM_FREQ_KEY] = options.waveform_freq - self[WAVEFORM_OFFSET_KEY] = options.offset - self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq + UHDApp.__init__(self, args=args, prefix="UHD-SIGGEN") + self.extra_sink = None + + # Initialize device: + self.setup_usrp( + ctor=uhd.usrp_sink, + args=args, + ) + print("[UHD-SIGGEN] UHD Signal Generator") + print("[UHD-SIGGEN] UHD Version: {ver}".format(ver=uhd.get_version_string())) + print("[UHD-SIGGEN] Using USRP configuration:") + print(self.get_usrp_info_string(tx_or_rx="tx")) + self.usrp_description = self.get_usrp_info_string(tx_or_rx="tx", compact=True) + + ### Set subscribers and publishers: + self.publish(SAMP_RATE_KEY, lambda: self.usrp.get_samp_rate()) + self.publish(DESC_KEY, lambda: self.usrp_description) + self.publish(FREQ_RANGE_KEY, lambda: self.usrp.get_freq_range(self.channels[0])) + self.publish(GAIN_RANGE_KEY, lambda: self.usrp.get_gain_range(self.channels[0])) + self.publish(GAIN_KEY, lambda: self.usrp.get_gain(self.channels[0])) + + self[SAMP_RATE_KEY] = args.samp_rate + self[TX_FREQ_KEY] = args.freq + self[AMPLITUDE_KEY] = args.amplitude + self[WAVEFORM_FREQ_KEY] = args.waveform_freq + self[WAVEFORM_OFFSET_KEY] = args.offset + self[WAVEFORM2_FREQ_KEY] = args.waveform2_freq self[DSP_FREQ_KEY] = 0 self[RF_FREQ_KEY] = 0 @@ -91,84 +119,15 @@ class top_block(gr.top_block, pubsub): AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): self[key] = self[key] - self[TYPE_KEY] = options.type #set type last - - def _setup_usrpx(self, options): - self._u = uhd.usrp_sink(device_addr=options.args, stream_args=uhd.stream_args('fc32')) - self._u.set_samp_rate(options.samp_rate) - - # Set the subdevice spec - if(options.spec): - self._u.set_subdev_spec(options.spec, 0) - - # Set the gain on the usrp from options - if(options.gain): - self._u.set_gain(options.gain) - - # Set the antenna - if(options.antenna): - self._u.set_antenna(options.antenna, 0) + self[TYPE_KEY] = args.type #set type last - # Setup USRP Configuration value - try: - usrp_info = self._u.get_usrp_info() - mboard_id = usrp_info["mboard_id"] - mboard_serial = usrp_info["mboard_serial"] - if mboard_serial == "": - mboard_serial = "no serial" - dboard_subdev_name = usrp_info["tx_subdev_name"] - dboard_serial = usrp_info["tx_serial"] - if dboard_serial == "": - dboard_serial = "no serial" - subdev = self._u.get_subdev_spec() - antenna = self._u.get_antenna() - - desc_key_str = "Motherboard: %s [%s]\n" % (mboard_id, mboard_serial) - if "B200" in mboard_id or "B210" in mboard_id: - desc_key_str += "Daughterboard: %s\n" % dboard_subdev_name - else: - desc_key_str += "Daughterboard: %s [%s]\n" % (dboard_subdev_name, dboard_serial) - desc_key_str += "Subdev: %s\n" % subdev - desc_key_str += "Antenna: %s" % antenna - except: - desc_key_str = "USRP configuration output not implemented in this version" - - self.publish(DESC_KEY, lambda: desc_key_str) - self.publish(FREQ_RANGE_KEY, self._u.get_freq_range) - self.publish(GAIN_RANGE_KEY, self._u.get_gain_range) - self.publish(GAIN_KEY, self._u.get_gain) - - print "UHD Signal Generator" - print "Version: %s" % uhd.get_version_string() - print "\nUsing USRP configuration:" - print desc_key_str + "\n" - - # Direct asynchronous notifications to callback function - if options.show_async_msg: - self.async_msgq = gr.msg_queue(0) - self.async_src = uhd.amsg_source("", self.async_msgq) - self.async_rcv = gru.msgq_runner(self.async_msgq, self.async_callback) - - def async_callback(self, msg): - md = self.async_src.msg_to_async_metadata_t(msg) - print "Channel: %i Time: %f Event: %i" % (md.channel, md.time_spec.get_real_secs(), md.event_code) - - def _set_tx_amplitude(self, ampl): + def set_samp_rate(self, sr): """ - Sets the transmit amplitude sent to the USRP - - Args: - ampl: the amplitude or None for automatic + When sampling rate is updated, also update the signal sources. """ - ampl_range = self[AMPL_RANGE_KEY] - if ampl is None: - ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0] - self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) - - def set_samp_rate(self, sr): - self._u.set_samp_rate(sr) - sr = self._u.get_samp_rate() - + self.vprint("Setting sampling rate to: {rate} Msps".format(rate=sr/1e6)) + self.usrp.set_samp_rate(sr) + sr = self.usrp.get_samp_rate() if self[TYPE_KEY] in (analog.GR_SIN_WAVE, analog.GR_CONST_WAVE): self._src.set_sampling_freq(self[SAMP_RATE_KEY]) elif self[TYPE_KEY] == "2tone": @@ -179,48 +138,9 @@ class top_block(gr.top_block, pubsub): self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) else: return True # Waveform not yet set - - if self._verbose: - print "Set sample rate to:", sr - + self.vprint("Set sample rate to: {rate} Msps".format(rate=sr/1e6)) return True - def set_gain(self, gain): - if gain is None: - g = self[GAIN_RANGE_KEY] - gain = float(g.start()+g.stop())/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self[GAIN_KEY] = gain - return - self._u.set_gain(gain) - if self._verbose: - print "Set TX gain to:", gain - - def set_freq(self, target_freq): - - if target_freq is None: - f = self[FREQ_RANGE_KEY] - target_freq = float(f.start()+f.stop())/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - self[TX_FREQ_KEY] = target_freq - return - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - self[DSP_FREQ_KEY] = tr.actual_dsp_freq - self[RF_FREQ_KEY] = tr.actual_rf_freq - if self._verbose: - print "Set center frequency to", self._u.get_center_freq() - print "Tx RF frequency: %sHz" % (n2s(tr.actual_rf_freq),) - print "Tx DSP frequency: %sHz" % (n2s(tr.actual_dsp_freq),) - elif self._verbose: - print "Failed to set freq." - return tr - def set_waveform_freq(self, freq): if self[TYPE_KEY] == analog.GR_SIN_WAVE: self._src.set_frequency(freq) @@ -242,6 +162,7 @@ class top_block(gr.top_block, pubsub): return True def set_waveform(self, type): + self.vprint("Selecting waveform...") self.lock() self.disconnect_all() if type == analog.GR_SIN_WAVE or type == analog.GR_CONST_WAVE: @@ -258,9 +179,8 @@ class top_block(gr.top_block, pubsub): self[WAVEFORM_FREQ_KEY], self[AMPLITUDE_KEY]/2.0, 0) - if(self[WAVEFORM2_FREQ_KEY] is None): + if self[WAVEFORM2_FREQ_KEY] is None: self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] - self._src2 = analog.sig_source_c(self[SAMP_RATE_KEY], analog.GR_SIN_WAVE, self[WAVEFORM2_FREQ_KEY], @@ -276,7 +196,6 @@ class top_block(gr.top_block, pubsub): # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) if self[WAVEFORM2_FREQ_KEY] is None: self[WAVEFORM2_FREQ_KEY] = 0.1 - self._src1 = analog.sig_source_f(self[SAMP_RATE_KEY], analog.GR_TRI_WAVE, self[WAVEFORM2_FREQ_KEY], @@ -284,33 +203,33 @@ class top_block(gr.top_block, pubsub): -0.5) self._src2 = analog.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) self._src = blocks.multiply_const_cc(self[AMPLITUDE_KEY]) - self.connect(self._src1,self._src2,self._src) + self.connect(self._src1, self._src2, self._src) else: - raise RuntimeError("Unknown waveform type") - - self.connect(self._src, self._u) + raise RuntimeError("[UHD-SIGGEN] Unknown waveform type") + for c in xrange(len(self.channels)): + self.connect(self._src, (self.usrp, c)) + if self.extra_sink is not None: + self.connect(self._src, self.extra_sink) self.unlock() - - if self._verbose: - print "Set baseband modulation to:", waveforms[type] - if type == analog.GR_SIN_WAVE: - print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) - print "Initial phase:", self[WAVEFORM_OFFSET_KEY] - elif type == "2tone": - print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) - print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) - elif type == "sweep": - print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) - print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) - print "TX amplitude:", self[AMPLITUDE_KEY] - + self.vprint("Set baseband modulation to:", waveforms[type]) + if type == analog.GR_SIN_WAVE: + self.vprint("Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)) + self.vprint("Initial phase:", self[WAVEFORM_OFFSET_KEY]) + elif type == "2tone": + self.vprint("Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),)) + self.vprint("Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)) + elif type == "sweep": + self.vprint("Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0))) + self.vprint("Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),)) + self.vprint("TX amplitude:", self[AMPLITUDE_KEY]) def set_amplitude(self, amplitude): + """ + amplitude subscriber + """ if amplitude < 0.0 or amplitude > 1.0: - if self._verbose: - print "Amplitude out of range:", amplitude + self.vprint("Amplitude out of range:", amplitude) return False - if self[TYPE_KEY] in (analog.GR_SIN_WAVE, analog.GR_CONST_WAVE, analog.GR_GAUSSIAN, analog.GR_UNIFORM): self._src.set_amplitude(amplitude) elif self[TYPE_KEY] == "2tone": @@ -320,83 +239,55 @@ class top_block(gr.top_block, pubsub): self._src.set_k(amplitude) else: return True # Waveform not yet set - - if self._verbose: - print "Set amplitude to:", amplitude + self.vprint("Set amplitude to:", amplitude) return True -def get_options(): - usage="%prog: [options]" - parser = OptionParser(option_class=eng_option, usage=usage) - parser.add_option("-a", "--args", type="string", default="", - help="UHD device address args , [default=%default]") - parser.add_option("", "--spec", type="string", default=None, - help="Subdevice of UHD device where appropriate") - 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("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") - parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="Set carrier frequency to FREQ [default=mid-point]", - metavar="FREQ") - parser.add_option("-x", "--waveform-freq", type="eng_float", default=0, - help="Set baseband waveform frequency to FREQ [default=%default]") - parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None, - help="Set 2nd waveform frequency to FREQ [default=%default]") - parser.add_option("--sine", dest="type", action="store_const", const=analog.GR_SIN_WAVE, +def setup_argparser(): + """ + Create argument parser for signal generator. + """ + parser = UHDApp.setup_argparser( + description="USRP Signal Generator.", + tx_or_rx="Tx", + ) + group = parser.add_argument_group('Siggen Arguments') + group.add_argument("-x", "--waveform-freq", type=eng_arg.eng_float, default=0.0, + help="Set baseband waveform frequency to FREQ") + group.add_argument("-y", "--waveform2-freq", type=eng_arg.eng_float, default=0.0, + help="Set 2nd waveform frequency to FREQ") + group.add_argument("--sine", dest="type", action="store_const", const=analog.GR_SIN_WAVE, help="Generate a carrier modulated by a complex sine wave", default=analog.GR_SIN_WAVE) - parser.add_option("--const", dest="type", action="store_const", const=analog.GR_CONST_WAVE, + group.add_argument("--const", dest="type", action="store_const", const=analog.GR_CONST_WAVE, help="Generate a constant carrier") - parser.add_option("--offset", type="eng_float", default=0, - help="Set waveform phase offset to OFFSET [default=%default]") - parser.add_option("--gaussian", dest="type", action="store_const", const=analog.GR_GAUSSIAN, + group.add_argument("--offset", type=eng_arg.eng_float, default=0, + help="Set waveform phase offset to OFFSET", metavar="OFFSET") + group.add_argument("--gaussian", dest="type", action="store_const", const=analog.GR_GAUSSIAN, help="Generate Gaussian random output") - parser.add_option("--uniform", dest="type", action="store_const", const=analog.GR_UNIFORM, + group.add_argument("--uniform", dest="type", action="store_const", const=analog.GR_UNIFORM, help="Generate Uniform random output") - parser.add_option("--2tone", dest="type", action="store_const", const="2tone", + group.add_argument("--2tone", dest="type", action="store_const", const="2tone", help="Generate Two Tone signal for IMD testing") - parser.add_option("--sweep", dest="type", action="store_const", const="sweep", + group.add_argument("--sweep", dest="type", action="store_const", const="sweep", help="Generate a swept sine wave") - parser.add_option("", "--amplitude", type="eng_float", default=0.15, - help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", - metavar="AMPL") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="Use verbose console output [default=%default]") - parser.add_option("", "--show-async-msg", action="store_true", default=False, - help="Show asynchronous message notifications from UHD [default=%default]") - - (options, args) = parser.parse_args() - - return (options, args) + return parser -# If this script is executed, the following runs. If it is imported, -# the below does not run. -def test_main(): +def main(): if gr.enable_realtime_scheduling() != gr.RT_OK: - print "Note: failed to enable realtime scheduling, continuing" - - # Grab command line options and create top block + print("Note: failed to enable realtime scheduling, continuing") + # Grab command line args and create top block try: - (options, args) = get_options() - tb = top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - + parser = setup_argparser() + args = parser.parse_args() + tb = USRPSiggen(args) + except RuntimeError as e: + print(e) + exit(1) tb.start() - raw_input('Press Enter to quit: ') + raw_input('[UHD-SIGGEN] Press Enter to quit:\n') tb.stop() tb.wait() -# Make sure to create the top block (tb) within a function: -# That code in main will allow tb to go out of scope on return, -# which will call the decontructor on usrp and stop transmit. -# Whats odd is that grc works fine with tb in the __main__, -# perhaps its because the try/except clauses around tb. if __name__ == "__main__": - test_main() + main() diff --git a/gr-uhd/apps/uhd_siggen_gui b/gr-uhd/apps/uhd_siggen_gui index 80fcf8e673..ab04ccc8e2 100755 --- a/gr-uhd/apps/uhd_siggen_gui +++ b/gr-uhd/apps/uhd_siggen_gui @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # -# Copyright 2009,2011,2012 Free Software Foundation, Inc. +# Copyright 2015 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,301 +19,452 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # +""" +Signal Generator App +""" -import wx -from gnuradio import gr, uhd +# Started off with this flow graph: +################################################## +# GNU Radio Python Flow Graph +# Title: UHD Signal Generator +# Author: Ettus Research +# Description: Signal Generator for use with USRP Devices +# Generated: Sun Jun 28 17:21:28 2015 +################################################## + +import sip +import sys +import threading +import time +from distutils.version import StrictVersion +from PyQt4 import Qt +from PyQt4.QtCore import QObject, pyqtSlot from gnuradio import analog -from gnuradio.gr.pubsub import pubsub -from gnuradio.wxgui import gui, forms -from gnuradio.uhd import uhd_siggen_base as uhd_siggen -import sys, math +from gnuradio import eng_notation +from gnuradio import gr +from gnuradio import qtgui +from gnuradio import uhd +from gnuradio.filter import firdes +from gnuradio.qtgui import Range, RangeWidget +try: + import uhd_siggen_base as uhd_siggen +except ImportError: + from gnuradio.uhd import uhd_siggen_base as uhd_siggen + -class app_gui(pubsub): - def __init__(self, frame, panel, vbox, top_block, options, args): - pubsub.__init__(self) - self.frame = frame # Use for top-level application window frame - self.panel = panel # Use as parent class for created windows - self.vbox = vbox # Use as sizer for created windows - self.tb = top_block # GUI-unaware flowgraph class - self.options = options # Supplied command-line options - self.args = args # Supplied command-line arguments - self.build_gui() +class uhd_siggen_gui(Qt.QWidget): + """ + Signal Generator Flowgraph + """ + def __init__(self, args): + ################################################## + # Set up the siggen app + ################################################## + self._sg = uhd_siggen.USRPSiggen(args) + self.usrp = self._sg.usrp - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) + ################################################## + # GUI Setup + ################################################## + Qt.QWidget.__init__(self) + self.setWindowTitle("UHD Signal Generator") + try: + self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) + except: + pass + self.top_scroll_layout = Qt.QVBoxLayout() + self.setLayout(self.top_scroll_layout) + self.top_scroll = Qt.QScrollArea() + self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) + self.top_scroll_layout.addWidget(self.top_scroll) + self.top_scroll.setWidgetResizable(True) + self.top_widget = Qt.QWidget() + self.top_scroll.setWidget(self.top_widget) + self.top_layout = Qt.QVBoxLayout(self.top_widget) + self.top_grid_layout = Qt.QGridLayout() + self.top_layout.addLayout(self.top_grid_layout) + self.settings = Qt.QSettings("GNU Radio", "uhd_siggen_gui") + self.restoreGeometry(self.settings.value("geometry").toByteArray()) - # GUI construction - def build_gui(self): - self.vbox.AddSpacer(5) - self.vbox.AddStretchSpacer() ################################################## - # Baseband controls + # Widgets + Controls ################################################## - bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - #callback to show/hide forms - def set_type(type): - sine_bb_hbox.ShowItems(type == analog.GR_SIN_WAVE) - sweep_bb_hbox.ShowItems(type == 'sweep') - tone_bb_hbox.ShowItems(type == '2tone') - self.vbox.Layout() - self.tb.subscribe(uhd_siggen.TYPE_KEY, set_type) - #create sine forms - sine_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=sine_bb_hbox, - label='Frequency (Hz)', - ps=self.tb, - key=uhd_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), + ### Waveform Selector + self._waveform_options = uhd_siggen.waveforms.keys() + self._waveform_labels = uhd_siggen.waveforms.values() + self._waveform_group_box = Qt.QGroupBox("Waveform") + self._waveform_box = Qt.QHBoxLayout() + class variable_chooser_button_group(Qt.QButtonGroup): + def __init__(self, parent=None): + Qt.QButtonGroup.__init__(self, parent) + @pyqtSlot(int) + def updateButtonChecked(self, button_id): + self.button(button_id).setChecked(True) + self._waveform_button_group = variable_chooser_button_group() + self._waveform_group_box.setLayout(self._waveform_box) + for i, label in enumerate(self._waveform_labels): + radio_button = Qt.QRadioButton(label) + self._waveform_box.addWidget(radio_button) + self._waveform_button_group.addButton(radio_button, i) + self._waveform_callback = lambda i: Qt.QMetaObject.invokeMethod( + self._waveform_button_group, + "updateButtonChecked", + Qt.Q_ARG("int", self._waveform_options.index(i)) ) - sine_bb_hbox.AddStretchSpacer() - #create sweep forms - sweep_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=sweep_bb_hbox, - label='Sweep Width (Hz)', - ps=self.tb, - key=uhd_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), + self._waveform_callback(self._sg[uhd_siggen.TYPE_KEY]) + self._waveform_button_group.buttonClicked[int].connect( + lambda i: self.set_waveform(self._waveform_options[i]) ) - sweep_bb_hbox.AddStretchSpacer() - forms.text_box( - parent=self.panel, sizer=sweep_bb_hbox, - label='Sweep Rate (Hz)', - ps=self.tb, - key=uhd_siggen.WAVEFORM2_FREQ_KEY, - converter=forms.float_converter(), + self.top_grid_layout.addWidget(self._waveform_group_box, 0,0,1,5) + ### Center Frequency Sliders + self.freq_coarse = self._sg.usrp.get_center_freq(self._sg.channels[0]) + self._freq_coarse_range = Range( + self.usrp.get_freq_range(self._sg.channels[0]).start(), + self.usrp.get_freq_range(self._sg.channels[0]).stop(), + 1e3, # Step + self.freq_coarse, + 200, # Min Width ) - sweep_bb_hbox.AddStretchSpacer() - #create 2tone forms - tone_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=tone_bb_hbox, - label='Tone 1 (Hz)', - ps=self.tb, - key=uhd_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), + self._freq_coarse_win = RangeWidget( + self._freq_coarse_range, + self.set_freq_coarse, + "Center Frequency", + "counter_slider", + float ) - tone_bb_hbox.AddStretchSpacer() - forms.text_box( - parent=self.panel, sizer=tone_bb_hbox, - label='Tone 2 (Hz)', - ps=self.tb, - key=uhd_siggen.WAVEFORM2_FREQ_KEY, - converter=forms.float_converter(), + self.top_grid_layout.addWidget(self._freq_coarse_win, 1,0,1,5) + self.freq_fine = 0.0 + self._freq_fine_range = Range( + -1e6, 1e6, 1e3, + self.freq_fine, + 200 ) - tone_bb_hbox.AddStretchSpacer() - forms.radio_buttons( - parent=self.panel, sizer=bb_vbox, - choices=uhd_siggen.waveforms.keys(), - labels=uhd_siggen.waveforms.values(), - ps=self.tb, - key=uhd_siggen.TYPE_KEY, - style=wx.NO_BORDER | wx.RA_HORIZONTAL, + self._freq_fine_win = RangeWidget( + self._freq_fine_range, + self.set_freq_fine, + "Fine Tuning", + "counter_slider", + float ) - bb_vbox.AddSpacer(10) - bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND) - bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND) - bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND) - set_type(self.tb[uhd_siggen.TYPE_KEY]) - - ################################################## - # Frequency controls - ################################################## - fc_vbox = forms.static_box_sizer(parent=self.panel, - label="Center Frequency", - orient=wx.VERTICAL, - bold=True) - fc_vbox.AddSpacer(5) - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - fc_vbox.AddSpacer(10) - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - fc_vbox.AddSpacer(5) - # Add frequency controls to top window sizer - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - freq_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=freq_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=uhd_siggen.TX_FREQ_KEY, + self.top_grid_layout.addWidget(self._freq_fine_win, 2,0,1,5) + self.lo_offset = self._sg.args.lo_offset + self._lo_offset_range = Range( + -self._sg[uhd_siggen.SAMP_RATE_KEY]/2, + self._sg[uhd_siggen.SAMP_RATE_KEY]/2, + 1e3, + self.lo_offset, + 200 ) - freq_hbox.AddSpacer(10) - - forms.slider( - parent=self.panel, sizer=freq_hbox, - proportion=2, - ps=self.tb, - key=uhd_siggen.TX_FREQ_KEY, - minimum=self.tb[uhd_siggen.FREQ_RANGE_KEY].start(), - maximum=self.tb[uhd_siggen.FREQ_RANGE_KEY].stop(), - num_steps=100, + self._lo_offset_win = RangeWidget( + self._lo_offset_range, + self.set_lo_offset, + "LO Offset", + "counter_slider", + float ) - freq_hbox.AddSpacer(5) - tr_hbox.AddSpacer(5) - forms.static_text( - parent=self.panel, sizer=tr_hbox, - label='RF Frequency', - ps=self.tb, - key=uhd_siggen.RF_FREQ_KEY, - converter=forms.float_converter(), - proportion=1, + self.top_grid_layout.addWidget(self._lo_offset_win, 3,0,1,5) + ### Signal frequencies + self._freq1_enable_on = (analog.GR_SIN_WAVE, "2tone", "sweep") + self._freq1_offset_range = Range( + -self._sg[uhd_siggen.SAMP_RATE_KEY]/4, + self._sg[uhd_siggen.SAMP_RATE_KEY]/4, + 100, + self._sg.args.waveform_freq, + 200 ) - tr_hbox.AddSpacer(10) - forms.static_text( - parent=self.panel, sizer=tr_hbox, - label='DSP Frequency', - ps=self.tb, - key=uhd_siggen.DSP_FREQ_KEY, - converter=forms.float_converter(), - proportion=1, + self._freq1_offset_win = RangeWidget( + self._freq1_offset_range, + self.set_freq1_offset, + "Frequency Offset: Signal 1", + "counter_slider", + float ) - tr_hbox.AddSpacer(5) - - ################################################## - # Amplitude controls - ################################################## - amp_hbox = forms.static_box_sizer(parent=self.panel, - label="Amplitude", - orient=wx.VERTICAL, - bold=True) - amp_hbox.AddSpacer(5) - # First row of amp controls (ampl) - lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) - amp_hbox.Add(lvl_hbox, 0, wx.EXPAND) - amp_hbox.AddSpacer(10) - # Second row of amp controls (tx gain) - gain_hbox = wx.BoxSizer(wx.HORIZONTAL) - amp_hbox.Add(gain_hbox, 0, wx.EXPAND) - amp_hbox.AddSpacer(5) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - lvl_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=lvl_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=uhd_siggen.AMPLITUDE_KEY, - label="Level (0.0-1.0)", + self._freq1_offset_win.setEnabled(self._sg[uhd_siggen.TYPE_KEY] in self._freq1_enable_on) + self.top_grid_layout.addWidget(self._freq1_offset_win, 4,0,1,3) + self._freq2_enable_on = ("2tone", "sweep") + self._freq2_offset_range = Range( + -self._sg[uhd_siggen.SAMP_RATE_KEY]/4, + self._sg[uhd_siggen.SAMP_RATE_KEY]/4, + 100, + self._sg.args.waveform2_freq, + 200 ) - lvl_hbox.AddSpacer(10) - forms.log_slider( - parent=self.panel, sizer=lvl_hbox, - proportion=2, - ps=self.tb, - key=uhd_siggen.AMPLITUDE_KEY, - min_exp=-6, - max_exp=0, - base=10, - num_steps=100, + self._freq2_offset_win = RangeWidget( + self._freq2_offset_range, + self.set_freq2_offset, + "Signal 2 ", + "counter_slider", + float ) - lvl_hbox.AddSpacer(5) - if self.tb[uhd_siggen.GAIN_RANGE_KEY].start() < self.tb[uhd_siggen.GAIN_RANGE_KEY].stop(): - gain_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=gain_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=uhd_siggen.GAIN_KEY, - label="TX Gain (dB)", - ) - gain_hbox.AddSpacer(10) - forms.slider( - parent=self.panel, sizer=gain_hbox, - proportion=2, - ps=self.tb, - key=uhd_siggen.GAIN_KEY, - minimum=self.tb[uhd_siggen.GAIN_RANGE_KEY].start(), - maximum=self.tb[uhd_siggen.GAIN_RANGE_KEY].stop(), - step_size=self.tb[uhd_siggen.GAIN_RANGE_KEY].step(), + self._freq2_offset_win.setEnabled(self._sg[uhd_siggen.TYPE_KEY] in self._freq2_enable_on) + self.top_grid_layout.addWidget(self._freq2_offset_win, 4,3,1,2) + ### Amplitude + self._amplitude_range = Range(0, 1, .001, .7, 200) + self._amplitude_win = RangeWidget( + self._amplitude_range, + self.set_amplitude, + "Signal Amplitude", + "counter_slider", + float + ) + self.top_grid_layout.addWidget(self._amplitude_win, 5,0,1,5) + ### Gain + self._gain_range = Range( + self.usrp.get_gain_range(self._sg.channels[0]).start(), + self.usrp.get_gain_range(self._sg.channels[0]).stop(), + .5, + self.usrp.get_gain(self._sg.channels[0]), + 200., + ) + self._gain_win = RangeWidget( + self._gain_range, + self._sg.set_gain, + "TX Gain", "counter_slider", float + ) + self.top_grid_layout.addWidget(self._gain_win, 6,0,1,5) + ### Samp rate, LO sync, Antenna Select + self.samp_rate = self._sg[uhd_siggen.SAMP_RATE_KEY] + self._samp_rate_tool_bar = Qt.QToolBar(self) + self._samp_rate_tool_bar.addWidget(Qt.QLabel("Sampling Rate: ")) + self._samp_rate_line_edit = Qt.QLineEdit(eng_notation.num_to_str(self._sg[uhd_siggen.SAMP_RATE_KEY])) + self._samp_rate_tool_bar.addWidget(self._samp_rate_line_edit) + self._samp_rate_line_edit.returnPressed.connect( + lambda: self.set_samp_rate(eng_notation.str_to_num(str(self._samp_rate_line_edit.text().toAscii()))) + ) + self.top_grid_layout.addWidget(self._samp_rate_tool_bar, 7,0,1,2) + _sync_phases_push_button = Qt.QPushButton("Sync LOs") + _sync_phases_push_button.pressed.connect(lambda: self.set_sync_phases(True)) + _sync_phases_push_button.setEnabled(bool(len(self._sg.channels) > 1)) + self.top_grid_layout.addWidget(_sync_phases_push_button, 7,2,1,1) + # Antenna Select + self._ant_tool_bar = Qt.QToolBar(self) + self._ant_tool_bar.addWidget(Qt.QLabel("Antenna: ")) + self._ant_combo_box = Qt.QComboBox() + self._ant_tool_bar.addWidget(self._ant_combo_box) + self._ant_options = self.usrp.get_antennas(self._sg.channels[0]) + for label in self._ant_options: + self._ant_combo_box.addItem(label) + self._ant_callback = lambda i: Qt.QMetaObject.invokeMethod( + self._ant_combo_box, "setCurrentIndex", + Qt.Q_ARG("int", self._ant_options.index(i)) + ) + self._ant_callback(self.usrp.get_antenna(self._sg.channels[0])) + self._ant_combo_box.currentIndexChanged.connect(lambda i: self.set_ant(self._ant_options[i])) + self.top_grid_layout.addWidget(self._ant_tool_bar, 7,4,1,1) + # Labels + Lock Sensors + self._lo_locked_probe_0_tool_bar = Qt.QToolBar(self) + self._lo_locked_probe_0_formatter = lambda x: x + self._lo_locked_probe_0_tool_bar.addWidget(Qt.QLabel("LO locked: ")) + self._lo_locked_probe_0_label = Qt.QLabel(str(False)) + self._lo_locked_probe_0_tool_bar.addWidget(self._lo_locked_probe_0_label) + self.top_grid_layout.addWidget(self._lo_locked_probe_0_tool_bar, 8,0,1,1) + def _chan0_lo_locked_probe(): + while True: + val = all([self.usrp.get_sensor('lo_locked', c).to_bool() for c in range(len(self._sg.channels))]) + try: + self.set_chan0_lo_locked(val) + except AttributeError: + pass + time.sleep(.1) + _chan0_lo_locked_thread = threading.Thread(target=_chan0_lo_locked_probe) + _chan0_lo_locked_thread.daemon = True + _chan0_lo_locked_thread.start() + self.label_rf_freq = self._sg.tr.actual_rf_freq + self._label_rf_freq_tool_bar = Qt.QToolBar(self) + self._label_rf_freq_formatter = lambda x: x + self._label_rf_freq_tool_bar.addWidget(Qt.QLabel("LO freq: ")) + self._label_rf_freq_label = Qt.QLabel(str(self._label_rf_freq_formatter(self.label_rf_freq))) + self._label_rf_freq_tool_bar.addWidget(self._label_rf_freq_label) + self.top_grid_layout.addWidget(self._label_rf_freq_tool_bar, 8,1,1,1) + self.label_dsp_freq = self._sg.tr.actual_dsp_freq + self._label_dsp_freq_tool_bar = Qt.QToolBar(self) + self._label_dsp_freq_formatter = lambda x: x + self._label_dsp_freq_tool_bar.addWidget(Qt.QLabel("DSP Freq: ")) + self._label_dsp_freq_label = Qt.QLabel(str(self._label_dsp_freq_formatter(self.label_dsp_freq))) + self._label_dsp_freq_tool_bar.addWidget(self._label_dsp_freq_label) + self.top_grid_layout.addWidget(self._label_dsp_freq_tool_bar, 8,2,1,1) + ################################################## + # Freq Sink + ################################################## + if self._sg.args.show_freq_sink: + self.qtgui_freq_sink_x_0 = qtgui.freq_sink_c( + 1024, #size + firdes.WIN_BLACKMAN_hARRIS, #wintype + self.freq_coarse + self.freq_fine, #fc + self.samp_rate, #bw + "", #name + 1 #number of inputs ) - gain_hbox.AddSpacer(5) - + self.qtgui_freq_sink_x_0.set_update_time(0.10) + self.qtgui_freq_sink_x_0.set_y_axis(-100, 10) + self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "") + self.qtgui_freq_sink_x_0.enable_autoscale(False) + self.qtgui_freq_sink_x_0.enable_grid(False) + self.qtgui_freq_sink_x_0.set_fft_average(1.0) + self.qtgui_freq_sink_x_0.enable_control_panel(False) + self.qtgui_freq_sink_x_0.set_line_label(0, "Siggen Spectrum") + self.qtgui_freq_sink_x_0.set_line_width(0, 1) + self.qtgui_freq_sink_x_0.set_line_color(0, "blue") + self.qtgui_freq_sink_x_0.set_line_alpha(0, 1.0) + self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget) + self.top_grid_layout.addWidget(self._qtgui_freq_sink_x_0_win, 9,0,2,5) + # Reconnect: + self._sg.extra_sink = self.qtgui_freq_sink_x_0 + self._sg[uhd_siggen.TYPE_KEY] = self._sg[uhd_siggen.TYPE_KEY] ################################################## - # Sample Rate controls + # Start transmitting ################################################## - sam_hbox = forms.static_box_sizer(parent=self.panel, - label="Sample Rate", - orient=wx.HORIZONTAL, - bold=True) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - sam_hbox.AddStretchSpacer(20) - forms.static_text( - parent=self.panel, sizer=sam_hbox, - label='Sample Rate (sps)', - ps=self.tb, - key=uhd_siggen.SAMP_RATE_KEY, - converter=forms.float_converter(), + self._sg.start() + + ################################################## + # QT + Flowgraph stuff + ################################################## + def closeEvent(self, event): + self.settings = Qt.QSettings("GNU Radio", "uhd_siggen_gui") + self.settings.setValue("geometry", self.saveGeometry()) + event.accept() + + def stop(self): + """ + Stop flow graph, tear down blocks + """ + self._sg.stop() + self._sg.wait() + self._sg = None + + ################################################## + # Setters + ################################################## + def set_waveform(self, waveform): + self._freq1_offset_win.setEnabled(waveform in self._freq1_enable_on) + self._freq2_offset_win.setEnabled(waveform in self._freq2_enable_on) + self._sg[uhd_siggen.TYPE_KEY] = waveform + self._waveform_callback(waveform) + + def set_freq_coarse(self, freq_coarse): + self.freq_coarse = freq_coarse + self.update_center_freq() + + def set_freq_fine(self, freq_fine): + self.freq_fine = freq_fine + self.update_center_freq() + + def set_lo_offset(self, lo_offset): + self.lo_offset = lo_offset + self.update_center_freq() + + def update_center_freq(self): + if hasattr(self, "qtgui_freq_sink_x_0"): + self.qtgui_freq_sink_x_0.set_frequency_range(self.freq_coarse + self.freq_fine, self.samp_rate) + self.tune() + + def tune(self): + """ + Multi-channel tune + """ + tune_req = uhd.tune_request( + self.freq_fine + self.freq_coarse, + self.lo_offset ) - sam_hbox.AddStretchSpacer(20) + for idx, c in enumerate(self._sg.channels): + tune_res = self.usrp.set_center_freq(tune_req, c) + if idx == 0: + self.set_label_dsp_freq(tune_res.actual_dsp_freq) + self.set_label_rf_freq(tune_res.actual_rf_freq) - ################################################## - # UHD status - ################################################## - u2_hbox = forms.static_box_sizer(parent=self.panel, - label="UHD (%s)" % (uhd.get_version_string()), - orient=wx.HORIZONTAL, - bold=True) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - u2_hbox.AddSpacer(10) - forms.static_text( - parent=self.panel, sizer=u2_hbox, - ps=self.tb, - key=uhd_siggen.DESC_KEY, - converter=forms.str_converter(), + def set_freq1_offset(self, freq1_offset): + self._sg[uhd_siggen.WAVEFORM_FREQ_KEY] = freq1_offset + + def set_freq2_offset(self, freq2_offset): + self._sg[uhd_siggen.WAVEFORM2_FREQ_KEY] = freq2_offset + + def set_amplitude(self, amplitude): + self.amplitude = amplitude + self._sg[uhd_siggen.AMPLITUDE_KEY] = amplitude + + def set_sync_phases(self, sync): + if sync: + self._sg.vprint("Attempting to sync LO phases. This does not work with all boards.") + self._sg.set_freq(self.freq_coarse + self.freq_fine, False) + + def set_ant(self, ant): + self.ant = ant + self._ant_callback(self.ant) + + def set_samp_rate(self, samp_rate): + self.samp_rate = samp_rate + Qt.QMetaObject.invokeMethod( + self._samp_rate_line_edit, "setText", + Qt.Q_ARG("QString", eng_notation.num_to_str(self.samp_rate)) ) - self.vbox.AddSpacer(5) - self.vbox.AddStretchSpacer() + self._sg[uhd_siggen.SAMP_RATE_KEY] = samp_rate + self.update_center_freq() -def main(): - try: - # Get command line parameters - (options, args) = uhd_siggen.get_options() + def set_label_rf_freq(self, label_rf_freq): + self.label_rf_freq = label_rf_freq + Qt.QMetaObject.invokeMethod( + self._label_rf_freq_label, "setText", + Qt.Q_ARG( + "QString", + eng_notation.num_to_str(self.label_rf_freq) + ) + ) - # Create the top block using these - tb = uhd_siggen.top_block(options, args) + def set_label_dsp_freq(self, label_dsp_freq): + self.label_dsp_freq = label_dsp_freq + Qt.QMetaObject.invokeMethod( + self._label_dsp_freq_label, "setText", + Qt.Q_ARG( + "QString", + eng_notation.num_to_str(self.label_dsp_freq) + ) + ) - # Create the GUI application - app = gui.app(top_block=tb, # Constructed top block - gui=app_gui, # User interface class - options=options, # Command line options - args=args, # Command line args - title="UHD Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority + def set_chan0_lo_locked(self, chan0_lo_locked): + self.set_lo_locked_probe_0(chan0_lo_locked) - # And run it - app.MainLoop() + def set_lo_locked_probe_0(self, lo_locked_probe_0): + Qt.QMetaObject.invokeMethod( + self._lo_locked_probe_0_label, "setText", + Qt.Q_ARG("QString", str(self.lo_locked_probe_0)) + ) + + +def setup_parser(): + """ + Argument parser for siggen_gui + """ + parser = uhd_siggen.setup_argparser() + group = parser.add_argument_group('GUI Arguments') + group.add_argument( + "-q", "--show-freq-sink", action="store_true", + help="Show QT Frequency Widget" + ) + return parser + +def main(): + """ Go, go, go! """ + parser = setup_parser() + args = parser.parse_args() + if(StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0")): + Qt.QApplication.setGraphicsSystem(gr.prefs().get_string('qtgui', 'style', 'raster')) + qapp = Qt.QApplication(sys.argv) + siggen_gui = uhd_siggen_gui(args) + siggen_gui.show() + def quitting(): + siggen_gui.stop() + qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting) + qapp.exec_() + siggen_gui = None #to clean up Qt widgets - except RuntimeError, e: - print e - sys.exit(1) +if __name__ == '__main__': + import ctypes + import sys + if sys.platform.startswith('linux'): + try: + x11 = ctypes.cdll.LoadLibrary('libX11.so') + x11.XInitThreads() + except: + print("Warning: failed to XInitThreads()") + main() -# Make sure to create the top block (tb) within a function: That code -# in main will allow tb to go out of scope on return, which will call -# the decontructor on uhd device and stop transmit. Whats odd is that -# grc works fine with tb in the __main__, perhaps its because the -# try/except clauses around tb. -if __name__ == "__main__": main() diff --git a/gr-uhd/examples/grc/uhd_siggen_gui.grc b/gr-uhd/examples/grc/uhd_siggen_gui.grc new file mode 100644 index 0000000000..27eda7c4c7 --- /dev/null +++ b/gr-uhd/examples/grc/uhd_siggen_gui.grc @@ -0,0 +1,2154 @@ +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.9'?> +<flow_graph> + <timestamp>Sat Jun 27 12:02:49 2015</timestamp> + <block> + <key>options</key> + <param> + <key>author</key> + <value>Ettus Research</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>category</key> + <value>Custom</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value>Signal Generator for use with USRP Devices</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(-8, -11)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>qt_gui</value> + </param> + <param> + <key>id</key> + <value>uhd_siggen_gui</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>title</key> + <value>UHD Signal Generator</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>.7</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(984, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>5,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>amplitude</value> + </param> + <param> + <key>label</key> + <value>Signal Amplitude</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>step</key> + <value>.001</value> + </param> + <param> + <key>stop</key> + <value>1</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_chooser</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>RX2</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(304, 175)</value> + </param> + <param> + <key>gui_hint</key> + <value>7,4,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>ant</value> + </param> + <param> + <key>label0</key> + <value>RX2</value> + </param> + <param> + <key>label1</key> + <value>TX/RX</value> + </param> + <param> + <key>label2</key> + <value>J1</value> + </param> + <param> + <key>label3</key> + <value>J2</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>label</key> + <value>Antenna</value> + </param> + <param> + <key>labels</key> + <value>[]</value> + </param> + <param> + <key>num_opts</key> + <value>2</value> + </param> + <param> + <key>option0</key> + <value>RX2</value> + </param> + <param> + <key>option1</key> + <value>TX/RX</value> + </param> + <param> + <key>option2</key> + <value>J1</value> + </param> + <param> + <key>option3</key> + <value>J2</value> + </param> + <param> + <key>option4</key> + <value>4</value> + </param> + <param> + <key>options</key> + <value>[0, 1, 2]</value> + </param> + <param> + <key>orient</key> + <value>Qt.QVBoxLayout</value> + </param> + <param> + <key>type</key> + <value>string</value> + </param> + <param> + <key>widget</key> + <value>combo_box</value> + </param> + </block> + <block> + <key>variable_function_probe</key> + <param> + <key>block_id</key> + <value>uhd_usrp_source_0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>function_args</key> + <value>"'lo_locked'"</value> + </param> + <param> + <key>function_name</key> + <value>get_sensor</value> + </param> + <param> + <key>_coordinate</key> + <value>(0, 110)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>chan0_lo_locked</value> + </param> + <param> + <key>poll_rate</key> + <value>10</value> + </param> + <param> + <key>value</key> + <value>uhd.sensor_value("", False, "")</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(656, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>4,0,1,3</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>freq1_offset</value> + </param> + <param> + <key>label</key> + <value>Frequency Offset: Signal 1</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>-1e6</value> + </param> + <param> + <key>step</key> + <value>100</value> + </param> + <param> + <key>stop</key> + <value>1e6</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(816, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>4,3,1,2</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>freq2_offset</value> + </param> + <param> + <key>label</key> + <value>Signal 2 </value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>-1e6</value> + </param> + <param> + <key>step</key> + <value>100</value> + </param> + <param> + <key>stop</key> + <value>1e6</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>1e9</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(296, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>1,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>freq_coarse</value> + </param> + <param> + <key>label</key> + <value>Center Frequency</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>100e6</value> + </param> + <param> + <key>step</key> + <value>1e3</value> + </param> + <param> + <key>stop</key> + <value>2e9</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(440, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>2,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>freq_fine</value> + </param> + <param> + <key>label</key> + <value>Fine Tuning</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>-1e6</value> + </param> + <param> + <key>step</key> + <value>1e3</value> + </param> + <param> + <key>stop</key> + <value>1e6</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>20</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(1128, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>6,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>gain</value> + </param> + <param> + <key>label</key> + <value>TX Gain</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>0</value> + </param> + <param> + <key>step</key> + <value>.5</value> + </param> + <param> + <key>stop</key> + <value>50</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_label</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>1e3</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>_coordinate</key> + <value>(688, 236)</value> + </param> + <param> + <key>gui_hint</key> + <value>8,2,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>label_dsp_freq</value> + </param> + <param> + <key>label</key> + <value>DSP Freq</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + </block> + <block> + <key>variable_qtgui_label</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>1e9</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>_coordinate</key> + <value>(576, 236)</value> + </param> + <param> + <key>gui_hint</key> + <value>8,1,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>label_lo_freq</value> + </param> + <param> + <key>label</key> + <value>LO freq</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + </block> + <block> + <key>variable_qtgui_label</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>chan0_lo_locked.to_bool()</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>formatter</key> + <value>None</value> + </param> + <param> + <key>_coordinate</key> + <value>(448, 236)</value> + </param> + <param> + <key>gui_hint</key> + <value>8,0,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>lo_locked_probe_0</value> + </param> + <param> + <key>label</key> + <value>LO locked</value> + </param> + <param> + <key>type</key> + <value>bool</value> + </param> + </block> + <block> + <key>variable_qtgui_range</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(552, -2)</value> + </param> + <param> + <key>gui_hint</key> + <value>3,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>lo_offset</value> + </param> + <param> + <key>label</key> + <value>LO Offset</value> + </param> + <param> + <key>min_len</key> + <value>200</value> + </param> + <param> + <key>orient</key> + <value>Qt.Horizontal</value> + </param> + <param> + <key>start</key> + <value>-samp_rate/2</value> + </param> + <param> + <key>step</key> + <value>samp_rate/2</value> + </param> + <param> + <key>stop</key> + <value>1e3</value> + </param> + <param> + <key>rangeType</key> + <value>float</value> + </param> + <param> + <key>widget</key> + <value>counter_slider</value> + </param> + </block> + <block> + <key>variable_qtgui_entry</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>1e6</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(160, 259)</value> + </param> + <param> + <key>gui_hint</key> + <value>7,0,1,2</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>label</key> + <value>Sampling Rate</value> + </param> + <param> + <key>type</key> + <value>real</value> + </param> + </block> + <block> + <key>variable_qtgui_push_button</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>False</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(896, 315)</value> + </param> + <param> + <key>gui_hint</key> + <value>7,2,1,1</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>sync_phases</value> + </param> + <param> + <key>label</key> + <value>Sync LOs</value> + </param> + <param> + <key>pressed</key> + <value>True</value> + </param> + <param> + <key>released</key> + <value>False</value> + </param> + <param> + <key>type</key> + <value>bool</value> + </param> + </block> + <block> + <key>variable_qtgui_chooser</key> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(160, -6)</value> + </param> + <param> + <key>gui_hint</key> + <value>0,0,1,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>waveform</value> + </param> + <param> + <key>label0</key> + <value>Tone</value> + </param> + <param> + <key>label1</key> + <value>Two-Tone</value> + </param> + <param> + <key>label2</key> + <value>Uniform Noise</value> + </param> + <param> + <key>label3</key> + <value>Two Tone</value> + </param> + <param> + <key>label4</key> + <value>Sweep</value> + </param> + <param> + <key>label</key> + <value>Waveform</value> + </param> + <param> + <key>labels</key> + <value>[]</value> + </param> + <param> + <key>num_opts</key> + <value>5</value> + </param> + <param> + <key>option0</key> + <value>0</value> + </param> + <param> + <key>option1</key> + <value>1</value> + </param> + <param> + <key>option2</key> + <value>2</value> + </param> + <param> + <key>option3</key> + <value>3</value> + </param> + <param> + <key>option4</key> + <value>4</value> + </param> + <param> + <key>options</key> + <value>[0, 1, 2]</value> + </param> + <param> + <key>orient</key> + <value>Qt.QHBoxLayout</value> + </param> + <param> + <key>type</key> + <value>int</value> + </param> + <param> + <key>widget</key> + <value>radio_buttons</value> + </param> + </block> + <block> + <key>analog_sig_source_x</key> + <param> + <key>amp</key> + <value>amplitude if not sync_phases else 0</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>freq</key> + <value>freq1_offset</value> + </param> + <param> + <key>_coordinate</key> + <value>(720, 125)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>analog_sig_source_x_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>offset</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>waveform</key> + <value>analog.GR_TRI_WAVE</value> + </param> + </block> + <block> + <key>qtgui_freq_sink_x</key> + <param> + <key>autoscale</key> + <value>False</value> + </param> + <param> + <key>average</key> + <value>1.0</value> + </param> + <param> + <key>bw</key> + <value>samp_rate</value> + </param> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>fc</key> + <value>freq_coarse + freq_fine</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>ctrlpanel</key> + <value>False</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>fftsize</key> + <value>1024</value> + </param> + <param> + <key>_coordinate</key> + <value>(920, 220)</value> + </param> + <param> + <key>gui_hint</key> + <value>9,0,2,5</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>grid</key> + <value>False</value> + </param> + <param> + <key>id</key> + <value>qtgui_freq_sink_x_0</value> + </param> + <param> + <key>legend</key> + <value>True</value> + </param> + <param> + <key>alpha1</key> + <value>1.0</value> + </param> + <param> + <key>color1</key> + <value>"blue"</value> + </param> + <param> + <key>label1</key> + <value></value> + </param> + <param> + <key>width1</key> + <value>1</value> + </param> + <param> + <key>alpha10</key> + <value>1.0</value> + </param> + <param> + <key>color10</key> + <value>"dark blue"</value> + </param> + <param> + <key>label10</key> + <value></value> + </param> + <param> + <key>width10</key> + <value>1</value> + </param> + <param> + <key>alpha2</key> + <value>1.0</value> + </param> + <param> + <key>color2</key> + <value>"red"</value> + </param> + <param> + <key>label2</key> + <value></value> + </param> + <param> + <key>width2</key> + <value>1</value> + </param> + <param> + <key>alpha3</key> + <value>1.0</value> + </param> + <param> + <key>color3</key> + <value>"green"</value> + </param> + <param> + <key>label3</key> + <value></value> + </param> + <param> + <key>width3</key> + <value>1</value> + </param> + <param> + <key>alpha4</key> + <value>1.0</value> + </param> + <param> + <key>color4</key> + <value>"black"</value> + </param> + <param> + <key>label4</key> + <value></value> + </param> + <param> + <key>width4</key> + <value>1</value> + </param> + <param> + <key>alpha5</key> + <value>1.0</value> + </param> + <param> + <key>color5</key> + <value>"cyan"</value> + </param> + <param> + <key>label5</key> + <value></value> + </param> + <param> + <key>width5</key> + <value>1</value> + </param> + <param> + <key>alpha6</key> + <value>1.0</value> + </param> + <param> + <key>color6</key> + <value>"magenta"</value> + </param> + <param> + <key>label6</key> + <value></value> + </param> + <param> + <key>width6</key> + <value>1</value> + </param> + <param> + <key>alpha7</key> + <value>1.0</value> + </param> + <param> + <key>color7</key> + <value>"yellow"</value> + </param> + <param> + <key>label7</key> + <value></value> + </param> + <param> + <key>width7</key> + <value>1</value> + </param> + <param> + <key>alpha8</key> + <value>1.0</value> + </param> + <param> + <key>color8</key> + <value>"dark red"</value> + </param> + <param> + <key>label8</key> + <value></value> + </param> + <param> + <key>width8</key> + <value>1</value> + </param> + <param> + <key>alpha9</key> + <value>1.0</value> + </param> + <param> + <key>color9</key> + <value>"dark green"</value> + </param> + <param> + <key>label9</key> + <value></value> + </param> + <param> + <key>width9</key> + <value>1</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>name</key> + <value>""</value> + </param> + <param> + <key>nconnections</key> + <value>1</value> + </param> + <param> + <key>showports</key> + <value>True</value> + </param> + <param> + <key>freqhalf</key> + <value>True</value> + </param> + <param> + <key>tr_chan</key> + <value>0</value> + </param> + <param> + <key>tr_level</key> + <value>0.0</value> + </param> + <param> + <key>tr_mode</key> + <value>qtgui.TRIG_MODE_FREE</value> + </param> + <param> + <key>tr_tag</key> + <value>""</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>update_time</key> + <value>0.10</value> + </param> + <param> + <key>wintype</key> + <value>firdes.WIN_BLACKMAN_hARRIS</value> + </param> + <param> + <key>ymax</key> + <value>10</value> + </param> + <param> + <key>ymin</key> + <value>-140</value> + </param> + </block> + <block> + <key>uhd_usrp_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>ant0</key> + <value></value> + </param> + <param> + <key>bw0</key> + <value>0</value> + </param> + <param> + <key>center_freq0</key> + <value>0</value> + </param> + <param> + <key>norm_gain0</key> + <value>False</value> + </param> + <param> + <key>gain0</key> + <value>0</value> + </param> + <param> + <key>ant10</key> + <value></value> + </param> + <param> + <key>bw10</key> + <value>0</value> + </param> + <param> + <key>center_freq10</key> + <value>0</value> + </param> + <param> + <key>norm_gain10</key> + <value>False</value> + </param> + <param> + <key>gain10</key> + <value>0</value> + </param> + <param> + <key>ant11</key> + <value></value> + </param> + <param> + <key>bw11</key> + <value>0</value> + </param> + <param> + <key>center_freq11</key> + <value>0</value> + </param> + <param> + <key>norm_gain11</key> + <value>False</value> + </param> + <param> + <key>gain11</key> + <value>0</value> + </param> + <param> + <key>ant12</key> + <value></value> + </param> + <param> + <key>bw12</key> + <value>0</value> + </param> + <param> + <key>center_freq12</key> + <value>0</value> + </param> + <param> + <key>norm_gain12</key> + <value>False</value> + </param> + <param> + <key>gain12</key> + <value>0</value> + </param> + <param> + <key>ant13</key> + <value></value> + </param> + <param> + <key>bw13</key> + <value>0</value> + </param> + <param> + <key>center_freq13</key> + <value>0</value> + </param> + <param> + <key>norm_gain13</key> + <value>False</value> + </param> + <param> + <key>gain13</key> + <value>0</value> + </param> + <param> + <key>ant14</key> + <value></value> + </param> + <param> + <key>bw14</key> + <value>0</value> + </param> + <param> + <key>center_freq14</key> + <value>0</value> + </param> + <param> + <key>norm_gain14</key> + <value>False</value> + </param> + <param> + <key>gain14</key> + <value>0</value> + </param> + <param> + <key>ant15</key> + <value></value> + </param> + <param> + <key>bw15</key> + <value>0</value> + </param> + <param> + <key>center_freq15</key> + <value>0</value> + </param> + <param> + <key>norm_gain15</key> + <value>False</value> + </param> + <param> + <key>gain15</key> + <value>0</value> + </param> + <param> + <key>ant16</key> + <value></value> + </param> + <param> + <key>bw16</key> + <value>0</value> + </param> + <param> + <key>center_freq16</key> + <value>0</value> + </param> + <param> + <key>norm_gain16</key> + <value>False</value> + </param> + <param> + <key>gain16</key> + <value>0</value> + </param> + <param> + <key>ant17</key> + <value></value> + </param> + <param> + <key>bw17</key> + <value>0</value> + </param> + <param> + <key>center_freq17</key> + <value>0</value> + </param> + <param> + <key>norm_gain17</key> + <value>False</value> + </param> + <param> + <key>gain17</key> + <value>0</value> + </param> + <param> + <key>ant18</key> + <value></value> + </param> + <param> + <key>bw18</key> + <value>0</value> + </param> + <param> + <key>center_freq18</key> + <value>0</value> + </param> + <param> + <key>norm_gain18</key> + <value>False</value> + </param> + <param> + <key>gain18</key> + <value>0</value> + </param> + <param> + <key>ant19</key> + <value></value> + </param> + <param> + <key>bw19</key> + <value>0</value> + </param> + <param> + <key>center_freq19</key> + <value>0</value> + </param> + <param> + <key>norm_gain19</key> + <value>False</value> + </param> + <param> + <key>gain19</key> + <value>0</value> + </param> + <param> + <key>ant1</key> + <value></value> + </param> + <param> + <key>bw1</key> + <value>0</value> + </param> + <param> + <key>center_freq1</key> + <value>0</value> + </param> + <param> + <key>norm_gain1</key> + <value>False</value> + </param> + <param> + <key>gain1</key> + <value>0</value> + </param> + <param> + <key>ant20</key> + <value></value> + </param> + <param> + <key>bw20</key> + <value>0</value> + </param> + <param> + <key>center_freq20</key> + <value>0</value> + </param> + <param> + <key>norm_gain20</key> + <value>False</value> + </param> + <param> + <key>gain20</key> + <value>0</value> + </param> + <param> + <key>ant21</key> + <value></value> + </param> + <param> + <key>bw21</key> + <value>0</value> + </param> + <param> + <key>center_freq21</key> + <value>0</value> + </param> + <param> + <key>norm_gain21</key> + <value>False</value> + </param> + <param> + <key>gain21</key> + <value>0</value> + </param> + <param> + <key>ant22</key> + <value></value> + </param> + <param> + <key>bw22</key> + <value>0</value> + </param> + <param> + <key>center_freq22</key> + <value>0</value> + </param> + <param> + <key>norm_gain22</key> + <value>False</value> + </param> + <param> + <key>gain22</key> + <value>0</value> + </param> + <param> + <key>ant23</key> + <value></value> + </param> + <param> + <key>bw23</key> + <value>0</value> + </param> + <param> + <key>center_freq23</key> + <value>0</value> + </param> + <param> + <key>norm_gain23</key> + <value>False</value> + </param> + <param> + <key>gain23</key> + <value>0</value> + </param> + <param> + <key>ant24</key> + <value></value> + </param> + <param> + <key>bw24</key> + <value>0</value> + </param> + <param> + <key>center_freq24</key> + <value>0</value> + </param> + <param> + <key>norm_gain24</key> + <value>False</value> + </param> + <param> + <key>gain24</key> + <value>0</value> + </param> + <param> + <key>ant25</key> + <value></value> + </param> + <param> + <key>bw25</key> + <value>0</value> + </param> + <param> + <key>center_freq25</key> + <value>0</value> + </param> + <param> + <key>norm_gain25</key> + <value>False</value> + </param> + <param> + <key>gain25</key> + <value>0</value> + </param> + <param> + <key>ant26</key> + <value></value> + </param> + <param> + <key>bw26</key> + <value>0</value> + </param> + <param> + <key>center_freq26</key> + <value>0</value> + </param> + <param> + <key>norm_gain26</key> + <value>False</value> + </param> + <param> + <key>gain26</key> + <value>0</value> + </param> + <param> + <key>ant27</key> + <value></value> + </param> + <param> + <key>bw27</key> + <value>0</value> + </param> + <param> + <key>center_freq27</key> + <value>0</value> + </param> + <param> + <key>norm_gain27</key> + <value>False</value> + </param> + <param> + <key>gain27</key> + <value>0</value> + </param> + <param> + <key>ant28</key> + <value></value> + </param> + <param> + <key>bw28</key> + <value>0</value> + </param> + <param> + <key>center_freq28</key> + <value>0</value> + </param> + <param> + <key>norm_gain28</key> + <value>False</value> + </param> + <param> + <key>gain28</key> + <value>0</value> + </param> + <param> + <key>ant29</key> + <value></value> + </param> + <param> + <key>bw29</key> + <value>0</value> + </param> + <param> + <key>center_freq29</key> + <value>0</value> + </param> + <param> + <key>norm_gain29</key> + <value>False</value> + </param> + <param> + <key>gain29</key> + <value>0</value> + </param> + <param> + <key>ant2</key> + <value></value> + </param> + <param> + <key>bw2</key> + <value>0</value> + </param> + <param> + <key>center_freq2</key> + <value>0</value> + </param> + <param> + <key>norm_gain2</key> + <value>False</value> + </param> + <param> + <key>gain2</key> + <value>0</value> + </param> + <param> + <key>ant30</key> + <value></value> + </param> + <param> + <key>bw30</key> + <value>0</value> + </param> + <param> + <key>center_freq30</key> + <value>0</value> + </param> + <param> + <key>norm_gain30</key> + <value>False</value> + </param> + <param> + <key>gain30</key> + <value>0</value> + </param> + <param> + <key>ant31</key> + <value></value> + </param> + <param> + <key>bw31</key> + <value>0</value> + </param> + <param> + <key>center_freq31</key> + <value>0</value> + </param> + <param> + <key>norm_gain31</key> + <value>False</value> + </param> + <param> + <key>gain31</key> + <value>0</value> + </param> + <param> + <key>ant3</key> + <value></value> + </param> + <param> + <key>bw3</key> + <value>0</value> + </param> + <param> + <key>center_freq3</key> + <value>0</value> + </param> + <param> + <key>norm_gain3</key> + <value>False</value> + </param> + <param> + <key>gain3</key> + <value>0</value> + </param> + <param> + <key>ant4</key> + <value></value> + </param> + <param> + <key>bw4</key> + <value>0</value> + </param> + <param> + <key>center_freq4</key> + <value>0</value> + </param> + <param> + <key>norm_gain4</key> + <value>False</value> + </param> + <param> + <key>gain4</key> + <value>0</value> + </param> + <param> + <key>ant5</key> + <value></value> + </param> + <param> + <key>bw5</key> + <value>0</value> + </param> + <param> + <key>center_freq5</key> + <value>0</value> + </param> + <param> + <key>norm_gain5</key> + <value>False</value> + </param> + <param> + <key>gain5</key> + <value>0</value> + </param> + <param> + <key>ant6</key> + <value></value> + </param> + <param> + <key>bw6</key> + <value>0</value> + </param> + <param> + <key>center_freq6</key> + <value>0</value> + </param> + <param> + <key>norm_gain6</key> + <value>False</value> + </param> + <param> + <key>gain6</key> + <value>0</value> + </param> + <param> + <key>ant7</key> + <value></value> + </param> + <param> + <key>bw7</key> + <value>0</value> + </param> + <param> + <key>center_freq7</key> + <value>0</value> + </param> + <param> + <key>norm_gain7</key> + <value>False</value> + </param> + <param> + <key>gain7</key> + <value>0</value> + </param> + <param> + <key>ant8</key> + <value></value> + </param> + <param> + <key>bw8</key> + <value>0</value> + </param> + <param> + <key>center_freq8</key> + <value>0</value> + </param> + <param> + <key>norm_gain8</key> + <value>False</value> + </param> + <param> + <key>gain8</key> + <value>0</value> + </param> + <param> + <key>ant9</key> + <value></value> + </param> + <param> + <key>bw9</key> + <value>0</value> + </param> + <param> + <key>center_freq9</key> + <value>0</value> + </param> + <param> + <key>norm_gain9</key> + <value>False</value> + </param> + <param> + <key>gain9</key> + <value>0</value> + </param> + <param> + <key>clock_rate</key> + <value>0.0</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>dev_addr</key> + <value>""</value> + </param> + <param> + <key>dev_args</key> + <value>""</value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(960, 125)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>uhd_usrp_sink_0</value> + </param> + <param> + <key>type</key> + <value>fc32</value> + </param> + <param> + <key>clock_source0</key> + <value></value> + </param> + <param> + <key>sd_spec0</key> + <value></value> + </param> + <param> + <key>time_source0</key> + <value></value> + </param> + <param> + <key>clock_source1</key> + <value></value> + </param> + <param> + <key>sd_spec1</key> + <value></value> + </param> + <param> + <key>time_source1</key> + <value></value> + </param> + <param> + <key>clock_source2</key> + <value></value> + </param> + <param> + <key>sd_spec2</key> + <value></value> + </param> + <param> + <key>time_source2</key> + <value></value> + </param> + <param> + <key>clock_source3</key> + <value></value> + </param> + <param> + <key>sd_spec3</key> + <value></value> + </param> + <param> + <key>time_source3</key> + <value></value> + </param> + <param> + <key>clock_source4</key> + <value></value> + </param> + <param> + <key>sd_spec4</key> + <value></value> + </param> + <param> + <key>time_source4</key> + <value></value> + </param> + <param> + <key>clock_source5</key> + <value></value> + </param> + <param> + <key>sd_spec5</key> + <value></value> + </param> + <param> + <key>time_source5</key> + <value></value> + </param> + <param> + <key>clock_source6</key> + <value></value> + </param> + <param> + <key>sd_spec6</key> + <value></value> + </param> + <param> + <key>time_source6</key> + <value></value> + </param> + <param> + <key>clock_source7</key> + <value></value> + </param> + <param> + <key>sd_spec7</key> + <value></value> + </param> + <param> + <key>time_source7</key> + <value></value> + </param> + <param> + <key>nchan</key> + <value>1</value> + </param> + <param> + <key>num_mboards</key> + <value>1</value> + </param> + <param> + <key>samp_rate</key> + <value>samp_rate</value> + </param> + <param> + <key>hide_cmd_port</key> + <value>False</value> + </param> + <param> + <key>stream_args</key> + <value></value> + </param> + <param> + <key>stream_chans</key> + <value>[]</value> + </param> + <param> + <key>sync</key> + <value></value> + </param> + <param> + <key>len_tag_name</key> + <value></value> + </param> + <param> + <key>otw</key> + <value></value> + </param> + </block> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>qtgui_freq_sink_x_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>analog_sig_source_x_0</source_block_id> + <sink_block_id>uhd_usrp_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> |