apps: add named gain controls to fft and siggen apps
usage examples: osmocom_fft -a hackrf -v osmocom_fft -a rtl=0 -v osmocom_fft -a uhd -v osmocom_siggen -a hackrf -f 100e6 --sweep -x 2e6 -y 10 -v osmocom_siggen -a uhd,subdev=A:0 -f 100e6 --sweep -x 2e6 -y 10 -s 4e6 -v
This commit is contained in:
parent
7c22e6975c
commit
3393647bec
|
@ -29,6 +29,6 @@ GR_PYTHON_INSTALL(
|
||||||
PROGRAMS
|
PROGRAMS
|
||||||
osmocom_fft
|
osmocom_fft
|
||||||
osmocom_siggen
|
osmocom_siggen
|
||||||
osmocom_siggen_gui
|
osmocom_siggen_nogui
|
||||||
DESTINATION ${GR_RUNTIME_DIR}
|
DESTINATION ${GR_RUNTIME_DIR}
|
||||||
)
|
)
|
||||||
|
|
442
apps/osmocom_fft
442
apps/osmocom_fft
|
@ -20,9 +20,20 @@
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
SAMP_RANGE_KEY = 'samp_range'
|
||||||
|
SAMP_RATE_KEY = 'samp_rate'
|
||||||
|
GAIN_KEY = lambda x: 'gain:'+x
|
||||||
|
BWIDTH_KEY = 'bwidth'
|
||||||
|
CENTER_FREQ_KEY = 'center_freq'
|
||||||
|
FREQ_CORR_KEY = 'freq_corr'
|
||||||
|
FREQ_RANGE_KEY = 'freq_range'
|
||||||
|
GAIN_RANGE_KEY = lambda x: 'gain_range:'+x
|
||||||
|
BWIDTH_RANGE_KEY = 'bwidth_range'
|
||||||
|
|
||||||
import osmosdr
|
import osmosdr
|
||||||
from gnuradio import gr, gru
|
from gnuradio import gr, gru
|
||||||
from gnuradio import eng_notation
|
from gnuradio import eng_notation
|
||||||
|
from gnuradio.gr.pubsub import pubsub
|
||||||
from gnuradio.eng_option import eng_option
|
from gnuradio.eng_option import eng_option
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
@ -38,24 +49,27 @@ except ImportError:
|
||||||
sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n")
|
sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
class app_top_block(stdgui2.std_top_block):
|
class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
def __init__(self, frame, panel, vbox, argv):
|
def __init__(self, frame, panel, vbox, argv):
|
||||||
stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
|
stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
|
||||||
|
pubsub.__init__(self)
|
||||||
|
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
self.panel = panel
|
self.panel = panel
|
||||||
|
|
||||||
parser = OptionParser(option_class=eng_option)
|
parser = OptionParser(option_class=eng_option)
|
||||||
parser.add_option("-a", "--args", type="string", default="",
|
parser.add_option("-a", "--args", type="string", default="",
|
||||||
help="device args, [default=%default]")
|
help="Device args, [default=%default]")
|
||||||
parser.add_option("-A", "--antenna", type="string", default=None,
|
parser.add_option("-A", "--antenna", type="string", default=None,
|
||||||
help="select Rx Antenna where appropriate")
|
help="Select RX antenna where appropriate")
|
||||||
parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
|
parser.add_option("-s", "--samp-rate", type="eng_float", default=None,
|
||||||
help="set sample rate (bandwidth) [default=%default]")
|
help="Set sample rate (bandwidth), minimum by default")
|
||||||
parser.add_option("-f", "--freq", type="eng_float", default=None,
|
parser.add_option("-f", "--center-freq", type="eng_float", default=None,
|
||||||
help="set frequency to FREQ", metavar="FREQ")
|
help="Set frequency to FREQ", metavar="FREQ")
|
||||||
|
parser.add_option("-c", "--freq-corr", type="eng_float", default=0,
|
||||||
|
help="Set frequency correction (ppm)")
|
||||||
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
||||||
help="set gain in dB (default is midpoint)")
|
help="Set gain in dB (default is midpoint)")
|
||||||
parser.add_option("-W", "--waterfall", action="store_true", default=False,
|
parser.add_option("-W", "--waterfall", action="store_true", default=False,
|
||||||
help="Enable waterfall display")
|
help="Enable waterfall display")
|
||||||
parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
|
parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
|
||||||
|
@ -70,30 +84,83 @@ class app_top_block(stdgui2.std_top_block):
|
||||||
help="Set number of FFT bins [default=%default]")
|
help="Set number of FFT bins [default=%default]")
|
||||||
parser.add_option("", "--fft-rate", type="int", default=30,
|
parser.add_option("", "--fft-rate", type="int", default=30,
|
||||||
help="Set FFT update rate, [default=%default]")
|
help="Set FFT update rate, [default=%default]")
|
||||||
|
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
||||||
|
help="Use verbose console output [default=%default]")
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
if len(args) != 0:
|
if len(args) != 0:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self.options = options
|
self.options = options
|
||||||
self.show_debug_info = True
|
|
||||||
|
self._verbose = options.verbose
|
||||||
|
|
||||||
self.src = osmosdr.source_c(options.args)
|
self.src = osmosdr.source_c(options.args)
|
||||||
|
|
||||||
# Set the antenna
|
# Set the antenna
|
||||||
if(options.antenna):
|
if(options.antenna):
|
||||||
self.src.set_antenna(options.antenna, 0)
|
self.src.set_antenna(options.antenna)
|
||||||
|
|
||||||
self.src.set_sample_rate(options.samp_rate)
|
if options.samp_rate is None:
|
||||||
input_rate = self.src.get_sample_rate()
|
options.samp_rate = self.src.get_sample_rates().start()
|
||||||
|
|
||||||
|
if options.gain is None:
|
||||||
|
# if no gain was specified, use the mid-point in dB
|
||||||
|
r = self.src.get_gain_range()
|
||||||
|
options.gain = float(r.start()+r.stop())/2
|
||||||
|
|
||||||
|
if options.center_freq is None:
|
||||||
|
# if no freq was specified, use the mid-point in Hz
|
||||||
|
r = self.src.get_freq_range()
|
||||||
|
options.center_freq = float(r.start()+r.stop())/2
|
||||||
|
|
||||||
|
input_rate = self.src.set_sample_rate(options.samp_rate)
|
||||||
|
|
||||||
|
self.src.set_gain(options.gain)
|
||||||
|
|
||||||
|
#print self.src.get_sample_rates().to_pp_string()
|
||||||
|
|
||||||
|
self.publish(SAMP_RANGE_KEY, self.src.get_sample_rates)
|
||||||
|
self.publish(FREQ_RANGE_KEY, self.src.get_freq_range)
|
||||||
|
|
||||||
|
for name in self.get_gain_names():
|
||||||
|
self.publish(GAIN_RANGE_KEY(name), (lambda self=self,name=name: self.src.get_gain_range(name)))
|
||||||
|
|
||||||
|
self.publish(BWIDTH_RANGE_KEY, self.src.get_bandwidth_range)
|
||||||
|
|
||||||
|
for name in self.get_gain_names():
|
||||||
|
self.publish(GAIN_KEY(name), (lambda self=self,name=name: self.src.get_gain(name)))
|
||||||
|
|
||||||
|
self.publish(BWIDTH_KEY, self.src.get_bandwidth)
|
||||||
|
|
||||||
|
#initialize values from options
|
||||||
|
self[SAMP_RANGE_KEY] = self.src.get_sample_rates()
|
||||||
|
self[SAMP_RATE_KEY] = options.samp_rate
|
||||||
|
self[CENTER_FREQ_KEY] = options.center_freq
|
||||||
|
self[FREQ_CORR_KEY] = options.freq_corr
|
||||||
|
|
||||||
|
#subscribe set methods
|
||||||
|
self.subscribe(SAMP_RATE_KEY, self.set_sample_rate)
|
||||||
|
|
||||||
|
for name in self.get_gain_names():
|
||||||
|
self.subscribe(GAIN_KEY(name), (lambda gain,self=self,name=name: self.set_named_gain(gain, name)))
|
||||||
|
|
||||||
|
self.subscribe(BWIDTH_KEY, self.set_bandwidth)
|
||||||
|
self.subscribe(CENTER_FREQ_KEY, self.set_freq)
|
||||||
|
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr)
|
||||||
|
|
||||||
|
#force update on pubsub keys
|
||||||
|
for key in (SAMP_RATE_KEY, BWIDTH_KEY, CENTER_FREQ_KEY, FREQ_CORR_KEY):
|
||||||
|
print key, "=", self[key]
|
||||||
|
#self[key] = self[key]
|
||||||
|
|
||||||
if options.waterfall:
|
if options.waterfall:
|
||||||
self.scope = \
|
self.scope = \
|
||||||
waterfallsink2.waterfall_sink_c (panel, fft_size=1024,
|
waterfallsink2.waterfallsrc_c (panel, fft_size=options.fft_size,
|
||||||
sample_rate=input_rate)
|
sample_rate=input_rate)
|
||||||
self.frame.SetMinSize((800, 420))
|
self.frame.SetMinSize((800, 420))
|
||||||
elif options.oscilloscope:
|
elif options.oscilloscope:
|
||||||
self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
|
self.scope = scopesink2.scopesrc_c(panel, sample_rate=input_rate)
|
||||||
self.frame.SetMinSize((800, 600))
|
self.frame.SetMinSize((800, 600))
|
||||||
else:
|
else:
|
||||||
self.scope = fftsink2.fft_sink_c (panel,
|
self.scope = fftsink2.fft_sink_c (panel,
|
||||||
|
@ -107,7 +174,7 @@ class app_top_block(stdgui2.std_top_block):
|
||||||
fft_rate=options.fft_rate)
|
fft_rate=options.fft_rate)
|
||||||
def fftsink_callback(x, y):
|
def fftsink_callback(x, y):
|
||||||
self.set_freq(x)
|
self.set_freq(x)
|
||||||
|
|
||||||
self.scope.set_callback(fftsink_callback)
|
self.scope.set_callback(fftsink_callback)
|
||||||
self.frame.SetMinSize((800, 420))
|
self.frame.SetMinSize((800, 420))
|
||||||
|
|
||||||
|
@ -116,25 +183,8 @@ class app_top_block(stdgui2.std_top_block):
|
||||||
self._build_gui(vbox)
|
self._build_gui(vbox)
|
||||||
self._setup_events()
|
self._setup_events()
|
||||||
|
|
||||||
|
|
||||||
# set initial values
|
# set initial values
|
||||||
|
if not(self.set_freq(options.center_freq)):
|
||||||
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")
|
self._set_status_msg("Failed to set initial frequency")
|
||||||
|
|
||||||
def _set_status_msg(self, msg):
|
def _set_status_msg(self, msg):
|
||||||
|
@ -142,99 +192,271 @@ class app_top_block(stdgui2.std_top_block):
|
||||||
|
|
||||||
def _build_gui(self, vbox):
|
def _build_gui(self, vbox):
|
||||||
|
|
||||||
def _form_set_freq(kv):
|
vbox.Add(self.scope.win, 0, wx.EXPAND)
|
||||||
return self.set_freq(kv['freq'])
|
vbox.AddSpacer(3)
|
||||||
|
|
||||||
vbox.Add(self.scope.win, 10, wx.EXPAND)
|
|
||||||
|
|
||||||
# add control area at the bottom
|
# add control area at the bottom
|
||||||
self.myform = myform = form.form()
|
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()
|
# 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)
|
||||||
|
|
||||||
# some configurations don't have gain control
|
# Add frequency controls to top window sizer
|
||||||
if g.stop() <= g.start():
|
vbox.Add(fc_vbox, 0, wx.EXPAND)
|
||||||
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.AddSpacer(5)
|
||||||
|
vbox.AddStretchSpacer()
|
||||||
|
|
||||||
vbox.Add(hbox, 0, wx.EXPAND)
|
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,
|
||||||
|
key=CENTER_FREQ_KEY,
|
||||||
|
)
|
||||||
|
freq_hbox.AddSpacer(5)
|
||||||
|
|
||||||
|
forms.slider(
|
||||||
|
parent=self.panel, sizer=freq_hbox,
|
||||||
|
proportion=3,
|
||||||
|
ps=self,
|
||||||
|
key=CENTER_FREQ_KEY,
|
||||||
|
minimum=self[FREQ_RANGE_KEY].start(),
|
||||||
|
maximum=self[FREQ_RANGE_KEY].stop(),
|
||||||
|
num_steps=101,
|
||||||
|
)
|
||||||
|
freq_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
corr_hbox.AddSpacer(3)
|
||||||
|
forms.text_box(
|
||||||
|
parent=self.panel, sizer=corr_hbox,
|
||||||
|
label='Freq. Correction (ppm)',
|
||||||
|
proportion=1,
|
||||||
|
converter=forms.int_converter(),
|
||||||
|
ps=self,
|
||||||
|
key=FREQ_CORR_KEY,
|
||||||
|
)
|
||||||
|
corr_hbox.AddSpacer(5)
|
||||||
|
|
||||||
|
forms.slider(
|
||||||
|
parent=self.panel, sizer=corr_hbox,
|
||||||
|
proportion=3,
|
||||||
|
ps=self,
|
||||||
|
key=FREQ_CORR_KEY,
|
||||||
|
minimum=-100,
|
||||||
|
maximum=+100,
|
||||||
|
num_steps=201,
|
||||||
|
step_size=1,
|
||||||
|
)
|
||||||
|
corr_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Gain controls
|
||||||
|
##################################################
|
||||||
|
gc_vbox = forms.static_box_sizer(parent=self.panel,
|
||||||
|
label="Gain Settings",
|
||||||
|
orient=wx.VERTICAL,
|
||||||
|
bold=True)
|
||||||
|
gc_vbox.AddSpacer(3)
|
||||||
|
|
||||||
|
# Add gain controls to top window sizer
|
||||||
|
vbox.Add(gc_vbox, 0, wx.EXPAND)
|
||||||
vbox.AddSpacer(5)
|
vbox.AddSpacer(5)
|
||||||
|
vbox.AddStretchSpacer()
|
||||||
|
|
||||||
def set_freq(self, target_freq):
|
for gain_name in self.get_gain_names():
|
||||||
"""
|
range = self[GAIN_RANGE_KEY(gain_name)]
|
||||||
Set the center frequency we're interested in.
|
gain = self[GAIN_KEY(gain_name)]
|
||||||
|
|
||||||
@param target_freq: frequency in Hz
|
#print gain_name, gain, range.to_pp_string()
|
||||||
@rypte: bool
|
if range.start() < range.stop():
|
||||||
"""
|
gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
actual_freq = self.src.set_center_freq(target_freq, 0)
|
gc_vbox.Add(gain_hbox, 0, wx.EXPAND)
|
||||||
self.myform['freq'].set_value(actual_freq)
|
gc_vbox.AddSpacer(3)
|
||||||
|
|
||||||
if not self.options.oscilloscope:
|
gain_hbox.AddSpacer(3)
|
||||||
self.scope.set_baseband_freq(actual_freq)
|
forms.text_box(
|
||||||
|
parent=self.panel, sizer=gain_hbox,
|
||||||
|
proportion=1,
|
||||||
|
converter=forms.float_converter(),
|
||||||
|
ps=self,
|
||||||
|
key=GAIN_KEY(gain_name),
|
||||||
|
label=gain_name + " Gain (dB)",
|
||||||
|
)
|
||||||
|
gain_hbox.AddSpacer(5)
|
||||||
|
forms.slider(
|
||||||
|
parent=self.panel, sizer=gain_hbox,
|
||||||
|
proportion=3,
|
||||||
|
ps=self,
|
||||||
|
key=GAIN_KEY(gain_name),
|
||||||
|
minimum=range.start(),
|
||||||
|
maximum=range.stop(),
|
||||||
|
step_size=range.step(),
|
||||||
|
)
|
||||||
|
gain_hbox.AddSpacer(3)
|
||||||
|
|
||||||
return True
|
##################################################
|
||||||
|
# Bandwidth controls
|
||||||
|
##################################################
|
||||||
|
try:
|
||||||
|
|
||||||
def set_gain(self, gain):
|
bw_range = self[BWIDTH_RANGE_KEY]
|
||||||
if self.myform.has_key('gain'):
|
#print bw_range.to_pp_string()
|
||||||
self.myform['gain'].set_value(gain) # update displayed value
|
#if bw_range.start() < bw_range.stop():
|
||||||
self.src.set_gain(gain, 0)
|
if 0:
|
||||||
|
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)
|
||||||
|
|
||||||
|
vbox.Add(bwidth_vbox, 0, wx.EXPAND)
|
||||||
|
vbox.AddSpacer(5)
|
||||||
|
vbox.AddStretchSpacer()
|
||||||
|
|
||||||
|
bwidth_hbox.AddSpacer(3)
|
||||||
|
forms.text_box(
|
||||||
|
parent=self.panel, sizer=bwidth_hbox,
|
||||||
|
proportion=1,
|
||||||
|
converter=forms.float_converter(),
|
||||||
|
ps=self,
|
||||||
|
key=BWIDTH_KEY,
|
||||||
|
label="Bandwidth (Hz)",
|
||||||
|
)
|
||||||
|
bwidth_hbox.AddSpacer(5)
|
||||||
|
forms.slider(
|
||||||
|
parent=self.panel, sizer=bwidth_hbox,
|
||||||
|
proportion=3,
|
||||||
|
ps=self,
|
||||||
|
key=BWIDTH_KEY,
|
||||||
|
minimum=bw_range.start(),
|
||||||
|
maximum=bw_range.stop(),
|
||||||
|
step_size=bw_range.step(),
|
||||||
|
)
|
||||||
|
bwidth_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Sample rate controls
|
||||||
|
##################################################
|
||||||
|
sr_vbox = forms.static_box_sizer(parent=self.panel,
|
||||||
|
label="Sample Rate",
|
||||||
|
orient=wx.VERTICAL,
|
||||||
|
bold=True)
|
||||||
|
sr_vbox.AddSpacer(3)
|
||||||
|
# First row of sample rate controls
|
||||||
|
sr_hbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
sr_vbox.Add(sr_hbox, 0, wx.EXPAND)
|
||||||
|
sr_vbox.AddSpacer(5)
|
||||||
|
|
||||||
|
# Add frequency controls to top window sizer
|
||||||
|
vbox.Add(sr_vbox, 0, wx.EXPAND)
|
||||||
|
vbox.AddSpacer(5)
|
||||||
|
vbox.AddStretchSpacer()
|
||||||
|
|
||||||
|
sr_hbox.AddSpacer(3)
|
||||||
|
forms.text_box(
|
||||||
|
parent=self.panel, sizer=sr_hbox,
|
||||||
|
label='Sample Rate (Hz)',
|
||||||
|
proportion=1,
|
||||||
|
converter=forms.float_converter(),
|
||||||
|
ps=self,
|
||||||
|
key=SAMP_RATE_KEY,
|
||||||
|
)
|
||||||
|
sr_hbox.AddSpacer(5)
|
||||||
|
|
||||||
|
#forms.slider(
|
||||||
|
# parent=self.panel, sizer=sr_hbox,
|
||||||
|
# proportion=3,
|
||||||
|
# ps=self,
|
||||||
|
# key=SAMP_RATE_KEY,
|
||||||
|
# minimum=self[SAMP_RANGE_KEY].start(),
|
||||||
|
# maximum=self[SAMP_RANGE_KEY].stop(),
|
||||||
|
# step_size=self[SAMP_RANGE_KEY].step(),
|
||||||
|
#)
|
||||||
|
#sr_hbox.AddSpacer(3)
|
||||||
|
|
||||||
def set_sample_rate(self, samp_rate):
|
def set_sample_rate(self, samp_rate):
|
||||||
ok = self.src.set_sample_rate(samp_rate)
|
samp_rate = self.src.set_sample_rate(samp_rate)
|
||||||
input_rate = self.src.get_sample_rate()
|
self.scope.set_sample_rate(samp_rate)
|
||||||
self.scope.set_sample_rate(input_rate)
|
if self._verbose:
|
||||||
if self.show_debug_info: # update displayed values
|
print "Set sample rate to:", samp_rate
|
||||||
self.myform['samprate'].set_value(self.src.get_sample_rate())
|
return samp_rate
|
||||||
|
|
||||||
# set_sample_rate never fails; always falls back to closest requested.
|
def get_gain_names(self):
|
||||||
return True
|
return self.src.get_gain_names()
|
||||||
|
|
||||||
|
def set_named_gain(self, gain, name):
|
||||||
|
if gain is None:
|
||||||
|
g = self[GAIN_RANGE_KEY(name)]
|
||||||
|
gain = float(g.start()+g.stop())/2
|
||||||
|
if self._verbose:
|
||||||
|
print "Using auto-calculated mid-point gain"
|
||||||
|
self[GAIN_KEY(name)] = gain
|
||||||
|
return
|
||||||
|
|
||||||
|
gain = self.src.set_gain(gain, name)
|
||||||
|
if self._verbose:
|
||||||
|
print "Set " + name + " gain to:", gain
|
||||||
|
|
||||||
|
def set_bandwidth(self, bw):
|
||||||
|
bw = self.src.set_bandwidth(bw)
|
||||||
|
if self._verbose:
|
||||||
|
print "Set bandwidth to:", bw
|
||||||
|
|
||||||
|
def set_freq(self, freq):
|
||||||
|
if freq is None:
|
||||||
|
f = self[FREQ_RANGE_KEY]
|
||||||
|
freq = float(f.start()+f.stop())/2.0
|
||||||
|
if self._verbose:
|
||||||
|
print "Using auto-calculated mid-point frequency"
|
||||||
|
self[CENTER_FREQ_KEY] = freq
|
||||||
|
return
|
||||||
|
|
||||||
|
freq = self.src.set_center_freq(freq)
|
||||||
|
|
||||||
|
if not self.options.oscilloscope:
|
||||||
|
self.scope.set_baseband_freq(freq)
|
||||||
|
|
||||||
|
if freq is not None:
|
||||||
|
if self._verbose:
|
||||||
|
print "Set center frequency to", freq
|
||||||
|
elif self._verbose:
|
||||||
|
print "Failed to set freq."
|
||||||
|
return freq
|
||||||
|
|
||||||
|
def set_freq_corr(self, ppm):
|
||||||
|
if ppm is None:
|
||||||
|
ppm = 0.0
|
||||||
|
if self._verbose:
|
||||||
|
print "Using frequency corrrection of", ppm
|
||||||
|
self[FREQ_CORR_KEY] = ppm
|
||||||
|
return
|
||||||
|
|
||||||
|
ppm = self.src.set_freq_corr(ppm)
|
||||||
|
if self._verbose:
|
||||||
|
print "Set frequency correction to:", ppm
|
||||||
|
|
||||||
def _setup_events(self):
|
def _setup_events(self):
|
||||||
if not self.options.waterfall and not self.options.oscilloscope:
|
if not self.options.waterfall and not self.options.oscilloscope:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
#
|
||||||
# Copyright 2008,2009,2011,2012 Free Software Foundation, Inc.
|
# Copyright 2009,2011,2012 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of GNU Radio
|
# This file is part of GNU Radio
|
||||||
#
|
#
|
||||||
|
@ -21,31 +21,347 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from gnuradio import gr
|
from gnuradio import gr
|
||||||
|
from gnuradio.gr.pubsub import pubsub
|
||||||
from osmosdr import osmocom_siggen_base as osmocom_siggen
|
from osmosdr import osmocom_siggen_base as osmocom_siggen
|
||||||
import sys
|
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=101,
|
||||||
|
)
|
||||||
|
freq_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
corr_hbox.AddSpacer(3)
|
||||||
|
forms.text_box(
|
||||||
|
parent=self.panel, sizer=corr_hbox,
|
||||||
|
label='Freq. 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,
|
||||||
|
step_size=1,
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
|
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.1-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=-1,
|
||||||
|
max_exp=0,
|
||||||
|
base=10,
|
||||||
|
num_steps=100,
|
||||||
|
)
|
||||||
|
lvl_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
for gain_name in self.tb.get_gain_names():
|
||||||
|
range = self.tb[osmocom_siggen.GAIN_RANGE_KEY(gain_name)]
|
||||||
|
gain = self.tb[osmocom_siggen.GAIN_KEY(gain_name)]
|
||||||
|
|
||||||
|
#print gain_name, gain, range.to_pp_string()
|
||||||
|
if range.start() < range.stop():
|
||||||
|
gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
amp_vbox.Add(gain_hbox, 0, wx.EXPAND)
|
||||||
|
amp_vbox.AddSpacer(3)
|
||||||
|
|
||||||
|
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(gain_name),
|
||||||
|
label=gain_name + " Gain (dB)",
|
||||||
|
)
|
||||||
|
gain_hbox.AddSpacer(5)
|
||||||
|
forms.slider(
|
||||||
|
parent=self.panel, sizer=gain_hbox,
|
||||||
|
proportion=2,
|
||||||
|
ps=self.tb,
|
||||||
|
key=osmocom_siggen.GAIN_KEY(gain_name),
|
||||||
|
minimum=range.start(),
|
||||||
|
maximum=range.stop(),
|
||||||
|
step_size=range.step(),
|
||||||
|
)
|
||||||
|
gain_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Bandwidth controls
|
||||||
|
##################################################
|
||||||
|
try:
|
||||||
|
|
||||||
|
bw_range = self.tb[osmocom_siggen.BWIDTH_RANGE_KEY]
|
||||||
|
#print bw_range.to_pp_string()
|
||||||
|
#if bw_range.start() < bw_range.stop():
|
||||||
|
if 0:
|
||||||
|
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()
|
||||||
|
|
||||||
|
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=bw_range.start(),
|
||||||
|
maximum=bw_range.stop(),
|
||||||
|
step_size=bw_range.step(),
|
||||||
|
)
|
||||||
|
bwidth_hbox.AddSpacer(3)
|
||||||
|
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# 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():
|
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:
|
try:
|
||||||
|
# Get command line parameters
|
||||||
(options, args) = osmocom_siggen.get_options()
|
(options, args) = osmocom_siggen.get_options()
|
||||||
|
|
||||||
|
# Create the top block using these
|
||||||
tb = osmocom_siggen.top_block(options, args)
|
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:
|
except RuntimeError, e:
|
||||||
print e
|
print e
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
tb.start()
|
# Make sure to create the top block (tb) within a function: That code
|
||||||
raw_input('Press Enter to quit: ')
|
# in main will allow tb to go out of scope on return, which will call
|
||||||
tb.stop()
|
# the decontructor on radio device and stop transmit. Whats odd is that
|
||||||
tb.wait()
|
# grc works fine with tb in the __main__, perhaps its because the
|
||||||
|
# try/except clauses around tb.
|
||||||
# Make sure to create the top block (tb) within a function:
|
if __name__ == "__main__": main()
|
||||||
# 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()
|
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
SAMP_RATE_KEY = 'samp_rate'
|
SAMP_RATE_KEY = 'samp_rate'
|
||||||
LINK_RATE_KEY = 'link_rate'
|
GAIN_KEY = lambda x: 'gain:'+x
|
||||||
GAIN_KEY = 'gain'
|
|
||||||
IF_GAIN_KEY = 'if_gain'
|
|
||||||
BWIDTH_KEY = 'bwidth'
|
BWIDTH_KEY = 'bwidth'
|
||||||
TX_FREQ_KEY = 'tx_freq'
|
TX_FREQ_KEY = 'tx_freq'
|
||||||
FREQ_CORR_KEY = 'freq_corr'
|
FREQ_CORR_KEY = 'freq_corr'
|
||||||
|
@ -33,8 +31,7 @@ WAVEFORM_FREQ_KEY = 'waveform_freq'
|
||||||
WAVEFORM_OFFSET_KEY = 'waveform_offset'
|
WAVEFORM_OFFSET_KEY = 'waveform_offset'
|
||||||
WAVEFORM2_FREQ_KEY = 'waveform2_freq'
|
WAVEFORM2_FREQ_KEY = 'waveform2_freq'
|
||||||
FREQ_RANGE_KEY = 'freq_range'
|
FREQ_RANGE_KEY = 'freq_range'
|
||||||
GAIN_RANGE_KEY = 'gain_range'
|
GAIN_RANGE_KEY = lambda x: 'gain_range:'+x
|
||||||
IF_GAIN_RANGE_KEY = 'if_gain_range'
|
|
||||||
BWIDTH_RANGE_KEY = 'bwidth_range'
|
BWIDTH_RANGE_KEY = 'bwidth_range'
|
||||||
TYPE_KEY = 'type'
|
TYPE_KEY = 'type'
|
||||||
|
|
||||||
|
@ -50,12 +47,12 @@ import math
|
||||||
|
|
||||||
n2s = eng_notation.num_to_str
|
n2s = eng_notation.num_to_str
|
||||||
|
|
||||||
waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid",
|
waveforms = { gr.GR_SIN_WAVE : "Sinusoid",
|
||||||
gr.GR_CONST_WAVE : "Constant",
|
gr.GR_CONST_WAVE : "Constant",
|
||||||
gr.GR_GAUSSIAN : "Gaussian Noise",
|
gr.GR_GAUSSIAN : "Gaussian Noise",
|
||||||
gr.GR_UNIFORM : "Uniform Noise",
|
gr.GR_UNIFORM : "Uniform Noise",
|
||||||
"2tone" : "Two Tone",
|
"2tone" : "Two Tone (IMD)",
|
||||||
"sweep" : "Sweep" }
|
"sweep" : "Freq. Sweep" }
|
||||||
|
|
||||||
#
|
#
|
||||||
# GUI-unaware GNU Radio flowgraph. This may be used either with command
|
# GUI-unaware GNU Radio flowgraph. This may be used either with command
|
||||||
|
@ -79,8 +76,10 @@ class top_block(gr.top_block, pubsub):
|
||||||
|
|
||||||
#subscribe set methods
|
#subscribe set methods
|
||||||
self.subscribe(SAMP_RATE_KEY, self.set_samp_rate)
|
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)
|
for name in self.get_gain_names():
|
||||||
|
self.subscribe(GAIN_KEY(name), (lambda gain,self=self,name=name: self.set_named_gain(gain, name)))
|
||||||
|
|
||||||
self.subscribe(BWIDTH_KEY, self.set_bandwidth)
|
self.subscribe(BWIDTH_KEY, self.set_bandwidth)
|
||||||
self.subscribe(TX_FREQ_KEY, self.set_freq)
|
self.subscribe(TX_FREQ_KEY, self.set_freq)
|
||||||
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr)
|
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr)
|
||||||
|
@ -90,58 +89,50 @@ class top_block(gr.top_block, pubsub):
|
||||||
self.subscribe(TYPE_KEY, self.set_waveform)
|
self.subscribe(TYPE_KEY, self.set_waveform)
|
||||||
|
|
||||||
#force update on pubsub keys
|
#force update on pubsub keys
|
||||||
for key in (SAMP_RATE_KEY, GAIN_KEY, IF_GAIN_KEY, BWIDTH_KEY,
|
for key in (SAMP_RATE_KEY, GAIN_KEY, BWIDTH_KEY,
|
||||||
TX_FREQ_KEY, FREQ_CORR_KEY, AMPLITUDE_KEY,
|
TX_FREQ_KEY, FREQ_CORR_KEY, AMPLITUDE_KEY,
|
||||||
WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY):
|
WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY):
|
||||||
# print "key: ", key, "=", self[key]
|
#print key, "=", self[key]
|
||||||
self[key] = self[key]
|
self[key] = self[key]
|
||||||
self[TYPE_KEY] = options.type #set type last
|
self[TYPE_KEY] = options.type #set type last
|
||||||
|
|
||||||
def _setup_osmosdr(self, options):
|
def _setup_osmosdr(self, options):
|
||||||
self._sink = osmosdr.sink_c(options.args)
|
self._sink = osmosdr.sink_c(options.args)
|
||||||
self._sink.set_sample_rate(options.samp_rate)
|
|
||||||
|
if options.samp_rate is None:
|
||||||
|
options.samp_rate = self._sink.get_sample_rates().start()
|
||||||
|
|
||||||
|
self.set_samp_rate(options.samp_rate)
|
||||||
|
|
||||||
# Set the gain from options
|
# Set the gain from options
|
||||||
if(options.gain):
|
if(options.gain):
|
||||||
self._sink.set_gain(options.gain)
|
gain = self._sink.set_gain(options.gain)
|
||||||
|
if self._verbose:
|
||||||
|
print "Set gain to:", gain
|
||||||
|
|
||||||
# Set the antenna
|
# Set the antenna
|
||||||
if(options.antenna):
|
if(options.antenna):
|
||||||
self._sink.set_antenna(options.antenna, 0)
|
ant = self._sink.set_antenna(options.antenna, 0)
|
||||||
|
if self._verbose:
|
||||||
|
print "Set antenna to:", ant
|
||||||
|
|
||||||
self.publish(FREQ_RANGE_KEY, self._sink.get_freq_range)
|
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)
|
for name in self.get_gain_names():
|
||||||
|
self.publish(GAIN_RANGE_KEY(name), (lambda self=self,name=name: self._sink.get_gain_range(name)))
|
||||||
|
|
||||||
self.publish(BWIDTH_RANGE_KEY, self._sink.get_bandwidth_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)
|
for name in self.get_gain_names():
|
||||||
|
self.publish(GAIN_KEY(name), (lambda self=self,name=name: self._sink.get_gain(name)))
|
||||||
|
|
||||||
self.publish(BWIDTH_KEY, self._sink.get_bandwidth)
|
self.publish(BWIDTH_KEY, self._sink.get_bandwidth)
|
||||||
|
|
||||||
def _get_rf_gain_range(self):
|
def get_gain_names(self):
|
||||||
return self._sink.get_gain_range("RF")
|
return self._sink.get_gain_names()
|
||||||
|
|
||||||
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):
|
def set_samp_rate(self, sr):
|
||||||
self._sink.set_sample_rate(sr)
|
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):
|
if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE):
|
||||||
self._src.set_sampling_freq(self[SAMP_RATE_KEY])
|
self._src.set_sampling_freq(self[SAMP_RATE_KEY])
|
||||||
|
@ -159,64 +150,53 @@ class top_block(gr.top_block, pubsub):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_gain(self, gain):
|
def set_named_gain(self, gain, name):
|
||||||
if gain is None:
|
if gain is None:
|
||||||
g = self[GAIN_RANGE_KEY]
|
g = self[GAIN_RANGE_KEY(name)]
|
||||||
gain = float(g.start()+g.stop())/2
|
gain = float(g.start()+g.stop())/2
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Using auto-calculated mid-point RF gain"
|
print "Using auto-calculated mid-point gain"
|
||||||
self[GAIN_KEY] = gain
|
self[GAIN_KEY(name)] = gain
|
||||||
return
|
return
|
||||||
gain = self._sink.set_gain(gain, "RF")
|
|
||||||
if self._verbose:
|
|
||||||
print "Set RF gain to:", gain
|
|
||||||
|
|
||||||
def set_if_gain(self, gain):
|
gain = self._sink.set_gain(gain, name)
|
||||||
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:
|
if self._verbose:
|
||||||
print "Set IF gain to:", gain
|
print "Set " + name + " gain to:", gain
|
||||||
|
|
||||||
def set_bandwidth(self, bw):
|
def set_bandwidth(self, bw):
|
||||||
bw = self._sink.set_bandwidth(bw)
|
bw = self._sink.set_bandwidth(bw)
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Set bandwidth to:", bw
|
print "Set bandwidth to:", bw
|
||||||
|
|
||||||
def set_freq(self, target_freq):
|
def set_freq(self, freq):
|
||||||
|
if freq is None:
|
||||||
if target_freq is None:
|
|
||||||
f = self[FREQ_RANGE_KEY]
|
f = self[FREQ_RANGE_KEY]
|
||||||
target_freq = float(f.start()+f.stop())/2.0
|
freq = float(f.start()+f.stop())/2.0
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Using auto-calculated mid-point frequency"
|
print "Using auto-calculated mid-point frequency"
|
||||||
self[TX_FREQ_KEY] = target_freq
|
self[TX_FREQ_KEY] = freq
|
||||||
return
|
return
|
||||||
|
|
||||||
tr = self._sink.set_center_freq(target_freq)
|
freq = self._sink.set_center_freq(freq)
|
||||||
if tr is not None:
|
if freq is not None:
|
||||||
self._freq = tr
|
self._freq = freq
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Set center frequency to", tr
|
print "Set center frequency to", freq
|
||||||
elif self._verbose:
|
elif self._verbose:
|
||||||
print "Failed to set freq."
|
print "Failed to set freq."
|
||||||
return tr
|
return freq
|
||||||
|
|
||||||
def set_freq_corr(self, ppm):
|
def set_freq_corr(self, ppm):
|
||||||
if ppm is None:
|
if ppm is None:
|
||||||
|
ppm = 0.0
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Setting freq corrrection to 0"
|
print "Using frequency corrrection of", ppm
|
||||||
self[FREQ_CORR_KEY] = 0
|
self[FREQ_CORR_KEY] = ppm
|
||||||
return
|
return
|
||||||
|
|
||||||
ppm = self._sink.set_freq_corr(ppm)
|
ppm = self._sink.set_freq_corr(ppm)
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
print "Set freq correction to:", ppm
|
print "Set frequency correction to:", ppm
|
||||||
|
|
||||||
def set_waveform_freq(self, freq):
|
def set_waveform_freq(self, freq):
|
||||||
if self[TYPE_KEY] == gr.GR_SIN_WAVE:
|
if self[TYPE_KEY] == gr.GR_SIN_WAVE:
|
||||||
|
@ -242,11 +222,11 @@ class top_block(gr.top_block, pubsub):
|
||||||
self.lock()
|
self.lock()
|
||||||
self.disconnect_all()
|
self.disconnect_all()
|
||||||
if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
|
if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE:
|
||||||
self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate
|
self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate
|
||||||
type, # Waveform type
|
type, # Waveform type
|
||||||
self[WAVEFORM_FREQ_KEY], # Waveform frequency
|
self[WAVEFORM_FREQ_KEY], # Waveform frequency
|
||||||
self[AMPLITUDE_KEY], # Waveform amplitude
|
self[AMPLITUDE_KEY], # Waveform amplitude
|
||||||
self[WAVEFORM_OFFSET_KEY]) # Waveform offset
|
self[WAVEFORM_OFFSET_KEY]) # Waveform offset
|
||||||
elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
|
elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM:
|
||||||
self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY])
|
self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY])
|
||||||
elif type == "2tone":
|
elif type == "2tone":
|
||||||
|
@ -330,8 +310,8 @@ def get_options():
|
||||||
help="Device args, [default=%default]")
|
help="Device args, [default=%default]")
|
||||||
parser.add_option("-A", "--antenna", type="string", default=None,
|
parser.add_option("-A", "--antenna", type="string", default=None,
|
||||||
help="Select Rx Antenna where appropriate")
|
help="Select Rx Antenna where appropriate")
|
||||||
parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
|
parser.add_option("-s", "--samp-rate", type="eng_float", default=None,
|
||||||
help="Set sample rate (bandwidth) [default=%default]")
|
help="Set sample rate (bandwidth), minimum by default")
|
||||||
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
||||||
help="Set gain in dB (default is midpoint)")
|
help="Set gain in dB (default is midpoint)")
|
||||||
parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
|
parser.add_option("-f", "--tx-freq", type="eng_float", default=None,
|
||||||
|
@ -359,7 +339,7 @@ def get_options():
|
||||||
parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
|
parser.add_option("--sweep", dest="type", action="store_const", const="sweep",
|
||||||
help="Generate a swept sine wave")
|
help="Generate a swept sine wave")
|
||||||
parser.add_option("", "--amplitude", type="eng_float", default=0.3,
|
parser.add_option("", "--amplitude", type="eng_float", default=0.3,
|
||||||
help="Set output amplitude to AMPL (0.0-1.0) [default=%default]",
|
help="Set output amplitude to AMPL (0.1-1.0) [default=%default]",
|
||||||
metavar="AMPL")
|
metavar="AMPL")
|
||||||
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
||||||
help="Use verbose console output [default=%default]")
|
help="Use verbose console output [default=%default]")
|
||||||
|
|
|
@ -1,374 +0,0 @@
|
||||||
#!/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()
|
|
|
@ -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()
|
Loading…
Reference in New Issue