From 3393647bec42b37a5f05ac67d171da9ac8e837d4 Mon Sep 17 00:00:00 2001 From: Dimitri Stolnikov Date: Thu, 9 May 2013 13:48:16 +0200 Subject: [PATCH] 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 --- apps/CMakeLists.txt | 2 +- apps/osmocom_fft | 442 +++++++++++++++++++++++++++--------- apps/osmocom_siggen | 352 ++++++++++++++++++++++++++-- apps/osmocom_siggen_base.py | 140 +++++------- apps/osmocom_siggen_gui | 374 ------------------------------ apps/osmocom_siggen_nogui | 51 +++++ 6 files changed, 778 insertions(+), 583 deletions(-) delete mode 100755 apps/osmocom_siggen_gui create mode 100755 apps/osmocom_siggen_nogui diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 88e5d4a..9f1a958 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -29,6 +29,6 @@ GR_PYTHON_INSTALL( PROGRAMS osmocom_fft osmocom_siggen - osmocom_siggen_gui + osmocom_siggen_nogui DESTINATION ${GR_RUNTIME_DIR} ) diff --git a/apps/osmocom_fft b/apps/osmocom_fft index 5449354..85406b1 100755 --- a/apps/osmocom_fft +++ b/apps/osmocom_fft @@ -20,9 +20,20 @@ # 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 from gnuradio import gr, gru from gnuradio import eng_notation +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option 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.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): stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + pubsub.__init__(self) 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]") + 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") + help="Select RX antenna where appropriate") + parser.add_option("-s", "--samp-rate", type="eng_float", default=None, + help="Set sample rate (bandwidth), minimum by default") + parser.add_option("-f", "--center-freq", type="eng_float", default=None, + 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, - 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, help="Enable waterfall display") 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]") parser.add_option("", "--fft-rate", type="int", default=30, 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() if len(args) != 0: parser.print_help() sys.exit(1) self.options = options - self.show_debug_info = True + + self._verbose = options.verbose self.src = osmosdr.source_c(options.args) # Set the 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) - input_rate = self.src.get_sample_rate() + if options.samp_rate is None: + 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: self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, + waterfallsink2.waterfallsrc_c (panel, fft_size=options.fft_size, sample_rate=input_rate) self.frame.SetMinSize((800, 420)) 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)) else: self.scope = fftsink2.fft_sink_c (panel, @@ -107,7 +174,7 @@ class app_top_block(stdgui2.std_top_block): 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)) @@ -116,25 +183,8 @@ class app_top_block(stdgui2.std_top_block): 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)): + if not(self.set_freq(options.center_freq)): self._set_status_msg("Failed to set initial frequency") def _set_status_msg(self, msg): @@ -142,99 +192,271 @@ class app_top_block(stdgui2.std_top_block): def _build_gui(self, vbox): - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) + vbox.Add(self.scope.win, 0, wx.EXPAND) + vbox.AddSpacer(3) # 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() + ################################################## + # 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 - 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)) + # Add frequency controls to top window sizer + vbox.Add(fc_vbox, 0, wx.EXPAND) 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.AddStretchSpacer() - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. + for gain_name in self.get_gain_names(): + range = self[GAIN_RANGE_KEY(gain_name)] + gain = self[GAIN_KEY(gain_name)] - @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) + #print gain_name, gain, range.to_pp_string() + if range.start() < range.stop(): + gain_hbox = wx.BoxSizer(wx.HORIZONTAL) + gc_vbox.Add(gain_hbox, 0, wx.EXPAND) + gc_vbox.AddSpacer(3) - if not self.options.oscilloscope: - self.scope.set_baseband_freq(actual_freq) + gain_hbox.AddSpacer(3) + 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): - if self.myform.has_key('gain'): - self.myform['gain'].set_value(gain) # update displayed value - self.src.set_gain(gain, 0) + bw_range = self[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) + + 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): - 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()) + samp_rate = self.src.set_sample_rate(samp_rate) + self.scope.set_sample_rate(samp_rate) + if self._verbose: + print "Set sample rate to:", samp_rate + return samp_rate - # set_sample_rate never fails; always falls back to closest requested. - return True + def get_gain_names(self): + 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): if not self.options.waterfall and not self.options.oscilloscope: diff --git a/apps/osmocom_siggen b/apps/osmocom_siggen index 0283fcf..3724c5b 100755 --- a/apps/osmocom_siggen +++ b/apps/osmocom_siggen @@ -1,6 +1,6 @@ #!/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 # @@ -21,31 +21,347 @@ # from gnuradio import gr +from gnuradio.gr.pubsub import pubsub 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(): - 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: + # 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) - 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() +# 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() diff --git a/apps/osmocom_siggen_base.py b/apps/osmocom_siggen_base.py index 3b5d1d7..6a12015 100644 --- a/apps/osmocom_siggen_base.py +++ b/apps/osmocom_siggen_base.py @@ -21,9 +21,7 @@ # SAMP_RATE_KEY = 'samp_rate' -LINK_RATE_KEY = 'link_rate' -GAIN_KEY = 'gain' -IF_GAIN_KEY = 'if_gain' +GAIN_KEY = lambda x: 'gain:'+x BWIDTH_KEY = 'bwidth' TX_FREQ_KEY = 'tx_freq' FREQ_CORR_KEY = 'freq_corr' @@ -33,8 +31,7 @@ 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' +GAIN_RANGE_KEY = lambda x: 'gain_range:'+x BWIDTH_RANGE_KEY = 'bwidth_range' TYPE_KEY = 'type' @@ -50,12 +47,12 @@ import math 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_GAUSSIAN : "Gaussian Noise", gr.GR_UNIFORM : "Uniform Noise", - "2tone" : "Two Tone", - "sweep" : "Sweep" } + "2tone" : "Two Tone (IMD)", + "sweep" : "Freq. Sweep" } # # 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 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(TX_FREQ_KEY, self.set_freq) 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) #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, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): -# print "key: ", key, "=", self[key] + #print 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) + + 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 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 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(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(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) - 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 get_gain_names(self): + return self._sink.get_gain_names() def set_samp_rate(self, sr): - self._sink.set_sample_rate(sr) - sr = self._sink.get_sample_rate() + sr = self._sink.set_sample_rate(sr) if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): self._src.set_sampling_freq(self[SAMP_RATE_KEY]) @@ -159,64 +150,53 @@ class top_block(gr.top_block, pubsub): return True - def set_gain(self, gain): + def set_named_gain(self, gain, name): if gain is None: - g = self[GAIN_RANGE_KEY] + g = self[GAIN_RANGE_KEY(name)] gain = float(g.start()+g.stop())/2 if self._verbose: - print "Using auto-calculated mid-point RF gain" - self[GAIN_KEY] = gain + print "Using auto-calculated mid-point gain" + self[GAIN_KEY(name)] = 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") + gain = self._sink.set_gain(gain, name) if self._verbose: - print "Set IF gain to:", gain + print "Set " + name + " 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: + def set_freq(self, freq): + if freq is None: 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: print "Using auto-calculated mid-point frequency" - self[TX_FREQ_KEY] = target_freq + self[TX_FREQ_KEY] = freq return - tr = self._sink.set_center_freq(target_freq) - if tr is not None: - self._freq = tr + freq = self._sink.set_center_freq(freq) + if freq is not None: + self._freq = freq if self._verbose: - print "Set center frequency to", tr + print "Set center frequency to", freq elif self._verbose: print "Failed to set freq." - return tr + return freq def set_freq_corr(self, ppm): if ppm is None: + ppm = 0.0 if self._verbose: - print "Setting freq corrrection to 0" - self[FREQ_CORR_KEY] = 0 + print "Using frequency corrrection of", ppm + self[FREQ_CORR_KEY] = ppm return ppm = self._sink.set_freq_corr(ppm) if self._verbose: - print "Set freq correction to:", ppm + print "Set frequency correction to:", ppm def set_waveform_freq(self, freq): if self[TYPE_KEY] == gr.GR_SIN_WAVE: @@ -242,11 +222,11 @@ class top_block(gr.top_block, pubsub): 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 + 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": @@ -330,8 +310,8 @@ def get_options(): 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("-s", "--samp-rate", type="eng_float", default=None, + help="Set sample rate (bandwidth), minimum by 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, @@ -359,7 +339,7 @@ def get_options(): 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]", + help="Set output amplitude to AMPL (0.1-1.0) [default=%default]", metavar="AMPL") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Use verbose console output [default=%default]") diff --git a/apps/osmocom_siggen_gui b/apps/osmocom_siggen_gui deleted file mode 100755 index 86003c4..0000000 --- a/apps/osmocom_siggen_gui +++ /dev/null @@ -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() diff --git a/apps/osmocom_siggen_nogui b/apps/osmocom_siggen_nogui new file mode 100755 index 0000000..0283fcf --- /dev/null +++ b/apps/osmocom_siggen_nogui @@ -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()