forked from sdr/gr-osmosdr
367 lines
13 KiB
Python
Executable File
367 lines
13 KiB
Python
Executable File
#!/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=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.float_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=2010,
|
|
step_size=0.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():
|
|
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():
|
|
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()
|