From f0bf96fad3e02e494fa8ae3edde548844342569b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 9 Sep 2009 12:33:10 -0700 Subject: [PATCH] copied usrp_siggen stuff from experimental gui into gnuradio tree --- gnuradio-core/src/python/gnuradio/Makefile.am | 1 + .../src/python/gnuradio/blks2impl/Makefile.am | 1 + .../python/gnuradio/blks2impl/generic_usrp.py | 239 +++++++++ .../src/python/gnuradio/usrp_options.py | 123 +++++ gr-utils/src/python/Makefile.am | 5 +- gr-utils/src/python/usrp2_siggen.py | 389 --------------- gr-utils/src/python/usrp2_siggen_gui.py | 275 ---------- gr-utils/src/python/usrp_siggen.py | 471 +++++++++++------- gr-utils/src/python/usrp_siggen_gui.py | 310 ++++++++++++ 9 files changed, 965 insertions(+), 849 deletions(-) create mode 100644 gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py create mode 100644 gnuradio-core/src/python/gnuradio/usrp_options.py delete mode 100755 gr-utils/src/python/usrp2_siggen.py delete mode 100755 gr-utils/src/python/usrp2_siggen_gui.py create mode 100755 gr-utils/src/python/usrp_siggen_gui.py diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am index ed36bbae..dcc0017b 100644 --- a/gnuradio-core/src/python/gnuradio/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/Makefile.am @@ -34,5 +34,6 @@ grpython_PYTHON = \ packet_utils.py \ gr_unittest.py \ optfir.py \ + usrp_options.py \ window.py endif diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am index 17be09cc..f0825b15 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am @@ -36,6 +36,7 @@ grblkspython_PYTHON = \ filterbank.py \ fm_demod.py \ fm_emph.py \ + generic_usrp.py \ gmsk.py \ cpm.py \ logpwrfft.py \ diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py new file mode 100644 index 00000000..c7ccbe53 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_usrp.py @@ -0,0 +1,239 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +USRP1_TYPE = 'usrp1' +USRP2_TYPE = 'usrp2' +DUMMY_TYPE = 'dummy' +#usrp2 rates common for decim and interp +_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) +#dummy common rates +_DUMMY_XRATES = range(4, 512, 2) +_DUMMY_CONVERTER_RATE = 100e6 +#dummy freq result +class _dummy_freq_result(object): + def __init__(self, target_freq): + self.baseband_freq = target_freq + self.dxc_freq = 0 + self.residual_freq = 0 +from gnuradio import gr, usrp, usrp2 + +######################################################################## +# generic usrp common stuff +######################################################################## +class _generic_usrp_base(object): + + def __init__(self, which=0, subdev_spec=None, interface="", mac_addr="", + fusb_block_size=0, fusb_nblocks=0, usrpx=None, lo_offset=None, gain=None): + self._lo_offset = lo_offset + #usrp options + self._which = which + self._subdev_spec = subdev_spec + #usrp2 options + self._interface = interface + self._mac_addr = mac_addr + #fusb options + self._fusb_block_size = fusb_block_size + self._fusb_nblocks = fusb_nblocks + #pick which usrp model + if usrpx == '0': self._setup_usrpx(DUMMY_TYPE) + elif usrpx == '1' or self._subdev_spec: self._setup_usrpx(USRP1_TYPE) + elif usrpx == '2' or self._mac_addr: self._setup_usrpx(USRP2_TYPE) + else: #automatic + try: self._setup_usrpx(USRP2_TYPE) + except: + try: self._setup_usrpx(USRP1_TYPE) + except: raise Exception, 'Failed to automatically setup a usrp device.' + #post usrp setup + if self._lo_offset is not None: + self.set_lo_offset(self._lo_offset) + self.set_gain(gain) + self.set_auto_tr(True) + + def _setup_usrpx(self, type): + """ + Call the appropriate setup method. + @param type the usrp type constant + """ + self._type = type + if self._type == USRP1_TYPE: self._setup_usrp1() + elif self._type == USRP2_TYPE: self._setup_usrp2() + elif self._type == DUMMY_TYPE: self._setup_dummy() + + def __str__(self): + if self._type == USRP1_TYPE: return self._subdev.side_and_name() + elif self._type == USRP2_TYPE: + return 'Interface: %s MAC Address: %s D-Board ID: 0x%.2x'%( + self._u.interface_name(), self._u.mac_addr(), self._u.daughterboard_id()) + elif self._type == DUMMY_TYPE: return 'Dummy USRP Device' + + def gain(self): return self._gain + + def set_gain(self, gain=None): + #automatic gain calculation + r = self.gain_range() + if gain is None: gain = (r[0] + r[1])/2 # set gain to midpoint + #set gain for usrp + self._gain = gain + if self._type == USRP1_TYPE: return self._subdev.set_gain(gain) + elif self._type == USRP2_TYPE: return self._u.set_gain(gain) + elif self._type == DUMMY_TYPE: return True + + def gain_range(self): + if self._type == USRP1_TYPE: return self._subdev.gain_range() + elif self._type == USRP2_TYPE: return self._u.gain_range() + elif self._type == DUMMY_TYPE: return (0, 0, 0) + + def set_center_freq(self, target_freq): + if self._type == USRP1_TYPE: + return self._u.tune(self._dxc, self._subdev, target_freq) + elif self._type == USRP2_TYPE: + return self._u.set_center_freq(target_freq) + elif self._type == DUMMY_TYPE: return _dummy_freq_result(target_freq) + + def freq_range(self): + if self._type == USRP1_TYPE: return self._subdev.freq_range() + elif self._type == USRP2_TYPE: return self._u.freq_range() + elif self._type == DUMMY_TYPE: return (-10e9, 10e9, 100e3) + + def set_lo_offset(self, lo_offset): + if self._type == USRP1_TYPE: return self._subdev.set_lo_offset(lo_offset) + elif self._type == USRP2_TYPE: return self._u.set_lo_offset(lo_offset) + elif self._type == DUMMY_TYPE: return True + + def set_auto_tr(self, enable): + if self._type == USRP1_TYPE: return self._subdev.set_auto_tr(enable) + + def __del__(self): + try: # Avoid weak reference error + del self._u + del self._subdev + except: pass + +######################################################################## +# generic usrp source +######################################################################## +class generic_usrp_source_c(_generic_usrp_base, gr.hier_block2): + """ + Create a generic usrp source that represents usrp and usrp2. + Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2. + Provide generic access methods so the API looks the same for both. + """ + + def __init__(self, **kwargs): + gr.hier_block2.__init__(self, "generic_usrp_source", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature + _generic_usrp_base.__init__(self, **kwargs) + self.connect(self._u, self) + + #################################################################### + # generic access methods + #################################################################### + def set_decim(self, decim): + if decim not in self.get_decim_rates(): return False + if self._type == USRP1_TYPE: return self._u.set_decim_rate(decim) + elif self._type == USRP2_TYPE: return self._u.set_decim(decim) + elif self._type == DUMMY_TYPE: return True + + def get_decim_rates(self): + if self._type == USRP1_TYPE: return range(8, 256+1, 2) #default firmware w/ hb filters + if self._type == USRP2_TYPE: return _USRP2_RATES + elif self._type == DUMMY_TYPE: return _DUMMY_XRATES + + def adc_rate(self): + if self._type == USRP1_TYPE: return self._u.adc_rate() + if self._type == USRP2_TYPE: return self._u.adc_rate() + elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE + + #################################################################### + # setup usrp methods + #################################################################### + def _setup_usrp1(self): + self._u = usrp.source_c (self._which, + fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + # determine the daughterboard subdevice we're using + if self._subdev_spec is None: + self._subdev_spec = usrp.pick_rx_subdevice(self._u) + self._subdev = usrp.selected_subdev(self._u, self._subdev_spec) + self._u.set_mux(usrp.determine_rx_mux_value(self._u, self._subdev_spec)) + self._dxc = 0 + + def _setup_usrp2(self): + self._u = usrp2.source_32fc(self._interface, self._mac_addr) + + def _setup_dummy(self): self._u = gr.null_source(gr.sizeof_gr_complex) + +######################################################################## +# generic usrp sink +######################################################################## +class generic_usrp_sink_c(_generic_usrp_base, gr.hier_block2): + """ + Create a generic usrp sink that represents usrp and usrp2. + Take usrp and usrp2 constructor arguments and try to figure out usrp or usrp2. + Provide generic access methods so the API looks the same for both. + """ + + def __init__(self, **kwargs): + gr.hier_block2.__init__(self, "generic_usrp_sink", + gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature + gr.io_signature(0, 0, 0)) # Output signature + _generic_usrp_base.__init__(self, **kwargs) + if self._type == USRP1_TYPE: #scale 0.0 to 1.0 input for usrp1 + self.connect(self, gr.multiply_const_cc((2**15)-1), self._u) + else: self.connect(self, self._u) + + #################################################################### + # generic access methods + #################################################################### + def set_interp(self, interp): + if interp not in self.get_interp_rates(): return False + if self._type == USRP1_TYPE: return self._u.set_interp_rate(interp) + elif self._type == USRP2_TYPE: return self._u.set_interp(interp) + elif self._type == DUMMY_TYPE: return True + + def get_interp_rates(self): + if self._type == USRP1_TYPE: return range(16, 512+1, 4) + if self._type == USRP2_TYPE: return _USRP2_RATES + elif self._type == DUMMY_TYPE: return _DUMMY_XRATES + + def dac_rate(self): + if self._type == USRP1_TYPE: return self._u.dac_rate() + if self._type == USRP2_TYPE: return self._u.dac_rate() + elif self._type == DUMMY_TYPE: return _DUMMY_CONVERTER_RATE + + #################################################################### + # setup usrp methods + #################################################################### + def _setup_usrp1(self): + self._u = usrp.sink_c (self._which, + fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + # determine the daughterboard subdevice we're using + if self._subdev_spec is None: + self._subdev_spec = usrp.pick_tx_subdevice(self._u) + self._subdev = usrp.selected_subdev(self._u, self._subdev_spec) + self._u.set_mux(usrp.determine_tx_mux_value(self._u, self._subdev_spec)) + self._dxc = self._subdev.which() + + def _setup_usrp2(self): self._u = usrp2.sink_32fc(self._interface, self._mac_addr) + + def _setup_dummy(self): self._u = gr.null_sink(gr.sizeof_gr_complex) diff --git a/gnuradio-core/src/python/gnuradio/usrp_options.py b/gnuradio-core/src/python/gnuradio/usrp_options.py new file mode 100644 index 00000000..86dba2f9 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/usrp_options.py @@ -0,0 +1,123 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +_parser_to_groups_dict = dict() +class _parser_groups(object): + def __init__(self, parser): + self.usrpx_grp = parser.add_option_group("General USRP Options") + self.usrp1_grp = parser.add_option_group("USRP1 Specific Options") + self.usrp1exp_grp = parser.add_option_group("USRP1 Expert Options") + self.usrp2_grp = parser.add_option_group("USRP2 Specific Options") + +from gnuradio import blks2 + +def _add_options(parser): + """ + Add options to manually choose between usrp or usrp2. + Add options for usb. Add options common to source and sink. + @param parser: instance of OptionParser + @return the parser group + """ + #cache groups so they dont get added twice on tranceiver apps + if not _parser_to_groups_dict.has_key(parser): _parser_to_groups_dict[parser] = _parser_groups(parser) + pg = _parser_to_groups_dict[parser] + #pick usrp or usrp2 + pg.usrpx_grp.add_option("-u", "--usrpx", type="string", default=None, + help="specify which usrp model: 1 for USRP, 2 for USRP2 [default=auto]") + #fast usb options + pg.usrp1exp_grp.add_option("-B", "--fusb-block-size", type="int", default=0, + help="specify fast usb block size [default=%default]") + pg.usrp1exp_grp.add_option("-N", "--fusb-nblocks", type="int", default=0, + help="specify number of fast usb blocks [default=%default]") + #lo offset + pg.usrpx_grp.add_option("--lo-offset", type="eng_float", default=None, + help="set LO Offset in Hz [default=automatic].") + #usrp options + pg.usrp1_grp.add_option("-w", "--which", type="int", default=0, + help="select USRP board [default=%default]") + #usrp2 options + pg.usrp2_grp.add_option("-e", "--interface", type="string", default="eth0", + help="Use USRP2 at specified Ethernet interface [default=%default]") + pg.usrp2_grp.add_option("-a", "--mac-addr", type="string", default="", + help="Use USRP2 at specified MAC address [default=None]") + return pg + +def add_rx_options(parser): + """ + Add receive specific usrp options. + @param parser: instance of OptionParser + """ + pg = _add_options(parser) + pg.usrp1_grp.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + pg.usrpx_grp.add_option("--rx-gain", type="eng_float", default=None, metavar="GAIN", + help="set receiver gain in dB [default=midpoint]. See also --show-rx-gain-range") + pg.usrpx_grp.add_option("--show-rx-gain-range", action="store_true", default=False, + help="print min and max Rx gain available on selected daughterboard") + pg.usrpx_grp.add_option("-d", "--decim", type="intx", default=None, + help="set fpga decimation rate to DECIM [default=%default]") + +def create_usrp_source(options): + u = blks2.generic_usrp_source_c( + usrpx=options.usrpx, + which=options.which, + subdev_spec=options.rx_subdev_spec, + interface=options.interface, + mac_addr=options.mac_addr, + fusb_block_size=options.fusb_block_size, + fusb_nblocks=options.fusb_nblocks, + lo_offset=options.lo_offset, + gain=options.rx_gain, + ) + if options.show_rx_gain_range: + print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range()) + return u + +def add_tx_options(parser): + """ + Add transmit specific usrp options. + @param parser: instance of OptionParser + """ + pg = _add_options(parser) + pg.usrp1_grp.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + pg.usrpx_grp.add_option("--tx-gain", type="eng_float", default=None, metavar="GAIN", + help="set transmitter gain in dB [default=midpoint]. See also --show-tx-gain-range") + pg.usrpx_grp.add_option("--show-tx-gain-range", action="store_true", default=False, + help="print min and max Tx gain available on selected daughterboard") + pg.usrpx_grp.add_option("-i", "--interp", type="intx", default=None, + help="set fpga interpolation rate to INTERP [default=%default]") + +def create_usrp_sink(options): + u = blks2.generic_usrp_sink_c( + usrpx=options.usrpx, + which=options.which, + subdev_spec=options.tx_subdev_spec, + interface=options.interface, + mac_addr=options.mac_addr, + fusb_block_size=options.fusb_block_size, + fusb_nblocks=options.fusb_nblocks, + lo_offset=options.lo_offset, + gain=options.tx_gain, + ) + if options.show_tx_gain_range: + print "Tx Gain Range: minimum = %g, maximum = %g, step size = %g"%tuple(u.gain_range()) + return u diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 0c8240fe..fb21e4f4 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -56,10 +56,9 @@ bin_SCRIPTS = \ usrp_rx_cfile.py \ usrp_rx_nogui.py \ usrp_siggen.py \ + usrp_siggen_gui.py \ usrp_test_counting.py \ usrp_test_loopback.py \ usrp2_fft.py \ - usrp2_rx_cfile.py \ - usrp2_siggen.py \ - usrp2_siggen_gui.py + usrp2_rx_cfile.py diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py deleted file mode 100755 index 9ade933c..00000000 --- a/gr-utils/src/python/usrp2_siggen.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio import gr, eng_notation, usrp2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys -import math - -n2s = eng_notation.num_to_str - -waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", - gr.GR_CONST_WAVE : "Constant", - gr.GR_GAUSSIAN : "Gaussian Noise", - gr.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): - def __init__(self, options, args): - gr.top_block.__init__(self) - self._verbose = options.verbose - - self._interp = 0 - self._gain = 0 - self._freq = None # Indicates frequency hasn't been successfully set yet - self._bb_freq = 0 - self._ddc_freq = 0 - self._amplitude = 0 - self._type = None # Indicates waveform flowgraph not created yet - self._offset = options.offset - - self.set_usrp2(options.interface, options.mac_addr) - self.set_interp(options.interp) - self.set_gain(options.gain) - self.set_freq(options.tx_freq, options.lo_offset) - self.set_amplitude(options.amplitude) - - self.set_waveform_freq(options.waveform_freq) - self.set_waveform2_freq(options.waveform2_freq) - self.set_waveform(options.type) - - def set_usrp2(self, interface, mac_addr): - self._u = usrp2.sink_32fc(interface, mac_addr) - self._dac_rate = self._u.dac_rate() - if self._verbose: - print "Network interface:", interface - print "Network address:", self._u.mac_addr() - print "Daughterboard ID:", hex(self._u.daughterboard_id()) - - def set_interp(self, interp): - if interp < 4 or interp > 512: # FIXME get from flowgraph - if self._verbose: print "Interpolation rate out of range:", interp - return False - - if not self._u.set_interp(interp): - raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - - self._interp = interp - self._eth_rate = self._dac_rate/self._interp - if self._verbose: - print "USRP2 interpolation rate:", self._interp - print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),) - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE): - self._src.set_sampling_freq(self._eth_rate) - elif self._type == "2tone": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._eth_rate) - elif self._type == "sweep": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate) - else: - return True # Waveform not yet set - - if self._verbose: print "Set interpolation rate to:", interp - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - self._ddc_freq = tr.dxc_freq - self._bb_freq = tr.baseband_freq - if self._verbose: - print "Set center frequency to", fs - print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) - print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) - print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) - - return tr - - def set_waveform_freq(self, freq): - self._waveform_freq = freq - if self._type == gr.GR_SIN_WAVE: - self._src.set_frequency(freq) - elif self._type == "2tone" or self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform2_freq(self, freq): - self._waveform2_freq = freq - if self._type == "2tone": - self._src2.set_frequency(freq) - elif self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform(self, type): - self.lock() - self.disconnect_all() - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(self._eth_rate, # Sample rate - type, # Waveform type - self._waveform_freq, # Waveform frequency - self._amplitude, # Waveform amplitude - self._offset) # Waveform offset - elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(type, self._amplitude) - elif type == "2tone": - self._src1 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform_freq, - self._amplitude/2.0, - 0) - if(self._waveform2_freq is None): - self._waveform2_freq = -self._waveform_freq - - self._src2 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform2_freq, - self._amplitude/2.0, - 0) - self._src = gr.add_cc() - self.connect(self._src1,(self._src,0)) - self.connect(self._src2,(self._src,1)) - elif type == "sweep": - # rf freq is center frequency - # waveform_freq is total swept width - # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - if self._waveform2_freq is None: - self._waveform2_freq = 0.1 - - self._src1 = gr.sig_source_f(self._eth_rate, - gr.GR_TRI_WAVE, - self._waveform2_freq, - 1.0, - -0.5) - self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate) - self._src = gr.multiply_const_cc(self._amplitude) - self.connect(self._src1,self._src2,self._src) - else: - raise RuntimeError("Unknown waveform type") - - self.connect(self._src, self._u) - self._type = type - self.unlock() - - if self._verbose: - print "Set baseband modulation to:", waveforms[self._type] - if type == gr.GR_SIN_WAVE: - print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),) - print "Initial phase:", self._offset - elif type == "2tone": - print "Tone 1: %sHz" % (n2s(self._waveform_freq),) - print "Tone 2: %sHz" % (n2s(self._waveform2_freq),) - elif type == "sweep": - print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0)) - print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),) - print "TX amplitude:", self._amplitude - - - def set_amplitude(self, amplitude): - if amplitude < 0.0 or amplitude > 1.0: - if self._verbose: print "Amplitude out of range:", amplitude - return False - - self._amplitude = amplitude - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE or - self._type == gr.GR_GAUSSIAN or - self._type == gr.GR_UNIFORM): - self._src.set_amplitude(amplitude) - elif self._type == "2tone": - self._src1.set_amplitude(amplitude/2.0) - self._src2.set_amplitude(amplitude/2.0) - elif self._type == "sweep": - self._src.set_k(amplitude) - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - - # Property getters - - def mac_addr(self): - return self._u.mac_addr() - - def interface_name(self): - return self._u.interface_name() - - def daughterboard_id(self): - return self._u.daughterboard_id() - - def interp_rate(self): - return self._interp - - def eth_rate(self): - return self._eth_rate - - def freq(self): - return self._freq - - def freq_range(self): - return self._u.freq_range() - - def ddc_freq(self): - return self._ddc_freq - - def baseband_freq(self): - return self._bb_freq - - def amplitude(self): - return self._amplitude - - def waveform_type(self): - return self._type - - def waveform_freq(self): - return self._waveform_freq - - def waveform2_freq(self): - if self._waveform2_freq is None: - return -self._waveform_freq - else: - return self._waveform2_freq - -def get_options(): - usage="%prog: [options]" - - parser = OptionParser(option_class=eng_option, usage=usage) - - parser.add_option("-e", "--interface", type="string", default="eth0", - help="Use specified Ethernet interface [default=%default]") - parser.add_option("-m", "--mac-addr", type="string", default="", - help="Use USRP2 at specified MAC address [default=None]") - parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP", - help="Set FPGA interpolation rate of INTERP [default=%default]") - 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("--lo-offset", type="eng_float", default=None, - help="set daughterboard LO offset to OFFSET [default=hw default]") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="Set TX gain to GAIN [default=mid-point]") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, - help="Set baseband waveform frequency to FREQ [default=%default]") - parser.add_option("-x", "--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=gr.GR_SIN_WAVE, - help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) - parser.add_option("--const", dest="type", action="store_const", const=gr.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=gr.GR_GAUSSIAN, - help="Generate Gaussian random output") - parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="Generate Uniform random output") - parser.add_option("--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", - help="Generate a swept sine wave") - parser.add_option("-a", "--amplitude", type="eng_float", default=0.1, - 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]") - - (options, args) = parser.parse_args() - - return (options, args) - -# If this script is executed, the following runs. If it is imported, the below does not run. -if __name__ == "__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) = get_options() - tb = top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - - # Run it - try: - tb.run() - - except KeyboardInterrupt: - pass diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py deleted file mode 100755 index 89bc6e58..00000000 --- a/gr-utils/src/python/usrp2_siggen_gui.py +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import wx -from gnuradio.wxgui import form, slider, gui -import usrp2_siggen -import sys, math - -class app_gui(object): - def __init__(self, frame, panel, vbox, top_block, options, args): - 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 - - freq_range = self.tb.freq_range() - self.min_freq = freq_range[0] - self.max_freq = freq_range[1] - self.freq_step = (self.max_freq-self.min_freq)/100.0 - self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items()) - - self.build_gui() - - # TODO: turn these into listeners - self.myform['ifc'].set_value(self.tb.interface_name()) - self.myform['mac'].set_value(self.tb.mac_addr()) - dbid = self.tb.daughterboard_id() - self.myform['dbid'].set_value("%04x" % (dbid,)) - - w = usrp2_siggen.waveforms[self.tb.waveform_type()] - self.myform['type'].set_value(w) - self.myform['w1freq'].set_value(self.tb.waveform_freq()) - self.myform['w2freq'].set_value(self.tb.waveform2_freq()) - - freq = self.tb.freq() - if freq is None: - self.evt_set_status_msg("Failed to set initial frequency") - else: - self.myform['freq'].set_value(freq) - self.myform['freq_slider'].set_value(self.tb.freq()) - - amp = self.tb.amplitude() - if (amp > 0.0): - db = 20*math.log10(amp) - else: - db = -100.0 - self.myform['amp'].set_value(amp) - self.myform['amp_slider'].set_value(db) - self.myform['eth'].set_value(self.tb.eth_rate()) - self.myform['gbe'].set_value(self.tb.eth_rate()*32) - self.myform['interp'].set_value(self.tb.interp_rate()) - self.myform['DDC'].set_value(self.tb.ddc_freq()) - self.myform['analog'].set_value(self.tb.baseband_freq()) - - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) - - def evt_set_freq1(self, kv): - return self.tb.set_waveform_freq(kv['w1freq']) - - def evt_set_freq2(self, kv): - return self.tb.set_waveform2_freq(kv['w2freq']) - - def evt_set_freq(self, kv): - if type(kv) == type(0.0): # Set from slider - tr = self.tb.set_freq(kv) - if tr is not None: - self.myform['freq'].set_value(kv) - else: # Set from edit box - f = kv['freq'] - tr = self.tb.set_freq(f) - if tr is not None: - self.myform['freq_slider'].set_value(f) - - if tr is not None: - self.myform['DDC'].set_value(tr.dxc_freq) - self.myform['analog'].set_value(tr.baseband_freq) - - return (tr is not None) - - def evt_set_amplitude(self, kv): - if type(kv) == type(0.0): # Set from slider - amp = math.pow(10, kv/20.0) - self.myform['amp'].set_value(amp) - return self.tb.set_amplitude(amp) - else: # Set from edit box - amp = kv['amp'] - if amp < 0.0 or amp > 1.0: - return False - if amp == 0.0: - db = -100.0 - else: - db = 20*math.log10(amp) - self.myform['amp_slider'].set_value(db) - return self.tb.set_amplitude(amp) - - def evt_set_interp(self): - interp = self.myform['interp'].get_value() - if self.tb.set_interp(interp): - eth_rate = self.tb.eth_rate() - self.myform['eth'].set_value(eth_rate) - self.myform['gbe'].set_value(eth_rate*32) - return True - return False - - def evt_set_waveform_type(self, type): - # TODO: update frequency labels - return self.tb.set_waveform(self._types[type]) - - # GUI construction - def build_gui(self): - self.myform = myform = form.form() - - # Baseband controls - bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation") - bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit - - # First row of baseband controls (modulation type) - mod_hbox = wx.BoxSizer(wx.HORIZONTAL) - mod_hbox.Add((10,0), 0, 0) - myform['type'] = form.radiobox_field( - parent=self.panel, label="Type", sizer=mod_hbox, value=None, - callback=self.evt_set_waveform_type, weight=1, major_dimension=0, - choices=usrp2_siggen.waveforms.values() ) - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(mod_hbox, 0, wx.EXPAND) - - # Second row of baseband controls (frequencies) - bbf_hbox = wx.BoxSizer(wx.HORIZONTAL) - bbf_hbox.Add((10,0), 0, 0) - myform['w1freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - myform['w2freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(bbf_hbox, 0, wx.EXPAND) - - # Add baseband controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - - # Frequency controls - fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency") - fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit - - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - freq_hbox.Add((10,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=freq_hbox, label=None, weight=1, - callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) ) - freq_hbox.Add((10,0), 0, 0) - myform['freq_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4, - range = (self.min_freq, self.max_freq, self.freq_step), - callback=self.evt_set_freq) - freq_hbox.Add((10,0), 0, 0) - - fc_vbox.Add((10,0), 0, 0) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - tr_hbox.Add((10,0), 0, 0) - myform['analog'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - myform['DDC'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - - # Add frequency controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - - # Amplitude row - amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude") - amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL) - amp_hbox.Add((10,0), 0, 0) - myform['amp'] = form.float_field( - parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1, - callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) ) - amp_hbox.Add((10,0), 0, 0) - myform['amp_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4, - range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude) - amp_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - - # Sample rate row - sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate") - sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL) - sam_hbox.Add((10,0), 0, 0) - myform['interp'] = form.int_field( - parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1, - callback=self.evt_set_interp) - sam_hbox.Add((10,0), 0, 0) - myform['eth'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1) - sam_hbox.Add((10,0), 0, 0) - myform['gbe'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1) - sam_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - - # USRP2 row - u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware") - u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL) - u2_hbox.Add((10,0), 0, 0) - myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Interface", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="MAC Address", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Daughterboard ID", weight=1) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.Add((0,20), 0, 0) - -if __name__ == "__main__": - try: - # Get command line parameters - (options, args) = usrp2_siggen.get_options() - - # Create the top block using these - tb = usrp2_siggen.top_block(options, args) - - # 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="USRP2 Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 8ae2fbfb..8ee8cfd2 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,200 +20,307 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru -from gnuradio import usrp +DESC_KEY = 'desc' +SAMP_RATE_KEY = 'samp_rate' +LINK_RATE_KEY = 'link_rate' +DAC_RATE_KEY = 'dac_rate' +INTERP_KEY = 'interp' +GAIN_KEY = 'gain' +TX_FREQ_KEY = 'tx_freq' +DDC_FREQ_KEY = 'ddc_freq' +BB_FREQ_KEY = 'bb_freq' +AMPLITUDE_KEY = 'amplitude' +AMPL_RANGE_KEY = 'ampl_range' +WAVEFORM_FREQ_KEY = 'waveform_freq' +WAVEFORM_OFFSET_KEY = 'waveform_offset' +WAVEFORM2_FREQ_KEY = 'waveform2_freq' +FREQ_RANGE_KEY = 'freq_range' +GAIN_RANGE_KEY = 'gain_range' +TYPE_KEY = 'type' + +def setter(ps, key, val): ps[key] = val + +from gnuradio import gr, eng_notation +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option -from gnuradio import eng_notation +from gnuradio import usrp_options from optparse import OptionParser import sys +import math +n2s = eng_notation.num_to_str -class my_top_block(gr.top_block): - def __init__ (self, nsamples): +waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", + gr.GR_CONST_WAVE : "Constant", + gr.GR_GAUSSIAN : "Gaussian Noise", + gr.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): gr.top_block.__init__(self) + pubsub.__init__(self) + self._verbose = options.verbose + #initialize values from options + self._setup_usrpx(options) + self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i)) + self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32)) + self[INTERP_KEY] = options.interp or 16 + 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 + self[BB_FREQ_KEY] = 0 + self[DDC_FREQ_KEY] = 0 + #subscribe set methods + self.subscribe(INTERP_KEY, self.set_interp) + self.subscribe(GAIN_KEY, self.set_gain) + self.subscribe(TX_FREQ_KEY, self.set_freq) + self.subscribe(AMPLITUDE_KEY, self.set_amplitude) + self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) + self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) + self.subscribe(TYPE_KEY, self.set_waveform) + #force update on pubsub keys + for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY, + 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 = usrp_options.create_usrp_sink(options) + self.publish(DESC_KEY, lambda: str(self._u)) + self.publish(DAC_RATE_KEY, self._u.dac_rate) + self.publish(FREQ_RANGE_KEY, self._u.freq_range) + self.publish(GAIN_RANGE_KEY, self._u.gain_range) + self.publish(GAIN_KEY, self._u.gain) + if self._verbose: print str(self._u) + + def _set_tx_amplitude(self, ampl): + """ + Sets the transmit amplitude sent to the USRP + @param ampl the amplitude or None for automatic + """ + 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_interp(self, interp): + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) + + if self._verbose: + print "USRP interpolation rate:", interp + print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),) + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "2tone": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "sweep": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + else: + return True # Waveform not yet set - # controllable values - self.interp = 64 - self.waveform_type = gr.GR_SIN_WAVE - self.waveform_ampl = 16000 - self.waveform_freq = 100.12345e3 - self.waveform_offset = 0 - self.nsamples = nsamples - self._instantiate_blocks () - self.set_waveform_type (self.waveform_type) - - def usb_freq (self): - return self.u.dac_freq() / self.interp - - def usb_throughput (self): - return self.usb_freq () * 4 - - def set_waveform_type (self, type): - ''' - valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, - gr.GR_UNIFORM and gr.GR_GAUSSIAN - ''' - self._configure_graph (type) - self.waveform_type = type - - def set_waveform_ampl (self, ampl): - self.waveform_ampl = ampl - self.siggen.set_amplitude (ampl) - self.noisegen.set_amplitude (ampl) - - def set_waveform_freq (self, freq): - self.waveform_freq = freq - self.siggen.set_frequency (freq) - - def set_waveform_offset (self, offset): - self.waveform_offset = offset - self.siggen.set_offset (offset) - - def set_interpolator (self, interp): - self.interp = interp - self.siggen.set_sampling_freq (self.usb_freq ()) - self.u.set_interp_rate (interp) - - def _instantiate_blocks (self): - self.src = None - self.u = usrp.sink_c (0, self.interp) - - self.siggen = gr.sig_source_c (self.usb_freq (), - gr.GR_SIN_WAVE, - self.waveform_freq, - self.waveform_ampl, - self.waveform_offset) - - self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, - self.waveform_ampl) - - self.head = None - if self.nsamples > 0: - self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples)) - - # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") - - def _configure_graph (self, type): - try: - self.lock() - self.disconnect_all () - - if self.head: - self.connect(self.head, self.u) - tail = self.head - else: - tail = self.u - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, tail) - # self.connect (self.siggen, self.file_sink) - self.siggen.set_waveform (type) - self.src = self.siggen - elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, tail) - self.noisegen.set_type (type) - self.src = self.noisegen - else: - raise ValueError, type - finally: - self.unlock() + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: + g = self[GAIN_RANGE_KEY] + gain = float(g[0]+g[1])/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): - """ - 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 up converter. - """ - r = self.u.tune(self.subdev.which(), self.subdev, target_freq) - if r: - #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) - #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) - #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) - #print "r.inverted =", r.inverted - return True - - return False - - - -def main (): - parser = OptionParser (option_class=eng_option) - parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0), - help="select USRP Tx side A or B") - parser.add_option ("-f", "--rf-freq", type="eng_float", default=None, - help="set RF center frequency to FREQ") - parser.add_option ("-i", "--interp", type="int", default=64, - help="set fgpa interpolation rate to INTERP [default=%default]") - - parser.add_option ("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) - parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") - parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") - parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") - - parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, - help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") - parser.add_option ("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") - parser.add_option ("-o", "--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") - parser.add_option ("-N", "--nsamples", type="eng_float", default=0, - help="set number of samples to transmit [default=+inf]") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - raise SystemExit - - if options.rf_freq is None: - sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n") - parser.print_help() - raise SystemExit - - tb = my_top_block(options.nsamples) - tb.set_interpolator (options.interp) - tb.set_waveform_type (options.type) - tb.set_waveform_freq (options.waveform_freq) - tb.set_waveform_ampl (options.amplitude) - tb.set_waveform_offset (options.offset) - - # determine the daughterboard subdevice we're using - if options.tx_subdev_spec is None: - options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u) - - m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec) - #print "mux = %#04x" % (m,) - tb.u.set_mux(m) - tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec) - print "Using TX d'board %s" % (tb.subdev.side_and_name(),) - - if options.gain is None: - tb.subdev.set_gain(tb.subdev.gain_range()[1]) # set max Tx gain - else: - tb.subdev.set_gain(options.gain) # set max Tx gain - - if not tb.set_freq(options.rf_freq): - sys.stderr.write('Failed to set RF frequency\n') - raise SystemExit + if target_freq is None: + f = self[FREQ_RANGE_KEY] + target_freq = float(f[0]+f[1])/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[DDC_FREQ_KEY] = tr.dxc_freq + self[BB_FREQ_KEY] = tr.baseband_freq + if self._verbose: + print "Set center frequency to", fs + print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) + print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) + print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) + elif self._verbose: print "Failed to set freq." + return tr + + def set_waveform_freq(self, freq): + if self[TYPE_KEY] == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self[TYPE_KEY] == "2tone": + self._src1.set_frequency(freq) + elif self[TYPE_KEY] == 'sweep': + #there is no set sensitivity, redo fg + self[TYPE_KEY] = self[TYPE_KEY] + return True + + def set_waveform2_freq(self, freq): + if freq is None: + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + return + if self[TYPE_KEY] == "2tone": + self._src2.set_frequency(freq) + elif self[TYPE_KEY] == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform(self, type): + self.lock() + self.disconnect_all() + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate + type, # Waveform type + self[WAVEFORM_FREQ_KEY], # Waveform frequency + self[AMPLITUDE_KEY], # Waveform amplitude + self[WAVEFORM_OFFSET_KEY]) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) + elif type == "2tone": + self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + if(self[WAVEFORM2_FREQ_KEY] is None): + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + + self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM2_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + self._src = gr.add_cc() + self.connect(self._src1,(self._src,0)) + self.connect(self._src2,(self._src,1)) + elif type == "sweep": + # rf freq is center frequency + # waveform_freq is total swept width + # waveform2_freq is sweep rate + # 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 = gr.sig_source_f(self[SAMP_RATE_KEY], + gr.GR_TRI_WAVE, + self[WAVEFORM2_FREQ_KEY], + 1.0, + -0.5) + self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) + self.connect(self._src1,self._src2,self._src) + else: + raise RuntimeError("Unknown waveform type") + + self.connect(self._src, self._u) + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[type] + if type == gr.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] + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self[TYPE_KEY] == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self[TYPE_KEY] == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + +def get_options(): + usage="%prog: [options]" + + parser = OptionParser(option_class=eng_option, usage=usage) + usrp_options.add_tx_options(parser) + 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=gr.GR_SIN_WAVE, + help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) + parser.add_option("--const", dest="type", action="store_const", const=gr.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=gr.GR_GAUSSIAN, + help="Generate Gaussian random output") + parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="Generate Uniform random output") + parser.add_option("--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", + help="Generate a swept sine wave") + parser.add_option("-A", "--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]") + + (options, args) = parser.parse_args() + + return (options, args) + +# If this script is executed, the following runs. If it is imported, the below does not run. +if __name__ == "__main__": + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Note: failed to enable realtime scheduling, continuing" - tb.subdev.set_enable(True) # enable transmitter + # Grab command line options and create top block + try: + (options, args) = get_options() + tb = top_block(options, args) + except RuntimeError, e: + print e + sys.exit(1) + + # Run it try: tb.run() + except KeyboardInterrupt: pass - - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py new file mode 100755 index 00000000..5ac2369f --- /dev/null +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from gnuradio import gr +from gnuradio.gr.pubsub import pubsub +from gnuradio.wxgui import gui, forms +import usrp_siggen +import sys, math + +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() + + # Event response handlers + def evt_set_status_msg(self, msg): + self.frame.SetStatusText(msg, 0) + + # GUI construction + def build_gui(self): + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + ################################################## + # Baseband 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 == gr.GR_SIN_WAVE) + sweep_bb_hbox.ShowItems(type == 'sweep') + tone_bb_hbox.ShowItems(type == '2tone') + self.vbox.Layout() + self.tb.subscribe(usrp_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=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + 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=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Rate (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + 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=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 2 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.radio_buttons( + parent=self.panel, sizer=bb_vbox, + choices=usrp_siggen.waveforms.keys(), + labels=usrp_siggen.waveforms.values(), + ps=self.tb, + key=usrp_siggen.TYPE_KEY, + style=wx.NO_BORDER | wx.RA_HORIZONTAL, + ) + 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[usrp_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=usrp_siggen.TX_FREQ_KEY, + ) + freq_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=freq_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1], + num_steps=100, + ) + freq_hbox.AddSpacer(5) + tr_hbox.AddSpacer(5) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='Daughterboard (Hz)', + ps=self.tb, + key=usrp_siggen.BB_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='USRP DDC (Hz)', + ps=self.tb, + key=usrp_siggen.DDC_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + 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=usrp_siggen.AMPLITUDE_KEY, + label="Level (0.0-1.0)", + ) + lvl_hbox.AddSpacer(10) + forms.log_slider( + parent=self.panel, sizer=lvl_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + min_exp=-5, + max_exp=0, + base=10, + step_size=1, + ) + lvl_hbox.AddSpacer(5) + if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: + gain_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=gain_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_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=usrp_siggen.GAIN_KEY, + minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1], + step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2], + ) + gain_hbox.AddSpacer(5) + ################################################## + # Sample Rate controls + ################################################## + 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.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=sam_hbox, + converter=forms.int_converter(), + ps=self.tb, + key=usrp_siggen.INTERP_KEY, + label="Interpolation", + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Sample Rate (sps)', + ps=self.tb, + key=usrp_siggen.SAMP_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Link Rate (bits/sec)', + ps=self.tb, + key=usrp_siggen.LINK_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddSpacer(5) + ################################################## + # USRP status + ################################################## + u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", 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=usrp_siggen.DESC_KEY, + converter=forms.str_converter(), + ) + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + +if __name__ == "__main__": + try: + # Get command line parameters + (options, args) = usrp_siggen.get_options() + + # Create the top block using these + tb = usrp_siggen.top_block(options, args) + + # 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="USRP Signal Generator", # Top window title + nstatus=1, # Number of status lines + start=True, # Whether to start flowgraph + realtime=True) # Whether to set realtime priority + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) -- 2.30.2