forked from sdr/gr-osmosdr
usage examples: osmocom_fft -a "rtl=0" -f 100e6 -s 2.4e6 -g 15 osmocom_siggen_gui -a "hackrf=0" -s 5e6 -f 100e6 --sine osmocom_siggen_gui -a "hackrf=0" -s 5e6 -f 100e6 --sweep -x 2M -y 1 -c34 known issues: - switching between siggen modes is broken at the moment (WIP) and has to be made via cli switches only. - filter bandwidth controls have no effect for TX (this has to be investigated)gr3.6
parent
a5bdb27240
commit
a31ea525fb
@ -0,0 +1,270 @@ |
||||
#!/usr/bin/env python |
||||
# |
||||
# Copyright 2012 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 osmosdr |
||||
from gnuradio import gr, gru |
||||
from gnuradio import eng_notation |
||||
from gnuradio.eng_option import eng_option |
||||
from optparse import OptionParser |
||||
|
||||
import sys |
||||
import numpy |
||||
|
||||
try: |
||||
from gnuradio.wxgui import stdgui2, form, slider |
||||
from gnuradio.wxgui import forms |
||||
from gnuradio.wxgui import fftsink2, waterfallsink2, scopesink2 |
||||
import wx |
||||
except ImportError: |
||||
sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n") |
||||
sys.exit(1) |
||||
|
||||
class app_top_block(stdgui2.std_top_block): |
||||
def __init__(self, frame, panel, vbox, argv): |
||||
stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) |
||||
|
||||
self.frame = frame |
||||
self.panel = panel |
||||
|
||||
parser = OptionParser(option_class=eng_option) |
||||
parser.add_option("-a", "--args", type="string", default="", |
||||
help="device args, [default=%default]") |
||||
parser.add_option("-A", "--antenna", type="string", default=None, |
||||
help="select Rx Antenna where appropriate") |
||||
parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6, |
||||
help="set sample rate (bandwidth) [default=%default]") |
||||
parser.add_option("-f", "--freq", type="eng_float", default=None, |
||||
help="set frequency to FREQ", metavar="FREQ") |
||||
parser.add_option("-g", "--gain", type="eng_float", default=None, |
||||
help="set gain in dB (default is midpoint)") |
||||
parser.add_option("-W", "--waterfall", action="store_true", default=False, |
||||
help="Enable waterfall display") |
||||
parser.add_option("-S", "--oscilloscope", action="store_true", default=False, |
||||
help="Enable oscilloscope display") |
||||
parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, |
||||
help="Set fftsink averaging factor, default=[%default]") |
||||
parser.add_option ("", "--averaging", action="store_true", default=False, |
||||
help="Enable fftsink averaging, default=[%default]") |
||||
parser.add_option("", "--ref-scale", type="eng_float", default=1.0, |
||||
help="Set dBFS=0dB input value, default=[%default]") |
||||
parser.add_option("", "--fft-size", type="int", default=1024, |
||||
help="Set number of FFT bins [default=%default]") |
||||
parser.add_option("", "--fft-rate", type="int", default=30, |
||||
help="Set FFT update rate, [default=%default]") |
||||
|
||||
(options, args) = parser.parse_args() |
||||
if len(args) != 0: |
||||
parser.print_help() |
||||
sys.exit(1) |
||||
self.options = options |
||||
self.show_debug_info = True |
||||
|
||||
self.src = osmosdr.source_c(options.args) |
||||
|
||||
# Set the antenna |
||||
if(options.antenna): |
||||
self.src.set_antenna(options.antenna, 0) |
||||
|
||||
self.src.set_sample_rate(options.samp_rate) |
||||
input_rate = self.src.get_sample_rate() |
||||
|
||||
if options.waterfall: |
||||
self.scope = \ |
||||
waterfallsink2.waterfall_sink_c (panel, fft_size=1024, |
||||
sample_rate=input_rate) |
||||
self.frame.SetMinSize((800, 420)) |
||||
elif options.oscilloscope: |
||||
self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) |
||||
self.frame.SetMinSize((800, 600)) |
||||
else: |
||||
self.scope = fftsink2.fft_sink_c (panel, |
||||
fft_size=options.fft_size, |
||||
sample_rate=input_rate, |
||||
ref_scale=options.ref_scale, |
||||
ref_level=20.0, |
||||
y_divs = 12, |
||||
average=options.averaging, |
||||
avg_alpha=options.avg_alpha, |
||||
fft_rate=options.fft_rate) |
||||
def fftsink_callback(x, y): |
||||
self.set_freq(x) |
||||
|
||||
self.scope.set_callback(fftsink_callback) |
||||
self.frame.SetMinSize((800, 420)) |
||||
|
||||
self.connect(self.src, self.scope) |
||||
|
||||
self._build_gui(vbox) |
||||
self._setup_events() |
||||
|
||||
|
||||
# set initial values |
||||
|
||||
if options.gain is None: |
||||
# if no gain was specified, use the mid-point in dB |
||||
g = self.src.get_gain_range() |
||||
options.gain = float(g.start()+g.stop())/2 |
||||
|
||||
if options.freq is None: |
||||
# if no freq was specified, use the mid-point |
||||
r = self.src.get_freq_range() |
||||
options.freq = float(r.start()+r.stop())/2 |
||||
|
||||
self.set_gain(options.gain) |
||||
|
||||
if self.show_debug_info: |
||||
self.myform['samprate'].set_value(self.src.get_sample_rate()) |
||||
|
||||
if not(self.set_freq(options.freq)): |
||||
self._set_status_msg("Failed to set initial frequency") |
||||
|
||||
def _set_status_msg(self, msg): |
||||
self.frame.GetStatusBar().SetStatusText(msg, 0) |
||||
|
||||
def _build_gui(self, vbox): |
||||
|
||||
def _form_set_freq(kv): |
||||
return self.set_freq(kv['freq']) |
||||
|
||||
vbox.Add(self.scope.win, 10, wx.EXPAND) |
||||
|
||||
# add control area at the bottom |
||||
self.myform = myform = form.form() |
||||
hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
hbox.Add((4,0), 0, 0) |
||||
myform['freq'] = form.float_field( |
||||
parent=self.panel, sizer=hbox, label="Center freq", weight=1, |
||||
callback=myform.check_input_and_call(_form_set_freq, |
||||
self._set_status_msg)) |
||||
|
||||
hbox.Add((4,0), 0, 0) |
||||
g = self.src.get_gain_range() |
||||
|
||||
# some configurations don't have gain control |
||||
if g.stop() <= g.start(): |
||||
glow = 0.0 |
||||
ghigh = 1.0 |
||||
|
||||
else: |
||||
glow = g.start() |
||||
ghigh = g.stop() |
||||
|
||||
myform['gain'] = form.slider_field(parent=self.panel, |
||||
sizer=hbox, label="Gain", |
||||
weight=3, |
||||
min=int(glow), max=int(ghigh), |
||||
callback=self.set_gain) |
||||
hbox.Add((4,0), 0, 0) |
||||
vbox.Add(hbox, 0, wx.EXPAND) |
||||
|
||||
self._build_subpanel(vbox) |
||||
|
||||
def _build_subpanel(self, vbox_arg): |
||||
# build a secondary information panel (sometimes hidden) |
||||
|
||||
# FIXME figure out how to have this be a subpanel that is always |
||||
# created, but has its visibility controlled by foo.Show(True/False) |
||||
|
||||
def _form_set_sample_rate(kv): |
||||
return self.set_sample_rate(kv['samprate']) |
||||
|
||||
if not(self.show_debug_info): |
||||
return |
||||
|
||||
panel = self.panel |
||||
vbox = vbox_arg |
||||
myform = self.myform |
||||
|
||||
hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
|
||||
hbox.Add((4,0), 0) |
||||
myform['samprate'] = form.float_field( |
||||
parent=panel, sizer=hbox, label="Sample Rate", |
||||
callback=myform.check_input_and_call(_form_set_sample_rate, |
||||
self._set_status_msg)) |
||||
vbox.AddSpacer(5) |
||||
|
||||
vbox.Add(hbox, 0, wx.EXPAND) |
||||
vbox.AddSpacer(5) |
||||
|
||||
def set_freq(self, target_freq): |
||||
""" |
||||
Set the center frequency we're interested in. |
||||
|
||||
@param target_freq: frequency in Hz |
||||
@rypte: bool |
||||
""" |
||||
actual_freq = self.src.set_center_freq(target_freq, 0) |
||||
self.myform['freq'].set_value(actual_freq) |
||||
|
||||
if not self.options.oscilloscope: |
||||
self.scope.set_baseband_freq(actual_freq) |
||||
|
||||
return True |
||||
|
||||
def set_gain(self, gain): |
||||
if self.myform.has_key('gain'): |
||||
self.myform['gain'].set_value(gain) # update displayed value |
||||
self.src.set_gain(gain, 0) |
||||
|
||||
def set_sample_rate(self, samp_rate): |
||||
ok = self.src.set_sample_rate(samp_rate) |
||||
input_rate = self.src.get_sample_rate() |
||||
self.scope.set_sample_rate(input_rate) |
||||
if self.show_debug_info: # update displayed values |
||||
self.myform['samprate'].set_value(self.src.get_sample_rate()) |
||||
|
||||
# set_sample_rate never fails; always falls back to closest requested. |
||||
return True |
||||
|
||||
def _setup_events(self): |
||||
if not self.options.waterfall and not self.options.oscilloscope: |
||||
self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) |
||||
|
||||
def evt_left_dclick(self, event): |
||||
(ux, uy) = self.scope.win.GetXY(event) |
||||
if event.CmdDown(): |
||||
# Re-center on maximum power |
||||
points = self.scope.win._points |
||||
if self.scope.win.peak_hold: |
||||
if self.scope.win.peak_vals is not None: |
||||
ind = numpy.argmax(self.scope.win.peak_vals) |
||||
else: |
||||
ind = int(points.shape()[0]/2) |
||||
else: |
||||
ind = numpy.argmax(points[:,1]) |
||||
|
||||
(freq, pwr) = points[ind] |
||||
target_freq = freq/self.scope.win._scale_factor |
||||
print ind, freq, pwr |
||||
self.set_freq(target_freq) |
||||
else: |
||||
# Re-center on clicked frequency |
||||
target_freq = ux/self.scope.win._scale_factor |
||||
self.set_freq(target_freq) |
||||
|
||||
def main (): |
||||
app = stdgui2.stdapp(app_top_block, "OSMOCOM Spectrum Browser", nstatus=1) |
||||
app.MainLoop() |
||||
|
||||
if __name__ == '__main__': |
||||
main () |
@ -0,0 +1,51 @@ |
||||
#!/usr/bin/env python |
||||
# |
||||
# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc. |
||||
# |
||||
# This file is part of GNU Radio |
||||
# |
||||
# GNU Radio is free software; you can redistribute it and/or modify |
||||
# it under the terms of the GNU General Public License as published by |
||||
# the Free Software Foundation; either version 3, or (at your option) |
||||
# any later version. |
||||
# |
||||
# GNU Radio is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with GNU Radio; see the file COPYING. If not, write to |
||||
# the Free Software Foundation, Inc., 51 Franklin Street, |
||||
# Boston, MA 02110-1301, USA. |
||||
# |
||||
|
||||
from gnuradio import gr |
||||
from osmosdr import osmocom_siggen_base as osmocom_siggen |
||||
import sys |
||||
|
||||
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) = osmocom_siggen.get_options() |
||||
tb = osmocom_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() |
@ -0,0 +1,397 @@ |
||||
#!/usr/bin/env python |
||||
# |
||||
# Copyright 2008,2009,2011,2012 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. |
||||
# |
||||
|
||||
SAMP_RATE_KEY = 'samp_rate' |
||||
LINK_RATE_KEY = 'link_rate' |
||||
GAIN_KEY = 'gain' |
||||
IF_GAIN_KEY = 'if_gain' |
||||
BWIDTH_KEY = 'bwidth' |
||||
TX_FREQ_KEY = 'tx_freq' |
||||
FREQ_CORR_KEY = 'freq_corr' |
||||
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' |
||||
IF_GAIN_RANGE_KEY = 'if_gain_range' |
||||
BWIDTH_RANGE_KEY = 'bwidth_range' |
||||
TYPE_KEY = 'type' |
||||
|
||||
def setter(ps, key, val): ps[key] = val |
||||
|
||||
import osmosdr |
||||
from gnuradio import gr, gru, eng_notation |
||||
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 = { 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_osmosdr(options) |
||||
self[SAMP_RATE_KEY] = options.samp_rate |
||||
self[TX_FREQ_KEY] = options.tx_freq |
||||
self[FREQ_CORR_KEY] = options.freq_corr |
||||
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 |
||||
|
||||
#subscribe set methods |
||||
self.subscribe(SAMP_RATE_KEY, self.set_samp_rate) |
||||
self.subscribe(GAIN_KEY, self.set_gain) |
||||
self.subscribe(IF_GAIN_KEY, self.set_if_gain) |
||||
self.subscribe(BWIDTH_KEY, self.set_bandwidth) |
||||
self.subscribe(TX_FREQ_KEY, self.set_freq) |
||||
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr) |
||||
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 (SAMP_RATE_KEY, GAIN_KEY, IF_GAIN_KEY, BWIDTH_KEY, |
||||
TX_FREQ_KEY, FREQ_CORR_KEY, AMPLITUDE_KEY, |
||||
WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): |
||||
# print "key: ", key, "=", self[key] |
||||
self[key] = self[key] |
||||
self[TYPE_KEY] = options.type #set type last |
||||
|
||||
def _setup_osmosdr(self, options): |
||||
self._sink = osmosdr.sink_c(options.args) |
||||
self._sink.set_sample_rate(options.samp_rate) |
||||
|
||||
# Set the gain from options |
||||
if(options.gain): |
||||
self._sink.set_gain(options.gain) |
||||
|
||||
# Set the antenna |
||||
if(options.antenna): |
||||
self._sink.set_antenna(options.antenna, 0) |
||||
|
||||
self.publish(FREQ_RANGE_KEY, self._sink.get_freq_range) |
||||
self.publish(GAIN_RANGE_KEY, self._get_rf_gain_range) |
||||
self.publish(IF_GAIN_RANGE_KEY, self._get_if_gain_range) |
||||
self.publish(BWIDTH_RANGE_KEY, self._sink.get_bandwidth_range) |
||||
self.publish(GAIN_KEY, self._get_rf_gain) |
||||
self.publish(IF_GAIN_KEY, self._get_if_gain) |
||||
self.publish(BWIDTH_KEY, self._sink.get_bandwidth) |
||||
|
||||
def _get_rf_gain_range(self): |
||||
return self._sink.get_gain_range("RF") |
||||
|
||||
def _get_if_gain_range(self): |
||||
return self._sink.get_gain_range("IF") |
||||
|
||||
def _get_rf_gain(self): |
||||
return self._sink.get_gain("RF") |
||||
|
||||
def _get_if_gain(self): |
||||
return self._sink.get_gain("IF") |
||||
|
||||
def _set_tx_amplitude(self, ampl): |
||||
""" |
||||
Sets the transmit amplitude |
||||
@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.3 + ampl_range[0] |
||||
self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) |
||||
|
||||
def set_samp_rate(self, sr): |
||||
self._sink.set_sample_rate(sr) |
||||
sr = self._sink.get_sample_rate() |
||||
|
||||
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 |
||||
|
||||
if self._verbose: |
||||
print "Set sample rate to:", sr |
||||
|
||||
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 RF gain" |
||||
self[GAIN_KEY] = gain |
||||
return |
||||
gain = self._sink.set_gain(gain, "RF") |
||||
if self._verbose: |
||||
print "Set RF gain to:", gain |
||||
|
||||
def set_if_gain(self, gain): |
||||
if gain is None: |
||||
g = self[IF_GAIN_RANGE_KEY] |
||||
gain = float(g.start()+g.stop())/2 |
||||
if self._verbose: |
||||
print "Using auto-calculated mid-point IF gain" |
||||
self[IF_GAIN_KEY] = gain |
||||
return |
||||
gain = self._sink.set_gain(gain, "IF") |
||||
if self._verbose: |
||||
print "Set IF gain to:", gain |
||||
|
||||
def set_bandwidth(self, bw): |
||||
bw = self._sink.set_bandwidth(bw) |
||||
if self._verbose: |
||||
print "Set bandwidth to:", bw |
||||
|
||||
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._sink.set_center_freq(target_freq) |
||||
if tr is not None: |
||||
self._freq = tr |
||||
if self._verbose: |
||||
print "Set center frequency to", tr |
||||
elif self._verbose: |
||||
print "Failed to set freq." |
||||
return tr |
||||
|
||||
def set_freq_corr(self, ppm): |
||||
if ppm is None: |
||||
if self._verbose: |
||||
print "Setting freq corrrection to 0" |
||||
self[FREQ_CORR_KEY] = 0 |
||||
return |
||||
|
||||
ppm = self._sink.set_freq_corr(ppm) |
||||
if self._verbose: |
||||
print "Set freq correction to:", ppm |
||||
|
||||
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._sink) |
||||
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) |
||||
parser.add_option("-a", "--args", type="string", default="", |
||||
help="Device args, [default=%default]") |
||||
parser.add_option("-A", "--antenna", type="string", default=None, |
||||
help="Select Rx Antenna where appropriate") |
||||
parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6, |
||||
help="Set sample rate (bandwidth) [default=%default]") |
||||
parser.add_option("-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("-c", "--freq-corr", type="int", default=None, |
||||
help="Set carrier frequency correction [default=0]") |
||||
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("", "--amplitude", type="eng_float", default=0.3, |
||||
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. |
||||
def test_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) |
||||
|
||||
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 radio 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() |
@ -0,0 +1,374 @@ |
||||
#!/usr/bin/env python |
||||
# |
||||
# Copyright 2009,2011,2012 Free Software Foundation, Inc. |
||||
# |
||||
# This file is part of GNU Radio |
||||
# |
||||
# GNU Radio is free software; you can redistribute it and/or modify |
||||
# it under the terms of the GNU General Public License as published by |
||||
# the Free Software Foundation; either version 3, or (at your option) |
||||
# any later version. |
||||
# |
||||
# GNU Radio is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with GNU Radio; see the file COPYING. If not, write to |
||||
# the Free Software Foundation, Inc., 51 Franklin Street, |
||||
# Boston, MA 02110-1301, USA. |
||||
# |
||||
|
||||
from gnuradio import gr |
||||
from gnuradio.gr.pubsub import pubsub |
||||
from osmosdr import osmocom_siggen_base as osmocom_siggen |
||||
import sys, math |
||||
|
||||
try: |
||||
from gnuradio.wxgui import gui, forms |
||||
import wx |
||||
except ImportError: |
||||
sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n") |
||||
sys.exit(1) |
||||
|
||||
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(3) |
||||
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(5) |
||||
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(osmocom_siggen.TYPE_KEY, set_type) |
||||
#create sine forms |
||||
sine_bb_hbox.AddSpacer(5) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=sine_bb_hbox, |
||||
label='Frequency (Hz)', |
||||
ps=self.tb, |
||||
key=osmocom_siggen.WAVEFORM_FREQ_KEY, |
||||
converter=forms.float_converter(), |
||||
) |
||||
sine_bb_hbox.AddStretchSpacer() |
||||
#create sweep forms |
||||
sweep_bb_hbox.AddSpacer(5) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=sweep_bb_hbox, |
||||
label='Sweep Width (Hz)', |
||||
ps=self.tb, |
||||
key=osmocom_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=osmocom_siggen.WAVEFORM2_FREQ_KEY, |
||||
converter=forms.float_converter(), |
||||
) |
||||
sweep_bb_hbox.AddStretchSpacer() |
||||
#create 2tone forms |
||||
tone_bb_hbox.AddSpacer(5) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=tone_bb_hbox, |
||||
label='Tone 1 (Hz)', |
||||
ps=self.tb, |
||||
key=osmocom_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=osmocom_siggen.WAVEFORM2_FREQ_KEY, |
||||
converter=forms.float_converter(), |
||||
) |
||||
tone_bb_hbox.AddStretchSpacer() |
||||
forms.radio_buttons( |
||||
parent=self.panel, sizer=bb_vbox, |
||||
choices=osmocom_siggen.waveforms.keys(), |
||||
labels=osmocom_siggen.waveforms.values(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.TYPE_KEY, |
||||
style=wx.NO_BORDER | wx.RA_HORIZONTAL, |
||||
) |
||||
bb_vbox.AddSpacer(5) |
||||
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[osmocom_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(3) |
||||
# First row of frequency controls (center frequency) |
||||
freq_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
fc_vbox.Add(freq_hbox, 0, wx.EXPAND) |
||||
fc_vbox.AddSpacer(5) |
||||
# Second row of frequency controls (freq. correction) |
||||
corr_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
fc_vbox.Add(corr_hbox, 0, wx.EXPAND) |
||||
fc_vbox.AddSpacer(3) |
||||
# Add frequency controls to top window sizer |
||||
self.vbox.Add(fc_vbox, 0, wx.EXPAND) |
||||
self.vbox.AddSpacer(5) |
||||
self.vbox.AddStretchSpacer() |
||||
|
||||
freq_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=freq_hbox, |
||||
label='Center Frequency (Hz)', |
||||
proportion=1, |
||||
converter=forms.float_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.TX_FREQ_KEY, |
||||
) |
||||
freq_hbox.AddSpacer(5) |
||||
|
||||
forms.slider( |
||||
parent=self.panel, sizer=freq_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.TX_FREQ_KEY, |
||||
minimum=self.tb[osmocom_siggen.FREQ_RANGE_KEY].start(), |
||||
maximum=self.tb[osmocom_siggen.FREQ_RANGE_KEY].stop(), |
||||
num_steps=100, |
||||
) |
||||
freq_hbox.AddSpacer(3) |
||||
|
||||
corr_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=corr_hbox, |
||||
label='Frequency Correction (ppm)', |
||||
proportion=1, |
||||
converter=forms.int_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.FREQ_CORR_KEY, |
||||
) |
||||
corr_hbox.AddSpacer(5) |
||||
|
||||
forms.slider( |
||||
parent=self.panel, sizer=corr_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.FREQ_CORR_KEY, |
||||
minimum=-100, |
||||
maximum=+100, |
||||
num_steps=201, |
||||
) |
||||
corr_hbox.AddSpacer(3) |
||||
|
||||
################################################## |
||||
# Amplitude controls |
||||
################################################## |
||||
amp_vbox = forms.static_box_sizer(parent=self.panel, |
||||
label="Amplitude", |
||||
orient=wx.VERTICAL, |
||||
bold=True) |
||||
amp_vbox.AddSpacer(3) |
||||
# First row of amp controls (ampl) |
||||
lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
amp_vbox.Add(lvl_hbox, 0, wx.EXPAND) |
||||
amp_vbox.AddSpacer(5) |
||||
# Second row of amp controls (tx gain) |
||||
gain_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
amp_vbox.Add(gain_hbox, 0, wx.EXPAND) |
||||
amp_vbox.AddSpacer(3) |
||||
if_gain_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
amp_vbox.Add(if_gain_hbox, 0, wx.EXPAND) |
||||
amp_vbox.AddSpacer(3) |
||||
|
||||
self.vbox.Add(amp_vbox, 0, wx.EXPAND) |
||||
self.vbox.AddSpacer(5) |
||||
self.vbox.AddStretchSpacer() |
||||
|
||||
lvl_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=lvl_hbox, |
||||
proportion=1, |
||||
converter=forms.float_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.AMPLITUDE_KEY, |
||||
label="Level (0.0-1.0)", |
||||
) |
||||
lvl_hbox.AddSpacer(5) |
||||
forms.log_slider( |
||||
parent=self.panel, sizer=lvl_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.AMPLITUDE_KEY, |
||||
min_exp=-6, |
||||
max_exp=0, |
||||
base=10, |
||||
num_steps=100, |
||||
) |
||||
lvl_hbox.AddSpacer(3) |
||||
|
||||
if self.tb[osmocom_siggen.GAIN_RANGE_KEY].start() < self.tb[osmocom_siggen.GAIN_RANGE_KEY].stop(): |
||||
gain_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=gain_hbox, |
||||
proportion=1, |
||||
converter=forms.float_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.GAIN_KEY, |
||||
label="RF Gain (dB)", |
||||
) |
||||
gain_hbox.AddSpacer(5) |
||||
forms.slider( |
||||
parent=self.panel, sizer=gain_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.GAIN_KEY, |
||||
minimum=self.tb[osmocom_siggen.GAIN_RANGE_KEY].start(), |
||||
maximum=self.tb[osmocom_siggen.GAIN_RANGE_KEY].stop(), |
||||
step_size=self.tb[osmocom_siggen.GAIN_RANGE_KEY].step(), |
||||
) |
||||
gain_hbox.AddSpacer(3) |
||||
|
||||
if self.tb[osmocom_siggen.IF_GAIN_RANGE_KEY].start() < self.tb[osmocom_siggen.IF_GAIN_RANGE_KEY].stop(): |
||||
if_gain_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=if_gain_hbox, |
||||
proportion=1, |
||||
converter=forms.float_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.IF_GAIN_KEY, |
||||
label="IF Gain (dB)", |
||||
) |
||||
if_gain_hbox.AddSpacer(5) |
||||
forms.slider( |
||||
parent=self.panel, sizer=if_gain_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.IF_GAIN_KEY, |
||||
minimum=self.tb[osmocom_siggen.IF_GAIN_RANGE_KEY].start(), |
||||
maximum=self.tb[osmocom_siggen.IF_GAIN_RANGE_KEY].stop(), |
||||
step_size=self.tb[osmocom_siggen.IF_GAIN_RANGE_KEY].step(), |
||||
) |
||||
if_gain_hbox.AddSpacer(3) |
||||
|
||||
################################################## |
||||
# Bandiwdth controls |
||||
################################################## |
||||
bwidth_vbox = forms.static_box_sizer(parent=self.panel, |
||||
label="Bandwidth", |
||||
orient=wx.VERTICAL, |
||||
bold=True) |
||||
bwidth_vbox.AddSpacer(3) |
||||
bwidth_hbox = wx.BoxSizer(wx.HORIZONTAL) |
||||
bwidth_vbox.Add(bwidth_hbox, 0, wx.EXPAND) |
||||
bwidth_vbox.AddSpacer(3) |
||||
|
||||
self.vbox.Add(bwidth_vbox, 0, wx.EXPAND) |
||||
self.vbox.AddSpacer(5) |
||||
self.vbox.AddStretchSpacer() |
||||
|
||||
if self.tb[osmocom_siggen.BWIDTH_RANGE_KEY].start() < self.tb[osmocom_siggen.BWIDTH_RANGE_KEY].stop(): |
||||
bwidth_hbox.AddSpacer(3) |
||||
forms.text_box( |
||||
parent=self.panel, sizer=bwidth_hbox, |
||||
proportion=1, |
||||
converter=forms.float_converter(), |
||||
ps=self.tb, |
||||
key=osmocom_siggen.BWIDTH_KEY, |
||||
label="Bandwidth (Hz)", |
||||
) |
||||
bwidth_hbox.AddSpacer(5) |
||||
forms.slider( |
||||
parent=self.panel, sizer=bwidth_hbox, |
||||
proportion=2, |
||||
ps=self.tb, |
||||
key=osmocom_siggen.BWIDTH_KEY, |
||||
minimum=self.tb[osmocom_siggen.BWIDTH_RANGE_KEY].start(), |
||||
maximum=self.tb[osmocom_siggen.BWIDTH_RANGE_KEY].stop(), |
||||
step_size=self.tb[osmocom_siggen.BWIDTH_RANGE_KEY].step(), |
||||
) |
||||
bwidth_hbox.AddSpacer(3) |
||||
|
||||
################################################## |
||||
# 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(5) |
||||
self.vbox.AddStretchSpacer() |
||||
sam_hbox.AddStretchSpacer(20) |
||||
forms.static_text( |
||||
parent=self.panel, sizer=sam_hbox, |
||||
label='Sample Rate (sps)', |
||||
ps=self.tb, |
||||
key=osmocom_siggen.SAMP_RATE_KEY, |
||||
converter=forms.float_converter(), |
||||
) |
||||
sam_hbox.AddStretchSpacer(20) |
||||
|
||||
def main(): |
||||
try: |
||||
# Get command line parameters |
||||
(options, args) = osmocom_siggen.get_options() |
||||
|
||||
# Create the top block using these |
||||
tb = osmocom_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="OSMOCOM 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) |
||||
|
||||
# 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 radio 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() |
Loading…
Reference in new issue