From 54d6b9281dc233e0b2acf26884073d973b7663de Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 4 Sep 2007 02:43:56 +0000 Subject: Merged r6271:6278 from jcorgan/t182 into trunk. Implements ticket:182. Created new top-level component, gr-utils, to hold commonly used utility scripts (originally in gnuradio-examples). These now install into the system path, allowing their use from wherever. Reorganization of gnuradio-examples component: * Commonly used utility scripts moved from python/usrp into gr-utils. * Examples now install into $(prefix)/share/gnuradio/examples/... * Channel coding examples moved into gr-trellis/src/examples, now install from there, only if gr-atsc itself is going to built and installed. * ATSC example scripts now install into example hierarchy * Cruft has been moved into 'limbo' in repository, do not get installed Trunk passes 'make distcheck'. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6279 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 35 ++++ gr-utils/src/python/usrp_benchmark_usb.py | 106 ++++++++++++ gr-utils/src/python/usrp_fft.py | 254 +++++++++++++++++++++++++++++ gr-utils/src/python/usrp_oscope.py | 252 ++++++++++++++++++++++++++++ gr-utils/src/python/usrp_print_db.py | 42 +++++ gr-utils/src/python/usrp_rx_cfile.py | 107 ++++++++++++ gr-utils/src/python/usrp_rx_nogui.py | 186 +++++++++++++++++++++ gr-utils/src/python/usrp_siggen.py | 180 ++++++++++++++++++++ gr-utils/src/python/usrp_test_counting.py | 53 ++++++ gr-utils/src/python/usrp_test_loop.py | 65 ++++++++ gr-utils/src/python/usrp_test_loop_lfsr.py | 62 +++++++ 11 files changed, 1342 insertions(+) create mode 100644 gr-utils/src/python/Makefile.am create mode 100755 gr-utils/src/python/usrp_benchmark_usb.py create mode 100755 gr-utils/src/python/usrp_fft.py create mode 100755 gr-utils/src/python/usrp_oscope.py create mode 100755 gr-utils/src/python/usrp_print_db.py create mode 100755 gr-utils/src/python/usrp_rx_cfile.py create mode 100755 gr-utils/src/python/usrp_rx_nogui.py create mode 100755 gr-utils/src/python/usrp_siggen.py create mode 100755 gr-utils/src/python/usrp_test_counting.py create mode 100755 gr-utils/src/python/usrp_test_loop.py create mode 100755 gr-utils/src/python/usrp_test_loop_lfsr.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am new file mode 100644 index 000000000..cb8e9811c --- /dev/null +++ b/gr-utils/src/python/Makefile.am @@ -0,0 +1,35 @@ +# +# Copyright 2007 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. +# + +EXTRA_DIST = \ + $(bin_SCRIPTS) + +bin_SCRIPTS = \ + usrp_benchmark_usb.py \ + usrp_fft.py \ + usrp_oscope.py \ + usrp_print_db.py \ + usrp_rx_cfile.py \ + usrp_rx_nogui.py \ + usrp_siggen.py \ + usrp_test_counting.py \ + usrp_test_loop.py \ + usrp_test_loop_lfsr.py diff --git a/gr-utils/src/python/usrp_benchmark_usb.py b/gr-utils/src/python/usrp_benchmark_usb.py new file mode 100755 index 000000000..fc01514a1 --- /dev/null +++ b/gr-utils/src/python/usrp_benchmark_usb.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005 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. +# + +""" +Benchmark the USB/USRP throughput. Finds the maximum full-duplex speed +the USRP/USB combination can sustain without errors. + +This program does not currently give reliable results. Sorry about that... +""" + +from gnuradio import gr +from gnuradio import usrp +from gnuradio import eng_notation + +import sys + +def run_test (usb_throughput, verbose): + # usb_throughput is in bytes/sec. + # + # Returns True or False + + nsec = 1 + stream_length = int (usb_throughput/2 * nsec) # length of stream to examine + + adc_freq = 64e6 + dac_freq = 128e6 + sizeof_sample = 2 * gr.sizeof_short + + usb_throughput_in_samples = usb_throughput / sizeof_sample + + # allocate usb throughput 50/50 between Tx and Rx + + tx_interp = int (dac_freq) / int (usb_throughput_in_samples / 2) + rx_decim = int (adc_freq) / int (usb_throughput_in_samples / 2) + + # print "tx_interp =", tx_interp, "rx_decim =", rx_decim + assert (tx_interp == 2 * rx_decim) + + fg = gr.flow_graph () + + # Build the Tx pipeline + data_src = gr.lfsr_32k_source_s () + src_head = gr.head (gr.sizeof_short, int (stream_length * 2)) + usrp_tx = usrp.sink_s (0, tx_interp) + fg.connect (data_src, src_head, usrp_tx) + + # and the Rx pipeline + usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) + head = gr.head (gr.sizeof_short, stream_length) + check = gr.check_lfsr_32k_s () + fg.connect (usrp_rx, head, check) + + fg.run () + + ntotal = check.ntotal () + nright = check.nright () + runlength = check.runlength () + + if verbose: + print "usb_throughput =", eng_notation.num_to_str (usb_throughput) + print "ntotal =", ntotal + print "nright =", nright + print "runlength =", runlength + print "delta =", ntotal - runlength + + return runlength >= stream_length - 80000 + +def main (): + verbose = True + best_rate = 0 + usb_rate = [ 2e6, 4e6, 8e6, 16e6, 32e6 ] + #usb_rate = [ 32e6, 32e6, 32e6, 32e6, 32e6 ] + # usb_rate.reverse () + for rate in usb_rate: + sys.stdout.write ("Testing %sB/sec... " % (eng_notation.num_to_str (rate))) + sys.stdout.flush () + ok = run_test (rate, verbose) + if ok: + best_rate = max (best_rate, rate) + sys.stdout.write ("OK\n") + else: + sys.stdout.write ("FAILED\n") + + print "Max USB/USRP throughput = %sB/sec" % (eng_notation.num_to_str (best_rate),) + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py new file mode 100755 index 000000000..353c89218 --- /dev/null +++ b/gr-utils/src/python/usrp_fft.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005 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, gru +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui, fftsink, waterfallsink, scopesink, form, slider +from optparse import OptionParser +import wx +import sys + + +def pick_subdevice(u): + """ + The user didn't specify a subdevice on the command line. + If there's a daughterboard on A, select A. + If there's a daughterboard on B, select B. + Otherwise, select A. + """ + if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + return (0, 0) + if u.db[1][0].dbid() >= 0: + return (1, 0) + return (0, 0) + + +class app_flow_graph(stdgui.gui_flow_graph): + def __init__(self, frame, panel, vbox, argv): + stdgui.gui_flow_graph.__init__(self) + + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + parser.add_option("-w", "--which", type="int", default=0, + help="select which USRP (0, 1, ...) default is %default", + metavar="NUM") + parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B (default=first one with a daughterboard)") + parser.add_option("-d", "--decim", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option("-W", "--waterfall", action="store_true", default=False, + help="Enable waterfall display") + parser.add_option("-8", "--width-8", action="store_true", default=False, + help="Enable 8-bit samples across USB") + parser.add_option("-S", "--oscilloscope", action="store_true", default=False, + help="Enable oscilloscope display") + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + + self.show_debug_info = True + + # build the graph + + self.u = usrp.source_c(which=options.which, decim_rate=options.decim) + if options.rx_subdev_spec is None: + options.rx_subdev_spec = pick_subdevice(self.u) + self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) + + if options.width_8: + width = 8 + shift = 8 + format = self.u.make_format(width, shift) + print "format =", hex(format) + r = self.u.set_format(format) + print "set_format =", r + + # determine the daughterboard subdevice we're using + self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) + + input_rate = self.u.adc_freq() / self.u.decim_rate() + + if options.waterfall: + self.scope = \ + waterfallsink.waterfall_sink_c (self, panel, fft_size=1024, sample_rate=input_rate) + elif options.oscilloscope: + self.scope = scopesink.scope_sink_c(self, panel, sample_rate=input_rate) + else: + self.scope = fftsink.fft_sink_c (self, panel, fft_size=1024, sample_rate=input_rate) + + self.connect(self.u, self.scope) + + self._build_gui(vbox) + + # set initial values + + if options.gain is None: + # if no gain was specified, use the mid-point in dB + g = self.subdev.gain_range() + options.gain = float(g[0]+g[1])/2 + + if options.freq is None: + # if no freq was specified, use the mid-point + r = self.subdev.freq_range() + options.freq = float(r[0]+r[1])/2 + + self.set_gain(options.gain) + + if self.show_debug_info: + self.myform['decim'].set_value(self.u.decim_rate()) + self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) + self.myform['dbname'].set_value(self.subdev.name()) + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + if not(self.set_freq(options.freq)): + self._set_status_msg("Failed to set initial frequency") + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,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((5,0), 0, 0) + g = self.subdev.gain_range() + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g[0]), max=int(g[1]), + callback=self.set_gain) + + hbox.Add((5,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_decim(kv): + return self.set_decim(kv['decim']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + #panel = wx.Panel(self.panel, -1) + #vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0) + + myform['decim'] = form.int_field( + parent=panel, sizer=hbox, label="Decim", + callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@usb'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@USB") + + hbox.Add((5,0), 1) + myform['dbname'] = form.static_text_field( + parent=panel, sizer=hbox) + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + r = self.u.tune(0, self.subdev, target_freq) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.baseband_freq) + self.myform['ddc'].set_value(r.dxc_freq) + return True + + return False + + def set_gain(self, gain): + self.myform['gain'].set_value(gain) # update displayed value + self.subdev.set_gain(gain) + + def set_decim(self, decim): + ok = self.u.set_decim_rate(decim) + if not ok: + print "set_decim failed" + input_rate = self.u.adc_freq() / self.u.decim_rate() + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['decim'].set_value(self.u.decim_rate()) + self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) + return ok + +def main (): + app = stdgui.stdapp(app_flow_graph, "USRP FFT", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py new file mode 100755 index 000000000..5d7149281 --- /dev/null +++ b/gr-utils/src/python/usrp_oscope.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005,2006 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. +# + +# print "Loading revised usrp_oscope with additional options for scopesink..." + +from gnuradio import gr, gru +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui, fftsink, waterfallsink, scopesink, form, slider +from optparse import OptionParser +import wx +import sys + + +def pick_subdevice(u): + """ + The user didn't specify a subdevice on the command line. + If there's a daughterboard on A, select A. + If there's a daughterboard on B, select B. + Otherwise, select A. + """ + if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + return (0, 0) + if u.db[1][0].dbid() >= 0: + return (1, 0) + return (0, 0) + + +class app_flow_graph(stdgui.gui_flow_graph): + def __init__(self, frame, panel, vbox, argv): + stdgui.gui_flow_graph.__init__(self) + + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B (default=first one with a daughterboard)") + parser.add_option("-d", "--decim", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option("-8", "--width-8", action="store_true", default=False, + help="Enable 8-bit samples across USB") + parser.add_option("-n", "--frame-decim", type="int", default=1, + help="set oscope frame decimation factor to n [default=1]") + parser.add_option("-v", "--v-scale", type="eng_float", default=1000, + help="set oscope initial V/div to SCALE [default=%default]") + parser.add_option("-t", "--t-scale", type="eng_float", default=49e-6, + help="set oscope initial s/div to SCALE [default=50us]") + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + + self.show_debug_info = True + + # build the graph + + self.u = usrp.source_c(decim_rate=options.decim) + if options.rx_subdev_spec is None: + options.rx_subdev_spec = pick_subdevice(self.u) + self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) + + if options.width_8: + width = 8 + shift = 8 + format = self.u.make_format(width, shift) + #print "format =", hex(format) + r = self.u.set_format(format) + #print "set_format =", r + + # determine the daughterboard subdevice we're using + self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) + + input_rate = self.u.adc_freq() / self.u.decim_rate() + + self.scope = scopesink.scope_sink_c(self, panel, sample_rate=input_rate, + frame_decim=options.frame_decim, + v_scale=options.v_scale, + t_scale=options.t_scale) + self.connect(self.u, self.scope) + + self._build_gui(vbox) + + # set initial values + + if options.gain is None: + # if no gain was specified, use the mid-point in dB + g = self.subdev.gain_range() + options.gain = float(g[0]+g[1])/2 + + if options.freq is None: + # if no freq was specified, use the mid-point + r = self.subdev.freq_range() + options.freq = float(r[0]+r[1])/2 + + self.set_gain(options.gain) + + if self.show_debug_info: + self.myform['decim'].set_value(self.u.decim_rate()) + self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) + self.myform['dbname'].set_value(self.subdev.name()) + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + if not(self.set_freq(options.freq)): + self._set_status_msg("Failed to set initial frequency") + + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,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((5,0), 0, 0) + g = self.subdev.gain_range() + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g[0]), max=int(g[1]), + callback=self.set_gain) + + hbox.Add((5,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_decim(kv): + return self.set_decim(kv['decim']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + #panel = wx.Panel(self.panel, -1) + #vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0) + + myform['decim'] = form.int_field( + parent=panel, sizer=hbox, label="Decim", + callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@usb'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@USB") + + hbox.Add((5,0), 1) + myform['dbname'] = form.static_text_field( + parent=panel, sizer=hbox) + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + r = usrp.tune(self.u, 0, self.subdev, target_freq) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.baseband_freq) + self.myform['ddc'].set_value(r.dxc_freq) + return True + + return False + + def set_gain(self, gain): + self.myform['gain'].set_value(gain) # update displayed value + self.subdev.set_gain(gain) + + def set_decim(self, decim): + ok = self.u.set_decim_rate(decim) + if not ok: + print "set_decim failed" + input_rate = self.u.adc_freq() / self.u.decim_rate() + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['decim'].set_value(self.u.decim_rate()) + self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) + return ok + +def main (): + app = stdgui.stdapp(app_flow_graph, "USRP O'scope", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_print_db.py b/gr-utils/src/python/usrp_print_db.py new file mode 100755 index 000000000..b082cb073 --- /dev/null +++ b/gr-utils/src/python/usrp_print_db.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# +# Copyright 2006,2007 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. +# + +#!/usr/bin/env python + +from gnuradio import gr +from gnuradio import usrp +from optparse import OptionParser +from usrpm import usrp_dbid + +u_source = usrp.source_c() +u_sink = usrp.sink_c() + +subdev_Ar = usrp.selected_subdev(u_source, (0,0)) +subdev_Br = usrp.selected_subdev(u_source, (1,0)) +subdev_At = usrp.selected_subdev(u_sink, (0,0)) +subdev_Bt = usrp.selected_subdev(u_sink, (1,0)) + +print "RX d'board %s" % (subdev_Ar.side_and_name(),) +print "RX d'board %s" % (subdev_Br.side_and_name(),) +print "TX d'board %s" % (subdev_At.side_and_name(),) +print "TX d'board %s" % (subdev_Bt.side_and_name(),) + diff --git a/gr-utils/src/python/usrp_rx_cfile.py b/gr-utils/src/python/usrp_rx_cfile.py new file mode 100755 index 000000000..306e101d3 --- /dev/null +++ b/gr-utils/src/python/usrp_rx_cfile.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +""" +Read samples from the USRP and write to file formatted as binary +outputs single precision complex float values or complex short values (interleaved 16 bit signed short integers). + +""" + +from gnuradio import gr, eng_notation +from gnuradio import audio +from gnuradio import usrp +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +class my_graph(gr.flow_graph): + + def __init__(self): + gr.flow_graph.__init__(self) + + usage="%prog: [options] output_filename" + parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0, 0), + help="select USRP Rx side A or B (default=A)") + parser.add_option("-d", "--decim", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option("-8", "--width-8", action="store_true", default=False, + help="Enable 8-bit samples across USB") + parser.add_option( "--no-hb", action="store_true", default=False, + help="don't use halfband filter in usrp") + parser.add_option( "-s","--output-shorts", action="store_true", default=False, + help="output interleaved shorts in stead of complex floats") + parser.add_option("-N", "--nsamples", type="eng_float", default=None, + help="number of samples to collect [default=+inf]") + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + if options.freq is None: + parser.print_help() + sys.stderr.write('You must specify the frequency with -f FREQ\n'); + raise SystemExit, 1 + + # build the graph + if options.no_hb or (options.decim<8): + self.fpga_filename="std_4rx_0tx.rbf" #Min decimation of this firmware is 4. contains 4 Rx paths without halfbands and 0 tx paths. + if options.output_shorts: + self.u = usrp.source_s(decim_rate=options.decim,fpga_filename=self.fpga_filename) + else: + self.u = usrp.source_c(decim_rate=options.decim,fpga_filename=self.fpga_filename) + else: + #standard fpga firmware "std_2rxhb_2tx.rbf" contains 2 Rx paths with halfband filters and 2 tx paths (the default) min decimation 8 + if options.output_shorts: + self.u = usrp.source_s(decim_rate=options.decim) + else: + self.u = usrp.source_c(decim_rate=options.decim) + if options.width_8: + sample_width = 8 + sample_shift = 8 + format = self.u.make_format(sample_width, sample_shift) + r = self.u.set_format(format) + if options.output_shorts: + self.dst = gr.file_sink(gr.sizeof_short, filename) + else: + self.dst = gr.file_sink(gr.sizeof_gr_complex, filename) + if options.nsamples is None: + self.connect(self.u, self.dst) + else: + if options.output_shorts: + self.head = gr.head(gr.sizeof_short, int(options.nsamples)*2) + else: + self.head = gr.head(gr.sizeof_gr_complex, int(options.nsamples)) + self.connect(self.u, self.head, self.dst) + + if options.rx_subdev_spec is None: + options.rx_subdev_spec = usrp.pick_rx_subdevice(self.u) + self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) + + # determine the daughterboard subdevice we're using + self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) + print "Using RX d'board %s" % (self.subdev.side_and_name(),) + input_rate = self.u.adc_freq() / self.u.decim_rate() + print "USB sample rate %s" % (eng_notation.num_to_str(input_rate)) + + if options.gain is None: + # if no gain was specified, use the mid-point in dB + g = self.subdev.gain_range() + options.gain = float(g[0]+g[1])/2 + + self.subdev.set_gain(options.gain) + + r = self.u.tune(0, self.subdev, options.freq) + if not r: + sys.stderr.write('Failed to set frequency\n') + raise SystemExit, 1 + + +if __name__ == '__main__': + try: + my_graph().run() + except KeyboardInterrupt: + pass diff --git a/gr-utils/src/python/usrp_rx_nogui.py b/gr-utils/src/python/usrp_rx_nogui.py new file mode 100755 index 000000000..b33d626e2 --- /dev/null +++ b/gr-utils/src/python/usrp_rx_nogui.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python + +from gnuradio import gr, gru, usrp, optfir, audio, eng_notation, blks +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +""" +This example application demonstrates receiving and demodulating +different types of signals using the USRP. + +A receive chain is built up of the following signal processing +blocks: + +USRP - Daughter board source generating complex baseband signal. +CHAN - Low pass filter to select channel bandwidth +RFSQL - RF squelch zeroing output when input power below threshold +AGC - Automatic gain control leveling signal at [-1.0, +1.0] +DEMOD - Demodulation block appropriate to selected signal type. + This converts the complex baseband to real audio frequencies, + and applies an appropriate low pass decimating filter. +CTCSS - Optional tone squelch zeroing output when tone is not present. +RSAMP - Resampler block to convert audio sample rate to user specified + sound card output rate. +AUDIO - Audio sink for playing final output to speakers. + +The following are required command line parameters: + +-f FREQ USRP receive frequency +-m MOD Modulation type, select from AM, FM, or WFM + +The following are optional command line parameters: + +-R SUBDEV Daughter board specification, defaults to first found +-c FREQ Calibration offset. Gets added to receive frequency. + Defaults to 0.0 Hz. +-g GAIN Daughterboard gain setting. Defaults to mid-range. +-o RATE Sound card output rate. Defaults to 32000. Useful if + your sound card only accepts particular sample rates. +-r RFSQL RF squelch in db. Defaults to -50.0. +-p FREQ CTCSS frequency. Opens squelch when tone is present. + +Once the program is running, ctrl-break (Ctrl-C) stops operation. + +Please see fm_demod.py and am_demod.py for details of the demodulation +blocks. +""" + +# (usrp_decim, channel_decim, audio_decim, channel_pass, channel_stop, demod) +demod_params = { + 'AM' : (250, 16, 1, 5000, 8000, blks.demod_10k0a3e_cf), + 'FM' : (250, 8, 4, 8000, 9000, blks.demod_20k0f3e_cf), + 'WFM' : (250, 1, 8, 90000, 100000, blks.demod_200kf3e_cf) + } + +class usrp_source_c(gr.hier_block): + """ + Create a USRP source object supplying complex floats. + + Selects user supplied subdevice or chooses first available one. + + Calibration value is the offset from the tuned frequency to + the actual frequency. + """ + def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0): + self._decim = decim + self._src = usrp.source_c() + if subdev_spec is None: + subdev_spec = usrp.pick_rx_subdevice(self._src) + self._subdev = usrp.selected_subdev(self._src, subdev_spec) + self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec)) + self._src.set_decim_rate(self._decim) + + # If no gain specified, set to midrange + if gain is None: + g = self._subdev.gain_range() + gain = (g[0]+g[1])/2.0 + + self._subdev.set_gain(gain) + self._cal = calibration + gr.hier_block.__init__(self, fg, self._src, self._src) + + def tune(self, freq): + result = usrp.tune(self._src, 0, self._subdev, freq+self._cal) + # TODO: deal with residual + + def rate(self): + return self._src.adc_rate()/self._decim + +class app_flow_graph(gr.flow_graph): + def __init__(self, options, args): + gr.flow_graph.__init__(self) + self.options = options + self.args = args + + (usrp_decim, channel_decim, audio_decim, + channel_pass, channel_stop, demod) = demod_params[options.modulation] + + USRP = usrp_source_c(self, # Flow graph + options.rx_subdev_spec, # Daugherboard spec + usrp_decim, # IF decimation ratio + options.gain, # Receiver gain + options.calibration) # Frequency offset + USRP.tune(options.frequency) + + if_rate = USRP.rate() + channel_rate = if_rate // channel_decim + audio_rate = channel_rate // audio_decim + + CHAN_taps = optfir.low_pass(1.0, # Filter gain + if_rate, # Sample rate + channel_pass, # One sided modulation bandwidth + channel_stop, # One sided channel bandwidth + 0.1, # Passband ripple + 60) # Stopband attenuation + + CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate + CHAN_taps, # Filter taps + 0.0, # Offset frequency + if_rate) # Sample rate + + RFSQL = gr.pwr_squelch_cc(options.rf_squelch, # Power threshold + 125.0/channel_rate, # Time constant + channel_rate/20, # 50ms rise/fall + False) # Zero, not gate output + + AGC = gr.agc_cc(1.0/channel_rate, # Time constant + 1.0, # Reference power + 1.0, # Initial gain + 1.0) # Maximum gain + + DEMOD = demod(self, channel_rate, audio_decim) + + # From RF to audio + self.connect(USRP, CHAN, RFSQL, AGC, DEMOD) + + # Optionally add CTCSS and RSAMP if needed + tail = DEMOD + if options.ctcss != None and options.ctcss > 60.0: + CTCSS = gr.ctcss_squelch_ff(audio_rate, # Sample rate + options.ctcss) # Squelch tone + self.connect(DEMOD, CTCSS) + tail = CTCSS + + if options.output_rate != audio_rate: + out_lcm = gru.lcm(audio_rate, options.output_rate) + out_interp = int(out_lcm // audio_rate) + out_decim = int(out_lcm // options.output_rate) + RSAMP = blks.rational_resampler_fff(self, out_interp, out_decim) + self.connect(tail, RSAMP) + tail = RSAMP + + # Send to default audio output + AUDIO = audio.sink(options.output_rate, "") + self.connect(tail, AUDIO) + +def main(): + parser = OptionParser(option_class=eng_option) + parser.add_option("-f", "--frequency", type="eng_float", + help="set receive frequency to Hz", metavar="Hz") + parser.add_option("-R", "--rx-subdev-spec", type="subdev", + help="select USRP Rx side A or B", metavar="SUBDEV") + parser.add_option("-c", "--calibration", type="eng_float", default=0.0, + help="set frequency offset to Hz", metavar="Hz") + parser.add_option("-g", "--gain", type="int", default=None, + help="set RF gain", metavar="dB") + parser.add_option("-m", "--modulation", type="choice", choices=('AM','FM','WFM'), + help="set modulation type (AM,FM)", metavar="TYPE") + parser.add_option("-o", "--output-rate", type="int", default=32000, + help="set audio output rate to RATE", metavar="RATE") + parser.add_option("-r", "--rf-squelch", type="eng_float", default=-50.0, + help="set RF squelch to dB", metavar="dB") + parser.add_option("-p", "--ctcss", type="float", + help="set CTCSS squelch to FREQ", metavar="FREQ") + (options, args) = parser.parse_args() + + if options.frequency < 1e6: + options.frequency *= 1e6 + + fg = app_flow_graph(options, args) + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == "__main__": + main() diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py new file mode 100755 index 000000000..7f5285885 --- /dev/null +++ b/gr-utils/src/python/usrp_siggen.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python + +from gnuradio import gr, gru +from gnuradio import usrp +from gnuradio.eng_option import eng_option +from gnuradio import eng_notation +from optparse import OptionParser +import sys + + +class my_graph(gr.flow_graph): + def __init__ (self): + gr.flow_graph.__init__(self) + + # controllable values + self.interp = 64 + self.waveform_type = gr.GR_SIN_WAVE + self.waveform_ampl = 16000 + self.waveform_freq = 100.12345e3 + self.waveform_offset = 0 + self._instantiate_blocks () + self.set_waveform_type (self.waveform_type) + + def usb_freq (self): + return self.u.dac_freq() / self.interp + + def usb_throughput (self): + return self.usb_freq () * 4 + + def set_waveform_type (self, type): + ''' + valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, + gr.GR_UNIFORM and gr.GR_GAUSSIAN + ''' + self._configure_graph (type) + self.waveform_type = type + + def set_waveform_ampl (self, ampl): + self.waveform_ampl = ampl + self.siggen.set_amplitude (ampl) + self.noisegen.set_amplitude (ampl) + + def set_waveform_freq (self, freq): + self.waveform_freq = freq + self.siggen.set_frequency (freq) + + def set_waveform_offset (self, offset): + self.waveform_offset = offset + self.siggen.set_offset (offset) + + def set_interpolator (self, interp): + self.interp = interp + self.siggen.set_sampling_freq (self.usb_freq ()) + self.u.set_interp_rate (interp) + + def _instantiate_blocks (self): + self.src = None + self.u = usrp.sink_c (0, self.interp) + + self.siggen = gr.sig_source_c (self.usb_freq (), + gr.GR_SIN_WAVE, + self.waveform_freq, + self.waveform_ampl, + self.waveform_offset) + + self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, + self.waveform_ampl) + + # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") + + def _configure_graph (self, type): + was_running = self.is_running () + if was_running: + self.stop () + self.disconnect_all () + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self.connect (self.siggen, self.u) + # self.connect (self.siggen, self.file_sink) + self.siggen.set_waveform (type) + self.src = self.siggen + elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: + self.connect (self.noisegen, self.u) + self.noisegen.set_type (type) + self.src = self.noisegen + else: + raise ValueError, type + if was_running: + self.start () + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital up converter. + """ + r = self.u.tune(self.subdev._which, self.subdev, target_freq) + if r: + #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) + #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) + #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) + #print "r.inverted =", r.inverted + return True + + return False + + + +def main (): + parser = OptionParser (option_class=eng_option) + parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0), + help="select USRP Tx side A or B") + parser.add_option ("-f", "--rf-freq", type="eng_float", default=None, + help="set RF center frequency to FREQ") + parser.add_option ("-i", "--interp", type="int", default=64, + help="set fgpa interpolation rate to INTERP [default=%default]") + + parser.add_option ("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, + help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) + parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, + help="generate a constant output") + parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, + help="generate Gaussian random output") + parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="generate Uniform random output") + + parser.add_option ("-w", "--waveform-freq", type="eng_float", default=100e3, + help="set waveform frequency to FREQ [default=%default]") + parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, + help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") + parser.add_option ("-o", "--offset", type="eng_float", default=0, + help="set waveform offset to OFFSET [default=%default]") + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + raise SystemExit + + if options.rf_freq is None: + sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n") + parser.print_help() + raise SystemExit + + fg = my_graph() + fg.set_interpolator (options.interp) + fg.set_waveform_type (options.type) + fg.set_waveform_freq (options.waveform_freq) + fg.set_waveform_ampl (options.amplitude) + fg.set_waveform_offset (options.offset) + + # determine the daughterboard subdevice we're using + if options.tx_subdev_spec is None: + options.tx_subdev_spec = usrp.pick_tx_subdevice(fg.u) + + m = usrp.determine_tx_mux_value(fg.u, options.tx_subdev_spec) + #print "mux = %#04x" % (m,) + fg.u.set_mux(m) + fg.subdev = usrp.selected_subdev(fg.u, options.tx_subdev_spec) + print "Using TX d'board %s" % (fg.subdev.side_and_name(),) + + fg.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain + + if not fg.set_freq(options.rf_freq): + sys.stderr.write('Failed to set RF frequency\n') + raise SystemExit + + fg.subdev.set_enable(True) # enable transmitter + + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_test_counting.py b/gr-utils/src/python/usrp_test_counting.py new file mode 100755 index 000000000..ccfa948c6 --- /dev/null +++ b/gr-utils/src/python/usrp_test_counting.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright 2004 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. +# + +""" +Check Rx path or USRP Rev 1. + +This configures the USRP to return a periodic sequence of integers +""" + +from gnuradio import gr +from gnuradio import usrp + +def build_graph (): + rx_decim = 32 + + fg = gr.flow_graph () + usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_COUNTING) + sink = gr.check_counting_s () + fg.connect (usrp_rx, sink) + + # file_sink = gr.file_sink (gr.sizeof_short, 'counting.dat') + # fg.connect (usrp_rx, file_sink) + + return fg + +def main (): + fg = build_graph () + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_test_loop.py b/gr-utils/src/python/usrp_test_loop.py new file mode 100755 index 000000000..51a705a05 --- /dev/null +++ b/gr-utils/src/python/usrp_test_loop.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# Copyright 2004 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. +# + +""" +Digital loopback (Tx to Rx) for the USRP Rev1. +""" + + +from gnuradio import gr +from gnuradio import usrp + + +def ramp_source (fg): + period = 2**16 + src = gr.vector_source_s (range (-period/2, period/2, 1), True) + return src + +def build_graph (): + tx_interp = 32 # tx should be twice rx + rx_decim = 16 + + fg = gr.flow_graph () + + data_src = ramp_source (fg) + # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) + usrp_tx = usrp.sink_s (0, tx_interp) + fg.connect (data_src, usrp_tx) + + usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) + sink = gr.check_counting_s () + fg.connect (usrp_rx, sink) + + # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") + # fg.connect (usrp_rx, file_sink) + + return fg + +def main (): + fg = build_graph () + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp_test_loop_lfsr.py b/gr-utils/src/python/usrp_test_loop_lfsr.py new file mode 100755 index 000000000..446ca30a1 --- /dev/null +++ b/gr-utils/src/python/usrp_test_loop_lfsr.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# Copyright 2004 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. +# + +""" +Digital loopback (Tx to Rx) for the USRP Rev1. +""" + +from gnuradio import gr +from gnuradio import usrp + + +def build_graph (): + tx_interp = 32 # tx should be twice rx + rx_decim = 16 + + fg = gr.flow_graph () + + data_src = gr.lfsr_32k_source_s () + + # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) + usrp_tx = usrp.sink_s (0, tx_interp) + + fg.connect (data_src, usrp_tx) + + usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) + + sink = gr.check_lfsr_32k_s () + fg.connect (usrp_rx, sink) + + # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") + # fg.connect (usrp_rx, file_sink) + + return fg + +def main (): + fg = build_graph () + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main () -- cgit From 42c1bfdc72b29f18c5a750a07959d4cc760411b4 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 4 Sep 2007 13:21:24 +0000 Subject: Cleanup on gnuradio-examples restructuring. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6287 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 4 +- gr-utils/src/python/usrp_benchmark_usb.py | 106 ----------------------------- gr-utils/src/python/usrp_test_loop.py | 65 ------------------ gr-utils/src/python/usrp_test_loop_lfsr.py | 62 ----------------- gr-utils/src/python/usrp_test_loopback.py | 65 ++++++++++++++++++ 5 files changed, 66 insertions(+), 236 deletions(-) delete mode 100755 gr-utils/src/python/usrp_benchmark_usb.py delete mode 100755 gr-utils/src/python/usrp_test_loop.py delete mode 100755 gr-utils/src/python/usrp_test_loop_lfsr.py create mode 100755 gr-utils/src/python/usrp_test_loopback.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index cb8e9811c..231153636 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -23,7 +23,6 @@ EXTRA_DIST = \ $(bin_SCRIPTS) bin_SCRIPTS = \ - usrp_benchmark_usb.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ @@ -31,5 +30,4 @@ bin_SCRIPTS = \ usrp_rx_nogui.py \ usrp_siggen.py \ usrp_test_counting.py \ - usrp_test_loop.py \ - usrp_test_loop_lfsr.py + usrp_test_loopback.py diff --git a/gr-utils/src/python/usrp_benchmark_usb.py b/gr-utils/src/python/usrp_benchmark_usb.py deleted file mode 100755 index fc01514a1..000000000 --- a/gr-utils/src/python/usrp_benchmark_usb.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005 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. -# - -""" -Benchmark the USB/USRP throughput. Finds the maximum full-duplex speed -the USRP/USB combination can sustain without errors. - -This program does not currently give reliable results. Sorry about that... -""" - -from gnuradio import gr -from gnuradio import usrp -from gnuradio import eng_notation - -import sys - -def run_test (usb_throughput, verbose): - # usb_throughput is in bytes/sec. - # - # Returns True or False - - nsec = 1 - stream_length = int (usb_throughput/2 * nsec) # length of stream to examine - - adc_freq = 64e6 - dac_freq = 128e6 - sizeof_sample = 2 * gr.sizeof_short - - usb_throughput_in_samples = usb_throughput / sizeof_sample - - # allocate usb throughput 50/50 between Tx and Rx - - tx_interp = int (dac_freq) / int (usb_throughput_in_samples / 2) - rx_decim = int (adc_freq) / int (usb_throughput_in_samples / 2) - - # print "tx_interp =", tx_interp, "rx_decim =", rx_decim - assert (tx_interp == 2 * rx_decim) - - fg = gr.flow_graph () - - # Build the Tx pipeline - data_src = gr.lfsr_32k_source_s () - src_head = gr.head (gr.sizeof_short, int (stream_length * 2)) - usrp_tx = usrp.sink_s (0, tx_interp) - fg.connect (data_src, src_head, usrp_tx) - - # and the Rx pipeline - usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) - head = gr.head (gr.sizeof_short, stream_length) - check = gr.check_lfsr_32k_s () - fg.connect (usrp_rx, head, check) - - fg.run () - - ntotal = check.ntotal () - nright = check.nright () - runlength = check.runlength () - - if verbose: - print "usb_throughput =", eng_notation.num_to_str (usb_throughput) - print "ntotal =", ntotal - print "nright =", nright - print "runlength =", runlength - print "delta =", ntotal - runlength - - return runlength >= stream_length - 80000 - -def main (): - verbose = True - best_rate = 0 - usb_rate = [ 2e6, 4e6, 8e6, 16e6, 32e6 ] - #usb_rate = [ 32e6, 32e6, 32e6, 32e6, 32e6 ] - # usb_rate.reverse () - for rate in usb_rate: - sys.stdout.write ("Testing %sB/sec... " % (eng_notation.num_to_str (rate))) - sys.stdout.flush () - ok = run_test (rate, verbose) - if ok: - best_rate = max (best_rate, rate) - sys.stdout.write ("OK\n") - else: - sys.stdout.write ("FAILED\n") - - print "Max USB/USRP throughput = %sB/sec" % (eng_notation.num_to_str (best_rate),) - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_test_loop.py b/gr-utils/src/python/usrp_test_loop.py deleted file mode 100755 index 51a705a05..000000000 --- a/gr-utils/src/python/usrp_test_loop.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004 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. -# - -""" -Digital loopback (Tx to Rx) for the USRP Rev1. -""" - - -from gnuradio import gr -from gnuradio import usrp - - -def ramp_source (fg): - period = 2**16 - src = gr.vector_source_s (range (-period/2, period/2, 1), True) - return src - -def build_graph (): - tx_interp = 32 # tx should be twice rx - rx_decim = 16 - - fg = gr.flow_graph () - - data_src = ramp_source (fg) - # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) - usrp_tx = usrp.sink_s (0, tx_interp) - fg.connect (data_src, usrp_tx) - - usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) - sink = gr.check_counting_s () - fg.connect (usrp_rx, sink) - - # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") - # fg.connect (usrp_rx, file_sink) - - return fg - -def main (): - fg = build_graph () - try: - fg.run() - except KeyboardInterrupt: - pass - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_test_loop_lfsr.py b/gr-utils/src/python/usrp_test_loop_lfsr.py deleted file mode 100755 index 446ca30a1..000000000 --- a/gr-utils/src/python/usrp_test_loop_lfsr.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004 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. -# - -""" -Digital loopback (Tx to Rx) for the USRP Rev1. -""" - -from gnuradio import gr -from gnuradio import usrp - - -def build_graph (): - tx_interp = 32 # tx should be twice rx - rx_decim = 16 - - fg = gr.flow_graph () - - data_src = gr.lfsr_32k_source_s () - - # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) - usrp_tx = usrp.sink_s (0, tx_interp) - - fg.connect (data_src, usrp_tx) - - usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) - - sink = gr.check_lfsr_32k_s () - fg.connect (usrp_rx, sink) - - # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") - # fg.connect (usrp_rx, file_sink) - - return fg - -def main (): - fg = build_graph () - try: - fg.run() - except KeyboardInterrupt: - pass - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_test_loopback.py b/gr-utils/src/python/usrp_test_loopback.py new file mode 100755 index 000000000..51a705a05 --- /dev/null +++ b/gr-utils/src/python/usrp_test_loopback.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# Copyright 2004 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. +# + +""" +Digital loopback (Tx to Rx) for the USRP Rev1. +""" + + +from gnuradio import gr +from gnuradio import usrp + + +def ramp_source (fg): + period = 2**16 + src = gr.vector_source_s (range (-period/2, period/2, 1), True) + return src + +def build_graph (): + tx_interp = 32 # tx should be twice rx + rx_decim = 16 + + fg = gr.flow_graph () + + data_src = ramp_source (fg) + # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) + usrp_tx = usrp.sink_s (0, tx_interp) + fg.connect (data_src, usrp_tx) + + usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) + sink = gr.check_counting_s () + fg.connect (usrp_rx, sink) + + # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") + # fg.connect (usrp_rx, file_sink) + + return fg + +def main (): + fg = build_graph () + try: + fg.run() + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main () -- cgit From 1de3b0ded031368de377d44305f6aa506e0d6ec5 Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 8 Sep 2007 21:16:25 +0000 Subject: added option to choose the antenna on RFX and WBX boards git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6369 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 353c89218..a8466092d 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -57,6 +57,8 @@ class app_flow_graph(stdgui.gui_flow_graph): metavar="NUM") parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, help="select USRP Rx side A or B (default=first one with a daughterboard)") + parser.add_option("-A", "--antenna", default=None, + help="select Rx Antenna (only on RFX-series boards)") parser.add_option("-d", "--decim", type="int", default=16, help="set fgpa decimation rate to DECIM [default=%default]") parser.add_option("-f", "--freq", type="eng_float", default=None, @@ -122,6 +124,10 @@ class app_flow_graph(stdgui.gui_flow_graph): self.set_gain(options.gain) + if options.antenna is not None: + print "Selecting antenna %s" % (options.antenna,) + self.subdev.select_rx_antenna(options.antenna) + if self.show_debug_info: self.myform['decim'].set_value(self.u.decim_rate()) self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) -- cgit From f1b81c4d4a4d5bc3d040970fa5296be7f932c854 Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 8 Sep 2007 21:17:20 +0000 Subject: added option to set the gain git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6370 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_siggen.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 7f5285885..c2929939c 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -133,6 +133,8 @@ def main (): help="set waveform frequency to FREQ [default=%default]") parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") + parser.add_option ("-g", "--gain", type="eng_float", default=None, + help="set output gain to GAIN [default=%default]") parser.add_option ("-o", "--offset", type="eng_float", default=0, help="set waveform offset to OFFSET [default=%default]") (options, args) = parser.parse_args () @@ -163,7 +165,10 @@ def main (): fg.subdev = usrp.selected_subdev(fg.u, options.tx_subdev_spec) print "Using TX d'board %s" % (fg.subdev.side_and_name(),) - fg.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain + if options.gain is None: + fg.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain + else: + fg.subdev.set_gain(options.gain) # set max Tx gain if not fg.set_freq(options.rf_freq): sys.stderr.write('Failed to set RF frequency\n') -- cgit From e692e71305ecd71d3681fe37f3d76f350d67e276 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 18 Sep 2007 18:59:00 +0000 Subject: Merge r6461:6464 from jcorgan/t162-staging into trunk. * Final gr.top_block and gr.hier_block2 implementation inside gnuradio-core/src/lib/runtime * Implementation of gr.hier_block2 versions of all the old-style blocks in blks. These live in blks2. * Addition of gr.hier_block2 based versions of gr-wxgui blocks * Conversion of all the example code in gnuradio-examples to use this new code * Conversion of all the gr-utils scripts to use the new code The OFDM examples and related hierarchical blocks have not yet been converted. Code in the rest of the tree that is outside the core and example components has also not yet been converted. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6466 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 16 +++---- gr-utils/src/python/usrp_oscope.py | 12 +++--- gr-utils/src/python/usrp_rx_cfile.py | 10 +++-- gr-utils/src/python/usrp_rx_nogui.py | 71 +++++++++++++++++++++---------- gr-utils/src/python/usrp_siggen.py | 36 ++++++++-------- gr-utils/src/python/usrp_test_counting.py | 14 +++--- gr-utils/src/python/usrp_test_loopback.py | 20 ++++----- 7 files changed, 105 insertions(+), 74 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index a8466092d..bdec44ce5 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005 Free Software Foundation, Inc. +# Copyright 2004,2005,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -24,7 +24,7 @@ from gnuradio import gr, gru from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui, fftsink, waterfallsink, scopesink, form, slider +from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider from optparse import OptionParser import wx import sys @@ -44,9 +44,9 @@ def pick_subdevice(u): return (0, 0) -class app_flow_graph(stdgui.gui_flow_graph): +class app_top_block(stdgui2.std_top_block): def __init__(self, frame, panel, vbox, argv): - stdgui.gui_flow_graph.__init__(self) + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) self.frame = frame self.panel = panel @@ -100,11 +100,11 @@ class app_flow_graph(stdgui.gui_flow_graph): if options.waterfall: self.scope = \ - waterfallsink.waterfall_sink_c (self, panel, fft_size=1024, sample_rate=input_rate) + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) elif options.oscilloscope: - self.scope = scopesink.scope_sink_c(self, panel, sample_rate=input_rate) + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: - self.scope = fftsink.fft_sink_c (self, panel, fft_size=1024, sample_rate=input_rate) + self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate) self.connect(self.u, self.scope) @@ -253,7 +253,7 @@ class app_flow_graph(stdgui.gui_flow_graph): return ok def main (): - app = stdgui.stdapp(app_flow_graph, "USRP FFT", nstatus=1) + app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1) app.MainLoop() if __name__ == '__main__': diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index 5d7149281..7c202136e 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2006 Free Software Foundation, Inc. +# Copyright 2004,2005,2006,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -26,7 +26,7 @@ from gnuradio import gr, gru from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui, fftsink, waterfallsink, scopesink, form, slider +from gnuradio.wxgui import stdgui2, scopesink2, form, slider from optparse import OptionParser import wx import sys @@ -46,9 +46,9 @@ def pick_subdevice(u): return (0, 0) -class app_flow_graph(stdgui.gui_flow_graph): +class app_top_block(stdgui2.std_top_block): def __init__(self, frame, panel, vbox, argv): - stdgui.gui_flow_graph.__init__(self) + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) self.frame = frame self.panel = panel @@ -97,7 +97,7 @@ class app_flow_graph(stdgui.gui_flow_graph): input_rate = self.u.adc_freq() / self.u.decim_rate() - self.scope = scopesink.scope_sink_c(self, panel, sample_rate=input_rate, + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate, frame_decim=options.frame_decim, v_scale=options.v_scale, t_scale=options.t_scale) @@ -245,7 +245,7 @@ class app_flow_graph(stdgui.gui_flow_graph): return ok def main (): - app = stdgui.stdapp(app_flow_graph, "USRP O'scope", nstatus=1) + app = stdgui2.stdapp(app_top_block, "USRP O'scope", nstatus=1) app.MainLoop() if __name__ == '__main__': diff --git a/gr-utils/src/python/usrp_rx_cfile.py b/gr-utils/src/python/usrp_rx_cfile.py index 306e101d3..23a7a94d8 100755 --- a/gr-utils/src/python/usrp_rx_cfile.py +++ b/gr-utils/src/python/usrp_rx_cfile.py @@ -11,11 +11,12 @@ from gnuradio import audio from gnuradio import usrp from gnuradio.eng_option import eng_option from optparse import OptionParser +import sys -class my_graph(gr.flow_graph): +class my_top_block(gr.top_block): def __init__(self): - gr.flow_graph.__init__(self) + gr.top_block.__init__(self) usage="%prog: [options] output_filename" parser = OptionParser(option_class=eng_option, usage=usage) @@ -99,9 +100,12 @@ class my_graph(gr.flow_graph): sys.stderr.write('Failed to set frequency\n') raise SystemExit, 1 + def __del__(self): + # Avoid weak reference error + del self.subdev if __name__ == '__main__': try: - my_graph().run() + my_top_block().run() except KeyboardInterrupt: pass diff --git a/gr-utils/src/python/usrp_rx_nogui.py b/gr-utils/src/python/usrp_rx_nogui.py index b33d626e2..a5d792c8b 100755 --- a/gr-utils/src/python/usrp_rx_nogui.py +++ b/gr-utils/src/python/usrp_rx_nogui.py @@ -1,8 +1,29 @@ #!/usr/bin/env python - -from gnuradio import gr, gru, usrp, optfir, audio, eng_notation, blks +# +# Copyright 2006,2007 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, gru, usrp, optfir, audio, eng_notation, blks2 from gnuradio.eng_option import eng_option from optparse import OptionParser +import sys """ This example application demonstrates receiving and demodulating @@ -47,12 +68,12 @@ blocks. # (usrp_decim, channel_decim, audio_decim, channel_pass, channel_stop, demod) demod_params = { - 'AM' : (250, 16, 1, 5000, 8000, blks.demod_10k0a3e_cf), - 'FM' : (250, 8, 4, 8000, 9000, blks.demod_20k0f3e_cf), - 'WFM' : (250, 1, 8, 90000, 100000, blks.demod_200kf3e_cf) + 'AM' : (250, 16, 1, 5000, 8000, blks2.demod_10k0a3e_cf), + 'FM' : (250, 8, 4, 8000, 9000, blks2.demod_20k0f3e_cf), + 'WFM' : (250, 1, 8, 90000, 100000, blks2.demod_200kf3e_cf) } -class usrp_source_c(gr.hier_block): +class usrp_src(gr.hier_block2): """ Create a USRP source object supplying complex floats. @@ -61,7 +82,11 @@ class usrp_source_c(gr.hier_block): Calibration value is the offset from the tuned frequency to the actual frequency. """ - def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0): + def __init__(self, subdev_spec, decim, gain=None, calibration=0.0): + gr.hier_block2.__init__(self, "usrp_src", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature + self._decim = decim self._src = usrp.source_c() if subdev_spec is None: @@ -77,7 +102,7 @@ class usrp_source_c(gr.hier_block): self._subdev.set_gain(gain) self._cal = calibration - gr.hier_block.__init__(self, fg, self._src, self._src) + self.connect(self._src, self) def tune(self, freq): result = usrp.tune(self._src, 0, self._subdev, freq+self._cal) @@ -86,20 +111,18 @@ class usrp_source_c(gr.hier_block): def rate(self): return self._src.adc_rate()/self._decim -class app_flow_graph(gr.flow_graph): - def __init__(self, options, args): - gr.flow_graph.__init__(self) +class app_top_block(gr.top_block): + def __init__(self, options): + gr.top_block.__init__(self) self.options = options - self.args = args (usrp_decim, channel_decim, audio_decim, channel_pass, channel_stop, demod) = demod_params[options.modulation] - USRP = usrp_source_c(self, # Flow graph - options.rx_subdev_spec, # Daugherboard spec - usrp_decim, # IF decimation ratio - options.gain, # Receiver gain - options.calibration) # Frequency offset + USRP = usrp_src(options.rx_subdev_spec, # Daugherboard spec + usrp_decim, # IF decimation ratio + options.gain, # Receiver gain + options.calibration) # Frequency offset USRP.tune(options.frequency) if_rate = USRP.rate() @@ -128,7 +151,7 @@ class app_flow_graph(gr.flow_graph): 1.0, # Initial gain 1.0) # Maximum gain - DEMOD = demod(self, channel_rate, audio_decim) + DEMOD = demod(channel_rate, audio_decim) # From RF to audio self.connect(USRP, CHAN, RFSQL, AGC, DEMOD) @@ -145,7 +168,7 @@ class app_flow_graph(gr.flow_graph): out_lcm = gru.lcm(audio_rate, options.output_rate) out_interp = int(out_lcm // audio_rate) out_decim = int(out_lcm // options.output_rate) - RSAMP = blks.rational_resampler_fff(self, out_interp, out_decim) + RSAMP = blks2.rational_resampler_fff(out_interp, out_decim) self.connect(tail, RSAMP) tail = RSAMP @@ -155,7 +178,7 @@ class app_flow_graph(gr.flow_graph): def main(): parser = OptionParser(option_class=eng_option) - parser.add_option("-f", "--frequency", type="eng_float", + parser.add_option("-f", "--frequency", type="eng_float", default=None, help="set receive frequency to Hz", metavar="Hz") parser.add_option("-R", "--rx-subdev-spec", type="subdev", help="select USRP Rx side A or B", metavar="SUBDEV") @@ -173,12 +196,16 @@ def main(): help="set CTCSS squelch to FREQ", metavar="FREQ") (options, args) = parser.parse_args() + if options.frequency is None: + print "Must supply receive frequency with -f" + sys.exit(1) + if options.frequency < 1e6: options.frequency *= 1e6 - fg = app_flow_graph(options, args) + tb = app_top_block(options) try: - fg.run() + tb.run() except KeyboardInterrupt: pass diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index c2929939c..af6eee167 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -8,9 +8,9 @@ from optparse import OptionParser import sys -class my_graph(gr.flow_graph): +class my_top_block(gr.top_block): def __init__ (self): - gr.flow_graph.__init__(self) + gr.top_block.__init__(self) # controllable values self.interp = 64 @@ -148,36 +148,36 @@ def main (): parser.print_help() raise SystemExit - fg = my_graph() - fg.set_interpolator (options.interp) - fg.set_waveform_type (options.type) - fg.set_waveform_freq (options.waveform_freq) - fg.set_waveform_ampl (options.amplitude) - fg.set_waveform_offset (options.offset) + tb = my_top_block() + tb.set_interpolator (options.interp) + tb.set_waveform_type (options.type) + tb.set_waveform_freq (options.waveform_freq) + tb.set_waveform_ampl (options.amplitude) + tb.set_waveform_offset (options.offset) # determine the daughterboard subdevice we're using if options.tx_subdev_spec is None: - options.tx_subdev_spec = usrp.pick_tx_subdevice(fg.u) + options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u) - m = usrp.determine_tx_mux_value(fg.u, options.tx_subdev_spec) + m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec) #print "mux = %#04x" % (m,) - fg.u.set_mux(m) - fg.subdev = usrp.selected_subdev(fg.u, options.tx_subdev_spec) - print "Using TX d'board %s" % (fg.subdev.side_and_name(),) + tb.u.set_mux(m) + tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec) + print "Using TX d'board %s" % (tb.subdev.side_and_name(),) if options.gain is None: - fg.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain + tb.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain else: - fg.subdev.set_gain(options.gain) # set max Tx gain + tb.subdev.set_gain(options.gain) # set max Tx gain - if not fg.set_freq(options.rf_freq): + if not tb.set_freq(options.rf_freq): sys.stderr.write('Failed to set RF frequency\n') raise SystemExit - fg.subdev.set_enable(True) # enable transmitter + tb.subdev.set_enable(True) # enable transmitter try: - fg.run() + tb.run() except KeyboardInterrupt: pass diff --git a/gr-utils/src/python/usrp_test_counting.py b/gr-utils/src/python/usrp_test_counting.py index ccfa948c6..a8300afe2 100755 --- a/gr-utils/src/python/usrp_test_counting.py +++ b/gr-utils/src/python/usrp_test_counting.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004 Free Software Foundation, Inc. +# Copyright 2004,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,20 +32,20 @@ from gnuradio import usrp def build_graph (): rx_decim = 32 - fg = gr.flow_graph () + tb = gr.top_block () usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_COUNTING) sink = gr.check_counting_s () - fg.connect (usrp_rx, sink) + tb.connect (usrp_rx, sink) # file_sink = gr.file_sink (gr.sizeof_short, 'counting.dat') - # fg.connect (usrp_rx, file_sink) + # tb.connect (usrp_rx, file_sink) - return fg + return tb def main (): - fg = build_graph () + tb = build_graph () try: - fg.run() + tb.run() except KeyboardInterrupt: pass diff --git a/gr-utils/src/python/usrp_test_loopback.py b/gr-utils/src/python/usrp_test_loopback.py index 51a705a05..b58ac06ae 100755 --- a/gr-utils/src/python/usrp_test_loopback.py +++ b/gr-utils/src/python/usrp_test_loopback.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004 Free Software Foundation, Inc. +# Copyright 2004,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -29,7 +29,7 @@ from gnuradio import gr from gnuradio import usrp -def ramp_source (fg): +def ramp_source (tb): period = 2**16 src = gr.vector_source_s (range (-period/2, period/2, 1), True) return src @@ -38,26 +38,26 @@ def build_graph (): tx_interp = 32 # tx should be twice rx rx_decim = 16 - fg = gr.flow_graph () + tb = gr.top_block () - data_src = ramp_source (fg) + data_src = ramp_source (tb) # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) usrp_tx = usrp.sink_s (0, tx_interp) - fg.connect (data_src, usrp_tx) + tb.connect (data_src, usrp_tx) usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) sink = gr.check_counting_s () - fg.connect (usrp_rx, sink) + tb.connect (usrp_rx, sink) # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") - # fg.connect (usrp_rx, file_sink) + # tb.connect (usrp_rx, file_sink) - return fg + return tb def main (): - fg = build_graph () + tb = build_graph () try: - fg.run() + tb.run() except KeyboardInterrupt: pass -- cgit From afa44e7107019fa5207fde4baf9a6f477bd995e9 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Wed, 19 Sep 2007 21:44:17 +0000 Subject: Fix missed variable name change. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6477 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_siggen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index af6eee167..f0a096e2d 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -166,7 +166,7 @@ def main (): print "Using TX d'board %s" % (tb.subdev.side_and_name(),) if options.gain is None: - tb.subdev.set_gain(fg.subdev.gain_range()[1]) # set max Tx gain + tb.subdev.set_gain(tb.subdev.gain_range()[1]) # set max Tx gain else: tb.subdev.set_gain(options.gain) # set max Tx gain -- cgit From 2b552c8dbf35c7efb26b5efd851f4682aa599ba3 Mon Sep 17 00:00:00 2001 From: nldudok1 Date: Sun, 28 Oct 2007 22:08:40 +0000 Subject: added complex and dualchan option for BasicRX and LFRX git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6720 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_oscope.py | 110 +++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index 7c202136e..d985dee03 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -30,6 +30,10 @@ from gnuradio.wxgui import stdgui2, scopesink2, form, slider from optparse import OptionParser import wx import sys +try: + import usrp_dbid +except: + from usrpm import usrp_dbid def pick_subdevice(u): @@ -64,6 +68,10 @@ class app_top_block(stdgui2.std_top_block): help="set gain in dB (default is midpoint)") parser.add_option("-8", "--width-8", action="store_true", default=False, help="Enable 8-bit samples across USB") + parser.add_option("-C", "--basic-complex", action="store_true", default=False, + help="Use both inputs of a basicRX or LFRX as a single Complex input channel") + parser.add_option("-D", "--basic-dualchan", action="store_true", default=False, + help="Use both inputs of a basicRX or LFRX as seperate Real input channels") parser.add_option("-n", "--frame-decim", type="int", default=1, help="set oscope frame decimation factor to n [default=1]") parser.add_option("-v", "--v-scale", type="eng_float", default=1000, @@ -78,11 +86,13 @@ class app_top_block(stdgui2.std_top_block): self.show_debug_info = True # build the graph - - self.u = usrp.source_c(decim_rate=options.decim) + if options.basic_dualchan: + self.num_inputs=2 + else: + self.num_inputs=1 + self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim) if options.rx_subdev_spec is None: options.rx_subdev_spec = pick_subdevice(self.u) - self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) if options.width_8: width = 8 @@ -94,14 +104,47 @@ class app_top_block(stdgui2.std_top_block): # determine the daughterboard subdevice we're using self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) + if (options.basic_complex or options.basic_dualchan ): + if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)): + side = options.rx_subdev_spec[0] # side A = 0, side B = 1 + if options.basic_complex: + #force Basic_RX and LF_RX in complex mode (use both I and Q channel) + print "Receiver daughterboard forced in complex mode. Both inputs will combined to form a single complex channel." + self.dualchan=False + if side==0: + self.u.set_mux(0x00000010) #enable adc 0 and 1 to form a single complex input on side A + else: #side ==1 + self.u.set_mux(0x00000032) #enable adc 3 and 2 to form a single complex input on side B + elif options.basic_dualchan: + #force Basic_RX and LF_RX in dualchan mode (use input A for channel 0 and input B for channel 1) + print "Receiver daughterboard forced in dualchannel mode. Each input will be used to form a seperate channel." + self.dualchan=True + if side==0: + self.u.set_mux(gru.hexint(0xf0f0f1f0)) #enable adc 0, side A to form a real input on channel 0 and adc1,side A to form a real input on channel 1 + else: #side ==1 + self.u.set_mux(0xf0f0f3f2) #enable adc 2, side B to form a real input on channel 0 and adc3,side B to form a real input on channel 1 + else: + sys.stderr.write('options basic_dualchan or basic_complex is only supported for Basic Rx or LFRX at the moment\n') + sys.exit(1) + else: + self.dualchan=False + self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) input_rate = self.u.adc_freq() / self.u.decim_rate() self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate, frame_decim=options.frame_decim, v_scale=options.v_scale, - t_scale=options.t_scale) - self.connect(self.u, self.scope) + t_scale=options.t_scale, + num_inputs=self.num_inputs) + if self.dualchan: + # deinterleave two channels from FPGA + self.di = gr.deinterleave(gr.sizeof_gr_complex) + self.connect(self.u,self.di) + self.connect((self.di,0),(self.scope,0)) + self.connect((self.di,1),(self.scope,1)) + else: + self.connect(self.u, self.scope) self._build_gui(vbox) @@ -113,9 +156,13 @@ class app_top_block(stdgui2.std_top_block): options.gain = float(g[0]+g[1])/2 if options.freq is None: - # if no freq was specified, use the mid-point - r = self.subdev.freq_range() - options.freq = float(r[0]+r[1])/2 + if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)): + #for Basic RX and LFRX if no freq is specified you probably want 0.0 Hz and not 45 GHz + options.freq=0.0 + else: + # if no freq was specified, use the mid-point + r = self.subdev.freq_range() + options.freq = float(r[0]+r[1])/2 self.set_gain(options.gain) @@ -125,9 +172,15 @@ class app_top_block(stdgui2.std_top_block): self.myform['dbname'].set_value(self.subdev.name()) self.myform['baseband'].set_value(0) self.myform['ddc'].set_value(0) + if self.num_inputs==2: + self.myform['baseband2'].set_value(0) + self.myform['ddc2'].set_value(0) if not(self.set_freq(options.freq)): self._set_status_msg("Failed to set initial frequency") + if self.num_inputs==2: + if not(self.set_freq2(options.freq)): + self._set_status_msg("Failed to set initial frequency for channel 2") def _set_status_msg(self, msg): @@ -137,7 +190,9 @@ class app_top_block(stdgui2.std_top_block): def _form_set_freq(kv): return self.set_freq(kv['freq']) - + + def _form_set_freq2(kv): + return self.set_freq2(kv['freq2']) vbox.Add(self.scope.win, 10, wx.EXPAND) # add control area at the bottom @@ -147,8 +202,11 @@ class app_top_block(stdgui2.std_top_block): 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((5,0), 0, 0) + if self.num_inputs==2: + myform['freq2'] = form.float_field( + parent=self.panel, sizer=hbox, label="Center freq2", weight=1, + callback=myform.check_input_and_call(_form_set_freq2, self._set_status_msg)) + hbox.Add((5,0), 0, 0) g = self.subdev.gain_range() myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", weight=3, @@ -201,6 +259,13 @@ class app_top_block(stdgui2.std_top_block): hbox.Add((5,0), 1) myform['ddc'] = form.static_float_field( parent=panel, sizer=hbox, label="DDC") + if self.num_inputs==2: + hbox.Add((1,0), 1) + myform['baseband2'] = form.static_float_field( + parent=panel, sizer=hbox, label="BB2") + hbox.Add((1,0), 1) + myform['ddc2'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC2") hbox.Add((5,0), 0) vbox.Add(hbox, 0, wx.EXPAND) @@ -229,6 +294,29 @@ class app_top_block(stdgui2.std_top_block): return False + def set_freq2(self, target_freq): + """ + Set the center frequency of we're interested in for the second channel. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + r = usrp.tune(self.u, 1, self.subdev, target_freq) + + if r: + self.myform['freq2'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband2'].set_value(r.baseband_freq) + self.myform['ddc2'].set_value(r.dxc_freq) + return True + + return False + def set_gain(self, gain): self.myform['gain'].set_value(gain) # update displayed value self.subdev.set_gain(gain) -- cgit From d3bc8c2ce9fdf9adec90b77e2da44e3b9d0a43bf Mon Sep 17 00:00:00 2001 From: eb Date: Mon, 29 Oct 2007 05:52:44 +0000 Subject: simplified import git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6732 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_oscope.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index d985dee03..25de80526 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -30,10 +30,7 @@ from gnuradio.wxgui import stdgui2, scopesink2, form, slider from optparse import OptionParser import wx import sys -try: - import usrp_dbid -except: - from usrpm import usrp_dbid +from usrpm import usrp_dbid def pick_subdevice(u): -- cgit From 32ea2fe9034c799557cfb63be6f56301a94621f1 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 8 Nov 2007 02:20:57 +0000 Subject: Fixes center frequency display in usrp_fft.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6829 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index bdec44ce5..6ffeb1f03 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -75,7 +75,7 @@ class app_top_block(stdgui2.std_top_block): if len(args) != 0: parser.print_help() sys.exit(1) - + self.options = options self.show_debug_info = True # build the graph @@ -233,7 +233,9 @@ class app_top_block(stdgui2.std_top_block): if self.show_debug_info: self.myform['baseband'].set_value(r.baseband_freq) self.myform['ddc'].set_value(r.dxc_freq) - return True + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.set_baseband_freq(target_freq) + return True return False -- cgit From 6fd683e2bef9b131bcf87dbdd04613b4a11f5e94 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 8 Nov 2007 07:03:45 +0000 Subject: Adds 'double-click to re-center' to usrp_fft.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6832 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 6ffeb1f03..5aee24fe6 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -109,7 +109,8 @@ class app_top_block(stdgui2.std_top_block): self.connect(self.u, self.scope) self._build_gui(vbox) - + self._setup_events() + # set initial values if options.gain is None: @@ -254,6 +255,15 @@ class app_top_block(stdgui2.std_top_block): self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) return ok + def _setup_events(self): + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) + + def evt_left_dclick(self, event): + (ux, uy) = self.scope.win.GetXY(event) + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + def main (): app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1) app.MainLoop() -- cgit From 9e9d90d528c8833c5b6a0a0982d7df198b6c9451 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 8 Nov 2007 19:46:06 +0000 Subject: Adds 'ctrl-double-click to re-center on maximum power' to usrp_fft.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6837 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 5aee24fe6..fae5ae4cd 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -28,7 +28,7 @@ from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, from optparse import OptionParser import wx import sys - +import numpy def pick_subdevice(u): """ @@ -261,8 +261,18 @@ class app_top_block(stdgui2.std_top_block): def evt_left_dclick(self, event): (ux, uy) = self.scope.win.GetXY(event) - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) + if event.CmdDown(): + # Re-center on maximum power + points = self.scope.win._points + ind = numpy.argmax(points[:,1]) + (freq, pwr) = points[ind] + target_freq = freq/self.scope.win._scale_factor + self.set_freq(target_freq) + else: + # Re-center on clicked frequency + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + def main (): app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1) -- cgit From 28edd49f3d5c1e7eb2f3f2826726bf688f037b1f Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 8 Nov 2007 20:50:47 +0000 Subject: Fix for working with peak hold in usrp_fft.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6839 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index fae5ae4cd..58da67147 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -235,7 +235,7 @@ class app_top_block(stdgui2.std_top_block): self.myform['baseband'].set_value(r.baseband_freq) self.myform['ddc'].set_value(r.dxc_freq) if not self.options.waterfall and not self.options.oscilloscope: - self.scope.set_baseband_freq(target_freq) + self.scope.win.set_baseband_freq(target_freq) return True return False @@ -264,9 +264,16 @@ class app_top_block(stdgui2.std_top_block): if event.CmdDown(): # Re-center on maximum power points = self.scope.win._points - ind = numpy.argmax(points[:,1]) + if self.scope.win.peak_hold: + if self.scope.win.peak_vals is not None: + ind = numpy.argmax(self.scope.win.peak_vals) + else: + ind = int(points.shape()[0]/2) + else: + ind = numpy.argmax(points[:,1]) (freq, pwr) = points[ind] target_freq = freq/self.scope.win._scale_factor + print ind, freq, pwr self.set_freq(target_freq) else: # Re-center on clicked frequency -- cgit From 387d6d26a45e1ac037164eea875d87ffae0a1bac Mon Sep 17 00:00:00 2001 From: nldudok1 Date: Fri, 21 Dec 2007 04:43:55 +0000 Subject: bugfix for low decimation rates (dec<8) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7236 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 13 ++++++++++++- gr-utils/src/python/usrp_oscope.py | 14 +++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 58da67147..c98f01eb4 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -69,6 +69,8 @@ class app_top_block(stdgui2.std_top_block): help="Enable waterfall display") parser.add_option("-8", "--width-8", action="store_true", default=False, help="Enable 8-bit samples across USB") + parser.add_option( "--no-hb", action="store_true", default=False, + help="don't use halfband filter in usrp") parser.add_option("-S", "--oscilloscope", action="store_true", default=False, help="Enable oscilloscope display") (options, args) = parser.parse_args() @@ -79,8 +81,17 @@ class app_top_block(stdgui2.std_top_block): self.show_debug_info = True # build the graph + if options.no_hb or (options.decim<8): + #Min decimation of this firmware is 4. + #contains 4 Rx paths without halfbands and 0 tx paths. + self.fpga_filename="std_4rx_0tx.rbf" + self.u = usrp.source_c(which=options.which, decim_rate=options.decim, fpga_filename=self.fpga_filename) + else: + #Min decimation of standard firmware is 8. + #standard fpga firmware "std_2rxhb_2tx.rbf" + #contains 2 Rx paths with halfband filters and 2 tx paths (the default) + self.u = usrp.source_c(which=options.which, decim_rate=options.decim) - self.u = usrp.source_c(which=options.which, decim_rate=options.decim) if options.rx_subdev_spec is None: options.rx_subdev_spec = pick_subdevice(self.u) self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index 25de80526..d3223cba3 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -65,6 +65,8 @@ class app_top_block(stdgui2.std_top_block): help="set gain in dB (default is midpoint)") parser.add_option("-8", "--width-8", action="store_true", default=False, help="Enable 8-bit samples across USB") + parser.add_option( "--no-hb", action="store_true", default=False, + help="don't use halfband filter in usrp") parser.add_option("-C", "--basic-complex", action="store_true", default=False, help="Use both inputs of a basicRX or LFRX as a single Complex input channel") parser.add_option("-D", "--basic-dualchan", action="store_true", default=False, @@ -87,7 +89,17 @@ class app_top_block(stdgui2.std_top_block): self.num_inputs=2 else: self.num_inputs=1 - self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim) + if options.no_hb or (options.decim<8): + #Min decimation of this firmware is 4. + #contains 4 Rx paths without halfbands and 0 tx paths. + self.fpga_filename="std_4rx_0tx.rbf" + self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim, fpga_filename=self.fpga_filename) + else: + #Min decimation of standard firmware is 8. + #standard fpga firmware "std_2rxhb_2tx.rbf" + #contains 2 Rx paths with halfband filters and 2 tx paths (the default) + self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim) + if options.rx_subdev_spec is None: options.rx_subdev_spec = pick_subdevice(self.u) -- cgit From bcb3b35f329f5cfc286c3fd86d349470d29366d5 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Wed, 16 Jan 2008 17:08:47 +0000 Subject: No longer need workaround. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7452 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_rx_cfile.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_rx_cfile.py b/gr-utils/src/python/usrp_rx_cfile.py index 23a7a94d8..3ac9fb56f 100755 --- a/gr-utils/src/python/usrp_rx_cfile.py +++ b/gr-utils/src/python/usrp_rx_cfile.py @@ -100,10 +100,7 @@ class my_top_block(gr.top_block): sys.stderr.write('Failed to set frequency\n') raise SystemExit, 1 - def __del__(self): - # Avoid weak reference error - del self.subdev - + if __name__ == '__main__': try: my_top_block().run() -- cgit From 6c7ee8932b84fa5dca0c88d7d80f2efe0aa30a06 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Fri, 1 Feb 2008 16:48:00 +0000 Subject: Moved gnuradio-core/src/utils/ plotting scripts into gr-utils, with some rework. The gr_plot_data.py class installs into the gnuradio namespace as gnuradio.plot_data, and the remainder of the scripts install into $prefix/bin. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7536 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 20 ++- gr-utils/src/python/README.plot | 40 ++++++ gr-utils/src/python/gr_plot_char.py | 58 +++++++++ gr-utils/src/python/gr_plot_const.py | 208 +++++++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_fft_c.py | 231 ++++++++++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_fft_f.py | 234 +++++++++++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_float.py | 58 +++++++++ gr-utils/src/python/gr_plot_int.py | 58 +++++++++ gr-utils/src/python/gr_plot_iq.py | 180 +++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_short.py | 58 +++++++++ gr-utils/src/python/plot_data.py | 168 +++++++++++++++++++++++++ 11 files changed, 1312 insertions(+), 1 deletion(-) create mode 100644 gr-utils/src/python/README.plot create mode 100755 gr-utils/src/python/gr_plot_char.py create mode 100755 gr-utils/src/python/gr_plot_const.py create mode 100755 gr-utils/src/python/gr_plot_fft_c.py create mode 100755 gr-utils/src/python/gr_plot_fft_f.py create mode 100755 gr-utils/src/python/gr_plot_float.py create mode 100755 gr-utils/src/python/gr_plot_int.py create mode 100755 gr-utils/src/python/gr_plot_iq.py create mode 100755 gr-utils/src/python/gr_plot_short.py create mode 100644 gr-utils/src/python/plot_data.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 231153636..8b190d660 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -19,10 +19,26 @@ # Boston, MA 02110-1301, USA. # +include $(top_srcdir)/Makefile.common + EXTRA_DIST = \ - $(bin_SCRIPTS) + $(bin_SCRIPTS) \ + README.plot + +ourpythondir = $(grpythondir) + +ourpython_PYTHON = \ + plot_data.py bin_SCRIPTS = \ + gr_plot_char.py \ + gr_plot_const.py \ + gr_plot_fft_c.py \ + gr_plot_fft_f.py \ + gr_plot_float.py \ + gr_plot_int.py \ + gr_plot_iq.py \ + gr_plot_short.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ @@ -31,3 +47,5 @@ bin_SCRIPTS = \ usrp_siggen.py \ usrp_test_counting.py \ usrp_test_loopback.py + +MOSTLYCLEANFILES = *~ *.pyc diff --git a/gr-utils/src/python/README.plot b/gr-utils/src/python/README.plot new file mode 100644 index 000000000..0c4657ba9 --- /dev/null +++ b/gr-utils/src/python/README.plot @@ -0,0 +1,40 @@ +* gr_plot_*.py: +These are a collection of Python scripts to enable viewing and analysis of files produced by GNU Radio flow graphs. Most of them work off complex data produced by digital waveforms. + + +** gr_plot_float.py: +Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. + +By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. + + + +** gr_plot_iq.py: +Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. + +By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. + + + +** gr_plot_const.py: +Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. + +By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. + + + +** gr_plot_fft_c.py: +Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). + +The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). + +By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. + + + +** gr_plot_fft_f.py: +Takes a GNU Radio floating point binary file and displays the samples versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). + +The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). + +By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. diff --git a/gr-utils/src/python/gr_plot_char.py b/gr-utils/src/python/gr_plot_char.py new file mode 100755 index 000000000..87a323c9c --- /dev/null +++ b/gr-utils/src/python/gr_plot_char.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio byte/char binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int8 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py new file mode 100755 index 000000000..d9a9daabf --- /dev/null +++ b/gr-utils/src/python/gr_plot_const.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * + from matplotlib.font_manager import fontManager, FontProperties +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +matplotlib.interactive(True) +matplotlib.use('TkAgg') + +class draw_constellation: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16) + self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16) + self.text_block = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length), + weight="heavy", size=16) + self.text_sr = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=16) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(iq) + if(len(iq) == 0): + print "End of File" + else: + self.reals = [r.real for r in iq] + self.imags = [i.imag for i in iq] + + self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') + self.sp_iq.axis([min(self.time), max(self.time), + 1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + + # Subplot for constellation plot + self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold") + self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold") + self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold") + self.plot_const = plot(self.reals, self.imags, 'bo') + self.sp_const.axis([-2, 2, -2, 2]) + + draw() + + def update_plots(self): + self.plot_iq[0].set_data([self.time, self.reals]) + self.plot_iq[1].set_data([self.time, self.imags]) + self.sp_iq.axis([min(self.time), max(self.time), + 1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + + self.plot_const[0].set_data([self.reals, self.imags]) + self.sp_const.axis([-2, 2, -2, 2]) + draw() + + def zoom(self, event): + newxlim = self.sp_iq.get_xlim() + if(newxlim != self.xlim): + self.xlim = newxlim + r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] + i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] + + self.plot_const[0].set_data(r, i) + self.sp_const.axis([-2, 2, -2, 2]) + self.manager.canvas.draw() + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_constellation(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_fft_c.py b/gr-utils/src/python/gr_plot_fft_c.py new file mode 100755 index 000000000..b7b802fd7 --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft_c.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser +from math import log10 + +matplotlib.interactive(True) +matplotlib.use('TkAgg') + +class draw_fft_c: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.iq) + if(len(self.iq) == 0): + print "End of File" + else: + self.reals = [r.real for r in self.iq] + self.imags = [i.imag for i in self.iq] + + self.iq_fft = self.dofft(self.iq) + + self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] + self.freq = self.calc_freq(self.time, self.sample_rate) + + + def dofft(self, iq): + N = len(iq) + iq_fft = fftpack.fftshift(scipy.fft(iq)) # fft and shift axis + iq_fft = [20*log10(abs(i/N)) for i in iq_fft] # convert to decibels, adjust power + return iq_fft + + def calc_freq(self, time, sample_rate): + N = len(time) + Fs = 1.0 / (max(time) - min(time)) + Fn = 0.5 * sample_rate + freq = [-Fn + i*Fs for i in range(N)] + return freq + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') + self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + + # Subplot for constellation plot + self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") + self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold") + self.plot_fft = plot(self.freq, self.iq_fft, '-bo') + self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) + + draw() + + def update_plots(self): + self.plot_iq[0].set_data([self.time, self.reals]) + self.plot_iq[1].set_data([self.time, self.imags]) + self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + + self.plot_fft[0].set_data([self.freq, self.iq_fft]) + self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) + + draw() + + def zoom(self, event): + newxlim = self.sp_iq.get_xlim() + if(newxlim != self.xlim): + self.xlim = newxlim + xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) + xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.iq)) + + iq = self.iq[xmin : xmax] + time = self.time[xmin : xmax] + + iq_fft = self.dofft(iq) + freq = self.calc_freq(time, self.sample_rate) + + self.plot_fft[0].set_data(freq, iq_fft) + self.sp_fft.axis([min(freq), max(freq), + min(iq_fft)-10, max(iq_fft)+10]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_fft_c(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_fft_f.py b/gr-utils/src/python/gr_plot_fft_f.py new file mode 100755 index 000000000..8f545c589 --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft_f.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser +from math import log10 + +matplotlib.interactive(True) +matplotlib.use('TkAgg') + +class draw_fft_f: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.float32 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_f.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + self.floats = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.floats) + if(len(self.floats) == 0): + print "End of File" + else: + self.f_fft = self.dofft(self.floats) + + self.time = [i*(1/self.sample_rate) for i in range(len(self.floats))] + self.freq = self.calc_freq(self.time, self.sample_rate) + + def dofft(self, f): + N = len(f) + f_fft = fftpack.fftshift(scipy.fft(f)) # fft and shift axis + f_dB = list() + for f in f_fft: + try: + f_dB.append(20*log10(abs(f/N))) # convert to decibels, adjust power + except OverflowError: # protect against taking log(0) + f = 1e-14 # not sure if this is the best way to do this + f_dB.append(20*log10(abs(f/N))) + + return f_dB + + def calc_freq(self, time, sample_rate): + N = len(time) + Fs = 1.0 / (max(time) - min(time)) + Fn = 0.5 * sample_rate + freq = [-Fn + i*Fs for i in range(N)] + return freq + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold") + self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_f = plot(self.time, self.floats, 'bo-') + self.sp_f.set_ylim([1.5*min(self.floats), + 1.5*max(self.floats)]) + + # Subplot for constellation plot + self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") + self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold") + self.plot_fft = plot(self.freq, self.f_fft, '-bo') + self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10]) + + draw() + + def update_plots(self): + self.plot_f[0].set_data([self.time, self.floats]) + self.sp_f.set_ylim([1.5*min(self.floats), + 1.5*max(self.floats)]) + + self.plot_fft[0].set_data([self.freq, self.f_fft]) + self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10]) + + draw() + + def zoom(self, event): + newxlim = self.sp_f.get_xlim() + if(newxlim != self.xlim): + self.xlim = newxlim + xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) + xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.floats)) + + f = self.floats[xmin : xmax] + time = self.time[xmin : xmax] + + f_fft = self.dofft(f) + freq = self.calc_freq(time, self.sample_rate) + + self.plot_fft[0].set_data(freq, f_fft) + self.sp_fft.axis([min(freq), max(freq), + min(f_fft)-10, max(f_fft)+10]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio floating point binary file and displays the sample data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_fft_f(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_float.py b/gr-utils/src/python/gr_plot_float.py new file mode 100755 index 000000000..e5c22a315 --- /dev/null +++ b/gr-utils/src/python/gr_plot_float.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.float32 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_int.py b/gr-utils/src/python/gr_plot_int.py new file mode 100755 index 000000000..b44d4360a --- /dev/null +++ b/gr-utils/src/python/gr_plot_int.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int32 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_iq.py b/gr-utils/src/python/gr_plot_iq.py new file mode 100755 index 000000000..2a4142a81 --- /dev/null +++ b/gr-utils/src/python/gr_plot_iq.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +matplotlib.interactive(True) +matplotlib.use('TkAgg') + +class draw_fft: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('key_press_event', self.click) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.iq) + if(len(self.iq) == 0): + print "End of File" + else: + self.reals = [r.real for r in self.iq] + self.imags = [i.imag for i in self.iq] + self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') + self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + + draw() + + def update_plots(self): + self.plot_iq[0].set_data([self.time, self.reals]) + self.plot_iq[1].set_data([self.time, self.imags]) + self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_fft(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_short.py b/gr-utils/src/python/gr_plot_short.py new file mode 100755 index 000000000..3466e0b7d --- /dev/null +++ b/gr-utils/src/python/gr_plot_short.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio short integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int16 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/plot_data.py b/gr-utils/src/python/plot_data.py new file mode 100644 index 000000000..7c79e1714 --- /dev/null +++ b/gr-utils/src/python/plot_data.py @@ -0,0 +1,168 @@ +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +matplotlib.interactive(True) +matplotlib.use('TkAgg') + +class plot_data: + def __init__(self, datatype, filenames, options): + self.hfile = list() + self.legend_text = list() + for f in filenames: + self.hfile.append(open(f, "r")) + self.legend_text.append(f) + + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = datatype + self.sizeof_data = datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_f.get_xlim() + + self.manager = get_current_fig_manager() + connect('key_press_event', self.click) + show() + + def get_data(self, hfile): + self.text_file_pos.set_text("File Position: %d" % (hfile.tell()//self.sizeof_data)) + f = scipy.fromfile(hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.f) + if(len(f) == 0): + print "End of File" + else: + self.f = f + self.time = [i*(1/self.sample_rate) for i in range(len(self.f))] + + def make_plots(self): + self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6]) + self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold") + self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_f = list() + + maxval = -1e12 + minval = 1e12 + + for hf in self.hfile: + # if specified on the command-line, set file pointer + hf.seek(self.sizeof_data*self.start, 1) + + self.get_data(hf) + + # Subplot for real and imaginary parts of signal + self.plot_f += plot(self.time, self.f, 'o-') + maxval = max(maxval, max(self.f)) + minval = min(minval, min(self.f)) + + self.sp_f.set_ylim([1.5*minval, 1.5*maxval]) + + self.leg = self.sp_f.legend(self.plot_f, self.legend_text) + + draw() + + def update_plots(self): + maxval = -1e12 + minval = 1e12 + for hf,p in zip(self.hfile,self.plot_f): + self.get_data(hf) + p.set_data([self.time, self.f]) + maxval = max(maxval, max(self.f)) + minval = min(minval, min(self.f)) + + self.sp_f.set_ylim([1.5*minval, 1.5*maxval]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.update_plots() + + def step_backward(self): + for hf in self.hfile: + # Step back in file position + if(hf.tell() >= 2*self.sizeof_data*self.block_length ): + hf.seek(-2*self.sizeof_data*self.block_length, 1) + else: + hf.seek(-hf.tell(),1) + self.update_plots() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False -- cgit From 46c1c946ef04c91d2d948143095c27d94b64167e Mon Sep 17 00:00:00 2001 From: matt Date: Fri, 15 Feb 2008 18:45:10 +0000 Subject: Show 100 dB git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7707 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index c98f01eb4..d549dd4e3 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -115,7 +115,7 @@ class app_top_block(stdgui2.std_top_block): elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: - self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate) + self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, y_divs = 10) self.connect(self.u, self.scope) -- cgit From 5ede0e2b1457d7c28ad29c5f2322305621a3b26a Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 28 Feb 2008 19:03:55 +0000 Subject: Added reference scaling to fftsink2. Default behavior is unchanged. The new parameter 'ref_scale', defaulting to 1.0, represents a 0 dB y-axis value. Updated usrp_fft.py to display dBFS by setting ref_scale to 32768.0 and ref_level to 0. This results in the full 100 dB of dynamic range being displayed. Updated some gnuradio-examples to use the new parameter. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7863 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index d549dd4e3..30a06911a 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007 Free Software Foundation, Inc. +# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -115,7 +115,8 @@ class app_top_block(stdgui2.std_top_block): elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: - self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, y_divs = 10) + self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, + ref_scale=32768.0, ref_level=0.0, y_divs = 10) self.connect(self.u, self.scope) -- cgit From a2d1e3699e0ce052b9005c708bc8d0c5c4c0ba03 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 28 Feb 2008 19:35:18 +0000 Subject: Make averaging alpha configurable git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7864 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 30a06911a..9a9f75fe6 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -73,6 +73,8 @@ class app_top_block(stdgui2.std_top_block): help="don't use halfband filter in usrp") parser.add_option("-S", "--oscilloscope", action="store_true", default=False, help="Enable oscilloscope display") + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() @@ -116,7 +118,8 @@ class app_top_block(stdgui2.std_top_block): self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, - ref_scale=32768.0, ref_level=0.0, y_divs = 10) + ref_scale=32768.0, ref_level=0.0, y_divs = 10, + avg_alpha=options.avg_alpha) self.connect(self.u, self.scope) -- cgit From f2fa77f61b3d569e475cda12ca683fe419e7bfdd Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 28 Feb 2008 19:40:12 +0000 Subject: Make usrp_fft.py reference scale configurable. Default is 14390, which is the ADC full scale * CORDIC gain in the FPGA DDC. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7865 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 9a9f75fe6..307ad1630 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -75,6 +75,8 @@ class app_top_block(stdgui2.std_top_block): help="Enable oscilloscope display") parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, help="Set fftsink averaging factor, default=[%default]") + parser.add_option("", "--ref-scale", type="eng_float", default=13490.0, + help="Set dBFS=0dB input value, default=[%default]") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() @@ -118,7 +120,7 @@ class app_top_block(stdgui2.std_top_block): self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, - ref_scale=32768.0, ref_level=0.0, y_divs = 10, + ref_scale=options.ref_scale, ref_level=0.0, y_divs = 10, avg_alpha=options.avg_alpha) self.connect(self.u, self.scope) -- cgit From 6fa9db14c7fc024b0c63efced61461a7309febc8 Mon Sep 17 00:00:00 2001 From: trondeau Date: Fri, 7 Mar 2008 19:59:28 +0000 Subject: Adds callback function so that the user can click on a point in the time sequence and highlight it and the corresponding point in the constellation diagram; can cycle forwards and backwards using < and > keys, respectively. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7957 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/gr_plot_const.py | 45 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index d9a9daabf..42c0260dc 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -78,6 +78,7 @@ class draw_constellation: self.manager = get_current_fig_manager() connect('draw_event', self.zoom) connect('key_press_event', self.click) + connect('button_press_event', self.mouse_button_callback) show() def get_data(self): @@ -103,17 +104,25 @@ class draw_constellation: self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') - self.sp_iq.axis([min(self.time), max(self.time), - 1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) + self.plot_iq = self.sp_iq.plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') # Subplot for constellation plot self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold") self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold") self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold") - self.plot_const = plot(self.reals, self.imags, 'bo') + self.plot_const = self.sp_const.plot(self.reals, self.imags, 'bo') + + # Add plots to mark current location of point between time and constellation plots + self.indx = 0 + self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.reals[self.indx],], 'mo', ms=8) + self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.imags[self.indx],], 'mo', ms=8) + self.plot_const += self.sp_const.plot([self.reals[self.indx],], [self.imags[self.indx],], 'mo', ms=12) + + # Adjust axis + self.sp_iq.axis([min(self.time), max(self.time), + 1.5*min([min(self.reals), min(self.imags)]), + 1.5*max([max(self.reals), max(self.imags)])]) self.sp_const.axis([-2, 2, -2, 2]) draw() @@ -144,6 +153,8 @@ class draw_constellation: def click(self, event): forward_valid_keys = [" ", "down", "right"] backward_valid_keys = ["up", "left"] + trace_forward_valid_keys = [">",] + trace_backward_valid_keys = ["<",] if(find(event.key, forward_valid_keys)): self.step_forward() @@ -151,6 +162,14 @@ class draw_constellation: elif(find(event.key, backward_valid_keys)): self.step_backward() + elif(find(event.key, trace_forward_valid_keys)): + self.indx = min(self.indx+1, len(self.time)-1) + self.set_trace(self.indx) + + elif(find(event.key, trace_backward_valid_keys)): + self.indx = max(0, self.indx-1) + self.set_trace(self.indx) + def button_left_click(self, event): self.step_backward() @@ -169,7 +188,23 @@ class draw_constellation: self.hfile.seek(-self.hfile.tell(),1) self.get_data() self.update_plots() + + def mouse_button_callback(self, event): + x, y = event.xdata, event.ydata + + if x is not None and y is not None: + if(event.inaxes == self.sp_iq): + self.indx = searchsorted(self.time, [x]) + self.set_trace(self.indx) + + + def set_trace(self, indx): + self.plot_iq[2].set_data(self.time[indx], self.reals[indx]) + self.plot_iq[3].set_data(self.time[indx], self.imags[indx]) + self.plot_const[1].set_data(self.reals[indx], self.imags[indx]) + draw() + def find(item_in, list_search): try: -- cgit From 4d5e702b2a7d511f22b8e5dcce7da5ce77a2d322 Mon Sep 17 00:00:00 2001 From: eb Date: Tue, 24 Jun 2008 20:48:39 +0000 Subject: removed is_running method from gr_top_block git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@8689 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_siggen.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index f0a096e2d..add3888ba 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -69,23 +69,22 @@ class my_top_block(gr.top_block): # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") def _configure_graph (self, type): - was_running = self.is_running () - if was_running: - self.stop () - self.disconnect_all () - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, self.u) - # self.connect (self.siggen, self.file_sink) - self.siggen.set_waveform (type) - self.src = self.siggen - elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, self.u) - self.noisegen.set_type (type) - self.src = self.noisegen - else: - raise ValueError, type - if was_running: - self.start () + try: + self.lock() + self.disconnect_all () + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self.connect (self.siggen, self.u) + # self.connect (self.siggen, self.file_sink) + self.siggen.set_waveform (type) + self.src = self.siggen + elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: + self.connect (self.noisegen, self.u) + self.noisegen.set_type (type) + self.src = self.noisegen + else: + raise ValueError, type + finally: + self.unlock() def set_freq(self, target_freq): """ -- cgit From f6195a3edd1eac5c5109ad6ffeb744cb7238cb55 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 10 Jul 2008 17:54:45 +0000 Subject: Adds lsusrp to gr-utils, obsoletes usrp_print_db.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@8857 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 1 + gr-utils/src/python/lsusrp | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100755 gr-utils/src/python/lsusrp (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 8b190d660..6852bbe1a 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -39,6 +39,7 @@ bin_SCRIPTS = \ gr_plot_int.py \ gr_plot_iq.py \ gr_plot_short.py \ + lsusrp \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ diff --git a/gr-utils/src/python/lsusrp b/gr-utils/src/python/lsusrp new file mode 100755 index 000000000..df52c608e --- /dev/null +++ b/gr-utils/src/python/lsusrp @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright 2008 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. +# + +MAX_USRPS = 8 + +from gnuradio import usrp +from optparse import OptionParser + +def disp_usrp(which): + u_source = usrp.source_c(which=which) + u_sink = usrp.sink_c(which=which) + + print "USRP", which, "serial number", u_source.serial_number() + subdev_A_rx = usrp.selected_subdev(u_source, (0,0)) + subdev_B_rx = usrp.selected_subdev(u_source, (1,0)) + subdev_A_tx = usrp.selected_subdev(u_sink, (0,0)) + subdev_B_tx = usrp.selected_subdev(u_sink, (1,0)) + print " RX d'board %s" % (subdev_A_rx.side_and_name(),) + print " RX d'board %s" % (subdev_B_rx.side_and_name(),) + print " TX d'board %s" % (subdev_A_tx.side_and_name(),) + print " TX d'board %s" % (subdev_B_tx.side_and_name(),) + +if __name__ == "__main__": + parser = OptionParser() + parser.add_option("-w", "--which", type="int", default=None, + help="select which USRP (0, 1, ...) default is all found", + metavar="NUM") + (options, args) = parser.parse_args() + if len(args) > 0: + print parser.print_help() + raise SystemExit, 1 + + if options.which is not None: + try: + disp_usrp(options.which) + except: + print "USRP", options.which, "not found." + else: + for n in range(MAX_USRPS): + try: + disp_usrp(n) + except: + pass + -- cgit From 241300330cfe393a3c19b7b1bedf87c127d649db Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 10 Jul 2008 19:56:51 +0000 Subject: Add lookup by serial number. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@8858 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/lsusrp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/lsusrp b/gr-utils/src/python/lsusrp index df52c608e..d2eab33fe 100755 --- a/gr-utils/src/python/lsusrp +++ b/gr-utils/src/python/lsusrp @@ -25,9 +25,14 @@ MAX_USRPS = 8 from gnuradio import usrp from optparse import OptionParser -def disp_usrp(which): +def disp_usrp(which, serial=None): u_source = usrp.source_c(which=which) u_sink = usrp.sink_c(which=which) + u_serial = u_source.serial_number() + + if serial is not None: + if serial != u_serial: + raise ValueError print "USRP", which, "serial number", u_source.serial_number() subdev_A_rx = usrp.selected_subdev(u_source, (0,0)) @@ -44,11 +49,18 @@ if __name__ == "__main__": parser.add_option("-w", "--which", type="int", default=None, help="select which USRP (0, 1, ...) default is all found", metavar="NUM") + parser.add_option("-s", "--serial", default=None, + help="select USRP by serial number", + metavar="SER") (options, args) = parser.parse_args() if len(args) > 0: print parser.print_help() raise SystemExit, 1 + if options.serial is not None and options.which is not None: + print "Use of --which or --serial is exclusive" + raise SystemExit, 1 + if options.which is not None: try: disp_usrp(options.which) @@ -57,7 +69,7 @@ if __name__ == "__main__": else: for n in range(MAX_USRPS): try: - disp_usrp(n) + disp_usrp(n, options.serial) except: pass -- cgit From 36649d4e472172fe840444ac0268c7b6b4da94b4 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 14 Aug 2008 18:43:15 +0000 Subject: Merged changeset r9241:9289 from jblum/glwxgui into trunk. Adds OpenGL versions of fftsink, waterfallsink, and scopesink, and new constsink. See README.gl for use. (Josh Blum) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9290 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 307ad1630..8a9008877 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -251,7 +251,7 @@ class app_top_block(stdgui2.std_top_block): if self.show_debug_info: self.myform['baseband'].set_value(r.baseband_freq) self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.waterfall and not self.options.oscilloscope: + if not self.options.oscilloscope: self.scope.win.set_baseband_freq(target_freq) return True -- cgit From e0fcbaee124d3e8c4c11bdda662f88e082352058 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 8 Sep 2008 01:00:12 +0000 Subject: Merged r9433:9527 from features/gr-usrp2 into trunk. Adds usrp2 and gr-usrp2 top-level components. Trunk passes distcheck with mb-gcc installed, but currently not without them. The key issue is that when mb-gcc is not installed, the build system skips over the usrp2/firmware directory, and the firmware include files don't get put into the dist tarball. But we can't do the usual DIST_SUBDIRS method as the firmware is a subpackage. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9528 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 4 +- gr-utils/src/python/usrp2_fft.py | 268 ++++++++++++++++++++++++++++++++++ gr-utils/src/python/usrp2_rx_cfile.py | 119 +++++++++++++++ 3 files changed, 390 insertions(+), 1 deletion(-) create mode 100755 gr-utils/src/python/usrp2_fft.py create mode 100755 gr-utils/src/python/usrp2_rx_cfile.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 6852bbe1a..a48180b49 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -47,6 +47,8 @@ bin_SCRIPTS = \ usrp_rx_nogui.py \ usrp_siggen.py \ usrp_test_counting.py \ - usrp_test_loopback.py + usrp_test_loopback.py \ + usrp2_fft.py \ + usrp2_rx_cfile.py MOSTLYCLEANFILES = *~ *.pyc diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py new file mode 100755 index 000000000..f4303f1f8 --- /dev/null +++ b/gr-utils/src/python/usrp2_fft.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005,2007,2008 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, gru +from gnuradio import usrp2 +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider +from optparse import OptionParser +import wx +import sys +import numpy + +class app_top_block(stdgui2.std_top_block): + def __init__(self, frame, panel, vbox, argv): + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + parser.add_option("-e", "--interface", type="string", default="eth0", + help="select Ethernet interface, default is eth0") + parser.add_option("-m", "--mac-addr", type="string", default="", + help="select USRP by MAC address, default is auto-select") + #parser.add_option("-A", "--antenna", default=None, + # help="select Rx Antenna (only on RFX-series boards)") + parser.add_option("-d", "--decim", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option("-W", "--waterfall", action="store_true", default=False, + help="Enable waterfall display") + parser.add_option("-S", "--oscilloscope", action="store_true", default=False, + help="Enable oscilloscope display") + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") + parser.add_option("", "--ref-scale", type="eng_float", default=1.0, + help="Set dBFS=0dB input value, 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.u = usrp2.source_32fc(options.interface, options.mac_addr) + self.u.set_decim(options.decim) + + #input_rate = self.u.adc_freq() / self.u.decim_rate() + input_rate = 100e6/options.decim + + if options.waterfall: + self.scope = \ + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + elif options.oscilloscope: + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) + else: + self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, + ref_scale=options.ref_scale, ref_level=0.0, y_divs = 10, + avg_alpha=options.avg_alpha) + + self.connect(self.u, self.scope) + + self._build_gui(vbox) + self._setup_events() + + # set initial values + + if options.gain is None: + # if no gain was specified, use the mid-point in dB + #g = self.subdev.gain_range() + #options.gain = float(g[0]+g[1])/2 + options.gain = 0 + + if options.freq is None: + # if no freq was specified, use the mid-point + #r = self.subdev.freq_range() + #options.freq = float(r[0]+r[1])/2 + options.freq = 0 + + self.set_gain(options.gain) + + #if options.antenna is not None: + # print "Selecting antenna %s" % (options.antenna,) + # self.subdev.select_rx_antenna(options.antenna) + + if self.show_debug_info: + self.myform['decim'].set_value(options.decim) + self.myform['fs@usb'].set_value(100e6/options.decim) #self.u.adc_freq() / self.u.decim_rate()) + #self.myform['dbname'].set_value(self.subdev.name()) + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + if not(self.u.set_center_freq(options.freq)): + self._set_status_msg("Failed to set initial frequency") + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,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((5,0), 0, 0) + #g = self.subdev.gain_range() + g = [0, 100, 1] #FIXME + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g[0]), max=int(g[1]), + callback=self.set_gain) + + hbox.Add((5,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_decim(kv): + return self.set_decim(kv['decim']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + #panel = wx.Panel(self.panel, -1) + #vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0) + + myform['decim'] = form.int_field( + parent=panel, sizer=hbox, label="Decim", + callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@usb'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@USB") + + hbox.Add((5,0), 1) + myform['dbname'] = form.static_text_field( + parent=panel, sizer=hbox) + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + r = self.u.set_center_freq(target_freq) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.baseband_freq) + self.myform['ddc'].set_value(r.dxc_freq) + if not self.options.oscilloscope: + self.scope.win.set_baseband_freq(target_freq) + return True + + return False + + def set_gain(self, gain): + self.myform['gain'].set_value(gain) # update displayed value + self.u.set_gain(gain) + + def set_decim(self, decim): + ok = self.u.set_decim(decim) + if not ok: + print "set_decim failed" + #input_rate = self.u.adc_freq() / self.u.decim_rate() + input_rate = 100e6/decim # FIXME + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['decim'].set_value(decim) #self.u.decim_rate()) + self.myform['fs@usb'].set_value(input_rate) #self.u.adc_freq() / self.u.decim_rate()) + return ok + + def _setup_events(self): + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) + + def evt_left_dclick(self, event): + (ux, uy) = self.scope.win.GetXY(event) + if event.CmdDown(): + # Re-center on maximum power + points = self.scope.win._points + if self.scope.win.peak_hold: + if self.scope.win.peak_vals is not None: + ind = numpy.argmax(self.scope.win.peak_vals) + else: + ind = int(points.shape()[0]/2) + else: + ind = numpy.argmax(points[:,1]) + (freq, pwr) = points[ind] + target_freq = freq/self.scope.win._scale_factor + print ind, freq, pwr + self.set_freq(target_freq) + else: + # Re-center on clicked frequency + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + + +def main (): + app = stdgui2.stdapp(app_top_block, "USRP2 FFT", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () diff --git a/gr-utils/src/python/usrp2_rx_cfile.py b/gr-utils/src/python/usrp2_rx_cfile.py new file mode 100755 index 000000000..9ab28607d --- /dev/null +++ b/gr-utils/src/python/usrp2_rx_cfile.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +""" +Read samples from the USRP2 and write to file formatted as binary +outputs single precision complex float values or complex short values (interleaved 16 bit signed short integers). + +""" + +from gnuradio import gr, eng_notation +from gnuradio import usrp2 +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import sys + +n2s = eng_notation.num_to_str + +class rx_cfile_block(gr.top_block): + + def __init__(self, options, filename): + gr.top_block.__init__(self) + + # Create a USRP2 source + if options.output_shorts: + self._u = usrp2.source_16sc(options.interface, options.mac_addr) + self._sink = gr.file_sink(gr.sizeof_short*2, filename) + else: + self._u = usrp2.source_32fc(options.interface, options.mac_addr) + self._sink = gr.file_sink(gr.sizeof_gr_complex, filename) + + # Set receiver decimation rate + self._u.set_decim(options.decim) + + # Set receive daughterboard gain + if options.gain is None: + #g = self._u.gain_range() + #options.gain = float(g[0]+g[1])/2 + options.gain = 0 # Until gain range is implemented + self._u.set_gain(options.gain) + + # Set receive frequency + tr = self._u.set_center_freq(options.freq) + if tr == None: + sys.stderr.write('Failed to set center frequency\n') + raise SystemExit, 1 + + # Create head block if needed wire it up + if options.nsamples is None: + self.connect(self._u, self._sink) + else: + if options.output_shorts: + self._head = gr.head(gr.sizeof_short*2, int(options.nsamples)) + else: + self._head = gr.head(gr.sizeof_gr_complex, int(options.nsamples)) + + self.connect(self._u, self._head, self._sink) + + #input_rate = self.u.adc_freq() / self.u.decim_rate() + input_rate = 100e6/options.decim + + if options.verbose: + print "Network interface:", options.interface + print "USRP2 address:", self._u.mac_addr() + #print "Using RX d'board %s" % (self._u.rx_name(),) + print "Rx gain:", options.gain + print "Rx baseband frequency:", n2s(tr.baseband_freq) + print "Rx DDC frequency:", n2s(tr.dxc_freq) + print "Rx residual frequency:", n2s(tr.residual_freq) + print "Rx decimation rate:", options.decim + print "Rx sample rate:", n2s(input_rate) + if options.nsamples is None: + print "Receiving samples until Ctrl-C" + else: + print "Receving", n2s(options.nsamples), "samples" + if options.output_shorts: + print "Writing 16-bit complex shorts" + else: + print "Writing 32-bit complex floats" + print "Output filename:", filename + +def get_options(): + usage="%prog: [options] output_filename" + parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-e", "--interface", type="string", default="eth0", + help="use specified Ethernet interface [default=%default]") + parser.add_option("-m", "--mac-addr", type="string", default="", + help="use USRP2 at specified MAC address [default=None]") + parser.add_option("-d", "--decim", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-f", "--freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set gain in dB (default is midpoint)") + parser.add_option( "-s","--output-shorts", action="store_true", default=False, + help="output interleaved shorts instead of complex floats") + parser.add_option("-N", "--nsamples", type="eng_float", default=None, + help="number of samples to collect [default=+inf]") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="verbose output") + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + + if options.freq is None: + parser.print_help() + sys.stderr.write('You must specify the frequency with -f FREQ\n'); + raise SystemExit, 1 + + return (options, args[0]) + + +if __name__ == '__main__': + (options, filename) = get_options() + tb = rx_cfile_block(options, filename) + + try: + tb.run() + except KeyboardInterrupt: + pass -- cgit From 16699b8ac2ab0c98ad3593b573e409ce39f9eb7c Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 23 Sep 2008 19:39:09 +0000 Subject: Adds usrp2_siggen.py to gr-utils, missed copyright notices git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9642 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 5 +- gr-utils/src/python/usrp2_rx_cfile.py | 20 +++++ gr-utils/src/python/usrp2_siggen.py | 143 ++++++++++++++++++++++++++++++++++ gr-utils/src/python/usrp_siggen.py | 20 +++++ 4 files changed, 186 insertions(+), 2 deletions(-) create mode 100755 gr-utils/src/python/usrp2_siggen.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index a48180b49..8b83dea73 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -49,6 +49,7 @@ bin_SCRIPTS = \ usrp_test_counting.py \ usrp_test_loopback.py \ usrp2_fft.py \ - usrp2_rx_cfile.py - + usrp2_rx_cfile.py \ + usrp2_siggen.py + MOSTLYCLEANFILES = *~ *.pyc diff --git a/gr-utils/src/python/usrp2_rx_cfile.py b/gr-utils/src/python/usrp2_rx_cfile.py index 9ab28607d..539b3e3d3 100755 --- a/gr-utils/src/python/usrp2_rx_cfile.py +++ b/gr-utils/src/python/usrp2_rx_cfile.py @@ -1,4 +1,24 @@ #!/usr/bin/env python +# +# Copyright 2004,2005,2007,2008 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. +# """ Read samples from the USRP2 and write to file formatted as binary diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py new file mode 100755 index 000000000..b4aee240a --- /dev/null +++ b/gr-utils/src/python/usrp2_siggen.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# +# Copyright 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, eng_notation +from gnuradio import usrp2 +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import sys + +n2s = eng_notation.num_to_str + +class siggen_top_block(gr.top_block): + def __init__(self, options): + gr.top_block.__init__(self) + + # Create a USRP2 sink with the requested interpolation rate + self._u = usrp2.sink_32fc(options.interface, options.mac_addr) + self._u.set_interp(options.interp) + + # Set the Tx daughterboard gain as requested + if options.gain is None: + #g = self._u.gain_range() + #options.gain = float(g[0]+g[1])/2 + options.gain = 0 # Until gain range is implemented + self._u.set_gain(options.gain) + + # Tune the USRP2 FPGA and daughterboard to the requested center frequency + tr = self._u.set_center_freq(options.tx_freq) + if tr == None: + sys.stderr.write('Failed to set center frequency\n') + raise SystemExit, 1 + + #eth_rate = self._u.dac_rate()/self._u.interp_rate() + eth_rate = 100e6/options.interp # FIXME + + # Create a source for the requested waveform type + if options.type == gr.GR_SIN_WAVE or options.type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(eth_rate, # Sample rate + options.type, # Waveform type + options.waveform_freq, # Waveform frequency + options.amplitude, # Waveform amplitude + options.offset) # Waveform offset + + elif options.type == gr.GR_GAUSSIAN or options.type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(options.type, options.amplitude) + else: + sys.stderr.write('Unknown waveform type\n') + raise SystemExit, 1 + + if options.verbose: + print "Network interface:", options.interface + print "USRP2 address:", self._u.mac_addr() + #print "Using TX d'board %s" % (self._u.tx_name(),) + print "Tx gain:", options.gain + print "Tx baseband frequency:", n2s(tr.baseband_freq), "Hz" + print "Tx DDC frequency:", n2s(tr.dxc_freq), "Hz" + print "Tx residual frequency:", n2s(tr.residual_freq), "Hz" + print "Tx interpolation rate:", options.interp + print "Tx GbE sample rate:", n2s(eth_rate), "samples/sec" + if options.type == gr.GR_SIN_WAVE: + print "Baseband waveform type: Sine wave" + print "Baseband waveform frequency:", n2s(options.waveform_freq), "Hz" + elif options.type == gr.GR_CONST_WAVE: + print "Baseband waveform type: Constant" + elif options.type == gr.GR_GAUSSIAN: + print "Baseband waveform type: Gaussian noise" + elif options.type == gr.GR_UNIFORM: + print "Baseband waveform type: Uniform noise" + + # Wire the flowgraph + self.connect(self._src, self._u) + +def get_options(): + usage="%prog: [options]" + + parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-e", "--interface", type="string", default="eth0", + help="use specified Ethernet interface [default=%default]") + parser.add_option("-m", "--mac-addr", type="string", default="", + help="use USRP2 at specified MAC address [default=None]") + parser.add_option("-i", "--interp", type="int", default=16, + help="set fgpa decimation rate to DECIM [default=%default]") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="set output gain to GAIN [default=%default]") + parser.add_option("-f", "--tx-freq", type="eng_float", default=None, + help="set frequency to FREQ", metavar="FREQ") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="verbose output") + parser.add_option("-w", "--waveform-freq", type="eng_float", default=100e3, + help="set waveform frequency to FREQ [default=%default]") + parser.add_option("-a", "--amplitude", type="eng_float", default=0.5, + help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") + parser.add_option("--offset", type="eng_float", default=0, + help="set waveform offset to OFFSET [default=%default]") + parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, + help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) + parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, + help="generate a constant output") + parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, + help="generate Gaussian random output") + parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="generate Uniform random output") + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + if options.tx_freq is None: + parser.print_help() + sys.stderr.write('You must specify the frequency with -f FREQ\n'); + raise SystemExit, 1 + + return options + + +if __name__ == '__main__': + options = get_options() + tb = siggen_top_block(options) + + try: + tb.run() + except KeyboardInterrupt: + pass diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index add3888ba..876b40056 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -1,4 +1,24 @@ #!/usr/bin/env python +# +# Copyright 2004,2005,2007,2008 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, gru from gnuradio import usrp -- cgit From b8ee82bdaac2b4ab3cac429e2dbd60b98d587547 Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 11 Oct 2008 19:28:45 +0000 Subject: Defaulting to a baseband frequency of 100kHz confuses everyone. Make the default 0 git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9777 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_siggen.py | 2 +- gr-utils/src/python/usrp_siggen.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index b4aee240a..26b7916ab 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -105,7 +105,7 @@ def get_options(): help="set frequency to FREQ", metavar="FREQ") parser.add_option("-v", "--verbose", action="store_true", default=False, help="verbose output") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=100e3, + parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, help="set waveform frequency to FREQ [default=%default]") parser.add_option("-a", "--amplitude", type="eng_float", default=0.5, help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 876b40056..fe29787f9 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -148,7 +148,7 @@ def main (): parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, help="generate Uniform random output") - parser.add_option ("-w", "--waveform-freq", type="eng_float", default=100e3, + parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0, help="set waveform frequency to FREQ [default=%default]") parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") -- cgit From e528d03294cf9785137228766097acae9351dd08 Mon Sep 17 00:00:00 2001 From: trondeau Date: Sat, 25 Oct 2008 21:22:12 +0000 Subject: updating FFT plotting utilities. New file gr_plot_fft.py can plot any data type with -d flag and gr_plot_fft_c and gr_plot_fft_f just call this one and pass in complex of float data types. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9842 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 1 + gr-utils/src/python/gr_plot_fft.py | 252 +++++++++++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_fft_c.py | 195 +-------------------------- gr-utils/src/python/gr_plot_fft_f.py | 198 +-------------------------- 4 files changed, 261 insertions(+), 385 deletions(-) create mode 100755 gr-utils/src/python/gr_plot_fft.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 8b83dea73..db0d688f5 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -33,6 +33,7 @@ ourpython_PYTHON = \ bin_SCRIPTS = \ gr_plot_char.py \ gr_plot_const.py \ + gr_plot_fft.py \ gr_plot_fft_c.py \ gr_plot_fft_f.py \ gr_plot_float.py \ diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py new file mode 100755 index 000000000..fa205e69a --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import matplotlib + matplotlib.use('TkAgg') + matplotlib.interactive(True) +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +class gr_plot_fft: + def __init__(self, datatype, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = getattr(scipy, datatype) + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 12), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.35, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + position = self.hfile.tell()/self.sizeof_data + self.text_file_pos.set_text("File Position: %d" % (position)) + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.iq) + if(len(self.iq) == 0): + print "End of File" + else: + self.iq_fft = self.dofft(self.iq) + + tstep = 1.0 / self.sample_rate + self.time = [tstep*position + tstep*(position + i) for i in xrange(len(self.iq))] + + self.freq = self.calc_freq(self.time, self.sample_rate) + + def dofft(self, iq): + N = len(iq) + iq_fft = fftpack.fftshift(scipy.fft(iq)) # fft and shift axis + iq_fft = 20*scipy.log10(abs((iq_fft+1e-15)/N)) # convert to decibels, adjust power + # adding 1e-15 (-300 dB) to protect against value errors if an item in iq_fft is 0 + return iq_fft + + def calc_freq(self, time, sample_rate): + N = len(time) + Fs = 1.0 / (max(time) - min(time)) + Fn = 0.5 * sample_rate + freq = [-Fn + i*Fs for i in xrange(N)] + return freq + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,2,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + + # Subplot for FFT plot + self.sp_fft = self.fig.add_subplot(2,2,2, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") + self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_fft.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") + + self.get_data() + + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals + self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags + self.draw_time() # draw the plot + + self.plot_fft = self.sp_fft.plot([], 'bo-') # make plot for FFT + self.draw_fft() # draw the plot + + draw() + + def draw_time(self): + reals = self.iq.real + imags = self.iq.imag + self.plot_iq[0].set_data([self.time, reals]) + self.plot_iq[1].set_data([self.time, imags]) + self.sp_iq.set_xlim(min(self.time), max(self.time)) + self.sp_iq.set_ylim([1.5*min([min(reals), min(imags)]), + 1.5*max([max(reals), max(imags)])]) + + def draw_fft(self): + self.plot_fft[0].set_data([self.freq, self.iq_fft]) + self.sp_fft.set_xlim(min(self.freq), max(self.freq)) + self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) + + def update_plots(self): + self.draw_time() + self.draw_fft() + + draw() + + def zoom(self, event): + newxlim = self.sp_iq.get_xlim() + #if(newxlim != self.xlim): + if(0): + self.xlim = newxlim + xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) + xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.iq)) + + iq = self.iq[xmin : xmax] + time = self.time[xmin : xmax] + + iq_fft = self.dofft(iq) + freq = self.calc_freq(time, self.sample_rate) + + self.plot_fft[0].set_data(freq, iq_fft) + self.sp_fft.axis([min(freq), max(freq), + min(iq_fft)-10, max(iq_fft)+10]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def setup_options(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-d", "--data-type", type="string", default="complex64", + help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + return parser + +def main(): + parser = setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = gr_plot_fft(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_fft_c.py b/gr-utils/src/python/gr_plot_fft_c.py index b7b802fd7..de59b36c9 100755 --- a/gr-utils/src/python/gr_plot_fft_c.py +++ b/gr-utils/src/python/gr_plot_fft_c.py @@ -20,198 +20,11 @@ # Boston, MA 02110-1301, USA. # -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from pylab import * -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser -from math import log10 - -matplotlib.interactive(True) -matplotlib.use('TkAgg') - -class draw_fft_c: - def __init__(self, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - - self.datatype = scipy.complex64 - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - self.text_size = 22 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 9), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) - self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), - weight="heavy", size=self.text_size) - self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=self.text_size) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = self.sp_iq.get_xlim() - - self.manager = get_current_fig_manager() - connect('draw_event', self.zoom) - connect('key_press_event', self.click) - show() - - def get_data(self): - self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.iq) - if(len(self.iq) == 0): - print "End of File" - else: - self.reals = [r.real for r in self.iq] - self.imags = [i.imag for i in self.iq] - - self.iq_fft = self.dofft(self.iq) - - self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] - self.freq = self.calc_freq(self.time, self.sample_rate) - - - def dofft(self, iq): - N = len(iq) - iq_fft = fftpack.fftshift(scipy.fft(iq)) # fft and shift axis - iq_fft = [20*log10(abs(i/N)) for i in iq_fft] # convert to decibels, adjust power - return iq_fft - - def calc_freq(self, time, sample_rate): - N = len(time) - Fs = 1.0 / (max(time) - min(time)) - Fn = 0.5 * sample_rate - freq = [-Fn + i*Fs for i in range(N)] - return freq - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - self.get_data() - - # Subplot for real and imaginary parts of signal - self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) - self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") - self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') - self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) - - # Subplot for constellation plot - self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) - self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") - self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold") - self.plot_fft = plot(self.freq, self.iq_fft, '-bo') - self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) - - draw() - - def update_plots(self): - self.plot_iq[0].set_data([self.time, self.reals]) - self.plot_iq[1].set_data([self.time, self.imags]) - self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) - - self.plot_fft[0].set_data([self.freq, self.iq_fft]) - self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) - - draw() - - def zoom(self, event): - newxlim = self.sp_iq.get_xlim() - if(newxlim != self.xlim): - self.xlim = newxlim - xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) - xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.iq)) - - iq = self.iq[xmin : xmax] - time = self.time[xmin : xmax] - - iq_fft = self.dofft(iq) - freq = self.calc_freq(time, self.sample_rate) - - self.plot_fft[0].set_data(freq, iq_fft) - self.sp_fft.axis([min(freq), max(freq), - min(iq_fft)-10, max(iq_fft)+10]) - - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - self.get_data() - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False +import gr_plot_fft def main(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") + parser = gr_plot_fft.setup_options() + parser.remove_option("--data-type") (options, args) = parser.parse_args () if len(args) != 1: @@ -219,7 +32,7 @@ def main(): raise SystemExit, 1 filename = args[0] - dc = draw_fft_c(filename, options) + dc = gr_plot_fft.gr_plot_fft("complex64", filename, options) if __name__ == "__main__": try: diff --git a/gr-utils/src/python/gr_plot_fft_f.py b/gr-utils/src/python/gr_plot_fft_f.py index 8f545c589..f50358f01 100755 --- a/gr-utils/src/python/gr_plot_fft_f.py +++ b/gr-utils/src/python/gr_plot_fft_f.py @@ -20,201 +20,11 @@ # Boston, MA 02110-1301, USA. # -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 +import gr_plot_fft -try: - from pylab import * -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser -from math import log10 - -matplotlib.interactive(True) -matplotlib.use('TkAgg') - -class draw_fft_f: - def __init__(self, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - - self.datatype = scipy.float32 - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - self.text_size = 22 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 9), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) - self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), - weight="heavy", size=self.text_size) - self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=self.text_size) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = self.sp_f.get_xlim() - - self.manager = get_current_fig_manager() - connect('draw_event', self.zoom) - connect('key_press_event', self.click) - show() - - def get_data(self): - self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - self.floats = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.floats) - if(len(self.floats) == 0): - print "End of File" - else: - self.f_fft = self.dofft(self.floats) - - self.time = [i*(1/self.sample_rate) for i in range(len(self.floats))] - self.freq = self.calc_freq(self.time, self.sample_rate) - - def dofft(self, f): - N = len(f) - f_fft = fftpack.fftshift(scipy.fft(f)) # fft and shift axis - f_dB = list() - for f in f_fft: - try: - f_dB.append(20*log10(abs(f/N))) # convert to decibels, adjust power - except OverflowError: # protect against taking log(0) - f = 1e-14 # not sure if this is the best way to do this - f_dB.append(20*log10(abs(f/N))) - - return f_dB - - def calc_freq(self, time, sample_rate): - N = len(time) - Fs = 1.0 / (max(time) - min(time)) - Fn = 0.5 * sample_rate - freq = [-Fn + i*Fs for i in range(N)] - return freq - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - self.get_data() - - # Subplot for real and imaginary parts of signal - self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) - self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold") - self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - self.plot_f = plot(self.time, self.floats, 'bo-') - self.sp_f.set_ylim([1.5*min(self.floats), - 1.5*max(self.floats)]) - - # Subplot for constellation plot - self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) - self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") - self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold") - self.plot_fft = plot(self.freq, self.f_fft, '-bo') - self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10]) - - draw() - - def update_plots(self): - self.plot_f[0].set_data([self.time, self.floats]) - self.sp_f.set_ylim([1.5*min(self.floats), - 1.5*max(self.floats)]) - - self.plot_fft[0].set_data([self.freq, self.f_fft]) - self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10]) - - draw() - - def zoom(self, event): - newxlim = self.sp_f.get_xlim() - if(newxlim != self.xlim): - self.xlim = newxlim - xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) - xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.floats)) - - f = self.floats[xmin : xmax] - time = self.time[xmin : xmax] - - f_fft = self.dofft(f) - freq = self.calc_freq(time, self.sample_rate) - - self.plot_fft[0].set_data(freq, f_fft) - self.sp_fft.axis([min(freq), max(freq), - min(f_fft)-10, max(f_fft)+10]) - - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - self.get_data() - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() - - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False - def main(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio floating point binary file and displays the sample data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") + parser = gr_plot_fft.setup_options() + parser.remove_option("--data-type") (options, args) = parser.parse_args () if len(args) != 1: @@ -222,7 +32,7 @@ def main(): raise SystemExit, 1 filename = args[0] - dc = draw_fft_f(filename, options) + dc = gr_plot_fft.gr_plot_fft("float32", filename, options) if __name__ == "__main__": try: -- cgit From 0c743f55580109e868610f534b5b9310988f8a23 Mon Sep 17 00:00:00 2001 From: trondeau Date: Sat, 25 Oct 2008 21:47:50 +0000 Subject: fixing time axes and zoom function git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9845 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/gr_plot_fft.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py index fa205e69a..69953f681 100755 --- a/gr-utils/src/python/gr_plot_fft.py +++ b/gr-utils/src/python/gr_plot_fft.py @@ -87,8 +87,8 @@ class gr_plot_fft: show() def get_data(self): - position = self.hfile.tell()/self.sizeof_data - self.text_file_pos.set_text("File Position: %d" % (position)) + self.position = self.hfile.tell()/self.sizeof_data + self.text_file_pos.set_text("File Position: %d" % (self.position)) self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) #print "Read in %d items" % len(self.iq) if(len(self.iq) == 0): @@ -97,8 +97,8 @@ class gr_plot_fft: self.iq_fft = self.dofft(self.iq) tstep = 1.0 / self.sample_rate - self.time = [tstep*position + tstep*(position + i) for i in xrange(len(self.iq))] - + self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + self.freq = self.calc_freq(self.time, self.sample_rate) def dofft(self, iq): @@ -160,15 +160,15 @@ class gr_plot_fft: self.draw_time() self.draw_fft() + self.xlim = self.sp_iq.get_xlim() draw() def zoom(self, event): newxlim = self.sp_iq.get_xlim() - #if(newxlim != self.xlim): - if(0): + if(newxlim != self.xlim): self.xlim = newxlim - xmin = max(0, int(ceil(self.sample_rate*self.xlim[0]))) - xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.iq)) + xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) + xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) iq = self.iq[xmin : xmax] time = self.time[xmin : xmax] -- cgit From 57b846ed17b0084563988d7817302f4f5b0d8e3c Mon Sep 17 00:00:00 2001 From: trondeau Date: Sat, 25 Oct 2008 22:11:31 +0000 Subject: added real PSD plotting tool with optional spectrogram plot. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9846 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 3 + gr-utils/src/python/gr_plot_psd.py | 281 +++++++++++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_psd_c.py | 47 ++++++ gr-utils/src/python/gr_plot_psd_f.py | 47 ++++++ 4 files changed, 378 insertions(+) create mode 100755 gr-utils/src/python/gr_plot_psd.py create mode 100755 gr-utils/src/python/gr_plot_psd_c.py create mode 100755 gr-utils/src/python/gr_plot_psd_f.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index db0d688f5..965f74c80 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -36,6 +36,9 @@ bin_SCRIPTS = \ gr_plot_fft.py \ gr_plot_fft_c.py \ gr_plot_fft_f.py \ + gr_plot_psd.py \ + gr_plot_psd_c.py \ + gr_plot_psd_f.py \ gr_plot_float.py \ gr_plot_int.py \ gr_plot_iq.py \ diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py new file mode 100755 index 000000000..b469d0cc8 --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import matplotlib + matplotlib.use('TkAgg') + matplotlib.interactive(True) +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser +from scipy import log10 + +class gr_plot_psd: + def __init__(self, datatype, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + self.psdfftsize = options.psd_size + self.specfftsize = options.spec_size + + self.dospec = options.enable_spec # if we want to plot the spectrogram + + self.datatype = getattr(scipy, datatype) #scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 12), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.92, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.35, 0.92, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.915, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.position = self.hfile.tell()/self.sizeof_data + self.text_file_pos.set_text("File Position: %d" % self.position) + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + #print "Read in %d items" % len(self.iq) + if(len(self.iq) == 0): + print "End of File" + else: + tstep = 1.0 / self.sample_rate + self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + + self.iq_psd, self.freq = self.dopsd(self.iq) + + def dopsd(self, iq): + ''' Need to do this here and plot later so we can do the fftshift ''' + overlap = self.psdfftsize/4 + winfunc = scipy.blackman + psd,freq = self.sp_psd.psd(iq, self.psdfftsize, self.sample_rate, + window = lambda d: d*winfunc(self.psdfftsize), + noverlap = overlap, visible=False) + psd = 10.0*log10(abs(fftpack.fftshift(psd))) + return (psd, freq) + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + iqdims = [[0.075, 0.2, 0.4, 0.6], [0.075, 0.55, 0.4, 0.3]] + psddims = [[0.575, 0.2, 0.4, 0.6], [0.575, 0.55, 0.4, 0.3]] + specdims = [0.2, 0.125, 0.6, 0.3] + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,2,1, position=iqdims[self.dospec]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + + # Subplot for PSD plot + self.sp_psd = self.fig.add_subplot(2,2,2, position=psddims[self.dospec]) + self.sp_psd.set_title(("PSD"), fontsize=self.title_font_size, fontweight="bold") + self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") + + self.get_data() + + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals + self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags + self.draw_time() # draw the plot + + self.plot_psd = self.sp_psd.plot([], 'b') # make plot for PSD + self.draw_psd() # draw the plot + + + if self.dospec: + # Subplot for spectrogram plot + self.sp_spec = self.fig.add_subplot(2,2,3, position=specdims) + self.sp_spec.set_title(("Spectrogram"), fontsize=self.title_font_size, fontweight="bold") + self.sp_spec.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + + self.draw_spec() + + draw() + + def draw_time(self): + reals = self.iq.real + imags = self.iq.imag + self.plot_iq[0].set_data([self.time, reals]) + self.plot_iq[1].set_data([self.time, imags]) + self.sp_iq.set_xlim(min(self.time), max(self.time)) + self.sp_iq.set_ylim([1.5*min([min(reals), min(imags)]), + 1.5*max([max(reals), max(imags)])]) + + def draw_psd(self): + self.plot_psd[0].set_data([self.freq, self.iq_psd]) + self.sp_psd.set_ylim([min(self.iq_psd)-10, max(self.iq_psd)+10]) + + def draw_spec(self): + overlap = self.specfftsize/4 + winfunc = scipy.blackman + self.sp_spec.clear() + self.sp_spec.specgram(self.iq, self.specfftsize, self.sample_rate, + window = lambda d: d*winfunc(self.specfftsize), + noverlap = overlap, xextent=[min(self.time), max(self.time)]) + + def update_plots(self): + self.draw_time() + self.draw_psd() + + if self.dospec: + self.draw_spec() + + self.xlim = self.sp_iq.get_xlim() # so zoom doesn't get called + draw() + + def zoom(self, event): + newxlim = self.sp_iq.get_xlim() + if(newxlim != self.xlim): + self.xlim = newxlim + xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) + xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) + + iq = self.iq[xmin : xmax] + time = self.time[xmin : xmax] + + iq_psd, freq = self.dopsd(iq) + + self.plot_psd[0].set_data(freq, iq_psd) + self.sp_psd.axis([min(freq), max(freq), + min(iq_psd)-10, max(iq_psd)+10]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def setup_options(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-d", "--data-type", type="string", default="complex64", + help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") + parser.add_option("-B", "--block", type="int", default=8192, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + parser.add_option("", "--psd-size", type="int", default=1024, + help="Set the size of the PSD FFT [default=%default]") + parser.add_option("", "--spec-size", type="int", default=256, + help="Set the size of the spectrogram FFT [default=%default]") + parser.add_option("-S", "--enable-spec", action="store_true", default=False, + help="Turn on plotting the spectrogram [default=%default]") + + return parser + +def main(): + parser = setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = gr_plot_psd(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_psd_c.py b/gr-utils/src/python/gr_plot_psd_c.py new file mode 100755 index 000000000..1edc04c2b --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd_c.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# Copyright 2008 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 optparse import OptionParser +import gr_plot_psd + +# This is a wrapper program for gr_plot_psd specifically for complex data + +def main(): + parser = gr_plot_psd.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = gr_plot_psd.gr_plot_psd("complex64", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_psd_f.py b/gr-utils/src/python/gr_plot_psd_f.py new file mode 100755 index 000000000..bad6788c3 --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd_f.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# Copyright 2008 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 optparse import OptionParser +import gr_plot_psd + +# This is a wrapper program for gr_plot_psd specifically for floating point data + +def main(): + parser = gr_plot_psd.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = gr_plot_psd.gr_plot_psd("float32", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + -- cgit From 7dd8552fb38a5bfdf68c280261fad60d43bdc328 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sun, 26 Oct 2008 19:46:59 +0000 Subject: Updated usrp2_rx_cfile.py and usrp2_siggen.py to use updated gr-usrp2 git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9858 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_rx_cfile.py | 17 ++++++++--------- gr-utils/src/python/usrp2_siggen.py | 8 +++----- 2 files changed, 11 insertions(+), 14 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_rx_cfile.py b/gr-utils/src/python/usrp2_rx_cfile.py index 539b3e3d3..f8f1de69b 100755 --- a/gr-utils/src/python/usrp2_rx_cfile.py +++ b/gr-utils/src/python/usrp2_rx_cfile.py @@ -22,8 +22,8 @@ """ Read samples from the USRP2 and write to file formatted as binary -outputs single precision complex float values or complex short values (interleaved 16 bit signed short integers). - +outputs single precision complex float values or complex short values +(interleaved 16 bit signed short integers). """ from gnuradio import gr, eng_notation @@ -52,9 +52,9 @@ class rx_cfile_block(gr.top_block): # Set receive daughterboard gain if options.gain is None: - #g = self._u.gain_range() - #options.gain = float(g[0]+g[1])/2 - options.gain = 0 # Until gain range is implemented + g = self._u.gain_range() + options.gain = float(g[0]+g[1])/2 + print "Using mid-point gain of", options.gain, "(", g[0], "-", g[1], ")" self._u.set_gain(options.gain) # Set receive frequency @@ -63,7 +63,7 @@ class rx_cfile_block(gr.top_block): sys.stderr.write('Failed to set center frequency\n') raise SystemExit, 1 - # Create head block if needed wire it up + # Create head block if needed and wire it up if options.nsamples is None: self.connect(self._u, self._sink) else: @@ -74,13 +74,12 @@ class rx_cfile_block(gr.top_block): self.connect(self._u, self._head, self._sink) - #input_rate = self.u.adc_freq() / self.u.decim_rate() - input_rate = 100e6/options.decim + input_rate = self._u.adc_rate()/self._u.decim() if options.verbose: print "Network interface:", options.interface print "USRP2 address:", self._u.mac_addr() - #print "Using RX d'board %s" % (self._u.rx_name(),) + print "Using RX d'board id 0x%04X" % (self._u.daughterboard_id(),) print "Rx gain:", options.gain print "Rx baseband frequency:", n2s(tr.baseband_freq) print "Rx DDC frequency:", n2s(tr.dxc_freq) diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 26b7916ab..40506213e 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -38,9 +38,8 @@ class siggen_top_block(gr.top_block): # Set the Tx daughterboard gain as requested if options.gain is None: - #g = self._u.gain_range() - #options.gain = float(g[0]+g[1])/2 - options.gain = 0 # Until gain range is implemented + g = self._u.gain_range() + options.gain = float(g[0]+g[1])/2 self._u.set_gain(options.gain) # Tune the USRP2 FPGA and daughterboard to the requested center frequency @@ -49,8 +48,7 @@ class siggen_top_block(gr.top_block): sys.stderr.write('Failed to set center frequency\n') raise SystemExit, 1 - #eth_rate = self._u.dac_rate()/self._u.interp_rate() - eth_rate = 100e6/options.interp # FIXME + eth_rate = self._u.dac_rate()/self._u.interp() # Create a source for the requested waveform type if options.type == gr.GR_SIN_WAVE or options.type == gr.GR_CONST_WAVE: -- cgit From 267cd744dda0cc857b623060023c658cf97b48f4 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sun, 26 Oct 2008 20:41:23 +0000 Subject: Update usrp2_fft.py to use updated gr-usrp2. Display is correct now, however, attempting to change parameters via the controls still isn't working. But this has been isolated to a libusrp2 issue, not a usrp2_fft.py issue. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9859 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_fft.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index f4303f1f8..54defd60d 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -68,8 +68,7 @@ class app_top_block(stdgui2.std_top_block): self.u = usrp2.source_32fc(options.interface, options.mac_addr) self.u.set_decim(options.decim) - #input_rate = self.u.adc_freq() / self.u.decim_rate() - input_rate = 100e6/options.decim + input_rate = self.u.adc_rate() / self.u.decim() if options.waterfall: self.scope = \ @@ -90,15 +89,13 @@ class app_top_block(stdgui2.std_top_block): if options.gain is None: # if no gain was specified, use the mid-point in dB - #g = self.subdev.gain_range() - #options.gain = float(g[0]+g[1])/2 - options.gain = 0 + g = self.u.gain_range() + options.gain = float(g[0]+g[1])/2 if options.freq is None: # if no freq was specified, use the mid-point - #r = self.subdev.freq_range() - #options.freq = float(r[0]+r[1])/2 - options.freq = 0 + r = self.u.freq_range() + options.freq = float(r[0]+r[1])/2 self.set_gain(options.gain) @@ -107,13 +104,13 @@ class app_top_block(stdgui2.std_top_block): # self.subdev.select_rx_antenna(options.antenna) if self.show_debug_info: - self.myform['decim'].set_value(options.decim) - self.myform['fs@usb'].set_value(100e6/options.decim) #self.u.adc_freq() / self.u.decim_rate()) - #self.myform['dbname'].set_value(self.subdev.name()) + self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) + self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name self.myform['baseband'].set_value(0) self.myform['ddc'].set_value(0) - if not(self.u.set_center_freq(options.freq)): + if not(self.set_freq(options.freq)): self._set_status_msg("Failed to set initial frequency") def _set_status_msg(self, msg): @@ -135,8 +132,10 @@ class app_top_block(stdgui2.std_top_block): callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg)) hbox.Add((5,0), 0, 0) - #g = self.subdev.gain_range() - g = [0, 100, 1] #FIXME + g = self.u.gain_range() + if self.u.daughterboard_id() == 0x0003: # FIXME: get range right in firmware for TVRX + g[1] = 104 + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", weight=3, min=int(g[0]), max=int(g[1]), @@ -174,8 +173,8 @@ class app_top_block(stdgui2.std_top_block): callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) hbox.Add((5,0), 1) - myform['fs@usb'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@USB") + myform['fs@gbe'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@GbE") hbox.Add((5,0), 1) myform['dbname'] = form.static_text_field( @@ -226,12 +225,11 @@ class app_top_block(stdgui2.std_top_block): ok = self.u.set_decim(decim) if not ok: print "set_decim failed" - #input_rate = self.u.adc_freq() / self.u.decim_rate() - input_rate = 100e6/decim # FIXME + input_rate = self.u.adc_rate() / self.u.decim() self.scope.set_sample_rate(input_rate) if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(decim) #self.u.decim_rate()) - self.myform['fs@usb'].set_value(input_rate) #self.u.adc_freq() / self.u.decim_rate()) + self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) return ok def _setup_events(self): -- cgit From debdeab95b8da60d33152177bf8d10a323e5be31 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 27 Oct 2008 00:22:12 +0000 Subject: Fix gain slider for configurations that have no gain control git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9862 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_fft.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index 54defd60d..c4b73753c 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -133,10 +133,10 @@ class app_top_block(stdgui2.std_top_block): hbox.Add((5,0), 0, 0) g = self.u.gain_range() - if self.u.daughterboard_id() == 0x0003: # FIXME: get range right in firmware for TVRX - g[1] = 104 - - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + + # some configurations don't have gain control + if g[1] > g[0]: + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", weight=3, min=int(g[0]), max=int(g[1]), callback=self.set_gain) @@ -218,7 +218,8 @@ class app_top_block(stdgui2.std_top_block): return False def set_gain(self, gain): - self.myform['gain'].set_value(gain) # update displayed value + if self.myform.has_key('gain'): + self.myform['gain'].set_value(gain) # update displayed value self.u.set_gain(gain) def set_decim(self, decim): -- cgit From 600ece085c9c107cd97cf85a879f49533a3dffd5 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 27 Oct 2008 03:09:27 +0000 Subject: Adds usrp2 example directory, WFM receiver. Default audio rate works out to 32015 Hz, which is close enough, but for ALSA, you can use -O plughw:0,0 to get rid of the warning message. A resampler would be ideal. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9863 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_fft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index c4b73753c..e46840da4 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -72,7 +72,7 @@ class app_top_block(stdgui2.std_top_block): if options.waterfall: self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + waterfallsink2.waterfall_sink_c (panel, fft_size=2048, sample_rate=input_rate) elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: -- cgit From a69420c91d0d95b9751f807cc6898bab2b3d9d8e Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 27 Oct 2008 03:32:36 +0000 Subject: Revert erroneous change to usrp2_fft.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9864 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_fft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index e46840da4..c4b73753c 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -72,7 +72,7 @@ class app_top_block(stdgui2.std_top_block): if options.waterfall: self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=2048, sample_rate=input_rate) + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: -- cgit From 9f6d3260f13cbfb138dc54bdec9935ea97cdcc22 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 11 Nov 2008 15:51:23 +0000 Subject: Add --fft-size command-line parameter, defaults to original behavior (1024) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9970 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 8a9008877..3da62e29e 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -77,6 +77,9 @@ class app_top_block(stdgui2.std_top_block): help="Set fftsink averaging factor, default=[%default]") parser.add_option("", "--ref-scale", type="eng_float", default=13490.0, help="Set dBFS=0dB input value, default=[%default]") + parser.add_option("", "--fft-size", type="int", default=1024, + help="Set FFT frame size"); + (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() @@ -115,11 +118,11 @@ class app_top_block(stdgui2.std_top_block): if options.waterfall: self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + waterfallsink2.waterfall_sink_c (panel, fft_size=options.fft_size, sample_rate=input_rate) elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: - self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, + self.scope = fftsink2.fft_sink_c (panel, fft_size=options.fft_size, sample_rate=input_rate, ref_scale=options.ref_scale, ref_level=0.0, y_divs = 10, avg_alpha=options.avg_alpha) -- cgit From 560c68ebfcfabcc9a75e32d24c44e0bdfa8e2450 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Tue, 11 Nov 2008 16:03:07 +0000 Subject: Fix help strings git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9972 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 3da62e29e..fcf4c0535 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -64,7 +64,7 @@ class app_top_block(stdgui2.std_top_block): parser.add_option("-f", "--freq", type="eng_float", default=None, help="set frequency to FREQ", metavar="FREQ") parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") + 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("-8", "--width-8", action="store_true", default=False, @@ -74,11 +74,11 @@ class app_top_block(stdgui2.std_top_block): parser.add_option("-S", "--oscilloscope", action="store_true", default=False, help="Enable oscilloscope display") parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, default=[%default]") + help="Set fftsink averaging factor, [default=%default]") parser.add_option("", "--ref-scale", type="eng_float", default=13490.0, - help="Set dBFS=0dB input value, default=[%default]") + help="Set dBFS=0dB input value, [default=%default]") parser.add_option("", "--fft-size", type="int", default=1024, - help="Set FFT frame size"); + help="Set FFT frame size, [default=%default]"); (options, args) = parser.parse_args() if len(args) != 0: -- cgit From 4f8ca94b8375ff482f43a143c0055d583986e3bf Mon Sep 17 00:00:00 2001 From: trondeau Date: Thu, 13 Nov 2008 03:29:54 +0000 Subject: proper comparison of vectors; I thought I had already fixed this... git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9984 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/gr_plot_const.py | 2 +- gr-utils/src/python/gr_plot_fft.py | 2 +- gr-utils/src/python/gr_plot_psd.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 42c0260dc..355309955 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -140,7 +140,7 @@ class draw_constellation: def zoom(self, event): newxlim = self.sp_iq.get_xlim() - if(newxlim != self.xlim): + if(newxlim.all() != self.xlim.all()): self.xlim = newxlim r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py index 69953f681..59a3f286b 100755 --- a/gr-utils/src/python/gr_plot_fft.py +++ b/gr-utils/src/python/gr_plot_fft.py @@ -165,7 +165,7 @@ class gr_plot_fft: def zoom(self, event): newxlim = self.sp_iq.get_xlim() - if(newxlim != self.xlim): + if(newxlim.all() != self.xlim.all()): self.xlim = newxlim xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index b469d0cc8..669d7b573 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -188,7 +188,7 @@ class gr_plot_psd: def zoom(self, event): newxlim = self.sp_iq.get_xlim() - if(newxlim != self.xlim): + if(newxlim.all() != self.xlim.all()): self.xlim = newxlim xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) -- cgit From 7e38bfd2cd47010aaf64d06c38e4bcb6804020e4 Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 13 Nov 2008 23:14:38 +0000 Subject: added 2tone capability git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9987 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_siggen.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 40506213e..6597170a4 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -60,6 +60,24 @@ class siggen_top_block(gr.top_block): elif options.type == gr.GR_GAUSSIAN or options.type == gr.GR_UNIFORM: self._src = gr.noise_source_c(options.type, options.amplitude) + elif options.type == "2tone": + self._src1 = gr.sig_source_c(eth_rate, + gr.GR_SIN_WAVE, + options.waveform_freq, + options.amplitude, + 0) + if(options.waveform2_freq is None): + w2freq = -options.waveform_freq + else: + w2freq = options.waveform2_freq + self._src2 = gr.sig_source_c(eth_rate, + gr.GR_SIN_WAVE, + w2freq, + options.amplitude, + 0) + self._src = gr.add_cc() + self.connect(self._src1,(self._src,0)) + self.connect(self._src2,(self._src,1)) else: sys.stderr.write('Unknown waveform type\n') raise SystemExit, 1 @@ -105,6 +123,8 @@ def get_options(): help="verbose output") parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, help="set waveform frequency to FREQ [default=%default]") + parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, + help="set waveform frequency to FREQ [default=%default]") parser.add_option("-a", "--amplitude", type="eng_float", default=0.5, help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") parser.add_option("--offset", type="eng_float", default=0, @@ -117,7 +137,9 @@ def get_options(): help="generate Gaussian random output") parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, help="generate Uniform random output") - + parser.add_option("--2tone", dest="type", action="store_const", const="2tone", + help="generate Two Tone signal for IMD testing") + (options, args) = parser.parse_args () if len(args) != 0: parser.print_help() -- cgit From 6dcbc791992abf8ec57b9208c39aa0539f0cdef7 Mon Sep 17 00:00:00 2001 From: matt Date: Thu, 18 Dec 2008 22:09:45 +0000 Subject: added frequency sweep capability git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10126 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_siggen.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 6597170a4..d3be4b26a 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -25,6 +25,7 @@ from gnuradio import usrp2 from gnuradio.eng_option import eng_option from optparse import OptionParser import sys +import math n2s = eng_notation.num_to_str @@ -78,6 +79,19 @@ class siggen_top_block(gr.top_block): self._src = gr.add_cc() self.connect(self._src1,(self._src,0)) self.connect(self._src2,(self._src,1)) + elif options.type == "sweep": + # rf freq is center frequency + # waveform_freq is total swept width + # waveform2_freq is sweep rate + # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) + self._src1 = gr.sig_source_f(eth_rate, + gr.GR_TRI_WAVE, + options.waveform2_freq, + 1.0, # options.waveform_freq, + -0.5) + self._src2 = gr.frequency_modulator_fc(options.waveform_freq*2*math.pi/eth_rate) + self._src = gr.multiply_const_cc(options.amplitude) + self.connect(self._src1,self._src2,self._src) else: sys.stderr.write('Unknown waveform type\n') raise SystemExit, 1 @@ -139,6 +153,8 @@ def get_options(): help="generate Uniform random output") parser.add_option("--2tone", dest="type", action="store_const", const="2tone", help="generate Two Tone signal for IMD testing") + parser.add_option("--sweep", dest="type", action="store_const", const="sweep", + help="generate a swept sine wave") (options, args) = parser.parse_args () if len(args) != 0: -- cgit From 72c625f7e50b65dc3b642112762e9eb1d633bd42 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Wed, 24 Dec 2008 08:10:48 +0000 Subject: Merged r10071:10164 from features/cppdb-test into trunk. Implements the fully native C++ API for the USRP. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10165 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_fft.py | 4 ++-- gr-utils/src/python/usrp_oscope.py | 4 ++-- gr-utils/src/python/usrp_siggen.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index fcf4c0535..4aa70adab 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -37,9 +37,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(0, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index d3223cba3..f4a539dd5 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -40,9 +40,9 @@ def pick_subdevice(u): If there's a daughterboard on B, select B. Otherwise, select A. """ - if u.db[0][0].dbid() >= 0: # dbid is < 0 if there's no d'board or a problem + if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db[1][0].dbid() >= 0: + if u.db(0, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index fe29787f9..3e7751c00 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -118,7 +118,7 @@ class my_top_block(gr.top_block): the result of that operation and our target_frequency to determine the value for the digital up converter. """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) + r = self.u.tune(self.subdev.which(), self.subdev, target_freq) if r: #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) @@ -200,5 +200,6 @@ def main (): except KeyboardInterrupt: pass + if __name__ == '__main__': main () -- cgit From 0dcb587d948787215b6367725e7483fc4cbcd94d Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 19 Jan 2009 21:51:07 +0000 Subject: enable_realtime in usrp2_siggen.py git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10262 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_siggen.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index d3be4b26a..9929112ef 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -173,6 +173,14 @@ if __name__ == '__main__': options = get_options() tb = siggen_top_block(options) + # Attempt to enable realtime scheduling + r = gr.enable_realtime_scheduling() + if r == gr.RT_OK: + realtime = True + else: + realtime = False + print "Note: failed to enable realtime scheduling" + try: tb.run() except KeyboardInterrupt: -- cgit From 99bacfb2b8a51698aa2e1f98079488a63484bfc3 Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 31 Jan 2009 23:23:27 +0000 Subject: set fft-size from command line, default to 12 divs vertical git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10354 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_fft.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index c4b73753c..1e8cf89ea 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -58,6 +58,8 @@ class app_top_block(stdgui2.std_top_block): help="Set fftsink averaging factor, default=[%default]") parser.add_option("", "--ref-scale", type="eng_float", default=1.0, help="Set dBFS=0dB input value, default=[%default]") + parser.add_option("--fft-size", type="int", default=1024, + help="Set number of FFT bins [default=%default]") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() @@ -76,8 +78,12 @@ class app_top_block(stdgui2.std_top_block): elif options.oscilloscope: self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) else: - self.scope = fftsink2.fft_sink_c (panel, fft_size=1024, sample_rate=input_rate, - ref_scale=options.ref_scale, ref_level=0.0, y_divs = 10, + self.scope = fftsink2.fft_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12, avg_alpha=options.avg_alpha) self.connect(self.u, self.scope) -- cgit From 9b388ac1184c71449c49fb44551c5c38f8098d8e Mon Sep 17 00:00:00 2001 From: jcorgan Date: Wed, 4 Feb 2009 23:06:02 +0000 Subject: Merged r10383:10390 from jcorgan/u2-wip into trunk. * Implements daughterboard independent LO offset tuning * Removes RFX specific LO offset code * Adds 'set_lo_offset' to libusrp2 and Python API * Adds --lo-offset to usrp2_fft.py and usrp2_rx_cfile.py * Ensures daughterboards are reset to default values at startup. Trunk passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10392 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_rx_cfile.py | 8 +++++++- gr-utils/src/python/usrp2_siggen.py | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_rx_cfile.py b/gr-utils/src/python/usrp2_rx_cfile.py index f8f1de69b..1f23eee4e 100755 --- a/gr-utils/src/python/usrp2_rx_cfile.py +++ b/gr-utils/src/python/usrp2_rx_cfile.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -58,6 +58,9 @@ class rx_cfile_block(gr.top_block): self._u.set_gain(options.gain) # Set receive frequency + if options.lo_offset is not None: + self._u.set_lo_offset(options.lo_offset) + tr = self._u.set_center_freq(options.freq) if tr == None: sys.stderr.write('Failed to set center frequency\n') @@ -115,6 +118,9 @@ def get_options(): help="number of samples to collect [default=+inf]") parser.add_option("-v", "--verbose", action="store_true", default=False, help="verbose output") + parser.add_option("", "--lo-offset", type="eng_float", default=None, + help="set daughterboard LO offset to OFFSET [default=hw default]") + (options, args) = parser.parse_args () if len(args) != 1: parser.print_help() diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 9929112ef..9cea2eff1 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -44,6 +44,10 @@ class siggen_top_block(gr.top_block): self._u.set_gain(options.gain) # Tune the USRP2 FPGA and daughterboard to the requested center frequency + # and LO offset + if options.lo_offset is not None: + self._u.set_lo_offset(options.lo_offset) + tr = self._u.set_center_freq(options.tx_freq) if tr == None: sys.stderr.write('Failed to set center frequency\n') @@ -143,6 +147,8 @@ def get_options(): help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") parser.add_option("--offset", type="eng_float", default=0, help="set waveform offset to OFFSET [default=%default]") + parser.add_option("--lo-offset", type="eng_float", default=None, + help="set daughterboard LO offset to OFFSET [default=hw default]") parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, -- cgit From 09ce7710430c32b09f549eda728e711e41e8f3a6 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sun, 22 Feb 2009 20:55:28 +0000 Subject: Re-implementation of usrp2_siggen.py with dynamically adjustable flowgraph. Adds new usrp2_siggen_gui.py that implements GUI interface on top if same, GUI-unaware flowgraph. Uses new gr.wxgui.gui class. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10476 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 5 +- gr-utils/src/python/usrp2_siggen.py | 439 +++++++++++++++++++++++--------- gr-utils/src/python/usrp2_siggen_gui.py | 275 ++++++++++++++++++++ 3 files changed, 599 insertions(+), 120 deletions(-) create mode 100755 gr-utils/src/python/usrp2_siggen_gui.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 965f74c80..5eb2ae555 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -54,6 +54,7 @@ bin_SCRIPTS = \ usrp_test_loopback.py \ usrp2_fft.py \ usrp2_rx_cfile.py \ - usrp2_siggen.py - + usrp2_siggen.py \ + usrp2_siggen_gui.py + MOSTLYCLEANFILES = *~ *.pyc diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 9cea2eff1..71f12cf4a 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -20,8 +20,7 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, eng_notation -from gnuradio import usrp2 +from gnuradio import gr, eng_notation, usrp2 from gnuradio.eng_option import eng_option from optparse import OptionParser import sys @@ -29,165 +28,369 @@ import math n2s = eng_notation.num_to_str -class siggen_top_block(gr.top_block): - def __init__(self, options): +waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", + gr.GR_CONST_WAVE : "Constant", + gr.GR_GAUSSIAN : "Gaussian Noise", + gr.GR_UNIFORM : "Uniform Noise", + "2tone" : "Two Tone", + "sweep" : "Sweep" } + +# +# GUI-unaware GNU Radio flowgraph. This may be used either with command +# line applications or GUI applications. +# +class top_block(gr.top_block): + def __init__(self, options, args): gr.top_block.__init__(self) + self._verbose = options.verbose + + self._interp = 0 + self._gain = 0 + self._freq = None # Indicates frequency hasn't been successfully set yet + self._bb_freq = 0 + self._ddc_freq = 0 + self._amplitude = 0 + self._type = None # Indicates waveform flowgraph not created yet + self._offset = options.offset + + self.set_usrp2(options.interface, options.mac_addr) + self.set_interp(options.interp) + self.set_gain(options.gain) + self.set_freq(options.tx_freq, options.lo_offset) + self.set_amplitude(options.amplitude) + + self.set_waveform_freq(options.waveform_freq) + #self.set_waveform2_freq(options.waveform2_freq) + self._waveform2_freq = options.waveform2_freq + self.set_waveform(options.type) + + def set_usrp2(self, interface, mac_addr): + self._u = usrp2.sink_32fc(interface, mac_addr) + self._dac_rate = self._u.dac_rate() + if self._verbose: + print "Network interface:", interface + print "Network address:", self._u.mac_addr() + print "Daughterboard ID:", hex(self._u.daughterboard_id()) + + def set_interp(self, interp): + if interp < 4 or interp > 512: # FIXME get from flowgraph + if self._verbose: print "Interpolation rate out of range:", interp + return False + + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - # Create a USRP2 sink with the requested interpolation rate - self._u = usrp2.sink_32fc(options.interface, options.mac_addr) - self._u.set_interp(options.interp) + self._interp = interp + self._eth_rate = self._dac_rate/self._interp + if self._verbose: + print "USRP2 interpolation rate:", self._interp + print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),) - # Set the Tx daughterboard gain as requested - if options.gain is None: + if (self._type == gr.GR_SIN_WAVE or + self._type == gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self._eth_rate) + elif self._type == "2tone": + self._src1.set_sampling_freq(self._eth_rate) + self._src1.set_sampling_freq(self._eth_rate) + elif self._type == "sweep": + self._src1.set_sampling_freq(self._eth_rate) + self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate) + else: + return True # Waveform not yet set + + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: g = self._u.gain_range() - options.gain = float(g[0]+g[1])/2 - self._u.set_gain(options.gain) + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self._u.set_gain(gain) + self._gain = gain + if self._verbose: + print "Set TX gain to:", self._gain + + def set_freq(self, target_freq, lo_offset=None): + if lo_offset is not None: + self._lo_offset = lo_offset + self._u.set_lo_offset(self._lo_offset) + if self._verbose: + print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - # Tune the USRP2 FPGA and daughterboard to the requested center frequency - # and LO offset - if options.lo_offset is not None: - self._u.set_lo_offset(options.lo_offset) + if target_freq is None: + f = self._u.freq_range() + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" - tr = self._u.set_center_freq(options.tx_freq) - if tr == None: - sys.stderr.write('Failed to set center frequency\n') - raise SystemExit, 1 + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq - eth_rate = self._u.dac_rate()/self._u.interp() + else: + return True # Waveform not yet set - # Create a source for the requested waveform type - if options.type == gr.GR_SIN_WAVE or options.type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(eth_rate, # Sample rate - options.type, # Waveform type - options.waveform_freq, # Waveform frequency - options.amplitude, # Waveform amplitude - options.offset) # Waveform offset - - elif options.type == gr.GR_GAUSSIAN or options.type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(options.type, options.amplitude) - elif options.type == "2tone": - self._src1 = gr.sig_source_c(eth_rate, + if self._verbose: print "Set amplitude to:", amplitude + return True + + def set_gain(self, gain): + if gain is None: + g = self._u.gain_range() + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self._u.set_gain(gain) + self._gain = gain + if self._verbose: + print "Set TX gain to:", self._gain + + def set_freq(self, target_freq, lo_offset=None): + if lo_offset is not None: + self._lo_offset = lo_offset + self._u.set_lo_offset(self._lo_offset) + if self._verbose: + print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) + + if target_freq is None: + f = self._u.freq_range() + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq + self._ddc_freq = tr.dxc_freq + self._bb_freq = tr.baseband_freq + if self._verbose: + print "Set center frequency to", fs + print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) + print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) + print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) + + return tr + + def set_waveform_freq(self, freq): + self._waveform_freq = freq + if self._type == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self._type == "2tone" or self._type == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform2_freq(self, freq): + self._waveform2_freq = freq + if self._type == "2tone": + self._src2.set_frequency(freq) + elif self._type == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform(self, type): + self.lock() + self.disconnect_all() + + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(self._eth_rate, # Sample rate + type, # Waveform type + self._waveform_freq, # Waveform frequency + self._amplitude, # Waveform amplitude + self._offset) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self._amplitude) + elif type == "2tone": + self._src1 = gr.sig_source_c(self._eth_rate, gr.GR_SIN_WAVE, - options.waveform_freq, - options.amplitude, + self._waveform_freq, + self._amplitude/2.0, 0) - if(options.waveform2_freq is None): - w2freq = -options.waveform_freq - else: - w2freq = options.waveform2_freq - self._src2 = gr.sig_source_c(eth_rate, + if(self._waveform2_freq is None): + self._waveform2_freq = -self._waveform_freq + + self._src2 = gr.sig_source_c(self._eth_rate, gr.GR_SIN_WAVE, - w2freq, - options.amplitude, + self._waveform2_freq, + self._amplitude/2.0, 0) self._src = gr.add_cc() self.connect(self._src1,(self._src,0)) self.connect(self._src2,(self._src,1)) - elif options.type == "sweep": + elif type == "sweep": # rf freq is center frequency # waveform_freq is total swept width # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - self._src1 = gr.sig_source_f(eth_rate, + # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) + if self._waveform2_freq is None: + self._waveform2_freq = 0.1 + + self._src1 = gr.sig_source_f(self._eth_rate, gr.GR_TRI_WAVE, - options.waveform2_freq, - 1.0, # options.waveform_freq, + self._waveform2_freq, + 1.0, -0.5) - self._src2 = gr.frequency_modulator_fc(options.waveform_freq*2*math.pi/eth_rate) - self._src = gr.multiply_const_cc(options.amplitude) + self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate) + self._src = gr.multiply_const_cc(self._amplitude) self.connect(self._src1,self._src2,self._src) else: - sys.stderr.write('Unknown waveform type\n') - raise SystemExit, 1 - - if options.verbose: - print "Network interface:", options.interface - print "USRP2 address:", self._u.mac_addr() - #print "Using TX d'board %s" % (self._u.tx_name(),) - print "Tx gain:", options.gain - print "Tx baseband frequency:", n2s(tr.baseband_freq), "Hz" - print "Tx DDC frequency:", n2s(tr.dxc_freq), "Hz" - print "Tx residual frequency:", n2s(tr.residual_freq), "Hz" - print "Tx interpolation rate:", options.interp - print "Tx GbE sample rate:", n2s(eth_rate), "samples/sec" - if options.type == gr.GR_SIN_WAVE: - print "Baseband waveform type: Sine wave" - print "Baseband waveform frequency:", n2s(options.waveform_freq), "Hz" - elif options.type == gr.GR_CONST_WAVE: - print "Baseband waveform type: Constant" - elif options.type == gr.GR_GAUSSIAN: - print "Baseband waveform type: Gaussian noise" - elif options.type == gr.GR_UNIFORM: - print "Baseband waveform type: Uniform noise" - - # Wire the flowgraph + raise RuntimeError("Unknown waveform type") + self.connect(self._src, self._u) - + self._type = type + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[self._type] + if type == gr.GR_SIN_WAVE: + print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),) + print "Initial phase:", self._offset + elif type == "2tone": + print "Tone 1: %sHz" % (n2s(self._waveform_freq),) + print "Tone 2: %sHz" % (n2s(self._waveform2_freq),) + elif type == "sweep": + print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0)) + print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),) + print "TX amplitude:", self._amplitude + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + self._amplitude = amplitude + + if (self._type == gr.GR_SIN_WAVE or + self._type == gr.GR_CONST_WAVE or + self._type == gr.GR_GAUSSIAN or + self._type == gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self._type == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self._type == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + + + # Property getters + + #def interface(self): + # return self._u.ifc_name() + + def mac_addr(self): + return self._u.mac_addr() + + def ifc_name(self): + return self._u.ifc_name() + + def daughterboard_id(self): + return self._u.daughterboard_id() + + def interp_rate(self): + return self._interp + + def eth_rate(self): + return self._eth_rate + + def freq(self): + return self._freq + + def freq_range(self): + fr = self._u.freq_range() + if self._u.daughterboard_id() == 0x0000: + fr = (-50e6, 50e6) # DEBUG + return fr + + def ddc_freq(self): + return self._ddc_freq + + def baseband_freq(self): + return self._bb_freq + + def amplitude(self): + return self._amplitude + + def waveform_type(self): + return self._type + + def waveform_freq(self): + return self._waveform_freq + + def waveform2_freq(self): + if self._waveform2_freq is None: + return -self._waveform_freq + else: + return self._waveform2_freq + def get_options(): usage="%prog: [options]" parser = OptionParser(option_class=eng_option, usage=usage) + parser.add_option("-e", "--interface", type="string", default="eth0", - help="use specified Ethernet interface [default=%default]") + help="Use specified Ethernet interface [default=%default]") parser.add_option("-m", "--mac-addr", type="string", default="", - help="use USRP2 at specified MAC address [default=None]") - parser.add_option("-i", "--interp", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") + help="Use USRP2 at specified MAC address [default=None]") + parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP", + help="Set FPGA interpolation rate of INTERP [default=%default]") parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="verbose output") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option("-a", "--amplitude", type="eng_float", default=0.5, - help="set waveform amplitude to AMPLITUDE (0-1.0) [default=%default]", metavar="AMPL") - parser.add_option("--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") + help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") parser.add_option("--lo-offset", type="eng_float", default=None, help="set daughterboard LO offset to OFFSET [default=hw default]") + parser.add_option("-g", "--gain", type="eng_float", default=None, + help="Set TX gain to GAIN [default=mid-point]") + parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, + help="Set baseband waveform frequency to FREQ [default=%default]") + parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, + help="Set 2nd waveform frequency to FREQ [default=%default]") parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) + help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") + help="Generate a constant carrier") + parser.add_option("--offset", type="eng_float", default=0, + help="Set waveform phase offset to OFFSET [default=%default]") parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") + help="Generate Gaussian random output") parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") + help="Generate Uniform random output") parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - help="generate Two Tone signal for IMD testing") + help="Generate Two Tone signal for IMD testing") parser.add_option("--sweep", dest="type", action="store_const", const="sweep", - help="generate a swept sine wave") - - (options, args) = parser.parse_args () - if len(args) != 0: - parser.print_help() - raise SystemExit, 1 - - if options.tx_freq is None: - parser.print_help() - sys.stderr.write('You must specify the frequency with -f FREQ\n'); - raise SystemExit, 1 - - return options + help="Generate a swept sine wave") + parser.add_option("-a", "--amplitude", type="eng_float", default=0.1, + help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Use verbose console output [default=%default]") + (options, args) = parser.parse_args() -if __name__ == '__main__': - options = get_options() - tb = siggen_top_block(options) + return (options, args) + +# If this script is executed, the following runs. If it is imported, the below does not run. +if __name__ == "__main__": + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Note: failed to enable realtime scheduling, continuing" - # Attempt to enable realtime scheduling - r = gr.enable_realtime_scheduling() - if r == gr.RT_OK: - realtime = True - else: - realtime = False - print "Note: failed to enable realtime scheduling" + # Grab command line options and create top block + try: + (options, args) = get_options() + tb = top_block(options, args) + except RuntimeError, e: + print e + sys.exit(1) + + # Run it try: tb.run() + except KeyboardInterrupt: pass diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py new file mode 100755 index 000000000..2d9f4f4df --- /dev/null +++ b/gr-utils/src/python/usrp2_siggen_gui.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from gnuradio.wxgui import form, slider, gui +import usrp2_siggen +import math + +class app_gui(object): + def __init__(self, frame, panel, vbox, top_block, options, args): + self.frame = frame # Use for top-level application window frame + self.panel = panel # Use as parent class for created windows + self.vbox = vbox # Use as sizer for created windows + self.tb = top_block # GUI-unaware flowgraph class + self.options = options # Supplied command-line options + self.args = args # Supplied command-line arguments + + freq_range = self.tb.freq_range() + self.min_freq = freq_range[0] + self.max_freq = freq_range[1] + self.freq_step = (self.max_freq-self.min_freq)/100.0 + self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items()) + + self.build_gui() + + # TODO: turn these into listeners + self.myform['ifc'].set_value(self.tb.ifc_name()) + self.myform['mac'].set_value(self.tb.mac_addr()) + dbid = self.tb.daughterboard_id() + self.myform['dbid'].set_value("%04x" % (dbid,)) + + w = usrp2_siggen.waveforms[self.tb.waveform_type()] + self.myform['type'].set_value(w) + self.myform['w1freq'].set_value(self.tb.waveform_freq()) + self.myform['w2freq'].set_value(self.tb.waveform2_freq()) + + freq = self.tb.freq() + if freq is None: + self.evt_set_status_msg("Failed to set initial frequency") + else: + self.myform['freq'].set_value(freq) + self.myform['freq_slider'].set_value(self.tb.freq()) + + amp = self.tb.amplitude() + if (amp > 0.0): + db = 20*math.log10(amp) + else: + db = -100.0 + self.myform['amp'].set_value(amp) + self.myform['amp_slider'].set_value(db) + self.myform['eth'].set_value(self.tb.eth_rate()) + self.myform['gbe'].set_value(self.tb.eth_rate()*32) + self.myform['interp'].set_value(self.tb.interp_rate()) + self.myform['DDC'].set_value(self.tb.ddc_freq()) + self.myform['analog'].set_value(self.tb.baseband_freq()) + + # Event response handlers + def evt_set_status_msg(self, msg): + self.frame.SetStatusText(msg, 0) + + def evt_set_freq1(self, kv): + return self.tb.set_waveform_freq(kv['w1freq']) + + def evt_set_freq2(self, kv): + return self.tb.set_waveform2_freq(kv['w2freq']) + + def evt_set_freq(self, kv): + if type(kv) == type(0.0): # Set from slider + tr = self.tb.set_freq(kv) + if tr is not None: + self.myform['freq'].set_value(kv) + else: # Set from edit box + f = kv['freq'] + tr = self.tb.set_freq(f) + if tr is not None: + self.myform['freq_slider'].set_value(f) + + if tr is not None: + self.myform['DDC'].set_value(tr.dxc_freq) + self.myform['analog'].set_value(tr.baseband_freq) + + return (tr is not None) + + def evt_set_amplitude(self, kv): + if type(kv) == type(0.0): # Set from slider + amp = math.pow(10, kv/20.0) + self.myform['amp'].set_value(amp) + return self.tb.set_amplitude(amp) + else: # Set from edit box + amp = kv['amp'] + if amp < 0.0 or amp > 1.0: + return False + if amp == 0.0: + db = -100.0 + else: + db = 20*math.log10(amp) + self.myform['amp_slider'].set_value(db) + return self.tb.set_amplitude(amp) + + def evt_set_interp(self): + interp = self.myform['interp'].get_value() + if self.tb.set_interp(interp): + eth_rate = self.tb.eth_rate() + self.myform['eth'].set_value(eth_rate) + self.myform['gbe'].set_value(eth_rate*32) + return True + return False + + def evt_set_waveform_type(self, type): + # TODO: update frequency labels + return self.tb.set_waveform(self._types[type]) + + # GUI construction + def build_gui(self): + self.myform = myform = form.form() + + # Baseband controls + bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation") + bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit + + # First row of baseband controls (modulation type) + mod_hbox = wx.BoxSizer(wx.HORIZONTAL) + mod_hbox.Add((10,0), 0, 0) + myform['type'] = form.radiobox_field( + parent=self.panel, label="Type", sizer=mod_hbox, value=None, + callback=self.evt_set_waveform_type, weight=1, major_dimension=0, + choices=usrp2_siggen.waveforms.values() ) + bb_vbox.Add((0,10), 0, 0) + bb_vbox.Add(mod_hbox, 0, wx.EXPAND) + + # Second row of baseband controls (frequencies) + bbf_hbox = wx.BoxSizer(wx.HORIZONTAL) + bbf_hbox.Add((10,0), 0, 0) + myform['w1freq'] = form.float_field( + parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1, + callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) ) + bbf_hbox.Add((10,0), 0, 0) + myform['w2freq'] = form.float_field( + parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1, + callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) ) + bbf_hbox.Add((10,0), 0, 0) + + bb_vbox.Add((0,10), 0, 0) + bb_vbox.Add(bbf_hbox, 0, wx.EXPAND) + + # Add baseband controls to top window sizer + self.vbox.Add((0,10), 0, 0) + self.vbox.Add(bb_vbox, 0, wx.EXPAND) + + # Frequency controls + fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency") + fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit + + # First row of frequency controls (center frequency) + freq_hbox = wx.BoxSizer(wx.HORIZONTAL) + freq_hbox.Add((10,0), 0, 0) + myform['freq'] = form.float_field( + parent=self.panel, sizer=freq_hbox, label=None, weight=1, + callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) ) + freq_hbox.Add((10,0), 0, 0) + myform['freq_slider'] = form.quantized_slider_field( + parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4, + range = (self.min_freq, self.max_freq, self.freq_step), + callback=self.evt_set_freq) + freq_hbox.Add((10,0), 0, 0) + + fc_vbox.Add((10,0), 0, 0) + fc_vbox.Add(freq_hbox, 0, wx.EXPAND) + + # Second row of frequency controls (results) + tr_hbox = wx.BoxSizer(wx.HORIZONTAL) + tr_hbox.Add((10,0), 0, 0) + myform['analog'] = form.static_float_field( + parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1) + tr_hbox.Add((10,0), 0, 0) + myform['DDC'] = form.static_float_field( + parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1) + tr_hbox.Add((10,0), 0, 0) + fc_vbox.Add(tr_hbox, 0, wx.EXPAND) + + # Add frequency controls to top window sizer + self.vbox.Add((0,10), 0, 0) + self.vbox.Add(fc_vbox, 0, wx.EXPAND) + + # Amplitude row + amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude") + amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL) + amp_hbox.Add((10,0), 0, 0) + myform['amp'] = form.float_field( + parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1, + callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) ) + amp_hbox.Add((10,0), 0, 0) + myform['amp_slider'] = form.quantized_slider_field( + parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4, + range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude) + amp_hbox.Add((10,0), 0, 0) + self.vbox.Add((0,10), 0, 0) + self.vbox.Add(amp_hbox, 0, wx.EXPAND) + + # Sample rate row + sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate") + sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL) + sam_hbox.Add((10,0), 0, 0) + myform['interp'] = form.int_field( + parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1, + callback=self.evt_set_interp) + sam_hbox.Add((10,0), 0, 0) + myform['eth'] = form.static_float_field( + parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1) + sam_hbox.Add((10,0), 0, 0) + myform['gbe'] = form.static_float_field( + parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1) + sam_hbox.Add((10,0), 0, 0) + self.vbox.Add((0,10), 0, 0) + self.vbox.Add(sam_hbox, 0, wx.EXPAND) + + # USRP2 row + u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware") + u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL) + u2_hbox.Add((10,0), 0, 0) + myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, + label="Interface", weight=2) + u2_hbox.Add((10,0), 0, 0) + myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, + label="MAC Address", weight=2) + u2_hbox.Add((10,0), 0, 0) + myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, + label="Daughterboard ID", weight=1) + self.vbox.Add((0,10), 0, 0) + self.vbox.Add(u2_hbox, 0, wx.EXPAND) + self.vbox.Add((0,20), 0, 0) + +if __name__ == "__main__": + try: + # Get command line parameters + (options, args) = usrp2_siggen.get_options() + + # Create the top block using these + tb = usrp2_siggen.top_block(options, args) + + # Create the GUI application + app = gui.app(top_block=tb, # Constructed top block + gui=app_gui, # User interface class + options=options, # Command line options + args=args, # Command line args + title="USRP2 Signal Generator", # Top window title + nstatus=1, # Number of status lines + start=True, # Whether to start flowgraph + realtime=True) # Whether to set realtime priority + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) -- cgit From 98dca512c2fdfbed0f9db14bc07fe5c2ed58b83b Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 23 Feb 2009 02:08:43 +0000 Subject: Cleanup, changed ifc_name() to interface_name() git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10477 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp2_siggen.py | 15 ++++----------- gr-utils/src/python/usrp2_siggen_gui.py | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py index 71f12cf4a..9ade933c7 100755 --- a/gr-utils/src/python/usrp2_siggen.py +++ b/gr-utils/src/python/usrp2_siggen.py @@ -60,8 +60,7 @@ class top_block(gr.top_block): self.set_amplitude(options.amplitude) self.set_waveform_freq(options.waveform_freq) - #self.set_waveform2_freq(options.waveform2_freq) - self._waveform2_freq = options.waveform2_freq + self.set_waveform2_freq(options.waveform2_freq) self.set_waveform(options.type) def set_usrp2(self, interface, mac_addr): @@ -282,14 +281,11 @@ class top_block(gr.top_block): # Property getters - #def interface(self): - # return self._u.ifc_name() - def mac_addr(self): return self._u.mac_addr() - def ifc_name(self): - return self._u.ifc_name() + def interface_name(self): + return self._u.interface_name() def daughterboard_id(self): return self._u.daughterboard_id() @@ -304,10 +300,7 @@ class top_block(gr.top_block): return self._freq def freq_range(self): - fr = self._u.freq_range() - if self._u.daughterboard_id() == 0x0000: - fr = (-50e6, 50e6) # DEBUG - return fr + return self._u.freq_range() def ddc_freq(self): return self._ddc_freq diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py index 2d9f4f4df..89bc6e589 100755 --- a/gr-utils/src/python/usrp2_siggen_gui.py +++ b/gr-utils/src/python/usrp2_siggen_gui.py @@ -23,7 +23,7 @@ import wx from gnuradio.wxgui import form, slider, gui import usrp2_siggen -import math +import sys, math class app_gui(object): def __init__(self, frame, panel, vbox, top_block, options, args): @@ -43,7 +43,7 @@ class app_gui(object): self.build_gui() # TODO: turn these into listeners - self.myform['ifc'].set_value(self.tb.ifc_name()) + self.myform['ifc'].set_value(self.tb.interface_name()) self.myform['mac'].set_value(self.tb.mac_addr()) dbid = self.tb.daughterboard_id() self.myform['dbid'].set_value("%04x" % (dbid,)) -- cgit From c3f962a1f0a4132ad643c58774bb69b190dccc49 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sat, 14 Mar 2009 02:28:41 +0000 Subject: Merged r10554:10595 from michaelld/am_swig_4 into trunk. Major overhaul of SWIG usage in build system, also fixes ticket:130. Trunk passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10596 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 5eb2ae555..b58faa9bf 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2007 Free Software Foundation, Inc. +# Copyright 2007,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -56,5 +56,3 @@ bin_SCRIPTS = \ usrp2_rx_cfile.py \ usrp2_siggen.py \ usrp2_siggen_gui.py - -MOSTLYCLEANFILES = *~ *.pyc -- cgit From 1910719ec29a12be380b9fa3dcd3ab893ce87ce2 Mon Sep 17 00:00:00 2001 From: eb Date: Thu, 19 Mar 2009 19:59:48 +0000 Subject: Merged remainder of eb/t348 10637:10648. This adds a -N argument to usrp_siggen.py, usrp_siggen.cc and test_usrp_standard_tx.cc. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10650 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/usrp_siggen.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 3e7751c00..8ae2fbfbf 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -29,7 +29,7 @@ import sys class my_top_block(gr.top_block): - def __init__ (self): + def __init__ (self, nsamples): gr.top_block.__init__(self) # controllable values @@ -38,6 +38,7 @@ class my_top_block(gr.top_block): self.waveform_ampl = 16000 self.waveform_freq = 100.12345e3 self.waveform_offset = 0 + self.nsamples = nsamples self._instantiate_blocks () self.set_waveform_type (self.waveform_type) @@ -86,19 +87,30 @@ class my_top_block(gr.top_block): self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, self.waveform_ampl) + self.head = None + if self.nsamples > 0: + self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples)) + # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") def _configure_graph (self, type): try: self.lock() self.disconnect_all () + + if self.head: + self.connect(self.head, self.u) + tail = self.head + else: + tail = self.u + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, self.u) + self.connect (self.siggen, tail) # self.connect (self.siggen, self.file_sink) self.siggen.set_waveform (type) self.src = self.siggen elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, self.u) + self.connect (self.noisegen, tail) self.noisegen.set_type (type) self.src = self.noisegen else: @@ -156,6 +168,8 @@ def main (): help="set output gain to GAIN [default=%default]") parser.add_option ("-o", "--offset", type="eng_float", default=0, help="set waveform offset to OFFSET [default=%default]") + parser.add_option ("-N", "--nsamples", type="eng_float", default=0, + help="set number of samples to transmit [default=+inf]") (options, args) = parser.parse_args () if len(args) != 0: @@ -167,7 +181,7 @@ def main (): parser.print_help() raise SystemExit - tb = my_top_block() + tb = my_top_block(options.nsamples) tb.set_interpolator (options.interp) tb.set_waveform_type (options.type) tb.set_waveform_freq (options.waveform_freq) -- cgit From a0d13b42bfb3fd081d77e9d73cf4db9695a6d88b Mon Sep 17 00:00:00 2001 From: trondeau Date: Wed, 12 Aug 2009 03:39:03 +0000 Subject: Merging trondeau/pfb r11249:11581 into trunk. This adds a few polyphase filterbank implementations that do (integer) decimation, (integer) interpolation, arbitrary resampling, and channelizing. gnuradio-example/python/pfb includes a number of different examples of how to use these blocks. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11583 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/gr_plot_const.py | 8 +++----- gr-utils/src/python/gr_plot_fft.py | 13 +++---------- gr-utils/src/python/gr_plot_iq.py | 7 ++----- gr-utils/src/python/gr_plot_psd.py | 13 +++---------- gr-utils/src/python/plot_data.py | 3 --- 5 files changed, 11 insertions(+), 33 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 355309955..ec2272c74 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -35,9 +35,6 @@ except ImportError: from optparse import OptionParser -matplotlib.interactive(True) -matplotlib.use('TkAgg') - class draw_constellation: def __init__(self, filename, options): self.hfile = open(filename, "r") @@ -139,8 +136,9 @@ class draw_constellation: draw() def zoom(self, event): - newxlim = self.sp_iq.get_xlim() - if(newxlim.all() != self.xlim.all()): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim.all() != curxlim.all()): self.xlim = newxlim r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py index 59a3f286b..a9c1417f9 100755 --- a/gr-utils/src/python/gr_plot_fft.py +++ b/gr-utils/src/python/gr_plot_fft.py @@ -20,14 +20,6 @@ # Boston, MA 02110-1301, USA. # -try: - import matplotlib - matplotlib.use('TkAgg') - matplotlib.interactive(True) -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - try: import scipy from scipy import fftpack @@ -164,8 +156,9 @@ class gr_plot_fft: draw() def zoom(self, event): - newxlim = self.sp_iq.get_xlim() - if(newxlim.all() != self.xlim.all()): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim.all() != curxlim.all()): self.xlim = newxlim xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) diff --git a/gr-utils/src/python/gr_plot_iq.py b/gr-utils/src/python/gr_plot_iq.py index 2a4142a81..371ce3b79 100755 --- a/gr-utils/src/python/gr_plot_iq.py +++ b/gr-utils/src/python/gr_plot_iq.py @@ -34,10 +34,7 @@ except ImportError: from optparse import OptionParser -matplotlib.interactive(True) -matplotlib.use('TkAgg') - -class draw_fft: +class draw_iq: def __init__(self, filename, options): self.hfile = open(filename, "r") self.block_length = options.block @@ -168,7 +165,7 @@ def main(): raise SystemExit, 1 filename = args[0] - dc = draw_fft(filename, options) + dc = draw_iq(filename, options) if __name__ == "__main__": try: diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 669d7b573..0e3dbecd9 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -20,14 +20,6 @@ # Boston, MA 02110-1301, USA. # -try: - import matplotlib - matplotlib.use('TkAgg') - matplotlib.interactive(True) -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - try: import scipy from scipy import fftpack @@ -187,8 +179,9 @@ class gr_plot_psd: draw() def zoom(self, event): - newxlim = self.sp_iq.get_xlim() - if(newxlim.all() != self.xlim.all()): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim.all() != curxlim.all()): self.xlim = newxlim xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) diff --git a/gr-utils/src/python/plot_data.py b/gr-utils/src/python/plot_data.py index 7c79e1714..08cdd6030 100644 --- a/gr-utils/src/python/plot_data.py +++ b/gr-utils/src/python/plot_data.py @@ -33,9 +33,6 @@ except ImportError: from optparse import OptionParser -matplotlib.interactive(True) -matplotlib.use('TkAgg') - class plot_data: def __init__(self, datatype, filenames, options): self.hfile = list() -- cgit From 253018c6cdb114f5662a2d7ba8ed748c6e68e3a7 Mon Sep 17 00:00:00 2001 From: git Date: Fri, 14 Aug 2009 18:10:11 +0000 Subject: Added git ignore files auto created from svn:ignore properties. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11592 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 gr-utils/src/python/.gitignore (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/.gitignore b/gr-utils/src/python/.gitignore new file mode 100644 index 000000000..b6950912c --- /dev/null +++ b/gr-utils/src/python/.gitignore @@ -0,0 +1,3 @@ +/Makefile +/Makefile.in +/*.pyc -- cgit From 392227182979367a981606e86c7ec24314555c04 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 14 Aug 2009 23:29:17 -0400 Subject: Adding a QT-based data file viewer. This is the start of an application to read in data files and display them in a useful manner. --- gr-utils/src/python/gr_plot_qt.py | 504 ++++++++++++++++++++++++++++++++++++++ gr-utils/src/python/pyqt_plot.py | 182 ++++++++++++++ gr-utils/src/python/pyqt_plot.ui | 340 +++++++++++++++++++++++++ 3 files changed, 1026 insertions(+) create mode 100755 gr-utils/src/python/gr_plot_qt.py create mode 100644 gr-utils/src/python/pyqt_plot.py create mode 100644 gr-utils/src/python/pyqt_plot.ui (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py new file mode 100755 index 000000000..7c744f2c6 --- /dev/null +++ b/gr-utils/src/python/gr_plot_qt.py @@ -0,0 +1,504 @@ +#!/usr/bin/env python + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +import sys, os +from PyQt4 import Qt, QtCore, QtGui +import PyQt4.Qwt5 as Qwt +from matplotlib import mlab +from optparse import OptionParser +from gnuradio import eng_notation + +from pyqt_plot import Ui_MainWindow + +class gr_plot_qt(QtGui.QMainWindow): + def __init__(self, qapp, filename, options, parent=None): + QtGui.QWidget.__init__(self, parent) + self.gui = Ui_MainWindow() + self.gui.setupUi(self) + + self.block_length = options.block_length + self.start = options.start + self.sample_rate = options.sample_rate + self.psdfftsize = options.psd_size + self.specfftsize = options.spec_size + self.winfunc = scipy.blackman + self.sizeof_data = 8 + self.datatype = scipy.complex64 + self.iq = list() + self.time = list() + + # Set up basic plot attributes + self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, "Time (sec)") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, "Frequency (Hz)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)") + + # Set up FFT size combo box + self.gui.fftComboBox.addItems(["128", "256", "512", "1024", "2048", + "4096", "8192", "16384", "32768"]) + pos = self.gui.fftComboBox.findText(Qt.QString("%1").arg(self.psdfftsize)) + self.gui.fftComboBox.setCurrentIndex(pos) + self.connect(self.gui.fftComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.fftComboBoxEdit) + + # Set up color scheme box + self.color_modes = {"Black on White" : self.color_black_on_white, + "White on Black" : self.color_white_on_black, + "Blue on Black" : self.color_blue_on_black, + "Green on Black" : self.color_green_on_black} + self.gui.colorComboBox.addItems(self.color_modes.keys()) + pos = self.gui.colorComboBox.findText("Blue on Black") + self.gui.colorComboBox.setCurrentIndex(pos) + self.connect(self.gui.colorComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.colorComboBoxEdit) + + + # Create zoom functionality for the plots + self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, + self.gui.timePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.timePlot.canvas()) + + self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, + self.gui.freqPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.freqPlot.canvas()) + + self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, + self.gui.timePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPlotPicker.CrossRubberBand, + Qwt.QwtPicker.AlwaysOn, + self.gui.timePlot.canvas()) + self.picker.connect(self.picker, + Qt.SIGNAL('selected(const QwtDoublePoint&)'), + self.clickMe) + + # Set up action when tab is changed + self.connect(self.gui.tabGroup, + Qt.SIGNAL("currentChanged (int)"), + self.tabChanged) + + # Add a legend to the Time plot + legend_real = Qwt.QwtLegend() + self.gui.timePlot.insertLegend(legend_real) + + # Set up slider + self.gui.plotHBar.setSingleStep(1) + self.gui.plotHBar.setPageStep(self.block_length) + self.gui.plotHBar.setMinimum(0) + self.gui.plotHBar.setMaximum(self.block_length) + self.connect(self.gui.plotHBar, + Qt.SIGNAL("valueChanged(int)"), + self.sliderMoved) + + # Connect Open action to Open Dialog box + self.connect(self.gui.action_open, + Qt.SIGNAL("activated()"), + self.open_file) + + # Set up file position boxes to update current figure + self.connect(self.gui.filePosStartLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_position_changed) + self.connect(self.gui.filePosStopLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_position_changed) + self.connect(self.gui.filePosLengthLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_length_changed) + + self.connect(self.gui.fileTimeStartLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_changed) + self.connect(self.gui.fileTimeStopLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_changed) + self.connect(self.gui.fileTimeLengthLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_length_changed) + + self.rcurve = Qwt.QwtPlotCurve("Real") + self.icurve = Qwt.QwtPlotCurve("Imaginary") + + self.icurve.attach(self.gui.timePlot) + self.rcurve.attach(self.gui.timePlot) + + self.psdcurve = Qwt.QwtPlotCurve("PSD") + self.psdcurve.attach(self.gui.freqPlot) + + # Set up initial color scheme + self.color_modes["Blue on Black"]() + + self.set_sample_rate(self.sample_rate) + self.connect(self.gui.sampleRateLineEdit, + Qt.SIGNAL("editingFinished()"), + self.sample_rate_changed) + + if(filename is not None): + self.initialize(filename) + + self.show() + + def open_file(self): + filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") + print filename + self.initialize(filename) + + def initialize(self, filename): + self.hfile = open(filename, "r") + + self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) + + self.cur_start = 0 + self.cur_stop = self.block_length + + self.init_data_input() + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.gui.plotHBar.setSliderPosition(0) + self.gui.plotHBar.setMaximum(self.signal_size) + + self.update_time_curves() + self.update_psd_curves() + + def init_data_input(self): + self.hfile.seek(0, os.SEEK_END) + self.signal_size = self.hfile.tell()/self.sizeof_data + print "Sizeof File: ", self.signal_size + self.hfile.seek(0, os.SEEK_SET) + + def get_data(self, start, end): + if(end > start): + self.hfile.seek(start*self.sizeof_data, os.SEEK_SET) + self.position = start + iq = scipy.fromfile(self.hfile, dtype=self.datatype, + count=end-start) + if(len(iq) < (end-start)): + print "End of File" + else: + tstep = 1.0 / self.sample_rate + self.iq = iq + self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + + self.set_file_pos_box(start, end) + else: + # Do we want to do anything about this? + pass + + def get_psd(self): + winpoints = self.winfunc(self.psdfftsize) + iq_psd, freq = mlab.psd(self.iq, Fs=self.sample_rate, + NFFT=self.psdfftsize, + noverlap=self.psdfftsize/4.0, + window=winpoints, + scale_by_freq=False) + self.iq_psd = 10.0*scipy.log10(abs(fftpack.fftshift(iq_psd))) + self.freq = freq - self.sample_rate/2.0 + + + def clickMe(self, qPoint): + print qPoint.x() + + def fftComboBoxEdit(self, fftSize): + self.psdfftsize = fftSize.toInt()[0] + self.get_psd() + self.update_psd_curves() + + def colorComboBoxEdit(self, colorSelection): + colorstr = str(colorSelection.toAscii()) + color_func = self.color_modes[colorstr] + color_func() + + def sliderMoved(self, value): + pos_start = value + pos_end = value + self.gui.plotHBar.pageStep() + + self.get_data(pos_start, pos_end) + self.get_psd() + self.update_time_curves() + self.update_psd_curves() + + def set_sample_rate(self, sr): + self.sample_rate = sr + srstr = eng_notation.num_to_str(self.sample_rate) + self.gui.sampleRateLineEdit.setText(Qt.QString("%1").arg(srstr)) + + def sample_rate_changed(self): + srstr = self.gui.sampleRateLineEdit.text().toAscii() + self.sample_rate = eng_notation.str_to_num(srstr) + self.set_file_pos_box(self.cur_start, self.cur_stop) + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.update_time_curves() + self.update_psd_curves() + + def set_file_pos_box(self, start, end): + tstart = start / self.sample_rate + tend = end / self.sample_rate + + self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(start)) + self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(end)) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end-start)) + + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tend-tstart)) + + def file_position_changed(self): + start = self.gui.filePosStartLineEdit.text().toInt() + end = self.gui.filePosStopLineEdit.text().toInt() + if((start[1] == True) and (end[1] == True)): + self.cur_start = start[0] + self.cur_stop = end[0] + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + + self.get_data(self.cur_start, self.cur_stop) + + self.update_time_curves() + self.update_psd_curves() + + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + def file_time_changed(self): + tstart = self.gui.fileTimeStartLineEdit.text().toDouble() + tstop = self.gui.fileTimeStopLineEdit.text().toDouble() + if((tstart[1] == True) and (tstop[1] == True)): + self.cur_start = int(tstart[0] * self.sample_rate) + self.cur_stop = int(tstop[0] * self.sample_rate) + self.get_data(self.cur_start, self.cur_stop) + + self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(self.cur_start)) + self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(self.cur_stop)) + + self.update_time_curves() + self.update_psd_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + def file_length_changed(self): + start = self.gui.filePosStartLineEdit.text().toInt() + length = self.gui.filePosLengthLineEdit.text().toInt() + if((start[1] == True) and (length[1] == True)): + self.cur_start = start[0] + self.block_length = length[0] + self.cur_stop = self.cur_start + self.block_length + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + tlen = self.block_length / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) + + self.gui.plotHBar.setPageStep(self.block_length) + + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + + self.update_time_curves() + self.update_psd_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + def file_time_length_changed(self): + tstart = self.gui.fileTimeStartLineEdit.text().toDouble() + tlength = self.gui.fileTimeLengthLineEdit.text().toDouble() + if((tstart[1] == True) and (tlength[1] == True)): + self.cur_start = int(tstart[0] * self.sample_rate) + self.block_length = int(tlength[0] * self.sample_rate) + self.cur_stop = self.cur_start + self.block_length + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + tlen = self.block_length / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) + + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + + self.update_time_curves() + self.update_psd_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + + def update_time_curves(self): + self.icurve.setData(self.time, self.iq.imag) + self.rcurve.setData(self.time, self.iq.real) + + # Reset the x-axis to the new time scale + iqmax = 1.5 * max(max(self.iq.real), max(self.iq.imag)) + iqmin = 1.5 * min(min(self.iq.real), min(self.iq.imag)) + self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, + min(self.time), + max(self.time)) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + iqmin, + iqmax) + + # Set the zoomer base to unzoom to the new axis + self.timeZoomer.setZoomBase() + + self.gui.timePlot.replot() + + def update_psd_curves(self): + self.psdcurve.setData(self.freq, self.iq_psd) + + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, + min(self.freq), + max(self.freq)) + + # Set the zoomer base to unzoom to the new axis + self.freqZoomer.setZoomBase() + + self.gui.freqPlot.replot() + + def tabChanged(self, index): + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + def color_black_on_white(self): + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + blackBrush = Qt.QBrush(Qt.QColor("black")) + blueBrush = Qt.QBrush(Qt.QColor(blue)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) + self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) + self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) + self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) + self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) + self.freqZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) + self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) + self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + def color_white_on_black(self): + white = QtGui.qRgb(0xFF, 0xFF, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + whiteBrush = Qt.QBrush(Qt.QColor(white)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.psdcurve.setPen(Qt.QPen(whiteBrush, 1)) + self.rcurve.setPen(Qt.QPen(whiteBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + + def color_green_on_black(self): + green = QtGui.qRgb(0x00, 0xFF, 0x00) + red = QtGui.qRgb(0xFF, 0x00, 0x50) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + greenBrush = Qt.QBrush(Qt.QColor(green)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.psdcurve.setPen(Qt.QPen(greenBrush, 1)) + self.rcurve.setPen(Qt.QPen(greenBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + def color_blue_on_black(self): + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + blueBrush = Qt.QBrush(Qt.QColor(blue)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) + self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) + self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + +def setup_options(): + usage="%prog: [options] (input_filename)" + description = "" + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block-length", type="int", default=8192, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + parser.add_option("", "--psd-size", type="int", default=2048, + help="Set the size of the PSD FFT [default=%default]") + parser.add_option("", "--spec-size", type="int", default=256, + help="Set the size of the spectrogram FFT [default=%default]") + + return parser + +def main(args): + parser = setup_options() + (options, args) = parser.parse_args () + + if(len(args) == 1): + filename = args[0] + else: + filename = None + + app = Qt.QApplication(args) + gplt = gr_plot_qt(app, filename, options) + app.exec_() + +if __name__ == '__main__': + main(sys.argv) + diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py new file mode 100644 index 000000000..796b6a238 --- /dev/null +++ b/gr-utils/src/python/pyqt_plot.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'pyqt_plot.ui' +# +# Created: Tue Aug 11 23:12:27 2009 +# by: PyQt4 UI code generator 4.4.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(927, 696) + self.centralwidget = QtGui.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtGui.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.plotHBar = QtGui.QScrollBar(self.centralwidget) + self.plotHBar.setOrientation(QtCore.Qt.Horizontal) + self.plotHBar.setObjectName("plotHBar") + self.gridLayout.addWidget(self.plotHBar, 2, 0, 1, 2) + self.tabGroup = QtGui.QTabWidget(self.centralwidget) + self.tabGroup.setObjectName("tabGroup") + self.timeTab = QtGui.QWidget() + self.timeTab.setObjectName("timeTab") + self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab) + self.horizontalLayout.setObjectName("horizontalLayout") + self.timePlot = Qwt5.QwtPlot(self.timeTab) + self.timePlot.setObjectName("timePlot") + self.horizontalLayout.addWidget(self.timePlot) + self.tabGroup.addTab(self.timeTab, "") + self.freqTab = QtGui.QWidget() + self.freqTab.setObjectName("freqTab") + self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.fftPropBox = QtGui.QGroupBox(self.freqTab) + self.fftPropBox.setMinimumSize(QtCore.QSize(160, 0)) + self.fftPropBox.setObjectName("fftPropBox") + self.formLayoutWidget = QtGui.QWidget(self.fftPropBox) + self.formLayoutWidget.setGeometry(QtCore.QRect(0, 20, 151, 191)) + self.formLayoutWidget.setObjectName("formLayoutWidget") + self.formLayout = QtGui.QFormLayout(self.formLayoutWidget) + self.formLayout.setObjectName("formLayout") + self.fftSizeLabel = QtGui.QLabel(self.formLayoutWidget) + self.fftSizeLabel.setObjectName("fftSizeLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fftSizeLabel) + self.fftComboBox = QtGui.QComboBox(self.formLayoutWidget) + self.fftComboBox.setObjectName("fftComboBox") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fftComboBox) + self.horizontalLayout_2.addWidget(self.fftPropBox) + self.freqPlot = Qwt5.QwtPlot(self.freqTab) + self.freqPlot.setObjectName("freqPlot") + self.horizontalLayout_2.addWidget(self.freqPlot) + self.tabGroup.addTab(self.freqTab, "") + self.gridLayout.addWidget(self.tabGroup, 1, 0, 1, 1) + self.filePosBox = QtGui.QGroupBox(self.centralwidget) + self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) + self.filePosBox.setObjectName("filePosBox") + self.formLayoutWidget_2 = QtGui.QWidget(self.filePosBox) + self.formLayoutWidget_2.setGeometry(QtCore.QRect(0, 20, 160, 92)) + self.formLayoutWidget_2.setObjectName("formLayoutWidget_2") + self.filePosLayout = QtGui.QFormLayout(self.formLayoutWidget_2) + self.filePosLayout.setObjectName("filePosLayout") + self.filePosStartLabel = QtGui.QLabel(self.formLayoutWidget_2) + self.filePosStartLabel.setObjectName("filePosStartLabel") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel) + self.filePosStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) + self.filePosStartLineEdit.setObjectName("filePosStartLineEdit") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit) + self.filePosStopLabel = QtGui.QLabel(self.formLayoutWidget_2) + self.filePosStopLabel.setObjectName("filePosStopLabel") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel) + self.filePosStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) + self.filePosStopLineEdit.setObjectName("filePosStopLineEdit") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit) + self.filePosLengthLabel = QtGui.QLabel(self.formLayoutWidget_2) + self.filePosLengthLabel.setObjectName("filePosLengthLabel") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel) + self.filePosLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) + self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit) + self.formLayoutWidget_4 = QtGui.QWidget(self.filePosBox) + self.formLayoutWidget_4.setGeometry(QtCore.QRect(180, 20, 231, 92)) + self.formLayoutWidget_4.setObjectName("formLayoutWidget_4") + self.fileTimeLayout = QtGui.QFormLayout(self.formLayoutWidget_4) + self.fileTimeLayout.setObjectName("fileTimeLayout") + self.fileTimeStartLabel = QtGui.QLabel(self.formLayoutWidget_4) + self.fileTimeStartLabel.setObjectName("fileTimeStartLabel") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel) + self.fileTimeStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) + self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit) + self.fileTimeStopLabel = QtGui.QLabel(self.formLayoutWidget_4) + self.fileTimeStopLabel.setObjectName("fileTimeStopLabel") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel) + self.fileTimeStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) + self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit) + self.fileTimeLengthLabel = QtGui.QLabel(self.formLayoutWidget_4) + self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel) + self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) + self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit) + self.sysGroupBox = QtGui.QGroupBox(self.filePosBox) + self.sysGroupBox.setGeometry(QtCore.QRect(530, 0, 200, 120)) + self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0)) + self.sysGroupBox.setObjectName("sysGroupBox") + self.formLayoutWidget_3 = QtGui.QWidget(self.sysGroupBox) + self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 20, 191, 91)) + self.formLayoutWidget_3.setObjectName("formLayoutWidget_3") + self.formLayout_2 = QtGui.QFormLayout(self.formLayoutWidget_3) + self.formLayout_2.setObjectName("formLayout_2") + self.sampleRateLabel = QtGui.QLabel(self.formLayoutWidget_3) + self.sampleRateLabel.setObjectName("sampleRateLabel") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) + self.sampleRateLineEdit = QtGui.QLineEdit(self.formLayoutWidget_3) + self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(0, 0)) + self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) + self.displayGroupBox = QtGui.QGroupBox(self.filePosBox) + self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 120)) + self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) + self.displayGroupBox.setObjectName("displayGroupBox") + self.verticalLayoutWidget = QtGui.QWidget(self.displayGroupBox) + self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 20, 160, 91)) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget) + self.verticalLayout.setObjectName("verticalLayout") + self.colorComboBox = QtGui.QComboBox(self.verticalLayoutWidget) + self.colorComboBox.setObjectName("colorComboBox") + self.verticalLayout.addWidget(self.colorComboBox) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtGui.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 25)) + self.menubar.setObjectName("menubar") + self.menu_File = QtGui.QMenu(self.menubar) + self.menu_File.setObjectName("menu_File") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtGui.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.action_open = QtGui.QAction(MainWindow) + self.action_open.setObjectName("action_open") + self.action_exit = QtGui.QAction(MainWindow) + self.action_exit.setObjectName("action_exit") + self.menu_File.addAction(self.action_open) + self.menu_File.addAction(self.action_exit) + self.menubar.addAction(self.menu_File.menuAction()) + + self.retranslateUi(MainWindow) + self.tabGroup.setCurrentIndex(0) + QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.fftSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosBox.setTitle(QtGui.QApplication.translate("MainWindow", "File Position", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosStopLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "Length", None, QtGui.QApplication.UnicodeUTF8)) + self.fileTimeStartLabel.setText(QtGui.QApplication.translate("MainWindow", "time start (sec)", None, QtGui.QApplication.UnicodeUTF8)) + self.fileTimeStopLabel.setText(QtGui.QApplication.translate("MainWindow", "time stop (sec)", None, QtGui.QApplication.UnicodeUTF8)) + self.fileTimeLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "time length (sec)", None, QtGui.QApplication.UnicodeUTF8)) + self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8)) + self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) + self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) + self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) + self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + +from PyQt4 import Qwt5 diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui new file mode 100644 index 000000000..f298735c4 --- /dev/null +++ b/gr-utils/src/python/pyqt_plot.ui @@ -0,0 +1,340 @@ + + + MainWindow + + + + 0 + 0 + 927 + 696 + + + + MainWindow + + + + + + + Qt::Horizontal + + + + + + + 0 + + + + Time Domain + + + + + + + + + + Frequency Domain + + + + + + + 160 + 0 + + + + FFT Properties + + + + + 0 + 20 + 151 + 191 + + + + + + + FFT Size + + + + + + + + + + + + + + + + + + + + + + 0 + 120 + + + + File Position + + + + + 0 + 20 + 160 + 92 + + + + + + + Start + + + + + + + + + + Stop + + + + + + + + + + Length + + + + + + + + + + + + 180 + 20 + 231 + 92 + + + + + + + time start (sec) + + + + + + + + + + time stop (sec) + + + + + + + + + + time length (sec) + + + + + + + + + + + + 530 + 0 + 200 + 120 + + + + + 200 + 0 + + + + System Properties + + + + + 0 + 20 + 191 + 91 + + + + + + + Sample Rate + + + + + + + + 0 + 0 + + + + + + + + + + + 730 + 0 + 170 + 120 + + + + + 170 + 0 + + + + Display Properties + + + + + 0 + 20 + 160 + 91 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + 0 + 0 + 927 + 25 + + + + + &File + + + + + + + + + + &Open + + + Ctrl+O + + + + + E&xit + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + + + action_exit + activated() + MainWindow + close() + + + -1 + -1 + + + 399 + 347 + + + + +
-- cgit From ea57c1b52b8bed12296ba51441afcfc57a0b9d34 Mon Sep 17 00:00:00 2001 From: eb Date: Sat, 15 Aug 2009 18:34:45 +0000 Subject: Merged VRT work-in-progress from eb/vrt2 (11518:11598) into trunk. Passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11600 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-utils/src/python/Makefile.am | 1 + gr-utils/src/python/qr_fft.py | 505 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 506 insertions(+) create mode 100755 gr-utils/src/python/qr_fft.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index b58faa9bf..65cbd536c 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -44,6 +44,7 @@ bin_SCRIPTS = \ gr_plot_iq.py \ gr_plot_short.py \ lsusrp \ + qr_fft.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py new file mode 100755 index 000000000..c2f06d715 --- /dev/null +++ b/gr-utils/src/python/qr_fft.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python +# +# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio.wxgui import forms +from gnuradio import gr, gru +from gnuradio import vrt +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider +from gnuradio.gr import pubsub +from optparse import OptionParser +import wx +import sys +import numpy +import time + +class app_top_block(stdgui2.std_top_block, pubsub.pubsub): + def __init__(self, frame, panel, vbox, argv): + stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) + pubsub.pubsub.__init__(self) + self.frame = frame + self.panel = panel + + parser = OptionParser(option_class=eng_option) + #parser.add_option("-e", "--interface", type="string", default="eth0", + # help="select Ethernet interface, default is eth0") + #parser.add_option("-m", "--mac-addr", type="string", default="", + # help="select USRP by MAC address, default is auto-select") + #parser.add_option("-A", "--antenna", default=None, + # help="select Rx Antenna (only on RFX-series boards)") + #parser.add_option("-d", "--decim", type="int", default=16, + # help="set fgpa decimation rate to DECIM [default=%default]") + #parser.add_option("-f", "--freq", type="eng_float", default=None, + # help="set frequency to FREQ", metavar="FREQ") + #parser.add_option("-g", "--gain", type="eng_float", default=None, + # help="set gain in dB (default is midpoint)") + parser.add_option("-W", "--waterfall", action="store_true", default=False, + help="Enable waterfall display") + parser.add_option("-S", "--oscilloscope", action="store_true", default=False, + help="Enable oscilloscope display") + parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, + help="Set fftsink averaging factor, default=[%default]") + parser.add_option("", "--ref-scale", type="eng_float", default=1.0, + help="Set dBFS=0dB input value, default=[%default]") + parser.add_option("--fft-size", type="int", default=1024, + help="Set number of FFT bins [default=%default]") + parser.add_option("--samples-per-pkt", type="int", default=0, + help="Set number of SAMPLES-PER-PKT [default=%default]") + parser.add_option("", "--ip-addr", type="string", default="192.168.10.2", + help="IP address 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.u = vrt.quadradio_source_32fc(options.ip_addr, + int(62.5e6), options.samples_per_pkt) + #self.u.set_decim(options.decim) + + #input_rate = self.u.adc_rate() / self.u.decim() + input_rate = int(120e6/4) + + if options.waterfall: + self.scope = \ + waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) + elif options.oscilloscope: + self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) + else: + self.scope = fftsink2.fft_sink_c (panel, + fft_size=options.fft_size, + sample_rate=input_rate, + ref_scale=options.ref_scale, + ref_level=20.0, + y_divs = 12, + avg_alpha=options.avg_alpha) + + self.connect(self.u, self.scope) + + self._build_gui(vbox) + self._setup_events() + + # set initial values + + #if options.gain is None: + # # if no gain was specified, use the mid-point in dB + # g = self.u.gain_range() + # options.gain = float(g[0]+g[1])/2 + + #if options.freq is None: + # # if no freq was specified, use the mid-point + # r = self.u.freq_range() + # options.freq = float(r[0]+r[1])/2 + + #self.set_gain(options.gain) + + #if options.antenna is not None: + # print "Selecting antenna %s" % (options.antenna,) + # self.subdev.select_rx_antenna(options.antenna) + + if self.show_debug_info: + # self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) + # self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name + self.myform['baseband'].set_value(0) + self.myform['ddc'].set_value(0) + + #if not(self.set_freq(options.freq)): + # self._set_status_msg("Failed to set initial frequency") + + def _set_status_msg(self, msg): + self.frame.GetStatusBar().SetStatusText(msg, 0) + + def _build_gui(self, vbox): + + def _form_set_freq(kv): + return self.set_freq(kv['freq']) + + vbox.Add(self.scope.win, 10, wx.EXPAND) + + # add control area at the bottom + self.myform = myform = form.form() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,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((5,0), 0, 0) + #g = self.u.gain_range() + + # some configurations don't have gain control + if 0 and g[1] > g[0]: + myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", + weight=3, + min=int(g[0]), max=int(g[1]), + callback=self.set_gain) + + hbox.Add((5,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_decim(kv): + return self.set_decim(kv['decim']) + + if not(self.show_debug_info): + return + + panel = self.panel + vbox = vbox_arg + myform = self.myform + + #panel = wx.Panel(self.panel, -1) + #vbox = wx.BoxSizer(wx.VERTICAL) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((5,0), 0) + + myform['decim'] = form.int_field( + parent=panel, sizer=hbox, label="Decim", + callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) + + hbox.Add((5,0), 1) + myform['fs@gbe'] = form.static_float_field( + parent=panel, sizer=hbox, label="Fs@GbE") + + hbox.Add((5,0), 1) + myform['dbname'] = form.static_text_field( + parent=panel, sizer=hbox) + + hbox.Add((5,0), 1) + myform['baseband'] = form.static_float_field( + parent=panel, sizer=hbox, label="Analog BB") + + hbox.Add((5,0), 1) + myform['ddc'] = form.static_float_field( + parent=panel, sizer=hbox, label="DDC") + + hbox.Add((5,0), 0) + vbox.Add(hbox, 0, wx.EXPAND) + ##### db control stuff ##### + self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01)) + self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq + self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01)) + self.subscribe('db_ctrl_atten0', self.u.set_attenuation0) + self.subscribe('db_ctrl_atten1', self.u.set_attenuation1) + self.subscribe('sys_beaming', self.u.set_beamforming) + #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten) + self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain) + self.subscribe('db_ctrl_diggain', self.u.set_digital_gain) + self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp) + self.subscribe('db_ctrl_bandsel', self.u.set_band_select) + self.subscribe('db_ctrl_type', self.u.select_rx_antenna) + self.subscribe('db_test_signal', self.u.set_test_signal) + self['db_ctrl_bandsel'] = 'A' + self['cal_div_lo_freq'] = 2.1e9 + self['cal_div_cal_freq'] = 2.102e9 + self['db_ctrl_atten0'] = 0 + self['db_ctrl_atten1'] = 0 + #self['db_ctrl_10db'] = False + self['db_ctrl_adcgain'] = False + self['db_ctrl_dcoffset'] = False + self['db_ctrl_diggain'] = 0.0 + self['db_ctrl_type'] = 'rf' + self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL + self['sys_beaming'] = [16.7e6, 0, 0, 0] + #slider and box for freqs + for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')): + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + forms.text_box( + label=name, + ps=self, + key=key, + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.float_converter() + ) + hbox.AddSpacer(20) + forms.slider( + ps=self, + key=key, + minimum=0, #TODO get bounds from cal_div, from vrt... + maximum=int(3.5e9), + step_size=int(5e6), + cast=float, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + ############################################ + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + #create slider for atten + atten0_txt_box = forms.static_text( + label='Attenuation (0)', + ps=self, + key='db_ctrl_atten0', + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.int_converter() + ) + hbox.AddSpacer(20) + atten0_slider = forms.slider( + ps=self, + key='db_ctrl_atten0', + minimum=0, + maximum=31, + step_size=1, + cast=int, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + #create slider for atten + forms.static_text( + label='Attenuation (1)', + ps=self, + key='db_ctrl_atten1', + sizer=hbox, + parent=panel, + proportion=0, + converter=forms.int_converter() + ) + hbox.AddSpacer(20) + forms.slider( + ps=self, + key='db_ctrl_atten1', + minimum=0, + maximum=31, + step_size=1, + cast=int, + sizer=hbox, + parent=panel, + proportion=2, + ) + hbox.AddSpacer(10) + def update_atten0(*args): + for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B') + update_atten0() + self.subscribe('db_ctrl_bandsel', update_atten0) + #create checkbox for 10dB att + #forms.check_box( + # label='10dB Attenuation', + # ps=self, + # key='db_ctrl_10db', + # sizer=hbox, + # parent=panel, + # proportion=1, + #) + #hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + hbox2 = wx.BoxSizer(wx.HORIZONTAL) + hbox2.AddSpacer(10) + forms.static_text( + label='ADC Controls', + ps=self, + key='db_ctrl_diggain', + sizer=hbox2, + parent=panel, + proportion=0, + converter=forms.float_converter() + ) + hbox2.AddSpacer(20) + #create checkbox for ADC digital gain + forms.slider( + #label='ADC Digital Gain', + ps=self, + minimum=0, + maximum=6, + step_size=0.5, + key='db_ctrl_diggain', + sizer=hbox2, + parent=panel, + proportion=2, + ) + hbox2.AddSpacer(10) + #create checkbox for 3.5dB ADC gain + forms.check_box( + label='3.5dB ADC Gain', + ps=self, + key='db_ctrl_adcgain', + sizer=hbox2, + parent=panel, + proportion=1, + ) + hbox2.AddSpacer(10) + #create checkbox for DC Offset Correction in ADC + forms.check_box( + label='DC Offset Correction', + ps=self, + key='db_ctrl_dcoffset', + sizer=hbox2, + parent=panel, + proportion=2, + ) + hbox2.AddSpacer(10) + vbox.Add(hbox2, 0, wx.EXPAND) + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.AddSpacer(10) + #create radio buttons for band sel + forms.radio_buttons( + label='Band Select', + ps=self, + key='db_ctrl_bandsel', + choices=['A', 'B', 'C', 'D'], + labels=['A', 'B', 'C', 'D'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + forms.radio_buttons( + label='RF Input', + ps=self, + key='db_ctrl_type', + choices=['rf', 'cal'], + labels=['Main RF', 'Calibrator'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + #create radio buttons for band sel + types = sorted( + filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)), + lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)), + ) + forms.drop_down( + label='Test Signal', + ps=self, + key='db_test_signal', + choices=map(lambda a: getattr(vrt, a), types), + labels=types, + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + #create radio buttons for type + forms.drop_down( + label='Beamformer', + ps=self, + key='sys_beaming', + choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4], + labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'], + sizer=hbox, + parent=panel, + proportion=0, + ) + hbox.AddSpacer(10) + vbox.Add(hbox, 0, wx.EXPAND) + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital down converter. + """ + return True + + r = self.u.set_center_freq(target_freq) + + if r: + self.myform['freq'].set_value(target_freq) # update displayed value + if self.show_debug_info: + self.myform['baseband'].set_value(r.baseband_freq) + self.myform['ddc'].set_value(r.dxc_freq) + if not self.options.oscilloscope: + self.scope.win.set_baseband_freq(target_freq) + return True + + return False + + def set_gain(self, gain): + return True + + if self.myform.has_key('gain'): + self.myform['gain'].set_value(gain) # update displayed value + self.u.set_gain(gain) + + def set_decim(self, decim): + return True + + ok = self.u.set_decim(decim) + if not ok: + print "set_decim failed" + #input_rate = self.u.adc_rate() / self.u.decim() + input_rate = 120e6/4 + self.scope.set_sample_rate(input_rate) + if self.show_debug_info: # update displayed values + self.myform['decim'].set_value(self.u.decim()) + self.myform['fs@gbe'].set_value(input_rate) + return ok + + def _setup_events(self): + if not self.options.waterfall and not self.options.oscilloscope: + self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) + + def evt_left_dclick(self, event): + (ux, uy) = self.scope.win.GetXY(event) + if event.CmdDown(): + # Re-center on maximum power + points = self.scope.win._points + if self.scope.win.peak_hold: + if self.scope.win.peak_vals is not None: + ind = numpy.argmax(self.scope.win.peak_vals) + else: + ind = int(points.shape()[0]/2) + else: + ind = numpy.argmax(points[:,1]) + (freq, pwr) = points[ind] + target_freq = freq/self.scope.win._scale_factor + print ind, freq, pwr + self.set_freq(target_freq) + else: + # Re-center on clicked frequency + target_freq = ux/self.scope.win._scale_factor + self.set_freq(target_freq) + + +def main (): + app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1) + app.MainLoop() + +if __name__ == '__main__': + main () -- cgit From e19946f858e7ede2e76cfd78bc194a3f81c13197 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 18 Aug 2009 22:57:27 -0400 Subject: Adding a graphical tool to design and analyze filters. --- gr-utils/src/python/gr_filter_design.py | 164 +++++++++++++++++++ gr-utils/src/python/pyqt_filter.py | 144 +++++++++++++++++ gr-utils/src/python/pyqt_filter.ui | 261 ++++++++++++++++++++++++++++++ gr-utils/src/python/pyqt_filter_firhpf.py | 47 ++++++ gr-utils/src/python/pyqt_filter_firhpf.ui | 60 +++++++ gr-utils/src/python/pyqt_filter_firlpf.py | 47 ++++++ gr-utils/src/python/pyqt_filter_firlpf.ui | 60 +++++++ 7 files changed, 783 insertions(+) create mode 100755 gr-utils/src/python/gr_filter_design.py create mode 100644 gr-utils/src/python/pyqt_filter.py create mode 100644 gr-utils/src/python/pyqt_filter.ui create mode 100644 gr-utils/src/python/pyqt_filter_firhpf.py create mode 100644 gr-utils/src/python/pyqt_filter_firhpf.ui create mode 100644 gr-utils/src/python/pyqt_filter_firlpf.py create mode 100644 gr-utils/src/python/pyqt_filter_firlpf.ui (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py new file mode 100755 index 000000000..a9f36ed02 --- /dev/null +++ b/gr-utils/src/python/gr_filter_design.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +import sys, os +from PyQt4 import Qt, QtCore, QtGui +import PyQt4.Qwt5 as Qwt +from optparse import OptionParser +from gnuradio import gr, eng_notation +from scipy import fftpack + +from pyqt_filter import Ui_MainWindow +from pyqt_filter_firlpf import Ui_firlpfForm +from pyqt_filter_firhpf import Ui_firhpfForm + +class gr_plot_filter(QtGui.QMainWindow): + def __init__(self, qapp, options): + QtGui.QWidget.__init__(self, None) + self.gui = Ui_MainWindow() + self.gui.setupUi(self) + + self.connect(self.gui.filterTypeComboBox, + Qt.SIGNAL("currentIndexChanged(const QString&)"), + self.changed_filter_type) + self.connect(self.gui.filterDesignTypeComboBox, + Qt.SIGNAL("currentIndexChanged(const QString&)"), + self.changed_filter_design_type) + + self.connect(self.gui.designButton, + Qt.SIGNAL("released()"), + self.design) + + self.fltdeslpf = Ui_firlpfForm() + self.fltdeshpf = Ui_firhpfForm() + + self.fltdeslpf.setupUi(self.gui.firlpfPage) + self.fltdeshpf.setupUi(self.gui.firhpfPage) + + # Initialize to LPF + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + + # Set up plot curves + self.rcurve = Qwt.QwtPlotCurve("Real") + self.rcurve.attach(self.gui.timePlot) + + self.freqcurve = Qwt.QwtPlotCurve("PSD") + self.freqcurve.attach(self.gui.freqPlot) + + # Create zoom functionality for the plots + self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, + self.gui.timePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.timePlot.canvas()) + + self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, + self.gui.freqPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.freqPlot.canvas()) + + # Set up pen for colors and line width + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + blueBrush = Qt.QBrush(Qt.QColor(blue)) + self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) + self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + + self.show() + + def changed_filter_type(self, ftype): + strftype = str(ftype.toAscii()) + if(ftype == "Low Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + elif(ftype == "High Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) + + def changed_filter_design_type(self, design): + print design + + def design(self): + fs = self.gui.sampleRateEdit.text().toDouble()[0] + gain = self.gui.filterGainEdit.text().toDouble()[0] + + ftype = self.gui.filterTypeComboBox.currentText() + if(ftype == "Low Pass"): + taps = self.design_win_lpf(fs, gain) + elif(ftype == "High Pass"): + taps = self.design_win_hpf(fs, gain) + + self.update_time_curves(taps) + self.update_freq_curves(taps) + + def design_win_lpf(self, fs, gain): + pb = self.fltdeslpf.endofPassBandEdit.text().toDouble()[0] + sb = self.fltdeslpf.startofStopBandEdit.text().toDouble()[0] + atten = self.fltdeslpf.stopBandAttenEdit.text().toDouble()[0] + tb = sb - pb + + taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, + gr.firdes.WIN_BLACKMAN_hARRIS) + return taps + + def design_win_hpf(self, fs, gain): + print fs + print widget + + def update_time_curves(self, taps): + ntaps = len(taps) + self.rcurve.setData(scipy.arange(ntaps), taps) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(taps) + ymin = 1.5 * min(taps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, + 0, ntaps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.timeZoomer.setZoomBase() + + self.gui.timePlot.replot() + + def update_freq_curves(self, taps, Npts=1000): + fftpts = fftpack.fft(taps, Npts) + freq = scipy.arange(0, Npts) + + fftdB = 20.0*scipy.log10(abs(fftpts)) + + self.freqcurve.setData(freq, fftdB) + + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, + 0, Npts/2) + + # Set the zoomer base to unzoom to the new axis + self.freqZoomer.setZoomBase() + + self.gui.freqPlot.replot() + + +def setup_options(): + usage="%prog: [options] (input_filename)" + description = "" + + parser = OptionParser(conflict_handler="resolve", + usage=usage, description=description) + return parser + +def main(args): + parser = setup_options() + (options, args) = parser.parse_args () + + app = Qt.QApplication(args) + gplt = gr_plot_filter(app, options) + app.exec_() + +if __name__ == '__main__': + main(sys.argv) + diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py new file mode 100644 index 000000000..a02a8e7f9 --- /dev/null +++ b/gr-utils/src/python/pyqt_filter.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'pyqt_filter.ui' +# +# Created: Tue Aug 18 22:48:21 2009 +# by: PyQt4 UI code generator 4.4.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(624, 696) + self.centralwidget = QtGui.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtGui.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.tabGroup = QtGui.QTabWidget(self.centralwidget) + self.tabGroup.setMinimumSize(QtCore.QSize(800, 0)) + self.tabGroup.setObjectName("tabGroup") + self.freqTab = QtGui.QWidget() + self.freqTab.setObjectName("freqTab") + self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.freqPlot = Qwt5.QwtPlot(self.freqTab) + self.freqPlot.setObjectName("freqPlot") + self.horizontalLayout_2.addWidget(self.freqPlot) + self.tabGroup.addTab(self.freqTab, "") + self.timeTab = QtGui.QWidget() + self.timeTab.setObjectName("timeTab") + self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab) + self.horizontalLayout.setObjectName("horizontalLayout") + self.timePlot = Qwt5.QwtPlot(self.timeTab) + self.timePlot.setObjectName("timePlot") + self.horizontalLayout.addWidget(self.timePlot) + self.tabGroup.addTab(self.timeTab, "") + self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) + self.filterFrame = QtGui.QFrame(self.centralwidget) + self.filterFrame.setMinimumSize(QtCore.QSize(300, 0)) + self.filterFrame.setMaximumSize(QtCore.QSize(300, 16777215)) + self.filterFrame.setFrameShape(QtGui.QFrame.StyledPanel) + self.filterFrame.setFrameShadow(QtGui.QFrame.Raised) + self.filterFrame.setObjectName("filterFrame") + self.verticalLayout = QtGui.QVBoxLayout(self.filterFrame) + self.verticalLayout.setObjectName("verticalLayout") + self.filterTypeComboBox = QtGui.QComboBox(self.filterFrame) + self.filterTypeComboBox.setObjectName("filterTypeComboBox") + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem(QtCore.QString()) + self.verticalLayout.addWidget(self.filterTypeComboBox) + self.filterDesignTypeComboBox = QtGui.QComboBox(self.filterFrame) + self.filterDesignTypeComboBox.setObjectName("filterDesignTypeComboBox") + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.verticalLayout.addWidget(self.filterDesignTypeComboBox) + self.formLayout_2 = QtGui.QFormLayout() + self.formLayout_2.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_2.setObjectName("formLayout_2") + self.sampleRateLabel = QtGui.QLabel(self.filterFrame) + self.sampleRateLabel.setMaximumSize(QtCore.QSize(16777215, 30)) + self.sampleRateLabel.setObjectName("sampleRateLabel") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) + self.sampleRateEdit = QtGui.QLineEdit(self.filterFrame) + self.sampleRateEdit.setMaximumSize(QtCore.QSize(16777215, 30)) + self.sampleRateEdit.setObjectName("sampleRateEdit") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateEdit) + self.filterGainLabel = QtGui.QLabel(self.filterFrame) + self.filterGainLabel.setObjectName("filterGainLabel") + self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.filterGainLabel) + self.filterGainEdit = QtGui.QLineEdit(self.filterFrame) + self.filterGainEdit.setObjectName("filterGainEdit") + self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.filterGainEdit) + self.verticalLayout.addLayout(self.formLayout_2) + self.filterTypeWidget = QtGui.QStackedWidget(self.filterFrame) + self.filterTypeWidget.setObjectName("filterTypeWidget") + self.firlpfPage = QtGui.QWidget() + self.firlpfPage.setObjectName("firlpfPage") + self.filterTypeWidget.addWidget(self.firlpfPage) + self.firhpfPage = QtGui.QWidget() + self.firhpfPage.setObjectName("firhpfPage") + self.filterTypeWidget.addWidget(self.firhpfPage) + self.verticalLayout.addWidget(self.filterTypeWidget) + self.designButton = QtGui.QPushButton(self.filterFrame) + self.designButton.setMinimumSize(QtCore.QSize(0, 0)) + self.designButton.setMaximumSize(QtCore.QSize(200, 16777215)) + self.designButton.setObjectName("designButton") + self.verticalLayout.addWidget(self.designButton) + self.gridLayout.addWidget(self.filterFrame, 1, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtGui.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 624, 25)) + self.menubar.setObjectName("menubar") + self.menu_File = QtGui.QMenu(self.menubar) + self.menu_File.setObjectName("menu_File") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtGui.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.action_open = QtGui.QAction(MainWindow) + self.action_open.setObjectName("action_open") + self.action_exit = QtGui.QAction(MainWindow) + self.action_exit.setObjectName("action_exit") + self.menu_File.addAction(self.action_exit) + self.menubar.addAction(self.menu_File.menuAction()) + + self.retranslateUi(MainWindow) + self.tabGroup.setCurrentIndex(0) + QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.filterTypeComboBox, self.filterDesignTypeComboBox) + MainWindow.setTabOrder(self.filterDesignTypeComboBox, self.sampleRateEdit) + MainWindow.setTabOrder(self.sampleRateEdit, self.filterGainEdit) + MainWindow.setTabOrder(self.filterGainEdit, self.designButton) + MainWindow.setTabOrder(self.designButton, self.tabGroup) + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Low Pass", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Band Pass", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(2, QtGui.QApplication.translate("MainWindow", "Complex Band Pass", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(3, QtGui.QApplication.translate("MainWindow", "Band Notch", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(4, QtGui.QApplication.translate("MainWindow", "High Pass", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(5, QtGui.QApplication.translate("MainWindow", "Root Raised Cosine", None, QtGui.QApplication.UnicodeUTF8)) + self.filterTypeComboBox.setItemText(6, QtGui.QApplication.translate("MainWindow", "Gaussian", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Windowed", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Equiripple", None, QtGui.QApplication.UnicodeUTF8)) + self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) + self.filterGainLabel.setText(QtGui.QApplication.translate("MainWindow", "Filter Gain", None, QtGui.QApplication.UnicodeUTF8)) + self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) + self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) + self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) + self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) + self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + +from PyQt4 import Qwt5 diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui new file mode 100644 index 000000000..ed3b1860b --- /dev/null +++ b/gr-utils/src/python/pyqt_filter.ui @@ -0,0 +1,261 @@ + + + MainWindow + + + + 0 + 0 + 624 + 696 + + + + MainWindow + + + + + + + + 800 + 0 + + + + 0 + + + + Frequency Domain + + + + + + + + + + Time Domain + + + + + + + + + + + + + + 300 + 0 + + + + + 300 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Low Pass + + + + + Band Pass + + + + + Complex Band Pass + + + + + Band Notch + + + + + High Pass + + + + + Root Raised Cosine + + + + + Gaussian + + + + + + + + + Windowed + + + + + Equiripple + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + 16777215 + 30 + + + + Sample Rate (sps) + + + + + + + + 16777215 + 30 + + + + + + + + Filter Gain + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 200 + 16777215 + + + + Design + + + + + + + + + + + + 0 + 0 + 624 + 25 + + + + + &File + + + + + + + + + &Open + + + Ctrl+O + + + + + E&xit + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+
+ + filterTypeComboBox + filterDesignTypeComboBox + sampleRateEdit + filterGainEdit + designButton + tabGroup + + + + + action_exit + activated() + MainWindow + close() + + + -1 + -1 + + + 399 + 347 + + + + +
diff --git a/gr-utils/src/python/pyqt_filter_firhpf.py b/gr-utils/src/python/pyqt_filter_firhpf.py new file mode 100644 index 000000000..9aa8d0ed6 --- /dev/null +++ b/gr-utils/src/python/pyqt_filter_firhpf.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'pyqt_filter_firhpf.ui' +# +# Created: Tue Aug 18 22:19:04 2009 +# by: PyQt4 UI code generator 4.4.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_firhpfForm(object): + def setupUi(self, firhpfForm): + firhpfForm.setObjectName("firhpfForm") + firhpfForm.resize(335, 300) + firhpfForm.setMinimumSize(QtCore.QSize(200, 0)) + self.formLayout = QtGui.QFormLayout(firhpfForm) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.endofPassBandLabel = QtGui.QLabel(firhpfForm) + self.endofPassBandLabel.setObjectName("endofPassBandLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofPassBandLabel) + self.endofPassBandEdit = QtGui.QLineEdit(firhpfForm) + self.endofPassBandEdit.setObjectName("endofPassBandEdit") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofPassBandEdit) + self.startofStopBandLabel = QtGui.QLabel(firhpfForm) + self.startofStopBandLabel.setObjectName("startofStopBandLabel") + self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofStopBandLabel) + self.startofStopBandEdit = QtGui.QLineEdit(firhpfForm) + self.startofStopBandEdit.setObjectName("startofStopBandEdit") + self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofStopBandEdit) + self.stopBandAttenLabel = QtGui.QLabel(firhpfForm) + self.stopBandAttenLabel.setObjectName("stopBandAttenLabel") + self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.stopBandAttenLabel) + self.stopBandAttenEdit = QtGui.QLineEdit(firhpfForm) + self.stopBandAttenEdit.setObjectName("stopBandAttenEdit") + self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.stopBandAttenEdit) + + self.retranslateUi(firhpfForm) + QtCore.QMetaObject.connectSlotsByName(firhpfForm) + + def retranslateUi(self, firhpfForm): + firhpfForm.setWindowTitle(QtGui.QApplication.translate("firhpfForm", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.endofPassBandLabel.setText(QtGui.QApplication.translate("firhpfForm", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofStopBandLabel.setText(QtGui.QApplication.translate("firhpfForm", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.stopBandAttenLabel.setText(QtGui.QApplication.translate("firhpfForm", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + diff --git a/gr-utils/src/python/pyqt_filter_firhpf.ui b/gr-utils/src/python/pyqt_filter_firhpf.ui new file mode 100644 index 000000000..4c04ef9c1 --- /dev/null +++ b/gr-utils/src/python/pyqt_filter_firhpf.ui @@ -0,0 +1,60 @@ + + + firhpfForm + + + + 0 + 0 + 335 + 300 + + + + + 200 + 0 + + + + Form + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + End of Stop Band (Hz) + + + + + + + + + + Start of Pass Band (Hz) + + + + + + + + + + Stop Band Attenuation (dB) + + + + + + + + + + + diff --git a/gr-utils/src/python/pyqt_filter_firlpf.py b/gr-utils/src/python/pyqt_filter_firlpf.py new file mode 100644 index 000000000..47aca0f2d --- /dev/null +++ b/gr-utils/src/python/pyqt_filter_firlpf.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'pyqt_filter_firlpf.ui' +# +# Created: Tue Aug 18 22:19:03 2009 +# by: PyQt4 UI code generator 4.4.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +class Ui_firlpfForm(object): + def setupUi(self, firlpfForm): + firlpfForm.setObjectName("firlpfForm") + firlpfForm.resize(335, 300) + firlpfForm.setMinimumSize(QtCore.QSize(200, 0)) + self.formLayout = QtGui.QFormLayout(firlpfForm) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.endofPassBandLabel = QtGui.QLabel(firlpfForm) + self.endofPassBandLabel.setObjectName("endofPassBandLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofPassBandLabel) + self.endofPassBandEdit = QtGui.QLineEdit(firlpfForm) + self.endofPassBandEdit.setObjectName("endofPassBandEdit") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofPassBandEdit) + self.startofStopBandLabel = QtGui.QLabel(firlpfForm) + self.startofStopBandLabel.setObjectName("startofStopBandLabel") + self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofStopBandLabel) + self.stopBandAttenLabel = QtGui.QLabel(firlpfForm) + self.stopBandAttenLabel.setObjectName("stopBandAttenLabel") + self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.stopBandAttenLabel) + self.stopBandAttenEdit = QtGui.QLineEdit(firlpfForm) + self.stopBandAttenEdit.setObjectName("stopBandAttenEdit") + self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.stopBandAttenEdit) + self.startofStopBandEdit = QtGui.QLineEdit(firlpfForm) + self.startofStopBandEdit.setObjectName("startofStopBandEdit") + self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofStopBandEdit) + + self.retranslateUi(firlpfForm) + QtCore.QMetaObject.connectSlotsByName(firlpfForm) + + def retranslateUi(self, firlpfForm): + firlpfForm.setWindowTitle(QtGui.QApplication.translate("firlpfForm", "Form", None, QtGui.QApplication.UnicodeUTF8)) + self.endofPassBandLabel.setText(QtGui.QApplication.translate("firlpfForm", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofStopBandLabel.setText(QtGui.QApplication.translate("firlpfForm", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.stopBandAttenLabel.setText(QtGui.QApplication.translate("firlpfForm", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + diff --git a/gr-utils/src/python/pyqt_filter_firlpf.ui b/gr-utils/src/python/pyqt_filter_firlpf.ui new file mode 100644 index 000000000..a96d609b8 --- /dev/null +++ b/gr-utils/src/python/pyqt_filter_firlpf.ui @@ -0,0 +1,60 @@ + + + firlpfForm + + + + 0 + 0 + 335 + 300 + + + + + 200 + 0 + + + + Form + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + End of Pass Band (Hz) + + + + + + + + + + Start of Stop Band (Hz) + + + + + + + Stop Band Attenuation (dB) + + + + + + + + + + + + + + -- cgit From ea99e2777b7a3692ee50ed0d80eeae006fa60322 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 20 Aug 2009 22:10:50 -0400 Subject: Removed the LFP and HPF ui's that are now a part of the main pyqt_filter.ui package. --- gr-utils/src/python/pyqt_filter_firhpf.py | 47 ------------------------ gr-utils/src/python/pyqt_filter_firhpf.ui | 60 ------------------------------- gr-utils/src/python/pyqt_filter_firlpf.py | 47 ------------------------ gr-utils/src/python/pyqt_filter_firlpf.ui | 60 ------------------------------- 4 files changed, 214 deletions(-) delete mode 100644 gr-utils/src/python/pyqt_filter_firhpf.py delete mode 100644 gr-utils/src/python/pyqt_filter_firhpf.ui delete mode 100644 gr-utils/src/python/pyqt_filter_firlpf.py delete mode 100644 gr-utils/src/python/pyqt_filter_firlpf.ui (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/pyqt_filter_firhpf.py b/gr-utils/src/python/pyqt_filter_firhpf.py deleted file mode 100644 index 9aa8d0ed6..000000000 --- a/gr-utils/src/python/pyqt_filter_firhpf.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'pyqt_filter_firhpf.ui' -# -# Created: Tue Aug 18 22:19:04 2009 -# by: PyQt4 UI code generator 4.4.4 -# -# WARNING! All changes made in this file will be lost! - -from PyQt4 import QtCore, QtGui - -class Ui_firhpfForm(object): - def setupUi(self, firhpfForm): - firhpfForm.setObjectName("firhpfForm") - firhpfForm.resize(335, 300) - firhpfForm.setMinimumSize(QtCore.QSize(200, 0)) - self.formLayout = QtGui.QFormLayout(firhpfForm) - self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) - self.formLayout.setObjectName("formLayout") - self.endofPassBandLabel = QtGui.QLabel(firhpfForm) - self.endofPassBandLabel.setObjectName("endofPassBandLabel") - self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofPassBandLabel) - self.endofPassBandEdit = QtGui.QLineEdit(firhpfForm) - self.endofPassBandEdit.setObjectName("endofPassBandEdit") - self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofPassBandEdit) - self.startofStopBandLabel = QtGui.QLabel(firhpfForm) - self.startofStopBandLabel.setObjectName("startofStopBandLabel") - self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofStopBandLabel) - self.startofStopBandEdit = QtGui.QLineEdit(firhpfForm) - self.startofStopBandEdit.setObjectName("startofStopBandEdit") - self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofStopBandEdit) - self.stopBandAttenLabel = QtGui.QLabel(firhpfForm) - self.stopBandAttenLabel.setObjectName("stopBandAttenLabel") - self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.stopBandAttenLabel) - self.stopBandAttenEdit = QtGui.QLineEdit(firhpfForm) - self.stopBandAttenEdit.setObjectName("stopBandAttenEdit") - self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.stopBandAttenEdit) - - self.retranslateUi(firhpfForm) - QtCore.QMetaObject.connectSlotsByName(firhpfForm) - - def retranslateUi(self, firhpfForm): - firhpfForm.setWindowTitle(QtGui.QApplication.translate("firhpfForm", "Form", None, QtGui.QApplication.UnicodeUTF8)) - self.endofPassBandLabel.setText(QtGui.QApplication.translate("firhpfForm", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) - self.startofStopBandLabel.setText(QtGui.QApplication.translate("firhpfForm", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) - self.stopBandAttenLabel.setText(QtGui.QApplication.translate("firhpfForm", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) - diff --git a/gr-utils/src/python/pyqt_filter_firhpf.ui b/gr-utils/src/python/pyqt_filter_firhpf.ui deleted file mode 100644 index 4c04ef9c1..000000000 --- a/gr-utils/src/python/pyqt_filter_firhpf.ui +++ /dev/null @@ -1,60 +0,0 @@ - - - firhpfForm - - - - 0 - 0 - 335 - 300 - - - - - 200 - 0 - - - - Form - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - End of Stop Band (Hz) - - - - - - - - - - Start of Pass Band (Hz) - - - - - - - - - - Stop Band Attenuation (dB) - - - - - - - - - - - diff --git a/gr-utils/src/python/pyqt_filter_firlpf.py b/gr-utils/src/python/pyqt_filter_firlpf.py deleted file mode 100644 index 47aca0f2d..000000000 --- a/gr-utils/src/python/pyqt_filter_firlpf.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'pyqt_filter_firlpf.ui' -# -# Created: Tue Aug 18 22:19:03 2009 -# by: PyQt4 UI code generator 4.4.4 -# -# WARNING! All changes made in this file will be lost! - -from PyQt4 import QtCore, QtGui - -class Ui_firlpfForm(object): - def setupUi(self, firlpfForm): - firlpfForm.setObjectName("firlpfForm") - firlpfForm.resize(335, 300) - firlpfForm.setMinimumSize(QtCore.QSize(200, 0)) - self.formLayout = QtGui.QFormLayout(firlpfForm) - self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) - self.formLayout.setObjectName("formLayout") - self.endofPassBandLabel = QtGui.QLabel(firlpfForm) - self.endofPassBandLabel.setObjectName("endofPassBandLabel") - self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofPassBandLabel) - self.endofPassBandEdit = QtGui.QLineEdit(firlpfForm) - self.endofPassBandEdit.setObjectName("endofPassBandEdit") - self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofPassBandEdit) - self.startofStopBandLabel = QtGui.QLabel(firlpfForm) - self.startofStopBandLabel.setObjectName("startofStopBandLabel") - self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofStopBandLabel) - self.stopBandAttenLabel = QtGui.QLabel(firlpfForm) - self.stopBandAttenLabel.setObjectName("stopBandAttenLabel") - self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.stopBandAttenLabel) - self.stopBandAttenEdit = QtGui.QLineEdit(firlpfForm) - self.stopBandAttenEdit.setObjectName("stopBandAttenEdit") - self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.stopBandAttenEdit) - self.startofStopBandEdit = QtGui.QLineEdit(firlpfForm) - self.startofStopBandEdit.setObjectName("startofStopBandEdit") - self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofStopBandEdit) - - self.retranslateUi(firlpfForm) - QtCore.QMetaObject.connectSlotsByName(firlpfForm) - - def retranslateUi(self, firlpfForm): - firlpfForm.setWindowTitle(QtGui.QApplication.translate("firlpfForm", "Form", None, QtGui.QApplication.UnicodeUTF8)) - self.endofPassBandLabel.setText(QtGui.QApplication.translate("firlpfForm", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) - self.startofStopBandLabel.setText(QtGui.QApplication.translate("firlpfForm", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) - self.stopBandAttenLabel.setText(QtGui.QApplication.translate("firlpfForm", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) - diff --git a/gr-utils/src/python/pyqt_filter_firlpf.ui b/gr-utils/src/python/pyqt_filter_firlpf.ui deleted file mode 100644 index a96d609b8..000000000 --- a/gr-utils/src/python/pyqt_filter_firlpf.ui +++ /dev/null @@ -1,60 +0,0 @@ - - - firlpfForm - - - - 0 - 0 - 335 - 300 - - - - - 200 - 0 - - - - Form - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - End of Pass Band (Hz) - - - - - - - - - - Start of Stop Band (Hz) - - - - - - - Stop Band Attenuation (dB) - - - - - - - - - - - - - - -- cgit From eec6476e69760994a01fbd3344a2af2f814f7d96 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 19:36:24 -0400 Subject: Adding features and usability. --- gr-utils/src/python/gr_filter_design.py | 293 +++++++++++++++++++++++++------- gr-utils/src/python/pyqt_filter.py | 200 ++++++++++++++++++---- gr-utils/src/python/pyqt_filter.ui | 267 ++++++++++++++++++++++++----- 3 files changed, 624 insertions(+), 136 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index a9f36ed02..28afacf08 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -11,7 +11,7 @@ import sys, os from PyQt4 import Qt, QtCore, QtGui import PyQt4.Qwt5 as Qwt from optparse import OptionParser -from gnuradio import gr, eng_notation +from gnuradio import gr, blks2, eng_notation from scipy import fftpack from pyqt_filter import Ui_MainWindow @@ -34,13 +34,22 @@ class gr_plot_filter(QtGui.QMainWindow): self.connect(self.gui.designButton, Qt.SIGNAL("released()"), self.design) - - self.fltdeslpf = Ui_firlpfForm() - self.fltdeshpf = Ui_firhpfForm() - self.fltdeslpf.setupUi(self.gui.firlpfPage) - self.fltdeshpf.setupUi(self.gui.firhpfPage) + self.connect(self.gui.tabGroup, + Qt.SIGNAL("currentChanged(int)"), + self.tab_changed) + + self.gui.designButton.setShortcut("Return") + + self.taps = [] + self.gui.lpfPassBandRippleLabel.setVisible(False) + self.gui.lpfPassBandRippleEdit.setVisible(False) + self.gui.bpfPassBandRippleLabel.setVisible(False) + self.gui.bpfPassBandRippleEdit.setVisible(False) + self.gui.hpfPassBandRippleLabel.setVisible(False) + self.gui.hpfPassBandRippleEdit.setVisible(False) + # Initialize to LPF self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) @@ -70,77 +79,243 @@ class gr_plot_filter(QtGui.QMainWindow): self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING, + "Hann Window" : gr.firdes.WIN_HANN, + "Blackman Window" : gr.firdes.WIN_BLACKMAN, + "Rectangular Window" : gr.firdes.WIN_RECTANGULAR, + "Kaiser Window" : gr.firdes.WIN_KAISER, + "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS} + self.show() def changed_filter_type(self, ftype): strftype = str(ftype.toAscii()) if(ftype == "Low Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + elif(ftype == "Band Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) elif(ftype == "High Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) + + self.design() def changed_filter_design_type(self, design): - print design - + if(design == "Equiripple"): + self.set_equiripple() + else: + self.set_windowed() + + self.design() + + def set_equiripple(self): + self.equiripple = True + self.gui.lpfPassBandRippleLabel.setVisible(True) + self.gui.lpfPassBandRippleEdit.setVisible(True) + self.gui.bpfPassBandRippleLabel.setVisible(True) + self.gui.bpfPassBandRippleEdit.setVisible(True) + self.gui.hpfPassBandRippleLabel.setVisible(True) + self.gui.hpfPassBandRippleEdit.setVisible(True) + + def set_windowed(self): + self.equiripple = False + self.gui.lpfPassBandRippleLabel.setVisible(False) + self.gui.lpfPassBandRippleEdit.setVisible(False) + self.gui.bpfPassBandRippleLabel.setVisible(False) + self.gui.bpfPassBandRippleEdit.setVisible(False) + self.gui.hpfPassBandRippleLabel.setVisible(False) + self.gui.hpfPassBandRippleEdit.setVisible(False) + def design(self): - fs = self.gui.sampleRateEdit.text().toDouble()[0] - gain = self.gui.filterGainEdit.text().toDouble()[0] + ret = True + fs,r = self.gui.sampleRateEdit.text().toDouble() + ret = r and ret + gain,r = self.gui.filterGainEdit.text().toDouble() + ret = r and ret + + if(ret): + winstr = str(self.gui.filterDesignTypeComboBox.currentText().toAscii()) + ftype = str(self.gui.filterTypeComboBox.currentText().toAscii()) + + if(winstr == "Equiripple"): + designer = {"Low Pass" : self.design_opt_lpf, + "Band Pass" : self.design_opt_bpf, + "High Pass" : self.design_opt_hpf} + taps,r = designer[ftype](fs, gain) + + else: + designer = {"Low Pass" : self.design_win_lpf, + "Band Pass" : self.design_win_bpf, + "High Pass" : self.design_win_hpf} + wintype = self.filterWindows[winstr] + taps,r = designer[ftype](fs, gain, wintype) + + if(r): + self.update_time_curves(taps) + self.update_freq_curves(taps) - ftype = self.gui.filterTypeComboBox.currentText() - if(ftype == "Low Pass"): - taps = self.design_win_lpf(fs, gain) - elif(ftype == "High Pass"): - taps = self.design_win_hpf(fs, gain) - self.update_time_curves(taps) - self.update_freq_curves(taps) - - def design_win_lpf(self, fs, gain): - pb = self.fltdeslpf.endofPassBandEdit.text().toDouble()[0] - sb = self.fltdeslpf.startofStopBandEdit.text().toDouble()[0] - atten = self.fltdeslpf.stopBandAttenEdit.text().toDouble()[0] - tb = sb - pb - - taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, - gr.firdes.WIN_BLACKMAN_hARRIS) - return taps + # Filter design functions using a window + def design_win_lpf(self, fs, gain, wintype): + ret = True + pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() + ret = r and ret + sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(ret): + tb = sb - pb + + taps = gr.firdes.low_pass_2(gain, fs, pb, tb, + atten, wintype) + return (taps, ret) + else: + return ([], ret) - def design_win_hpf(self, fs, gain): - print fs - print widget - + def design_win_bpf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.band_pass_2(gain, fs, pb1, pb2, tb, + atten, wintype) + return (taps,r) + else: + return ([],r) + + def design_win_hpf(self, fs, gain, wintype): + ret = True + sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() + ret = r and ret + pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + tb = pb - sb + taps = gr.firdes.high_pass_2(gain, fs, pb, tb, + atten, wintype) + return (taps,r) + else: + return ([],r) + + + + # Design Functions for Equiripple Filters + def design_opt_lpf(self, fs, gain, wintype=None): + ret = True + pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() + ret = r and ret + sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.lpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(ret): + taps = blks2.optfir.low_pass(gain, fs, pb, sb, + ripple, atten) + return (taps, ret) + else: + return ([], ret) + + def design_opt_bpf(self, fs, gain, wintype=None): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + sb1 = pb1 - tb + sb2 = pb2 + tb + taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + return (taps,r) + else: + return ([],r) + + def design_opt_hpf(self, fs, gain, wintype=None): + ret = True + sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() + ret = r and ret + pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.hpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + taps = blks2.optfir.high_pass(gain, fs, sb, pb, + atten, ripple) + return (taps,r) + else: + return ([],r) + + def tab_changed(self, tab): + if(tab == 0): + self.update_freq_curves(self.taps) + if(tab == 1): + self.update_time_curves(self.taps) + def update_time_curves(self, taps): + self.taps = taps ntaps = len(taps) - self.rcurve.setData(scipy.arange(ntaps), taps) - - # Reset the x-axis to the new time scale - ymax = 1.5 * max(taps) - ymin = 1.5 * min(taps) - self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, - 0, ntaps) - self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, - ymin, ymax) - - # Set the zoomer base to unzoom to the new axis - self.timeZoomer.setZoomBase() - - self.gui.timePlot.replot() + if(ntaps > 0): + self.rcurve.setData(scipy.arange(ntaps), taps) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(taps) + ymin = 1.5 * min(taps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, + 0, ntaps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + rect = Qt.QRectF(0, ymin, (ntaps-0), (ymax-ymin)) + self.timeZoomer.setZoomBase(rect) + + self.gui.timePlot.replot() def update_freq_curves(self, taps, Npts=1000): - fftpts = fftpack.fft(taps, Npts) - freq = scipy.arange(0, Npts) - - fftdB = 20.0*scipy.log10(abs(fftpts)) - - self.freqcurve.setData(freq, fftdB) - - self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, - 0, Npts/2) - - # Set the zoomer base to unzoom to the new axis - self.freqZoomer.setZoomBase() - - self.gui.freqPlot.replot() + if(len(taps) > 0): + fftpts = fftpack.fft(taps, Npts) + freq = scipy.arange(0, Npts) + + fftdB = 20.0*scipy.log10(abs(fftpts)) + + self.freqcurve.setData(freq, fftdB) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(fftdB) + ymin = 1.5 * min(fftdB) + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, + 0, Npts/2) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.freqZoomer.setZoomBase() + + self.gui.freqPlot.replot() def setup_options(): diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index a02a8e7f9..c848dbd1b 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Tue Aug 18 22:48:21 2009 +# Created: Sun Aug 23 18:03:28 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -12,31 +12,11 @@ from PyQt4 import QtCore, QtGui class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(624, 696) + MainWindow.resize(1124, 696) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtGui.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.tabGroup = QtGui.QTabWidget(self.centralwidget) - self.tabGroup.setMinimumSize(QtCore.QSize(800, 0)) - self.tabGroup.setObjectName("tabGroup") - self.freqTab = QtGui.QWidget() - self.freqTab.setObjectName("freqTab") - self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab) - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.freqPlot = Qwt5.QwtPlot(self.freqTab) - self.freqPlot.setObjectName("freqPlot") - self.horizontalLayout_2.addWidget(self.freqPlot) - self.tabGroup.addTab(self.freqTab, "") - self.timeTab = QtGui.QWidget() - self.timeTab.setObjectName("timeTab") - self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab) - self.horizontalLayout.setObjectName("horizontalLayout") - self.timePlot = Qwt5.QwtPlot(self.timeTab) - self.timePlot.setObjectName("timePlot") - self.horizontalLayout.addWidget(self.timePlot) - self.tabGroup.addTab(self.timeTab, "") - self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) self.filterFrame = QtGui.QFrame(self.centralwidget) self.filterFrame.setMinimumSize(QtCore.QSize(300, 0)) self.filterFrame.setMaximumSize(QtCore.QSize(300, 16777215)) @@ -59,43 +39,157 @@ class Ui_MainWindow(object): self.filterDesignTypeComboBox.setObjectName("filterDesignTypeComboBox") self.filterDesignTypeComboBox.addItem(QtCore.QString()) self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem(QtCore.QString()) self.verticalLayout.addWidget(self.filterDesignTypeComboBox) - self.formLayout_2 = QtGui.QFormLayout() - self.formLayout_2.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) - self.formLayout_2.setObjectName("formLayout_2") + self.globalParamsLayout = QtGui.QFormLayout() + self.globalParamsLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.globalParamsLayout.setObjectName("globalParamsLayout") self.sampleRateLabel = QtGui.QLabel(self.filterFrame) self.sampleRateLabel.setMaximumSize(QtCore.QSize(16777215, 30)) self.sampleRateLabel.setObjectName("sampleRateLabel") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) + self.globalParamsLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) self.sampleRateEdit = QtGui.QLineEdit(self.filterFrame) self.sampleRateEdit.setMaximumSize(QtCore.QSize(16777215, 30)) self.sampleRateEdit.setObjectName("sampleRateEdit") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateEdit) + self.globalParamsLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateEdit) self.filterGainLabel = QtGui.QLabel(self.filterFrame) self.filterGainLabel.setObjectName("filterGainLabel") - self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.filterGainLabel) + self.globalParamsLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filterGainLabel) self.filterGainEdit = QtGui.QLineEdit(self.filterFrame) self.filterGainEdit.setObjectName("filterGainEdit") - self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.filterGainEdit) - self.verticalLayout.addLayout(self.formLayout_2) + self.globalParamsLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filterGainEdit) + self.verticalLayout.addLayout(self.globalParamsLayout) self.filterTypeWidget = QtGui.QStackedWidget(self.filterFrame) self.filterTypeWidget.setObjectName("filterTypeWidget") self.firlpfPage = QtGui.QWidget() self.firlpfPage.setObjectName("firlpfPage") + self.formLayout = QtGui.QFormLayout(self.firlpfPage) + self.formLayout.setObjectName("formLayout") + self.endofLpfPassBandLabel = QtGui.QLabel(self.firlpfPage) + self.endofLpfPassBandLabel.setObjectName("endofLpfPassBandLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofLpfPassBandLabel) + self.endofLpfPassBandEdit = QtGui.QLineEdit(self.firlpfPage) + self.endofLpfPassBandEdit.setObjectName("endofLpfPassBandEdit") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofLpfPassBandEdit) + self.startofLpfStopBandLabel = QtGui.QLabel(self.firlpfPage) + self.startofLpfStopBandLabel.setObjectName("startofLpfStopBandLabel") + self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofLpfStopBandLabel) + self.startofLpfStopBandEdit = QtGui.QLineEdit(self.firlpfPage) + self.startofLpfStopBandEdit.setObjectName("startofLpfStopBandEdit") + self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofLpfStopBandEdit) + self.lpfStopBandAttenLabel = QtGui.QLabel(self.firlpfPage) + self.lpfStopBandAttenLabel.setObjectName("lpfStopBandAttenLabel") + self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.lpfStopBandAttenLabel) + self.lpfStopBandAttenEdit = QtGui.QLineEdit(self.firlpfPage) + self.lpfStopBandAttenEdit.setObjectName("lpfStopBandAttenEdit") + self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.lpfStopBandAttenEdit) + self.lpfPassBandRippleEdit = QtGui.QLineEdit(self.firlpfPage) + self.lpfPassBandRippleEdit.setObjectName("lpfPassBandRippleEdit") + self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.lpfPassBandRippleEdit) + self.lpfPassBandRippleLabel = QtGui.QLabel(self.firlpfPage) + self.lpfPassBandRippleLabel.setObjectName("lpfPassBandRippleLabel") + self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.lpfPassBandRippleLabel) self.filterTypeWidget.addWidget(self.firlpfPage) + self.firbpfPage = QtGui.QWidget() + self.firbpfPage.setObjectName("firbpfPage") + self.formLayout_2 = QtGui.QFormLayout(self.firbpfPage) + self.formLayout_2.setObjectName("formLayout_2") + self.startofBpfPassBandLabel = QtGui.QLabel(self.firbpfPage) + self.startofBpfPassBandLabel.setObjectName("startofBpfPassBandLabel") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.startofBpfPassBandLabel) + self.startofBpfPassBandEdit = QtGui.QLineEdit(self.firbpfPage) + self.startofBpfPassBandEdit.setObjectName("startofBpfPassBandEdit") + self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.startofBpfPassBandEdit) + self.endofBpfPassBandLabel = QtGui.QLabel(self.firbpfPage) + self.endofBpfPassBandLabel.setObjectName("endofBpfPassBandLabel") + self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.endofBpfPassBandLabel) + self.endofBpfPassBandEdit = QtGui.QLineEdit(self.firbpfPage) + self.endofBpfPassBandEdit.setObjectName("endofBpfPassBandEdit") + self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBpfPassBandEdit) + self.bpfStopBandAttenEdit = QtGui.QLineEdit(self.firbpfPage) + self.bpfStopBandAttenEdit.setObjectName("bpfStopBandAttenEdit") + self.formLayout_2.setWidget(3, QtGui.QFormLayout.FieldRole, self.bpfStopBandAttenEdit) + self.bpfStopBandAttenLabel = QtGui.QLabel(self.firbpfPage) + self.bpfStopBandAttenLabel.setObjectName("bpfStopBandAttenLabel") + self.formLayout_2.setWidget(3, QtGui.QFormLayout.LabelRole, self.bpfStopBandAttenLabel) + self.bpfTransitionLabel = QtGui.QLabel(self.firbpfPage) + self.bpfTransitionLabel.setObjectName("bpfTransitionLabel") + self.formLayout_2.setWidget(2, QtGui.QFormLayout.LabelRole, self.bpfTransitionLabel) + self.bpfTransitionEdit = QtGui.QLineEdit(self.firbpfPage) + self.bpfTransitionEdit.setObjectName("bpfTransitionEdit") + self.formLayout_2.setWidget(2, QtGui.QFormLayout.FieldRole, self.bpfTransitionEdit) + self.bpfPassBandRippleEdit = QtGui.QLineEdit(self.firbpfPage) + self.bpfPassBandRippleEdit.setObjectName("bpfPassBandRippleEdit") + self.formLayout_2.setWidget(4, QtGui.QFormLayout.FieldRole, self.bpfPassBandRippleEdit) + self.bpfPassBandRippleLabel = QtGui.QLabel(self.firbpfPage) + self.bpfPassBandRippleLabel.setObjectName("bpfPassBandRippleLabel") + self.formLayout_2.setWidget(4, QtGui.QFormLayout.LabelRole, self.bpfPassBandRippleLabel) + self.filterTypeWidget.addWidget(self.firbpfPage) self.firhpfPage = QtGui.QWidget() self.firhpfPage.setObjectName("firhpfPage") + self.formLayout_3 = QtGui.QFormLayout(self.firhpfPage) + self.formLayout_3.setObjectName("formLayout_3") + self.endofHpfStopBandLabel = QtGui.QLabel(self.firhpfPage) + self.endofHpfStopBandLabel.setObjectName("endofHpfStopBandLabel") + self.formLayout_3.setWidget(0, QtGui.QFormLayout.LabelRole, self.endofHpfStopBandLabel) + self.endofHpfStopBandEdit = QtGui.QLineEdit(self.firhpfPage) + self.endofHpfStopBandEdit.setObjectName("endofHpfStopBandEdit") + self.formLayout_3.setWidget(0, QtGui.QFormLayout.FieldRole, self.endofHpfStopBandEdit) + self.startofHpfPassBandLabel = QtGui.QLabel(self.firhpfPage) + self.startofHpfPassBandLabel.setObjectName("startofHpfPassBandLabel") + self.formLayout_3.setWidget(1, QtGui.QFormLayout.LabelRole, self.startofHpfPassBandLabel) + self.startofHpfPassBandEdit = QtGui.QLineEdit(self.firhpfPage) + self.startofHpfPassBandEdit.setObjectName("startofHpfPassBandEdit") + self.formLayout_3.setWidget(1, QtGui.QFormLayout.FieldRole, self.startofHpfPassBandEdit) + self.hpfStopBandAttenLabel = QtGui.QLabel(self.firhpfPage) + self.hpfStopBandAttenLabel.setObjectName("hpfStopBandAttenLabel") + self.formLayout_3.setWidget(2, QtGui.QFormLayout.LabelRole, self.hpfStopBandAttenLabel) + self.hpfStopBandAttenEdit = QtGui.QLineEdit(self.firhpfPage) + self.hpfStopBandAttenEdit.setObjectName("hpfStopBandAttenEdit") + self.formLayout_3.setWidget(2, QtGui.QFormLayout.FieldRole, self.hpfStopBandAttenEdit) + self.hpfPassBandRippleLabel = QtGui.QLabel(self.firhpfPage) + self.hpfPassBandRippleLabel.setObjectName("hpfPassBandRippleLabel") + self.formLayout_3.setWidget(3, QtGui.QFormLayout.LabelRole, self.hpfPassBandRippleLabel) + self.hpfPassBandRippleEdit = QtGui.QLineEdit(self.firhpfPage) + self.hpfPassBandRippleEdit.setObjectName("hpfPassBandRippleEdit") + self.formLayout_3.setWidget(3, QtGui.QFormLayout.FieldRole, self.hpfPassBandRippleEdit) self.filterTypeWidget.addWidget(self.firhpfPage) self.verticalLayout.addWidget(self.filterTypeWidget) self.designButton = QtGui.QPushButton(self.filterFrame) self.designButton.setMinimumSize(QtCore.QSize(0, 0)) self.designButton.setMaximumSize(QtCore.QSize(200, 16777215)) + self.designButton.setAutoDefault(True) + self.designButton.setDefault(True) self.designButton.setObjectName("designButton") self.verticalLayout.addWidget(self.designButton) self.gridLayout.addWidget(self.filterFrame, 1, 0, 1, 1) + self.tabGroup = QtGui.QTabWidget(self.centralwidget) + self.tabGroup.setMinimumSize(QtCore.QSize(800, 0)) + self.tabGroup.setObjectName("tabGroup") + self.freqTab = QtGui.QWidget() + self.freqTab.setObjectName("freqTab") + self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.freqPlot = Qwt5.QwtPlot(self.freqTab) + self.freqPlot.setObjectName("freqPlot") + self.horizontalLayout_2.addWidget(self.freqPlot) + self.tabGroup.addTab(self.freqTab, "") + self.timeTab = QtGui.QWidget() + self.timeTab.setObjectName("timeTab") + self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab) + self.horizontalLayout.setObjectName("horizontalLayout") + self.timePlot = Qwt5.QwtPlot(self.timeTab) + self.timePlot.setObjectName("timePlot") + self.horizontalLayout.addWidget(self.timePlot) + self.tabGroup.addTab(self.timeTab, "") + self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 624, 25)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 25)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -111,19 +205,31 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) + self.filterTypeWidget.setCurrentIndex(2) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.filterTypeComboBox, self.filterDesignTypeComboBox) MainWindow.setTabOrder(self.filterDesignTypeComboBox, self.sampleRateEdit) MainWindow.setTabOrder(self.sampleRateEdit, self.filterGainEdit) - MainWindow.setTabOrder(self.filterGainEdit, self.designButton) + MainWindow.setTabOrder(self.filterGainEdit, self.endofLpfPassBandEdit) + MainWindow.setTabOrder(self.endofLpfPassBandEdit, self.startofLpfStopBandEdit) + MainWindow.setTabOrder(self.startofLpfStopBandEdit, self.lpfStopBandAttenEdit) + MainWindow.setTabOrder(self.lpfStopBandAttenEdit, self.lpfPassBandRippleEdit) + MainWindow.setTabOrder(self.lpfPassBandRippleEdit, self.startofBpfPassBandEdit) + MainWindow.setTabOrder(self.startofBpfPassBandEdit, self.endofBpfPassBandEdit) + MainWindow.setTabOrder(self.endofBpfPassBandEdit, self.bpfTransitionEdit) + MainWindow.setTabOrder(self.bpfTransitionEdit, self.bpfStopBandAttenEdit) + MainWindow.setTabOrder(self.bpfStopBandAttenEdit, self.bpfPassBandRippleEdit) + MainWindow.setTabOrder(self.bpfPassBandRippleEdit, self.endofHpfStopBandEdit) + MainWindow.setTabOrder(self.endofHpfStopBandEdit, self.startofHpfPassBandEdit) + MainWindow.setTabOrder(self.startofHpfPassBandEdit, self.hpfStopBandAttenEdit) + MainWindow.setTabOrder(self.hpfStopBandAttenEdit, self.hpfPassBandRippleEdit) + MainWindow.setTabOrder(self.hpfPassBandRippleEdit, self.designButton) MainWindow.setTabOrder(self.designButton, self.tabGroup) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "GNU Radio Filter Design Tool", None, QtGui.QApplication.UnicodeUTF8)) self.filterTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Low Pass", None, QtGui.QApplication.UnicodeUTF8)) self.filterTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Band Pass", None, QtGui.QApplication.UnicodeUTF8)) self.filterTypeComboBox.setItemText(2, QtGui.QApplication.translate("MainWindow", "Complex Band Pass", None, QtGui.QApplication.UnicodeUTF8)) @@ -131,11 +237,31 @@ class Ui_MainWindow(object): self.filterTypeComboBox.setItemText(4, QtGui.QApplication.translate("MainWindow", "High Pass", None, QtGui.QApplication.UnicodeUTF8)) self.filterTypeComboBox.setItemText(5, QtGui.QApplication.translate("MainWindow", "Root Raised Cosine", None, QtGui.QApplication.UnicodeUTF8)) self.filterTypeComboBox.setItemText(6, QtGui.QApplication.translate("MainWindow", "Gaussian", None, QtGui.QApplication.UnicodeUTF8)) - self.filterDesignTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Windowed", None, QtGui.QApplication.UnicodeUTF8)) - self.filterDesignTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Equiripple", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(0, QtGui.QApplication.translate("MainWindow", "Hamming Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(1, QtGui.QApplication.translate("MainWindow", "Hann Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(2, QtGui.QApplication.translate("MainWindow", "Blackman Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(3, QtGui.QApplication.translate("MainWindow", "Rectangular Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(4, QtGui.QApplication.translate("MainWindow", "Kaiser Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(5, QtGui.QApplication.translate("MainWindow", "Blackman-harris Window", None, QtGui.QApplication.UnicodeUTF8)) + self.filterDesignTypeComboBox.setItemText(6, QtGui.QApplication.translate("MainWindow", "Equiripple", None, QtGui.QApplication.UnicodeUTF8)) self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) self.filterGainLabel.setText(QtGui.QApplication.translate("MainWindow", "Filter Gain", None, QtGui.QApplication.UnicodeUTF8)) + self.endofLpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofLpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.lpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.lpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofBpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.endofBpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.bpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.bpfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.bpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.endofHpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.hpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index ed3b1860b..69d570775 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -6,48 +6,15 @@ 0 0 - 624 + 1124 696 - MainWindow + GNU Radio Filter Design Tool - - - - - 800 - 0 - - - - 0 - - - - Frequency Domain - - - - - - - - - - Time Domain - - - - - - - - - @@ -112,7 +79,32 @@ - Windowed + Hamming Window + + + + + Hann Window + + + + + Blackman Window + + + + + Rectangular Window + + + + + Kaiser Window + + + + + Blackman-harris Window @@ -123,7 +115,7 @@ - + QFormLayout::AllNonFixedFieldsGrow @@ -164,8 +156,151 @@ - - + + 2 + + + + + + + End of Pass Band (Hz) + + + + + + + + + + Start of Stop Band (Hz) + + + + + + + + + + Stop Band Attenuation (dB) + + + + + + + + + + + + + Pass Band Ripple (dB) + + + + + + + + + + + Start of Pass Band (Hz) + + + + + + + + + + End of Pass Band (Hz) + + + + + + + + + + + + + Stop Band Attenuation (dB) + + + + + + + Transition Width (Hz) + + + + + + + + + + + + + Pass Band Ripple (dB) + + + + + + + + + + + End of Stop Band (Hz) + + + + + + + + + + Start of Pass Band (Hz) + + + + + + + + + + Stop Band Attenuation (dB) + + + + + + + + + + Pass Band Ripple (dB) + + + + + + + + @@ -185,11 +320,50 @@ Design + + true + + + true + + + + + + 800 + 0 + + + + 0 + + + + Frequency Domain + + + + + + + + + + Time Domain + + + + + + + + + @@ -197,7 +371,7 @@ 0 0 - 624 + 1124 25 @@ -236,6 +410,19 @@ filterDesignTypeComboBox sampleRateEdit filterGainEdit + endofLpfPassBandEdit + startofLpfStopBandEdit + lpfStopBandAttenEdit + lpfPassBandRippleEdit + startofBpfPassBandEdit + endofBpfPassBandEdit + bpfTransitionEdit + bpfStopBandAttenEdit + bpfPassBandRippleEdit + endofHpfStopBandEdit + startofHpfPassBandEdit + hpfStopBandAttenEdit + hpfPassBandRippleEdit designButton tabGroup -- cgit From be85d95e41ba883746ad109fa3eb9d280e74a4f8 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 20:52:33 -0400 Subject: Fixing time domain plot zoomer. --- gr-utils/src/python/gr_filter_design.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 28afacf08..cce04c881 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -290,8 +290,7 @@ class gr_plot_filter(QtGui.QMainWindow): ymin, ymax) # Set the zoomer base to unzoom to the new axis - rect = Qt.QRectF(0, ymin, (ntaps-0), (ymax-ymin)) - self.timeZoomer.setZoomBase(rect) + self.timeZoomer.setZoomBase() self.gui.timePlot.replot() -- cgit From aafbdf432b547529bea9ebe9ce2ad4c77ab20f03 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 21:19:12 -0400 Subject: Adding a phase and group delay plot to the GUI. --- gr-utils/src/python/gr_filter_design.py | 28 ++++++++++++++++++++-- gr-utils/src/python/pyqt_filter.py | 36 ++++++++++++++++++++++++++-- gr-utils/src/python/pyqt_filter.ui | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index cce04c881..cc24afbba 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -39,9 +39,15 @@ class gr_plot_filter(QtGui.QMainWindow): Qt.SIGNAL("currentChanged(int)"), self.tab_changed) + self.connect(self.gui.nfftEdit, + Qt.SIGNAL("textEdited(QString)"), + self.nfft_edit_changed) + self.gui.designButton.setShortcut("Return") self.taps = [] + self.nfftpts = int(10000) + self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts)) self.gui.lpfPassBandRippleLabel.setVisible(False) self.gui.lpfPassBandRippleEdit.setVisible(False) @@ -73,6 +79,18 @@ class gr_plot_filter(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.freqPlot.canvas()) + self.phaseZoomer = Qwt.QwtPlotZoomer(self.gui.phasePlot.xBottom, + self.gui.phasePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.phasePlot.canvas()) + + self.groupZoomer = Qwt.QwtPlotZoomer(self.gui.groupPlot.xBottom, + self.gui.groupPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.groupPlot.canvas()) + # Set up pen for colors and line width blue = QtGui.qRgb(0x00, 0x00, 0xFF) blueBrush = Qt.QBrush(Qt.QColor(blue)) @@ -151,7 +169,7 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): self.update_time_curves(taps) - self.update_freq_curves(taps) + self.update_freq_curves(taps, self.nfftpts) # Filter design functions using a window @@ -269,9 +287,15 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def nfft_edit_changed(self, nfft): + infft,r = nfft.toInt() + if(r and (infft != self.nfftpts)): + self.nfftpts = infft + self.update_freq_curves(self.taps, self.nfftpts) + def tab_changed(self, tab): if(tab == 0): - self.update_freq_curves(self.taps) + self.update_freq_curves(self.taps, self.nfftpts) if(tab == 1): self.update_time_curves(self.taps) diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index c848dbd1b..015232643 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Sun Aug 23 18:03:28 2009 +# Created: Sun Aug 23 21:18:30 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -132,6 +132,7 @@ class Ui_MainWindow(object): self.firhpfPage = QtGui.QWidget() self.firhpfPage.setObjectName("firhpfPage") self.formLayout_3 = QtGui.QFormLayout(self.firhpfPage) + self.formLayout_3.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_3.setObjectName("formLayout_3") self.endofHpfStopBandLabel = QtGui.QLabel(self.firhpfPage) self.endofHpfStopBandLabel.setObjectName("endofHpfStopBandLabel") @@ -159,6 +160,17 @@ class Ui_MainWindow(object): self.formLayout_3.setWidget(3, QtGui.QFormLayout.FieldRole, self.hpfPassBandRippleEdit) self.filterTypeWidget.addWidget(self.firhpfPage) self.verticalLayout.addWidget(self.filterTypeWidget) + self.sysParamsBox = QtGui.QGroupBox(self.filterFrame) + self.sysParamsBox.setObjectName("sysParamsBox") + self.formLayout_4 = QtGui.QFormLayout(self.sysParamsBox) + self.formLayout_4.setObjectName("formLayout_4") + self.nfftEdit = QtGui.QLineEdit(self.sysParamsBox) + self.nfftEdit.setObjectName("nfftEdit") + self.formLayout_4.setWidget(1, QtGui.QFormLayout.FieldRole, self.nfftEdit) + self.nfftLabel = QtGui.QLabel(self.sysParamsBox) + self.nfftLabel.setObjectName("nfftLabel") + self.formLayout_4.setWidget(1, QtGui.QFormLayout.LabelRole, self.nfftLabel) + self.verticalLayout.addWidget(self.sysParamsBox) self.designButton = QtGui.QPushButton(self.filterFrame) self.designButton.setMinimumSize(QtCore.QSize(0, 0)) self.designButton.setMaximumSize(QtCore.QSize(200, 16777215)) @@ -186,6 +198,22 @@ class Ui_MainWindow(object): self.timePlot.setObjectName("timePlot") self.horizontalLayout.addWidget(self.timePlot) self.tabGroup.addTab(self.timeTab, "") + self.phaseTab = QtGui.QWidget() + self.phaseTab.setObjectName("phaseTab") + self.horizontalLayout_3 = QtGui.QHBoxLayout(self.phaseTab) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.phasePlot = Qwt5.QwtPlot(self.phaseTab) + self.phasePlot.setObjectName("phasePlot") + self.horizontalLayout_3.addWidget(self.phasePlot) + self.tabGroup.addTab(self.phaseTab, "") + self.groupTab = QtGui.QWidget() + self.groupTab.setObjectName("groupTab") + self.horizontalLayout_4 = QtGui.QHBoxLayout(self.groupTab) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.groupPlot = Qwt5.QwtPlot(self.groupTab) + self.groupPlot.setObjectName("groupPlot") + self.horizontalLayout_4.addWidget(self.groupPlot) + self.tabGroup.addTab(self.groupTab, "") self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) @@ -206,7 +234,7 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) self.filterTypeWidget.setCurrentIndex(2) - self.tabGroup.setCurrentIndex(0) + self.tabGroup.setCurrentIndex(3) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.filterTypeComboBox, self.filterDesignTypeComboBox) @@ -259,9 +287,13 @@ class Ui_MainWindow(object): self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.sysParamsBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Parameters", None, QtGui.QApplication.UnicodeUTF8)) + self.nfftLabel.setText(QtGui.QApplication.translate("MainWindow", "Num FFT points", None, QtGui.QApplication.UnicodeUTF8)) self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.phaseTab), QtGui.QApplication.translate("MainWindow", "Phase", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.groupTab), QtGui.QApplication.translate("MainWindow", "Group Delay", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 69d570775..773b4cca9 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -259,6 +259,9 @@ + + QFormLayout::AllNonFixedFieldsGrow + @@ -303,6 +306,25 @@ + + + + System Parameters + + + + + + + + + Num FFT points + + + + + + @@ -362,6 +384,26 @@ + + + Phase + + + + + + + + + + Group Delay + + + + + + + -- cgit From 4085285a821d6dcf003d8a0fab1329599790f2be Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 21:57:34 -0400 Subject: Plotting phase of filter in its own tab now. --- gr-utils/src/python/gr_filter_design.py | 83 +++++++++++++++++++++++---------- gr-utils/src/python/pyqt_filter.py | 4 +- 2 files changed, 60 insertions(+), 27 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index cc24afbba..82af6d900 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -66,6 +66,12 @@ class gr_plot_filter(QtGui.QMainWindow): self.freqcurve = Qwt.QwtPlotCurve("PSD") self.freqcurve.attach(self.gui.freqPlot) + self.phasecurve = Qwt.QwtPlotCurve("Phase") + self.phasecurve.attach(self.gui.phasePlot) + + self.groupcurve = Qwt.QwtPlotCurve("Group Delay") + self.groupcurve.attach(self.gui.groupPlot) + # Create zoom functionality for the plots self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, self.gui.timePlot.yLeft, @@ -96,7 +102,9 @@ class gr_plot_filter(QtGui.QMainWindow): blueBrush = Qt.QBrush(Qt.QColor(blue)) self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - + self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) + self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) + self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING, "Hann Window" : gr.firdes.WIN_HANN, "Blackman Window" : gr.firdes.WIN_BLACKMAN, @@ -165,11 +173,13 @@ class gr_plot_filter(QtGui.QMainWindow): "Band Pass" : self.design_win_bpf, "High Pass" : self.design_win_hpf} wintype = self.filterWindows[winstr] - taps,r = designer[ftype](fs, gain, wintype) + self.taps,r = designer[ftype](fs, gain, wintype) if(r): - self.update_time_curves(taps) - self.update_freq_curves(taps, self.nfftpts) + self.get_fft(self.taps, self.nfftpts) + self.update_time_curves() + self.update_freq_curves() + self.update_phase_curves() # Filter design functions using a window @@ -291,23 +301,31 @@ class gr_plot_filter(QtGui.QMainWindow): infft,r = nfft.toInt() if(r and (infft != self.nfftpts)): self.nfftpts = infft - self.update_freq_curves(self.taps, self.nfftpts) + self.update_freq_curves() def tab_changed(self, tab): if(tab == 0): - self.update_freq_curves(self.taps, self.nfftpts) + self.update_freq_curves() if(tab == 1): - self.update_time_curves(self.taps) + self.update_time_curves() + if(tab == 2): + self.update_phase_curves() - def update_time_curves(self, taps): - self.taps = taps - ntaps = len(taps) + def get_fft(self, taps, Npts): + fftpts = fftpack.fft(taps, Npts) + self.freq = scipy.arange(0, Npts) + + self.fftdB = 20.0*scipy.log10(abs(fftpts)) + self.fftDeg = scipy.unwrap(scipy.angle(fftpts)) + + def update_time_curves(self): + ntaps = len(self.taps) if(ntaps > 0): - self.rcurve.setData(scipy.arange(ntaps), taps) + self.rcurve.setData(scipy.arange(ntaps), self.taps) # Reset the x-axis to the new time scale - ymax = 1.5 * max(taps) - ymin = 1.5 * min(taps) + ymax = 1.5 * max(self.taps) + ymin = 1.5 * min(self.taps) self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, 0, ntaps) self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, @@ -318,21 +336,17 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.timePlot.replot() - def update_freq_curves(self, taps, Npts=1000): - if(len(taps) > 0): - fftpts = fftpack.fft(taps, Npts) - freq = scipy.arange(0, Npts) - - fftdB = 20.0*scipy.log10(abs(fftpts)) - - self.freqcurve.setData(freq, fftdB) + def update_freq_curves(self): + npts = len(self.fftdB) + if(npts > 0): + self.freqcurve.setData(self.freq, self.fftdB) # Reset the x-axis to the new time scale - ymax = 1.5 * max(fftdB) - ymin = 1.5 * min(fftdB) + ymax = 1.5 * max(self.fftdB[0:npts/2]) + ymin = 1.1 * min(self.fftdB[0:npts/2]) self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, - 0, Npts/2) - self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + 0, npts/2) + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft, ymin, ymax) # Set the zoomer base to unzoom to the new axis @@ -341,6 +355,25 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.freqPlot.replot() + def update_phase_curves(self): + npts = len(self.fftDeg) + if(npts > 0): + self.phasecurve.setData(self.freq, self.fftDeg) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.fftDeg[0:npts/2]) + ymin = 1.1 * min(self.fftDeg[0:npts/2]) + self.gui.phasePlot.setAxisScale(self.gui.phasePlot.xBottom, + 0, npts/2) + self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.phaseZoomer.setZoomBase() + + self.gui.phasePlot.replot() + + def setup_options(): usage="%prog: [options] (input_filename)" description = "" diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 015232643..6b95e03bb 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Sun Aug 23 21:18:30 2009 +# Created: Sun Aug 23 21:53:02 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -234,7 +234,7 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) self.filterTypeWidget.setCurrentIndex(2) - self.tabGroup.setCurrentIndex(3) + self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.filterTypeComboBox, self.filterDesignTypeComboBox) -- cgit From 9d751503f53e2381ef6b94482948b16cbf913734 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 22:06:24 -0400 Subject: Adding labels to the plots. --- gr-utils/src/python/gr_filter_design.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 82af6d900..352e275db 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -59,6 +59,24 @@ class gr_plot_filter(QtGui.QMainWindow): # Initialize to LPF self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + # Set Axis labels + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, + "Frequency (Hz)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, + "Magnitude (dB)") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, + "Tap number") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, + "Amplitude") + self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.xBottom, + "Frequency (Hz)") + self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.yLeft, + "Phase (Radians)") + self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.xBottom, + "Frequency (Hz)") + self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.yLeft, + "Delay (sec)") + # Set up plot curves self.rcurve = Qwt.QwtPlotCurve("Real") self.rcurve.attach(self.gui.timePlot) -- cgit From 35871625e84c5e91af1fa8b7e741629e3880d323 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 22:30:35 -0400 Subject: Adding plotting of group delay. --- gr-utils/src/python/gr_filter_design.py | 46 +++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 352e275db..7a15b4030 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -46,6 +46,9 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.designButton.setShortcut("Return") self.taps = [] + self.fftdB = [] + self.fftDeg = [] + self.groupDelay = [] self.nfftpts = int(10000) self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts)) @@ -184,7 +187,7 @@ class gr_plot_filter(QtGui.QMainWindow): designer = {"Low Pass" : self.design_opt_lpf, "Band Pass" : self.design_opt_bpf, "High Pass" : self.design_opt_hpf} - taps,r = designer[ftype](fs, gain) + self.taps,r = designer[ftype](fs, gain) else: designer = {"Low Pass" : self.design_win_lpf, @@ -194,11 +197,11 @@ class gr_plot_filter(QtGui.QMainWindow): self.taps,r = designer[ftype](fs, gain, wintype) if(r): - self.get_fft(self.taps, self.nfftpts) + self.get_fft(fs, self.taps, self.nfftpts) self.update_time_curves() self.update_freq_curves() self.update_phase_curves() - + self.update_group_curves() # Filter design functions using a window def design_win_lpf(self, fs, gain, wintype): @@ -328,13 +331,16 @@ class gr_plot_filter(QtGui.QMainWindow): self.update_time_curves() if(tab == 2): self.update_phase_curves() + if(tab == 3): + self.update_group_curves() - def get_fft(self, taps, Npts): + def get_fft(self, fs, taps, Npts): + Ts = 1.0/fs fftpts = fftpack.fft(taps, Npts) - self.freq = scipy.arange(0, Npts) - + self.freq = scipy.arange(0, fs, 1.0/(Npts*Ts)) self.fftdB = 20.0*scipy.log10(abs(fftpts)) self.fftDeg = scipy.unwrap(scipy.angle(fftpts)) + self.groupDelay = -scipy.diff(self.fftDeg) def update_time_curves(self): ntaps = len(self.taps) @@ -362,8 +368,10 @@ class gr_plot_filter(QtGui.QMainWindow): # Reset the x-axis to the new time scale ymax = 1.5 * max(self.fftdB[0:npts/2]) ymin = 1.1 * min(self.fftdB[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, - 0, npts/2) + xmin, xmax) self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft, ymin, ymax) @@ -381,8 +389,10 @@ class gr_plot_filter(QtGui.QMainWindow): # Reset the x-axis to the new time scale ymax = 1.5 * max(self.fftDeg[0:npts/2]) ymin = 1.1 * min(self.fftDeg[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] self.gui.phasePlot.setAxisScale(self.gui.phasePlot.xBottom, - 0, npts/2) + xmin, xmax) self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft, ymin, ymax) @@ -391,6 +401,26 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.phasePlot.replot() + def update_group_curves(self): + npts = len(self.groupDelay) + if(npts > 0): + self.groupcurve.setData(self.freq, self.groupDelay) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.groupDelay[0:npts/2]) + ymin = 1.1 * min(self.groupDelay[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] + self.gui.groupPlot.setAxisScale(self.gui.groupPlot.xBottom, + xmin, xmax) + self.gui.groupPlot.setAxisScale(self.gui.groupPlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.groupZoomer.setZoomBase() + + self.gui.groupPlot.replot() + def setup_options(): usage="%prog: [options] (input_filename)" -- cgit From 548c972d642a35d888ef87f417db0badfa6c22d8 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 22:55:11 -0400 Subject: Adding complex bandpass filter design (for windowed filters only). --- gr-utils/src/python/gr_filter_design.py | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 7a15b4030..c69fa26c7 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -83,6 +83,8 @@ class gr_plot_filter(QtGui.QMainWindow): # Set up plot curves self.rcurve = Qwt.QwtPlotCurve("Real") self.rcurve.attach(self.gui.timePlot) + self.icurve = Qwt.QwtPlotCurve("Imag") + self.icurve.attach(self.gui.timePlot) self.freqcurve = Qwt.QwtPlotCurve("PSD") self.freqcurve.attach(self.gui.freqPlot) @@ -141,6 +143,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) elif(ftype == "Band Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) + elif(ftype == "Complex Band Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) elif(ftype == "High Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) @@ -187,16 +191,18 @@ class gr_plot_filter(QtGui.QMainWindow): designer = {"Low Pass" : self.design_opt_lpf, "Band Pass" : self.design_opt_bpf, "High Pass" : self.design_opt_hpf} - self.taps,r = designer[ftype](fs, gain) + taps,r = designer[ftype](fs, gain) else: designer = {"Low Pass" : self.design_win_lpf, "Band Pass" : self.design_win_bpf, + "Complex Band Pass" : self.design_win_cbpf, "High Pass" : self.design_win_hpf} wintype = self.filterWindows[winstr] - self.taps,r = designer[ftype](fs, gain, wintype) + taps,r = designer[ftype](fs, gain, wintype) if(r): + self.taps = scipy.array(taps) self.get_fft(fs, self.taps, self.nfftpts) self.update_time_curves() self.update_freq_curves() @@ -240,6 +246,24 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def design_win_cbpf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.complex_band_pass_2(gain, fs, pb1, pb2, tb, + atten, wintype) + return (taps,r) + else: + return ([],r) + def design_win_hpf(self, fs, gain, wintype): ret = True sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() @@ -345,8 +369,12 @@ class gr_plot_filter(QtGui.QMainWindow): def update_time_curves(self): ntaps = len(self.taps) if(ntaps > 0): - self.rcurve.setData(scipy.arange(ntaps), self.taps) - + if(type(self.taps[0]) == scipy.complex128): + self.rcurve.setData(scipy.arange(ntaps), self.taps.real) + self.icurve.setData(scipy.arange(ntaps), self.taps.imag) + else: + self.rcurve.setData(scipy.arange(ntaps), self.taps) + # Reset the x-axis to the new time scale ymax = 1.5 * max(self.taps) ymin = 1.5 * min(self.taps) -- cgit From a297059a8c5169edf8ef39d66ac556229dcfe640 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Aug 2009 23:27:05 -0400 Subject: Added Band Notch filter --- gr-utils/src/python/gr_filter_design.py | 21 ++++++++++++++++ gr-utils/src/python/pyqt_filter.py | 35 +++++++++++++++++++++++++- gr-utils/src/python/pyqt_filter.ui | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index c69fa26c7..9ef12294d 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -145,6 +145,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) elif(ftype == "Complex Band Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) + elif(ftype == "Band Notch"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbnfPage) elif(ftype == "High Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) @@ -197,6 +199,7 @@ class gr_plot_filter(QtGui.QMainWindow): designer = {"Low Pass" : self.design_win_lpf, "Band Pass" : self.design_win_bpf, "Complex Band Pass" : self.design_win_cbpf, + "Band Notch" : self.design_win_bnf, "High Pass" : self.design_win_hpf} wintype = self.filterWindows[winstr] taps,r = designer[ftype](fs, gain, wintype) @@ -264,6 +267,24 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def design_win_bnf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bnfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.band_reject_2(gain, fs, pb1, pb2, tb, + atten, wintype) + return (taps,r) + else: + return ([],r) + def design_win_hpf(self, fs, gain, wintype): ret = True sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 6b95e03bb..5fa0979de 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Sun Aug 23 21:53:02 2009 +# Created: Sun Aug 23 23:26:14 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -129,6 +129,35 @@ class Ui_MainWindow(object): self.bpfPassBandRippleLabel.setObjectName("bpfPassBandRippleLabel") self.formLayout_2.setWidget(4, QtGui.QFormLayout.LabelRole, self.bpfPassBandRippleLabel) self.filterTypeWidget.addWidget(self.firbpfPage) + self.firbnfPage = QtGui.QWidget() + self.firbnfPage.setObjectName("firbnfPage") + self.formLayout_5 = QtGui.QFormLayout(self.firbnfPage) + self.formLayout_5.setObjectName("formLayout_5") + self.startofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage) + self.startofBnfStopBandLabel.setObjectName("startofBnfStopBandLabel") + self.formLayout_5.setWidget(0, QtGui.QFormLayout.LabelRole, self.startofBnfStopBandLabel) + self.startofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage) + self.startofBnfStopBandEdit.setObjectName("startofBnfStopBandEdit") + self.formLayout_5.setWidget(0, QtGui.QFormLayout.FieldRole, self.startofBnfStopBandEdit) + self.endofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage) + self.endofBnfStopBandEdit.setObjectName("endofBnfStopBandEdit") + self.formLayout_5.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBnfStopBandEdit) + self.bnfTransitionEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfTransitionEdit.setObjectName("bnfTransitionEdit") + self.formLayout_5.setWidget(2, QtGui.QFormLayout.FieldRole, self.bnfTransitionEdit) + self.bnfStopBandAttenEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfStopBandAttenEdit.setObjectName("bnfStopBandAttenEdit") + self.formLayout_5.setWidget(3, QtGui.QFormLayout.FieldRole, self.bnfStopBandAttenEdit) + self.endofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage) + self.endofBnfStopBandLabel.setObjectName("endofBnfStopBandLabel") + self.formLayout_5.setWidget(1, QtGui.QFormLayout.LabelRole, self.endofBnfStopBandLabel) + self.bnfTransitionLabel = QtGui.QLabel(self.firbnfPage) + self.bnfTransitionLabel.setObjectName("bnfTransitionLabel") + self.formLayout_5.setWidget(2, QtGui.QFormLayout.LabelRole, self.bnfTransitionLabel) + self.bnfStopBandAttenLabel = QtGui.QLabel(self.firbnfPage) + self.bnfStopBandAttenLabel.setObjectName("bnfStopBandAttenLabel") + self.formLayout_5.setWidget(3, QtGui.QFormLayout.LabelRole, self.bnfStopBandAttenLabel) + self.filterTypeWidget.addWidget(self.firbnfPage) self.firhpfPage = QtGui.QWidget() self.firhpfPage.setObjectName("firhpfPage") self.formLayout_3 = QtGui.QFormLayout(self.firhpfPage) @@ -283,6 +312,10 @@ class Ui_MainWindow(object): self.bpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.bpfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.bpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.startofBnfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.endofBnfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.bnfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8)) + self.bnfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.endofHpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 773b4cca9..4e6c958a5 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -257,6 +257,50 @@ + + + + + + Start of Stop Band (Hz) + + + + + + + + + + + + + + + + + + + End of Stop Band (Hz) + + + + + + + Transition Width (Hz) + + + + + + + Stop Band Attenuation (dB) + + + + + -- cgit From 22a68fa5fab3307cd0ea3c4f3ba4270936fead6a Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 24 Aug 2009 00:24:26 -0400 Subject: Added design for RRC filters. --- gr-utils/src/python/gr_filter_design.py | 19 ++++++++++++++++- gr-utils/src/python/pyqt_filter.py | 30 +++++++++++++++++++++++++-- gr-utils/src/python/pyqt_filter.ui | 36 ++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 9ef12294d..2d0c72c76 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -149,6 +149,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbnfPage) elif(ftype == "High Pass"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) + elif(ftype == "Root Raised Cosine"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.rrcPage) self.design() @@ -200,7 +202,8 @@ class gr_plot_filter(QtGui.QMainWindow): "Band Pass" : self.design_win_bpf, "Complex Band Pass" : self.design_win_cbpf, "Band Notch" : self.design_win_bnf, - "High Pass" : self.design_win_hpf} + "High Pass" : self.design_win_hpf, + "Root Raised Cosine" : self.design_win_rrc} wintype = self.filterWindows[winstr] taps,r = designer[ftype](fs, gain, wintype) @@ -302,7 +305,21 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def design_win_rrc(self, fs, gain, wintype): + ret = True + sr,r = self.gui.rrcSymbolRateEdit.text().toDouble() + ret = r and ret + alpha,r = self.gui.rrcAlphaEdit.text().toDouble() + ret = r and ret + ntaps,r = self.gui.rrcNumTapsEdit.text().toInt() + ret = r and ret + if(r): + taps = gr.firdes.root_raised_cosine(gain, fs, sr, + alpha, ntaps) + return (taps,r) + else: + return ([],r) # Design Functions for Equiripple Filters def design_opt_lpf(self, fs, gain, wintype=None): diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 5fa0979de..15fccd27a 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Sun Aug 23 23:26:14 2009 +# Created: Mon Aug 24 00:20:11 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -188,6 +188,29 @@ class Ui_MainWindow(object): self.hpfPassBandRippleEdit.setObjectName("hpfPassBandRippleEdit") self.formLayout_3.setWidget(3, QtGui.QFormLayout.FieldRole, self.hpfPassBandRippleEdit) self.filterTypeWidget.addWidget(self.firhpfPage) + self.rrcPage = QtGui.QWidget() + self.rrcPage.setObjectName("rrcPage") + self.formLayout_6 = QtGui.QFormLayout(self.rrcPage) + self.formLayout_6.setObjectName("formLayout_6") + self.rrcSymbolRateLabel = QtGui.QLabel(self.rrcPage) + self.rrcSymbolRateLabel.setObjectName("rrcSymbolRateLabel") + self.formLayout_6.setWidget(0, QtGui.QFormLayout.LabelRole, self.rrcSymbolRateLabel) + self.rrcAlphaLabel = QtGui.QLabel(self.rrcPage) + self.rrcAlphaLabel.setObjectName("rrcAlphaLabel") + self.formLayout_6.setWidget(1, QtGui.QFormLayout.LabelRole, self.rrcAlphaLabel) + self.rrcNumTapsLabel = QtGui.QLabel(self.rrcPage) + self.rrcNumTapsLabel.setObjectName("rrcNumTapsLabel") + self.formLayout_6.setWidget(2, QtGui.QFormLayout.LabelRole, self.rrcNumTapsLabel) + self.rrcSymbolRateEdit = QtGui.QLineEdit(self.rrcPage) + self.rrcSymbolRateEdit.setObjectName("rrcSymbolRateEdit") + self.formLayout_6.setWidget(0, QtGui.QFormLayout.FieldRole, self.rrcSymbolRateEdit) + self.rrcAlphaEdit = QtGui.QLineEdit(self.rrcPage) + self.rrcAlphaEdit.setObjectName("rrcAlphaEdit") + self.formLayout_6.setWidget(1, QtGui.QFormLayout.FieldRole, self.rrcAlphaEdit) + self.rrcNumTapsEdit = QtGui.QLineEdit(self.rrcPage) + self.rrcNumTapsEdit.setObjectName("rrcNumTapsEdit") + self.formLayout_6.setWidget(2, QtGui.QFormLayout.FieldRole, self.rrcNumTapsEdit) + self.filterTypeWidget.addWidget(self.rrcPage) self.verticalLayout.addWidget(self.filterTypeWidget) self.sysParamsBox = QtGui.QGroupBox(self.filterFrame) self.sysParamsBox.setObjectName("sysParamsBox") @@ -262,7 +285,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.filterTypeWidget.setCurrentIndex(2) + self.filterTypeWidget.setCurrentIndex(4) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -320,6 +343,9 @@ class Ui_MainWindow(object): self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.rrcSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) + self.rrcAlphaLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8)) + self.rrcNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8)) self.sysParamsBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Parameters", None, QtGui.QApplication.UnicodeUTF8)) self.nfftLabel.setText(QtGui.QApplication.translate("MainWindow", "Num FFT points", None, QtGui.QApplication.UnicodeUTF8)) self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 4e6c958a5..199e339a5 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -157,7 +157,7 @@ - 2 + 4 @@ -348,6 +348,40 @@ + + + + + + Symbol Rate (sps) + + + + + + + Roll-off Factor + + + + + + + Number of Taps + + + + + + + + + + + + + + -- cgit From 2d4405ea55f3d9e4369fa903ce4d0d2a5addd7b4 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 24 Aug 2009 00:31:31 -0400 Subject: Added design for Guassian filters. --- gr-utils/src/python/gr_filter_design.py | 21 ++++++++++++++++++- gr-utils/src/python/pyqt_filter.py | 30 +++++++++++++++++++++++++-- gr-utils/src/python/pyqt_filter.ui | 36 ++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 2d0c72c76..0579d0fe2 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -151,6 +151,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) elif(ftype == "Root Raised Cosine"): self.gui.filterTypeWidget.setCurrentWidget(self.gui.rrcPage) + elif(ftype == "Gaussian"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.gausPage) self.design() @@ -203,7 +205,8 @@ class gr_plot_filter(QtGui.QMainWindow): "Complex Band Pass" : self.design_win_cbpf, "Band Notch" : self.design_win_bnf, "High Pass" : self.design_win_hpf, - "Root Raised Cosine" : self.design_win_rrc} + "Root Raised Cosine" : self.design_win_rrc, + "Gaussian" : self.design_win_gaus} wintype = self.filterWindows[winstr] taps,r = designer[ftype](fs, gain, wintype) @@ -321,6 +324,22 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def design_win_gaus(self, fs, gain, wintype): + ret = True + sr,r = self.gui.gausSymbolRateEdit.text().toDouble() + ret = r and ret + bt,r = self.gui.gausBTEdit.text().toDouble() + ret = r and ret + ntaps,r = self.gui.gausNumTapsEdit.text().toInt() + ret = r and ret + + if(r): + spb = fs / sr + taps = gr.firdes.gaussian(gain, spb, bt, ntaps) + return (taps,r) + else: + return ([],r) + # Design Functions for Equiripple Filters def design_opt_lpf(self, fs, gain, wintype=None): ret = True diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 15fccd27a..5591cc1a7 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Mon Aug 24 00:20:11 2009 +# Created: Mon Aug 24 00:28:45 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -211,6 +211,29 @@ class Ui_MainWindow(object): self.rrcNumTapsEdit.setObjectName("rrcNumTapsEdit") self.formLayout_6.setWidget(2, QtGui.QFormLayout.FieldRole, self.rrcNumTapsEdit) self.filterTypeWidget.addWidget(self.rrcPage) + self.gausPage = QtGui.QWidget() + self.gausPage.setObjectName("gausPage") + self.formLayout_7 = QtGui.QFormLayout(self.gausPage) + self.formLayout_7.setObjectName("formLayout_7") + self.gausSymbolRateLabel = QtGui.QLabel(self.gausPage) + self.gausSymbolRateLabel.setObjectName("gausSymbolRateLabel") + self.formLayout_7.setWidget(0, QtGui.QFormLayout.LabelRole, self.gausSymbolRateLabel) + self.gausSymbolRateEdit = QtGui.QLineEdit(self.gausPage) + self.gausSymbolRateEdit.setObjectName("gausSymbolRateEdit") + self.formLayout_7.setWidget(0, QtGui.QFormLayout.FieldRole, self.gausSymbolRateEdit) + self.gausBTLabel = QtGui.QLabel(self.gausPage) + self.gausBTLabel.setObjectName("gausBTLabel") + self.formLayout_7.setWidget(1, QtGui.QFormLayout.LabelRole, self.gausBTLabel) + self.gausBTEdit = QtGui.QLineEdit(self.gausPage) + self.gausBTEdit.setObjectName("gausBTEdit") + self.formLayout_7.setWidget(1, QtGui.QFormLayout.FieldRole, self.gausBTEdit) + self.gausNumTapsLabel = QtGui.QLabel(self.gausPage) + self.gausNumTapsLabel.setObjectName("gausNumTapsLabel") + self.formLayout_7.setWidget(2, QtGui.QFormLayout.LabelRole, self.gausNumTapsLabel) + self.gausNumTapsEdit = QtGui.QLineEdit(self.gausPage) + self.gausNumTapsEdit.setObjectName("gausNumTapsEdit") + self.formLayout_7.setWidget(2, QtGui.QFormLayout.FieldRole, self.gausNumTapsEdit) + self.filterTypeWidget.addWidget(self.gausPage) self.verticalLayout.addWidget(self.filterTypeWidget) self.sysParamsBox = QtGui.QGroupBox(self.filterFrame) self.sysParamsBox.setObjectName("sysParamsBox") @@ -285,7 +308,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.filterTypeWidget.setCurrentIndex(4) + self.filterTypeWidget.setCurrentIndex(5) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -346,6 +369,9 @@ class Ui_MainWindow(object): self.rrcSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) self.rrcAlphaLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8)) self.rrcNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8)) + self.gausSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) + self.gausBTLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8)) + self.gausNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8)) self.sysParamsBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Parameters", None, QtGui.QApplication.UnicodeUTF8)) self.nfftLabel.setText(QtGui.QApplication.translate("MainWindow", "Num FFT points", None, QtGui.QApplication.UnicodeUTF8)) self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 199e339a5..ed2037009 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -157,7 +157,7 @@ - 4 + 5 @@ -382,6 +382,40 @@ + + + + + + Symbol Rate (sps) + + + + + + + + + + Roll-off Factor + + + + + + + + + + Number of Taps + + + + + + + + -- cgit From ef44b1afa410d77dbf84ba79119c16bb4fd02606 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 24 Aug 2009 17:44:43 -0400 Subject: Added routine for optfir equiripple filter design code to create complex bandpass filters. Also adds this ability to the filter designer. --- gr-utils/src/python/gr_filter_design.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 0579d0fe2..4aa59360f 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -15,8 +15,6 @@ from gnuradio import gr, blks2, eng_notation from scipy import fftpack from pyqt_filter import Ui_MainWindow -from pyqt_filter_firlpf import Ui_firlpfForm -from pyqt_filter_firhpf import Ui_firhpfForm class gr_plot_filter(QtGui.QMainWindow): def __init__(self, qapp, options): @@ -196,7 +194,8 @@ class gr_plot_filter(QtGui.QMainWindow): if(winstr == "Equiripple"): designer = {"Low Pass" : self.design_opt_lpf, "Band Pass" : self.design_opt_bpf, - "High Pass" : self.design_opt_hpf} + "Complex Band Pass" : self.design_opt_cbpf, + "High Pass" : self.design_opt_hpf} taps,r = designer[ftype](fs, gain) else: @@ -381,6 +380,28 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) + def design_opt_cbpf(self, fs, gain, wintype=None): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + sb1 = pb1 - tb + sb2 = pb2 + tb + taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + return (taps,r) + else: + return ([],r) + def design_opt_hpf(self, fs, gain, wintype=None): ret = True sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() -- cgit From 09fb1c056189e676d4c905949d7608c866a9247e Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 24 Aug 2009 19:25:30 -0400 Subject: Adding equiripple band reject filter to filter design app. --- gr-utils/src/python/gr_filter_design.py | 41 ++- gr-utils/src/python/pyqt_filter.py | 15 +- gr-utils/src/python/pyqt_filter.ui | 457 ++++++++++++++++---------------- 3 files changed, 280 insertions(+), 233 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 4aa59360f..238fd63fe 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -41,7 +41,7 @@ class gr_plot_filter(QtGui.QMainWindow): Qt.SIGNAL("textEdited(QString)"), self.nfft_edit_changed) - self.gui.designButton.setShortcut("Return") + self.gui.designButton.setShortcut(QtCore.Qt.Key_Return) self.taps = [] self.fftdB = [] @@ -54,6 +54,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.lpfPassBandRippleEdit.setVisible(False) self.gui.bpfPassBandRippleLabel.setVisible(False) self.gui.bpfPassBandRippleEdit.setVisible(False) + self.gui.bnfPassBandRippleLabel.setVisible(False) + self.gui.bnfPassBandRippleEdit.setVisible(False) self.gui.hpfPassBandRippleLabel.setVisible(False) self.gui.hpfPassBandRippleEdit.setVisible(False) @@ -168,6 +170,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.lpfPassBandRippleEdit.setVisible(True) self.gui.bpfPassBandRippleLabel.setVisible(True) self.gui.bpfPassBandRippleEdit.setVisible(True) + self.gui.bnfPassBandRippleLabel.setVisible(True) + self.gui.bnfPassBandRippleEdit.setVisible(True) self.gui.hpfPassBandRippleLabel.setVisible(True) self.gui.hpfPassBandRippleEdit.setVisible(True) @@ -177,6 +181,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.lpfPassBandRippleEdit.setVisible(False) self.gui.bpfPassBandRippleLabel.setVisible(False) self.gui.bpfPassBandRippleEdit.setVisible(False) + self.gui.bnfPassBandRippleLabel.setVisible(False) + self.gui.bnfPassBandRippleEdit.setVisible(False) self.gui.hpfPassBandRippleLabel.setVisible(False) self.gui.hpfPassBandRippleEdit.setVisible(False) @@ -195,6 +201,7 @@ class gr_plot_filter(QtGui.QMainWindow): designer = {"Low Pass" : self.design_opt_lpf, "Band Pass" : self.design_opt_bpf, "Complex Band Pass" : self.design_opt_cbpf, + "Band Notch" : self.design_opt_bnf, "High Pass" : self.design_opt_hpf} taps,r = designer[ftype](fs, gain) @@ -210,6 +217,8 @@ class gr_plot_filter(QtGui.QMainWindow): taps,r = designer[ftype](fs, gain, wintype) if(r): + print "Number of taps: ", len(taps) + self.taps = scipy.array(taps) self.get_fft(fs, self.taps, self.nfftpts) self.update_time_curves() @@ -340,7 +349,7 @@ class gr_plot_filter(QtGui.QMainWindow): return ([],r) # Design Functions for Equiripple Filters - def design_opt_lpf(self, fs, gain, wintype=None): + def design_opt_lpf(self, fs, gain): ret = True pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() ret = r and ret @@ -358,7 +367,7 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([], ret) - def design_opt_bpf(self, fs, gain, wintype=None): + def design_opt_bpf(self, fs, gain): ret = True pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() ret = r and ret @@ -380,7 +389,7 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) - def design_opt_cbpf(self, fs, gain, wintype=None): + def design_opt_cbpf(self, fs, gain): ret = True pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() ret = r and ret @@ -402,7 +411,29 @@ class gr_plot_filter(QtGui.QMainWindow): else: return ([],r) - def design_opt_hpf(self, fs, gain, wintype=None): + def design_opt_bnf(self, fs, gain): + ret = True + sb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() + ret = r and ret + sb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bnfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bnfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + pb1 = sb1 - tb + pb2 = sb2 + tb + taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, + ripple, atten) + return (taps,r) + else: + return ([],r) + + def design_opt_hpf(self, fs, gain): ret = True sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() ret = r and ret diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 5591cc1a7..c10429cff 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Mon Aug 24 00:28:45 2009 -# by: PyQt4 UI code generator 4.4.4 +# Created: Mon Aug 24 17:59:37 2009 +# by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -157,6 +157,12 @@ class Ui_MainWindow(object): self.bnfStopBandAttenLabel = QtGui.QLabel(self.firbnfPage) self.bnfStopBandAttenLabel.setObjectName("bnfStopBandAttenLabel") self.formLayout_5.setWidget(3, QtGui.QFormLayout.LabelRole, self.bnfStopBandAttenLabel) + self.bnfPassBandRippleEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfPassBandRippleEdit.setObjectName("bnfPassBandRippleEdit") + self.formLayout_5.setWidget(4, QtGui.QFormLayout.FieldRole, self.bnfPassBandRippleEdit) + self.bnfPassBandRippleLabel = QtGui.QLabel(self.firbnfPage) + self.bnfPassBandRippleLabel.setObjectName("bnfPassBandRippleLabel") + self.formLayout_5.setWidget(4, QtGui.QFormLayout.LabelRole, self.bnfPassBandRippleLabel) self.filterTypeWidget.addWidget(self.firbnfPage) self.firhpfPage = QtGui.QWidget() self.firhpfPage.setObjectName("firhpfPage") @@ -292,7 +298,7 @@ class Ui_MainWindow(object): self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 25)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 24)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -308,7 +314,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.filterTypeWidget.setCurrentIndex(5) + self.filterTypeWidget.setCurrentIndex(2) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -362,6 +368,7 @@ class Ui_MainWindow(object): self.endofBnfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.bnfTransitionLabel.setText(QtGui.QApplication.translate("MainWindow", "Transition Width (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.bnfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) + self.bnfPassBandRippleLabel.setText(QtGui.QApplication.translate("MainWindow", "Pass Band Ripple (dB)", None, QtGui.QApplication.UnicodeUTF8)) self.endofHpfStopBandLabel.setText(QtGui.QApplication.translate("MainWindow", "End of Stop Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.startofHpfPassBandLabel.setText(QtGui.QApplication.translate("MainWindow", "Start of Pass Band (Hz)", None, QtGui.QApplication.UnicodeUTF8)) self.hpfStopBandAttenLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop Band Attenuation (dB)", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index ed2037009..d7dccfba1 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -1,8 +1,7 @@ - - + MainWindow - - + + 0 0 @@ -10,131 +9,131 @@ 696 - + GNU Radio Filter Design Tool - - - - - + + + + + 300 0 - + 300 16777215 - + QFrame::StyledPanel - + QFrame::Raised - + - + - + Low Pass - + Band Pass - + Complex Band Pass - + Band Notch - + High Pass - + Root Raised Cosine - + Gaussian - + - + Hamming Window - + Hann Window - + Blackman Window - + Rectangular Window - + Kaiser Window - + Blackman-harris Window - + Equiripple - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 16777215 30 - + Sample Rate (sps) - - - + + + 16777215 30 @@ -142,294 +141,304 @@ - - - + + + Filter Gain - - + + - - - 5 + + + 2 - - - - - + + + + + End of Pass Band (Hz) - - + + - - - + + + Start of Stop Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + + Start of Pass Band (Hz) - - + + - - - + + + End of Pass Band (Hz) - - + + - - + + - - - + + + Stop Band Attenuation (dB) - - - + + + Transition Width (Hz) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + + Start of Stop Band (Hz) - - + + - - + + - - + + - - + + - - - + + + End of Stop Band (Hz) - - - + + + Transition Width (Hz) - - - + + + Stop Band Attenuation (dB) + + + + + + + Pass Band Ripple (dB) + + + - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + End of Stop Band (Hz) - - + + - - - + + + Start of Pass Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - - - + + + + + Symbol Rate (sps) - - - + + + Roll-off Factor - - - + + + Number of Taps - - + + - - + + - - + + - - - - - + + + + + Symbol Rate (sps) - - + + - - - + + + Roll-off Factor - - + + - - - + + + Number of Taps - - + + - - + + System Parameters - - - + + + - - - + + + Num FFT points @@ -438,26 +447,26 @@ - - + + 0 0 - + 200 16777215 - + Design - + true - + true @@ -465,54 +474,54 @@ - - - + + + 800 0 - + 0 - - + + Frequency Domain - + - + - - + + Time Domain - + - + - - + + Phase - + - + - - + + Group Delay - + - + @@ -520,34 +529,34 @@ - - + + 0 0 1124 - 25 + 24 - - + + &File - + - + - - - + + + &Open - + Ctrl+O - - + + E&xit @@ -588,11 +597,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From f513de947ec9d15eb332abcba8a96927ff4dcc63 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 24 Aug 2009 23:02:52 -0400 Subject: Adding display for the number of taps in the filter. --- gr-utils/src/python/gr_filter_design.py | 8 +- gr-utils/src/python/pyqt_filter.py | 50 +++- gr-utils/src/python/pyqt_filter.ui | 514 ++++++++++++++++++-------------- 3 files changed, 325 insertions(+), 247 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 238fd63fe..2e490253a 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -128,6 +128,9 @@ class gr_plot_filter(QtGui.QMainWindow): self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) + + self.gui.nTapsEdit.setText("0") + self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING, "Hann Window" : gr.firdes.WIN_HANN, "Blackman Window" : gr.firdes.WIN_BLACKMAN, @@ -217,8 +220,6 @@ class gr_plot_filter(QtGui.QMainWindow): taps,r = designer[ftype](fs, gain, wintype) if(r): - print "Number of taps: ", len(taps) - self.taps = scipy.array(taps) self.get_fft(fs, self.taps, self.nfftpts) self.update_time_curves() @@ -226,6 +227,9 @@ class gr_plot_filter(QtGui.QMainWindow): self.update_phase_curves() self.update_group_curves() + self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) + + # Filter design functions using a window def design_win_lpf(self, fs, gain, wintype): ret = True diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index c10429cff..18e96bc11 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Mon Aug 24 17:59:37 2009 -# by: PyQt4 UI code generator 4.4.3 +# Created: Mon Aug 24 23:01:33 2009 +# by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -132,6 +132,7 @@ class Ui_MainWindow(object): self.firbnfPage = QtGui.QWidget() self.firbnfPage.setObjectName("firbnfPage") self.formLayout_5 = QtGui.QFormLayout(self.firbnfPage) + self.formLayout_5.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_5.setObjectName("formLayout_5") self.startofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage) self.startofBnfStopBandLabel.setObjectName("startofBnfStopBandLabel") @@ -139,30 +140,30 @@ class Ui_MainWindow(object): self.startofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage) self.startofBnfStopBandEdit.setObjectName("startofBnfStopBandEdit") self.formLayout_5.setWidget(0, QtGui.QFormLayout.FieldRole, self.startofBnfStopBandEdit) - self.endofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage) - self.endofBnfStopBandEdit.setObjectName("endofBnfStopBandEdit") - self.formLayout_5.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBnfStopBandEdit) - self.bnfTransitionEdit = QtGui.QLineEdit(self.firbnfPage) - self.bnfTransitionEdit.setObjectName("bnfTransitionEdit") - self.formLayout_5.setWidget(2, QtGui.QFormLayout.FieldRole, self.bnfTransitionEdit) - self.bnfStopBandAttenEdit = QtGui.QLineEdit(self.firbnfPage) - self.bnfStopBandAttenEdit.setObjectName("bnfStopBandAttenEdit") - self.formLayout_5.setWidget(3, QtGui.QFormLayout.FieldRole, self.bnfStopBandAttenEdit) self.endofBnfStopBandLabel = QtGui.QLabel(self.firbnfPage) self.endofBnfStopBandLabel.setObjectName("endofBnfStopBandLabel") self.formLayout_5.setWidget(1, QtGui.QFormLayout.LabelRole, self.endofBnfStopBandLabel) + self.endofBnfStopBandEdit = QtGui.QLineEdit(self.firbnfPage) + self.endofBnfStopBandEdit.setObjectName("endofBnfStopBandEdit") + self.formLayout_5.setWidget(1, QtGui.QFormLayout.FieldRole, self.endofBnfStopBandEdit) self.bnfTransitionLabel = QtGui.QLabel(self.firbnfPage) self.bnfTransitionLabel.setObjectName("bnfTransitionLabel") self.formLayout_5.setWidget(2, QtGui.QFormLayout.LabelRole, self.bnfTransitionLabel) + self.bnfTransitionEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfTransitionEdit.setObjectName("bnfTransitionEdit") + self.formLayout_5.setWidget(2, QtGui.QFormLayout.FieldRole, self.bnfTransitionEdit) self.bnfStopBandAttenLabel = QtGui.QLabel(self.firbnfPage) self.bnfStopBandAttenLabel.setObjectName("bnfStopBandAttenLabel") self.formLayout_5.setWidget(3, QtGui.QFormLayout.LabelRole, self.bnfStopBandAttenLabel) - self.bnfPassBandRippleEdit = QtGui.QLineEdit(self.firbnfPage) - self.bnfPassBandRippleEdit.setObjectName("bnfPassBandRippleEdit") - self.formLayout_5.setWidget(4, QtGui.QFormLayout.FieldRole, self.bnfPassBandRippleEdit) + self.bnfStopBandAttenEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfStopBandAttenEdit.setObjectName("bnfStopBandAttenEdit") + self.formLayout_5.setWidget(3, QtGui.QFormLayout.FieldRole, self.bnfStopBandAttenEdit) self.bnfPassBandRippleLabel = QtGui.QLabel(self.firbnfPage) self.bnfPassBandRippleLabel.setObjectName("bnfPassBandRippleLabel") self.formLayout_5.setWidget(4, QtGui.QFormLayout.LabelRole, self.bnfPassBandRippleLabel) + self.bnfPassBandRippleEdit = QtGui.QLineEdit(self.firbnfPage) + self.bnfPassBandRippleEdit.setObjectName("bnfPassBandRippleEdit") + self.formLayout_5.setWidget(4, QtGui.QFormLayout.FieldRole, self.bnfPassBandRippleEdit) self.filterTypeWidget.addWidget(self.firbnfPage) self.firhpfPage = QtGui.QWidget() self.firhpfPage.setObjectName("firhpfPage") @@ -241,6 +242,22 @@ class Ui_MainWindow(object): self.formLayout_7.setWidget(2, QtGui.QFormLayout.FieldRole, self.gausNumTapsEdit) self.filterTypeWidget.addWidget(self.gausPage) self.verticalLayout.addWidget(self.filterTypeWidget) + self.filterPropsBox = QtGui.QGroupBox(self.filterFrame) + self.filterPropsBox.setObjectName("filterPropsBox") + self.formLayout_8 = QtGui.QFormLayout(self.filterPropsBox) + self.formLayout_8.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_8.setObjectName("formLayout_8") + self.nTapsLabel = QtGui.QLabel(self.filterPropsBox) + self.nTapsLabel.setMinimumSize(QtCore.QSize(150, 0)) + self.nTapsLabel.setObjectName("nTapsLabel") + self.formLayout_8.setWidget(1, QtGui.QFormLayout.LabelRole, self.nTapsLabel) + self.nTapsEdit = QtGui.QLabel(self.filterPropsBox) + self.nTapsEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.nTapsEdit.setFrameShape(QtGui.QFrame.Box) + self.nTapsEdit.setFrameShadow(QtGui.QFrame.Raised) + self.nTapsEdit.setObjectName("nTapsEdit") + self.formLayout_8.setWidget(1, QtGui.QFormLayout.FieldRole, self.nTapsEdit) + self.verticalLayout.addWidget(self.filterPropsBox) self.sysParamsBox = QtGui.QGroupBox(self.filterFrame) self.sysParamsBox.setObjectName("sysParamsBox") self.formLayout_4 = QtGui.QFormLayout(self.sysParamsBox) @@ -249,6 +266,7 @@ class Ui_MainWindow(object): self.nfftEdit.setObjectName("nfftEdit") self.formLayout_4.setWidget(1, QtGui.QFormLayout.FieldRole, self.nfftEdit) self.nfftLabel = QtGui.QLabel(self.sysParamsBox) + self.nfftLabel.setMinimumSize(QtCore.QSize(150, 0)) self.nfftLabel.setObjectName("nfftLabel") self.formLayout_4.setWidget(1, QtGui.QFormLayout.LabelRole, self.nfftLabel) self.verticalLayout.addWidget(self.sysParamsBox) @@ -298,7 +316,7 @@ class Ui_MainWindow(object): self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 24)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 25)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -379,6 +397,8 @@ class Ui_MainWindow(object): self.gausSymbolRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Symbol Rate (sps)", None, QtGui.QApplication.UnicodeUTF8)) self.gausBTLabel.setText(QtGui.QApplication.translate("MainWindow", "Roll-off Factor", None, QtGui.QApplication.UnicodeUTF8)) self.gausNumTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps", None, QtGui.QApplication.UnicodeUTF8)) + self.filterPropsBox.setTitle(QtGui.QApplication.translate("MainWindow", "Filter Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.nTapsLabel.setText(QtGui.QApplication.translate("MainWindow", "Number of Taps:", None, QtGui.QApplication.UnicodeUTF8)) self.sysParamsBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Parameters", None, QtGui.QApplication.UnicodeUTF8)) self.nfftLabel.setText(QtGui.QApplication.translate("MainWindow", "Num FFT points", None, QtGui.QApplication.UnicodeUTF8)) self.designButton.setText(QtGui.QApplication.translate("MainWindow", "Design", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index d7dccfba1..b1f79f0b8 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -1,7 +1,8 @@ - + + MainWindow - - + + 0 0 @@ -9,131 +10,131 @@ 696 - + GNU Radio Filter Design Tool - - - - - + + + + + 300 0 - + 300 16777215 - + QFrame::StyledPanel - + QFrame::Raised - + - + - + Low Pass - + Band Pass - + Complex Band Pass - + Band Notch - + High Pass - + Root Raised Cosine - + Gaussian - + - + Hamming Window - + Hann Window - + Blackman Window - + Rectangular Window - + Kaiser Window - + Blackman-harris Window - + Equiripple - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 16777215 30 - + Sample Rate (sps) - - - + + + 16777215 30 @@ -141,304 +142,357 @@ - - - + + + Filter Gain - - + + - - + + 2 - - - - - + + + + + End of Pass Band (Hz) - - + + - - - + + + Start of Stop Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + + Start of Pass Band (Hz) - - + + - - - + + + End of Pass Band (Hz) - - + + - - + + - - - + + + Stop Band Attenuation (dB) - - - + + + Transition Width (Hz) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + QFormLayout::AllNonFixedFieldsGrow + + + + Start of Stop Band (Hz) - - - - - - - - + + - - - - - - + + + End of Stop Band (Hz) - - - + + + + + + Transition Width (Hz) - - - + + + + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) + + + - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + End of Stop Band (Hz) - - + + - - - + + + Start of Pass Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - - - + + + + + Symbol Rate (sps) - - - + + + Roll-off Factor - - - + + + Number of Taps - - + + - - + + - - + + - - - - - + + + + + Symbol Rate (sps) - - + + - - - + + + Roll-off Factor - - + + - - - + + + Number of Taps - - + + - - + + + Filter Properties + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + 150 + 0 + + + + Number of Taps: + + + + + + + + 100 + 16777215 + + + + QFrame::Box + + + QFrame::Raised + + + + + + + + + + + + System Parameters - - - + + + - - - + + + + + 150 + 0 + + + Num FFT points @@ -447,26 +501,26 @@ - - + + 0 0 - + 200 16777215 - + Design - + true - + true @@ -474,54 +528,54 @@ - - - + + + 800 0 - + 0 - - + + Frequency Domain - + - + - - + + Time Domain - + - + - - + + Phase - + - + - - + + Group Delay - + - + @@ -529,34 +583,34 @@ - - + + 0 0 1124 - 24 + 25 - - + + &File - + - + - - - + + + &Open - + Ctrl+O - - + + E&xit @@ -597,11 +651,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From 74921cb0e4df480266f05d0ec3b42b3a1fc86f8a Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 24 Aug 2009 23:08:31 -0400 Subject: Fixing tab order. --- gr-utils/src/python/pyqt_filter.ui | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index b1f79f0b8..497ea6912 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -157,7 +157,7 @@ - 2 + 0 @@ -636,10 +636,22 @@ bpfTransitionEdit bpfStopBandAttenEdit bpfPassBandRippleEdit + startofBnfStopBandEdit + endofBnfStopBandEdit + bnfTransitionEdit + bnfStopBandAttenEdit + bnfPassBandRippleEdit endofHpfStopBandEdit startofHpfPassBandEdit hpfStopBandAttenEdit hpfPassBandRippleEdit + rrcSymbolRateEdit + rrcAlphaEdit + rrcNumTapsEdit + gausSymbolRateEdit + gausBTEdit + gausNumTapsEdit + nfftEdit designButton tabGroup -- cgit From ebe5f1cacefd3b4b2c35adfd6a38b7fac387680b Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 24 Aug 2009 23:26:59 -0400 Subject: Setting validators for all edit boxes. --- gr-utils/src/python/gr_filter_design.py | 32 +++++++++++++++++++++++++++++++- gr-utils/src/python/pyqt_filter.py | 20 ++++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 2e490253a..4fbe6e34c 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -127,7 +127,37 @@ class gr_plot_filter(QtGui.QMainWindow): self.rcurve.setPen(Qt.QPen(blueBrush, 2)) self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) - + + # Set up validators for edit boxes + self.intVal = Qt.QIntValidator(None) + self.dblVal = Qt.QDoubleValidator(None) + self.gui.nfftEdit.setValidator(self.intVal) + self.gui.sampleRateEdit.setValidator(self.dblVal) + self.gui.filterGainEdit.setValidator(self.dblVal) + self.gui.endofLpfPassBandEdit.setValidator(self.dblVal) + self.gui.startofLpfStopBandEdit.setValidator(self.dblVal) + self.gui.lpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.lpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.startofBpfPassBandEdit.setValidator(self.dblVal) + self.gui.endofBpfPassBandEdit.setValidator(self.dblVal) + self.gui.bpfTransitionEdit.setValidator(self.dblVal) + self.gui.bpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.bpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.startofBnfStopBandEdit.setValidator(self.dblVal) + self.gui.endofBnfStopBandEdit.setValidator(self.dblVal) + self.gui.bnfTransitionEdit.setValidator(self.dblVal) + self.gui.bnfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.bnfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.endofHpfStopBandEdit.setValidator(self.dblVal) + self.gui.startofHpfPassBandEdit.setValidator(self.dblVal) + self.gui.hpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.hpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.rrcSymbolRateEdit.setValidator(self.dblVal) + self.gui.rrcAlphaEdit.setValidator(self.dblVal) + self.gui.rrcNumTapsEdit.setValidator(self.dblVal) + self.gui.gausSymbolRateEdit.setValidator(self.dblVal) + self.gui.gausBTEdit.setValidator(self.dblVal) + self.gui.gausNumTapsEdit.setValidator(self.dblVal) self.gui.nTapsEdit.setText("0") diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 18e96bc11..e2bdeb8bc 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Mon Aug 24 23:01:33 2009 +# Created: Mon Aug 24 23:10:31 2009 # by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -332,7 +332,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.filterTypeWidget.setCurrentIndex(2) + self.filterTypeWidget.setCurrentIndex(0) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -348,11 +348,23 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.endofBpfPassBandEdit, self.bpfTransitionEdit) MainWindow.setTabOrder(self.bpfTransitionEdit, self.bpfStopBandAttenEdit) MainWindow.setTabOrder(self.bpfStopBandAttenEdit, self.bpfPassBandRippleEdit) - MainWindow.setTabOrder(self.bpfPassBandRippleEdit, self.endofHpfStopBandEdit) + MainWindow.setTabOrder(self.bpfPassBandRippleEdit, self.startofBnfStopBandEdit) + MainWindow.setTabOrder(self.startofBnfStopBandEdit, self.endofBnfStopBandEdit) + MainWindow.setTabOrder(self.endofBnfStopBandEdit, self.bnfTransitionEdit) + MainWindow.setTabOrder(self.bnfTransitionEdit, self.bnfStopBandAttenEdit) + MainWindow.setTabOrder(self.bnfStopBandAttenEdit, self.bnfPassBandRippleEdit) + MainWindow.setTabOrder(self.bnfPassBandRippleEdit, self.endofHpfStopBandEdit) MainWindow.setTabOrder(self.endofHpfStopBandEdit, self.startofHpfPassBandEdit) MainWindow.setTabOrder(self.startofHpfPassBandEdit, self.hpfStopBandAttenEdit) MainWindow.setTabOrder(self.hpfStopBandAttenEdit, self.hpfPassBandRippleEdit) - MainWindow.setTabOrder(self.hpfPassBandRippleEdit, self.designButton) + MainWindow.setTabOrder(self.hpfPassBandRippleEdit, self.rrcSymbolRateEdit) + MainWindow.setTabOrder(self.rrcSymbolRateEdit, self.rrcAlphaEdit) + MainWindow.setTabOrder(self.rrcAlphaEdit, self.rrcNumTapsEdit) + MainWindow.setTabOrder(self.rrcNumTapsEdit, self.gausSymbolRateEdit) + MainWindow.setTabOrder(self.gausSymbolRateEdit, self.gausBTEdit) + MainWindow.setTabOrder(self.gausBTEdit, self.gausNumTapsEdit) + MainWindow.setTabOrder(self.gausNumTapsEdit, self.nfftEdit) + MainWindow.setTabOrder(self.nfftEdit, self.designButton) MainWindow.setTabOrder(self.designButton, self.tabGroup) def retranslateUi(self, MainWindow): -- cgit From be584380504e24f7841b4792290b9cb3bb52aed4 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 10:01:00 -0400 Subject: User messages if PyQt and PyQwt are not installed (or found). --- gr-utils/src/python/gr_filter_design.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 4fbe6e34c..1253056b5 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -1,5 +1,9 @@ #!/usr/bin/env python +import sys, os +from optparse import OptionParser +from gnuradio import gr, blks2, eng_notation + try: import scipy from scipy import fftpack @@ -7,14 +11,24 @@ except ImportError: print "Please install SciPy to run this script (http://www.scipy.org/)" raise SystemExit, 1 -import sys, os -from PyQt4 import Qt, QtCore, QtGui -import PyQt4.Qwt5 as Qwt -from optparse import OptionParser -from gnuradio import gr, blks2, eng_notation -from scipy import fftpack +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + from pyqt_filter import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" + raise SystemExit, 1 -from pyqt_filter import Ui_MainWindow class gr_plot_filter(QtGui.QMainWindow): def __init__(self, qapp, options): -- cgit From 6fa1fc320b539cac0add465652c0cac170a88db1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 11:15:25 -0400 Subject: Manages window/filter types better. Disables filter types if the designing algorithm doesn't support it (no RRC or Gaussian for equiripple filters). --- gr-utils/src/python/gr_filter_design.py | 63 ++++- gr-utils/src/python/pyqt_filter.py | 6 +- gr-utils/src/python/pyqt_filter.ui | 487 ++++++++++++++++---------------- 3 files changed, 300 insertions(+), 256 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 1253056b5..bf83cf69f 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -64,14 +64,12 @@ class gr_plot_filter(QtGui.QMainWindow): self.nfftpts = int(10000) self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts)) - self.gui.lpfPassBandRippleLabel.setVisible(False) - self.gui.lpfPassBandRippleEdit.setVisible(False) - self.gui.bpfPassBandRippleLabel.setVisible(False) - self.gui.bpfPassBandRippleEdit.setVisible(False) - self.gui.bnfPassBandRippleLabel.setVisible(False) - self.gui.bnfPassBandRippleEdit.setVisible(False) - self.gui.hpfPassBandRippleLabel.setVisible(False) - self.gui.hpfPassBandRippleEdit.setVisible(False) + self.firFilters = ("Low Pass", "Band Pass", "Complex Band Pass", "Band Notch", + "High Pass", "Root Raised Cosine", "Gaussian") + self.optFilters = ("Low Pass", "Band Pass", "Complex Band Pass", + "Band Notch", "High Pass") + + self.set_windowed() # Initialize to LPF self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) @@ -137,8 +135,11 @@ class gr_plot_filter(QtGui.QMainWindow): # Set up pen for colors and line width blue = QtGui.qRgb(0x00, 0x00, 0xFF) blueBrush = Qt.QBrush(Qt.QColor(blue)) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + redBrush = Qt.QBrush(Qt.QColor(red)) self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) @@ -212,6 +213,9 @@ class gr_plot_filter(QtGui.QMainWindow): self.design() def set_equiripple(self): + # Stop sending the signal for this function + self.gui.filterTypeComboBox.blockSignals(True) + self.equiripple = True self.gui.lpfPassBandRippleLabel.setVisible(True) self.gui.lpfPassBandRippleEdit.setVisible(True) @@ -221,8 +225,30 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.bnfPassBandRippleEdit.setVisible(True) self.gui.hpfPassBandRippleLabel.setVisible(True) self.gui.hpfPassBandRippleEdit.setVisible(True) + + # Save current type and repopulate the combo box for + # filters this window type can handle + currenttype = self.gui.filterTypeComboBox.currentText() + items = self.gui.filterTypeComboBox.count() + for i in xrange(items): + self.gui.filterTypeComboBox.removeItem(0) + self.gui.filterTypeComboBox.addItems(self.optFilters) + + # If the last filter type was valid for this window type, + # go back to it; otherwise, reset + try: + index = self.optFilters.index(currenttype) + self.gui.filterTypeComboBox.setCurrentIndex(index) + except ValueError: + pass + + # Tell gui its ok to start sending this signal again + self.gui.filterTypeComboBox.blockSignals(False) def set_windowed(self): + # Stop sending the signal for this function + self.gui.filterTypeComboBox.blockSignals(True) + self.equiripple = False self.gui.lpfPassBandRippleLabel.setVisible(False) self.gui.lpfPassBandRippleEdit.setVisible(False) @@ -232,7 +258,26 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.bnfPassBandRippleEdit.setVisible(False) self.gui.hpfPassBandRippleLabel.setVisible(False) self.gui.hpfPassBandRippleEdit.setVisible(False) - + + # Save current type and repopulate the combo box for + # filters this window type can handle + currenttype = self.gui.filterTypeComboBox.currentText() + items = self.gui.filterTypeComboBox.count() + for i in xrange(items): + self.gui.filterTypeComboBox.removeItem(0) + self.gui.filterTypeComboBox.addItems(self.firFilters) + + # If the last filter type was valid for this window type, + # go back to it; otherwise, reset + try: + index = self.optFilters.index(currenttype) + self.gui.filterTypeComboBox.setCurrentIndex(index) + except ValueError: + pass + + # Tell gui its ok to start sending this signal again + self.gui.filterTypeComboBox.blockSignals(False) + def design(self): ret = True fs,r = self.gui.sampleRateEdit.text().toDouble() diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index e2bdeb8bc..12ad183b0 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Mon Aug 24 23:10:31 2009 -# by: PyQt4 UI code generator 4.4.4 +# Created: Tue Aug 25 11:13:57 2009 +# by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -316,7 +316,7 @@ class Ui_MainWindow(object): self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 25)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 24)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 497ea6912..9b31112e8 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -1,8 +1,7 @@ - - + MainWindow - - + + 0 0 @@ -10,131 +9,131 @@ 696 - + GNU Radio Filter Design Tool - - - - - + + + + + 300 0 - + 300 16777215 - + QFrame::StyledPanel - + QFrame::Raised - + - + - + Low Pass - + Band Pass - + Complex Band Pass - + Band Notch - + High Pass - + Root Raised Cosine - + Gaussian - + - + Hamming Window - + Hann Window - + Blackman Window - + Rectangular Window - + Kaiser Window - + Blackman-harris Window - + Equiripple - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 16777215 30 - + Sample Rate (sps) - - - + + + 16777215 30 @@ -142,332 +141,332 @@ - - - + + + Filter Gain - - + + - - + + 0 - - - - - + + + + + End of Pass Band (Hz) - - + + - - - + + + Start of Stop Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + + Start of Pass Band (Hz) - - + + - - - + + + End of Pass Band (Hz) - - + + - - + + - - - + + + Stop Band Attenuation (dB) - - - + + + Transition Width (Hz) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + Start of Stop Band (Hz) - - + + - - - + + + End of Stop Band (Hz) - - + + - - - + + + Transition Width (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + End of Stop Band (Hz) - - + + - - - + + + Start of Pass Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - - - + + + + + Symbol Rate (sps) - - - + + + Roll-off Factor - - - + + + Number of Taps - - + + - - + + - - + + - - - - - + + + + + Symbol Rate (sps) - - + + - - - + + + Roll-off Factor - - + + - - - + + + Number of Taps - - + + - - + + Filter Properties - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 150 0 - + Number of Taps: - - - + + + 100 16777215 - + QFrame::Box - + QFrame::Raised - + @@ -476,23 +475,23 @@ - - + + System Parameters - - - + + + - - - + + + 150 0 - + Num FFT points @@ -501,26 +500,26 @@ - - + + 0 0 - + 200 16777215 - + Design - + true - + true @@ -528,54 +527,54 @@ - - - + + + 800 0 - + 0 - - + + Frequency Domain - + - + - - + + Time Domain - + - + - - + + Phase - + - + - - + + Group Delay - + - + @@ -583,34 +582,34 @@ - - + + 0 0 1124 - 25 + 24 - - + + &File - + - + - - - + + + &Open - + Ctrl+O - - + + E&xit @@ -663,11 +662,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From d4ba08af653a00af6530add2df14c1341d6a9b90 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 12:12:17 -0400 Subject: GR plotter tool handles end of file and files shorter than the block length. --- gr-utils/src/python/gr_plot_qt.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 7c744f2c6..e772151f0 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -152,14 +152,20 @@ class gr_plot_qt(QtGui.QMainWindow): def open_file(self): filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") - print filename - self.initialize(filename) + if(filename != ""): + print filename + self.initialize(filename) def initialize(self, filename): self.hfile = open(filename, "r") self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) - + + self.gui.filePosStartLineEdit.setText("0") + self.gui.filePosStopLineEdit.setText("0") + self.gui.fileTimeStartLineEdit.setText("0") + self.gui.fileTimeStopLineEdit.setText("0") + self.cur_start = 0 self.cur_stop = self.block_length @@ -169,6 +175,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.plotHBar.setSliderPosition(0) self.gui.plotHBar.setMaximum(self.signal_size) + self.update_time_curves() self.update_psd_curves() @@ -182,16 +189,24 @@ class gr_plot_qt(QtGui.QMainWindow): if(end > start): self.hfile.seek(start*self.sizeof_data, os.SEEK_SET) self.position = start - iq = scipy.fromfile(self.hfile, dtype=self.datatype, - count=end-start) - if(len(iq) < (end-start)): - print "End of File" - else: + try: + iq = scipy.fromfile(self.hfile, dtype=self.datatype, + count=end-start) + + if(len(iq) < (end-start)): + end = len(iq) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end)) + self.gui.plotHBar.setMaximum(end) + self.gui.plotHBar.setSingleStep(end) + self.file_length_changed() + tstep = 1.0 / self.sample_rate self.iq = iq self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] - self.set_file_pos_box(start, end) + self.set_file_pos_box(start, end) + except MemoryError: + pass else: # Do we want to do anything about this? pass @@ -296,6 +311,7 @@ class gr_plot_qt(QtGui.QMainWindow): def file_length_changed(self): start = self.gui.filePosStartLineEdit.text().toInt() length = self.gui.filePosLengthLineEdit.text().toInt() + if((start[1] == True) and (length[1] == True)): self.cur_start = start[0] self.block_length = length[0] -- cgit From f87944705b9fb251af9fe0c16ef2b47424c867d5 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 17:35:56 -0400 Subject: Adding a spectrogram plot. The axis need work. --- gr-utils/src/python/gr_plot_qt.py | 117 +++++++++++++-- gr-utils/src/python/pyqt_plot.py | 56 +++++-- gr-utils/src/python/pyqt_plot.ui | 307 ++++++++++++++++++++++---------------- 3 files changed, 328 insertions(+), 152 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index e772151f0..958be19ca 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -16,6 +16,36 @@ from gnuradio import eng_notation from pyqt_plot import Ui_MainWindow +class SpectrogramData(Qwt.QwtRasterData): + + def __init__(self, f, t): + Qwt.QwtArrayData.__init__(self, Qt.QRectF(0, 0, 0, 0)) + self.sp = scipy.array([[0], [0]]) + + def set_data(self, xfreq, ytime, data): + self.sp = data + self.freq = xfreq + self.time = ytime + boundingBox = Qt.QRectF(0, 0, self.freq.size, self.time.size) + self.setBoundingRect(boundingBox) + + def rasterHint(self, rect): + return Qt.QSize(self.sp.shape[0], self.sp.shape[1]) + + def copy(self): + return self + + def range(self): + + return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) + + def value(self, x, y): + #print x, y + x = int(x) + y = int(y) + return self.sp[x][y-1] + + class gr_plot_qt(QtGui.QMainWindow): def __init__(self, qapp, filename, options, parent=None): QtGui.QWidget.__init__(self, parent) @@ -32,7 +62,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.datatype = scipy.complex64 self.iq = list() self.time = list() - + # Set up basic plot attributes self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, "Time (sec)") self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)") @@ -40,13 +70,21 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)") # Set up FFT size combo box - self.gui.fftComboBox.addItems(["128", "256", "512", "1024", "2048", - "4096", "8192", "16384", "32768"]) - pos = self.gui.fftComboBox.findText(Qt.QString("%1").arg(self.psdfftsize)) - self.gui.fftComboBox.setCurrentIndex(pos) - self.connect(self.gui.fftComboBox, + self.fftsizes = ["128", "256", "512", "1024", "2048", + "4096", "8192", "16384", "32768"] + self.gui.psdFFTComboBox.addItems(self.fftsizes) + self.gui.specFFTComboBox.addItems(self.fftsizes) + pos = self.gui.psdFFTComboBox.findText(Qt.QString("%1").arg(self.psdfftsize)) + self.gui.psdFFTComboBox.setCurrentIndex(pos) + pos = self.gui.specFFTComboBox.findText(Qt.QString("%1").arg(self.specfftsize)) + self.gui.specFFTComboBox.setCurrentIndex(pos) + + self.connect(self.gui.psdFFTComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.psdFFTComboBoxEdit) + self.connect(self.gui.specFFTComboBox, Qt.SIGNAL("activated (const QString&)"), - self.fftComboBoxEdit) + self.specFFTComboBoxEdit) # Set up color scheme box self.color_modes = {"Black on White" : self.color_black_on_white, @@ -74,6 +112,12 @@ class gr_plot_qt(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.freqPlot.canvas()) + self.specZoomer = Qwt.QwtPlotZoomer(self.gui.specPlot.xBottom, + self.gui.specPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.specPlot.canvas()) + self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, self.gui.timePlot.yLeft, Qwt.QwtPicker.PointSelection, @@ -137,6 +181,21 @@ class gr_plot_qt(QtGui.QMainWindow): self.psdcurve = Qwt.QwtPlotCurve("PSD") self.psdcurve.attach(self.gui.freqPlot) + # Set up specTab plot as a spectrogram + self.specdata = SpectrogramData(range(0, 10), range(0, 10)) + + colorMap = Qwt.QwtLinearColorMap(Qt.Qt.darkCyan, Qt.Qt.red) + colorMap.addColorStop(0.1, Qt.Qt.cyan) + colorMap.addColorStop(0.6, Qt.Qt.green) + colorMap.addColorStop(0.95, Qt.Qt.yellow) + + self.spec = Qwt.QwtPlotSpectrogram() + self.spec.setColorMap(colorMap) + self.spec.attach(self.gui.specPlot) + self.spec.setContourLevels([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) + self.spec.setDisplayMode(Qwt.QwtPlotSpectrogram.ImageMode, True) + self.spec.setData(self.specdata) + # Set up initial color scheme self.color_modes["Blue on Black"]() @@ -172,12 +231,14 @@ class gr_plot_qt(QtGui.QMainWindow): self.init_data_input() self.get_data(self.cur_start, self.cur_stop) self.get_psd() + self.get_specgram() self.gui.plotHBar.setSliderPosition(0) self.gui.plotHBar.setMaximum(self.signal_size) self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() def init_data_input(self): self.hfile.seek(0, os.SEEK_END) @@ -218,17 +279,34 @@ class gr_plot_qt(QtGui.QMainWindow): noverlap=self.psdfftsize/4.0, window=winpoints, scale_by_freq=False) + self.iq_psd = 10.0*scipy.log10(abs(fftpack.fftshift(iq_psd))) self.freq = freq - self.sample_rate/2.0 + def get_specgram(self): + winpoints = self.winfunc(self.specfftsize) + iq_spec, f, t = mlab.specgram(self.iq, Fs=self.sample_rate, + NFFT=self.specfftsize, + noverlap=self.specfftsize/4.0, + window=winpoints, + scale_by_freq=False) + + self.iq_spec = 10.0*scipy.log10(abs(iq_spec)) + self.spec_f = f + self.spec_t = t def clickMe(self, qPoint): print qPoint.x() - def fftComboBoxEdit(self, fftSize): + def psdFFTComboBoxEdit(self, fftSize): self.psdfftsize = fftSize.toInt()[0] self.get_psd() self.update_psd_curves() + + def specFFTComboBoxEdit(self, fftSize): + self.specfftsize = fftSize.toInt()[0] + self.get_specgram() + self.update_specgram_curves() def colorComboBoxEdit(self, colorSelection): colorstr = str(colorSelection.toAscii()) @@ -241,8 +319,10 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_data(pos_start, pos_end) self.get_psd() + self.get_specgram() self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() def set_sample_rate(self, sr): self.sample_rate = sr @@ -255,6 +335,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.set_file_pos_box(self.cur_start, self.cur_stop) self.get_data(self.cur_start, self.cur_stop) self.get_psd() + self.get_specgram() self.update_time_curves() self.update_psd_curves() @@ -286,6 +367,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() # If there's a non-digit character, reset box else: @@ -304,6 +386,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() # If there's a non-digit character, reset box else: self.set_file_pos_box(self.cur_start, self.cur_stop) @@ -328,9 +411,11 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_data(self.cur_start, self.cur_stop) self.get_psd() + self.get_specgram() self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() # If there's a non-digit character, reset box else: self.set_file_pos_box(self.cur_start, self.cur_stop) @@ -352,9 +437,11 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_data(self.cur_start, self.cur_stop) self.get_psd() + self.get_specgram() self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() # If there's a non-digit character, reset box else: self.set_file_pos_box(self.cur_start, self.cur_stop) @@ -385,12 +472,22 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, min(self.freq), max(self.freq)) - + # Set the zoomer base to unzoom to the new axis self.freqZoomer.setZoomBase() self.gui.freqPlot.replot() + def update_specgram_curves(self): + # We don't have to reset the data for the speccurve here + # since this is taken care of in the SpectrogramData class + self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec) + + # Set the zoomer base to unzoom to the new axis + self.specZoomer.setZoomBase() + + self.gui.specPlot.replot() + def tabChanged(self, index): self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -497,7 +594,7 @@ def setup_options(): help="Set the sampler rate of the data [default=%default]") parser.add_option("", "--psd-size", type="int", default=2048, help="Set the size of the PSD FFT [default=%default]") - parser.add_option("", "--spec-size", type="int", default=256, + parser.add_option("", "--spec-size", type="int", default=2048, help="Set the size of the spectrogram FFT [default=%default]") return parser diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 796b6a238..2724d8546 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Aug 11 23:12:27 2009 -# by: PyQt4 UI code generator 4.4.4 +# Created: Tue Aug 25 15:28:55 2009 +# by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -38,22 +38,43 @@ class Ui_MainWindow(object): self.fftPropBox = QtGui.QGroupBox(self.freqTab) self.fftPropBox.setMinimumSize(QtCore.QSize(160, 0)) self.fftPropBox.setObjectName("fftPropBox") - self.formLayoutWidget = QtGui.QWidget(self.fftPropBox) - self.formLayoutWidget.setGeometry(QtCore.QRect(0, 20, 151, 191)) - self.formLayoutWidget.setObjectName("formLayoutWidget") - self.formLayout = QtGui.QFormLayout(self.formLayoutWidget) - self.formLayout.setObjectName("formLayout") - self.fftSizeLabel = QtGui.QLabel(self.formLayoutWidget) - self.fftSizeLabel.setObjectName("fftSizeLabel") - self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fftSizeLabel) - self.fftComboBox = QtGui.QComboBox(self.formLayoutWidget) - self.fftComboBox.setObjectName("fftComboBox") - self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fftComboBox) + self.formLayout_4 = QtGui.QFormLayout(self.fftPropBox) + self.formLayout_4.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_4.setObjectName("formLayout_4") + self.psdFFTComboBox = QtGui.QComboBox(self.fftPropBox) + self.psdFFTComboBox.setMinimumSize(QtCore.QSize(96, 0)) + self.psdFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215)) + self.psdFFTComboBox.setObjectName("psdFFTComboBox") + self.formLayout_4.setWidget(0, QtGui.QFormLayout.FieldRole, self.psdFFTComboBox) + self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox) + self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel") + self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel) self.horizontalLayout_2.addWidget(self.fftPropBox) self.freqPlot = Qwt5.QwtPlot(self.freqTab) self.freqPlot.setObjectName("freqPlot") self.horizontalLayout_2.addWidget(self.freqPlot) self.tabGroup.addTab(self.freqTab, "") + self.specTab = QtGui.QWidget() + self.specTab.setObjectName("specTab") + self.horizontalLayout_3 = QtGui.QHBoxLayout(self.specTab) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.groupBox = QtGui.QGroupBox(self.specTab) + self.groupBox.setObjectName("groupBox") + self.formLayout_3 = QtGui.QFormLayout(self.groupBox) + self.formLayout_3.setObjectName("formLayout_3") + self.specFFTLabel = QtGui.QLabel(self.groupBox) + self.specFFTLabel.setObjectName("specFFTLabel") + self.formLayout_3.setWidget(1, QtGui.QFormLayout.LabelRole, self.specFFTLabel) + self.specFFTComboBox = QtGui.QComboBox(self.groupBox) + self.specFFTComboBox.setMinimumSize(QtCore.QSize(96, 0)) + self.specFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215)) + self.specFFTComboBox.setObjectName("specFFTComboBox") + self.formLayout_3.setWidget(1, QtGui.QFormLayout.FieldRole, self.specFFTComboBox) + self.horizontalLayout_3.addWidget(self.groupBox) + self.specPlot = Qwt5.QwtPlot(self.specTab) + self.specPlot.setObjectName("specPlot") + self.horizontalLayout_3.addWidget(self.specPlot) + self.tabGroup.addTab(self.specTab, "") self.gridLayout.addWidget(self.tabGroup, 1, 0, 1, 1) self.filePosBox = QtGui.QGroupBox(self.centralwidget) self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) @@ -137,7 +158,7 @@ class Ui_MainWindow(object): self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 25)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 24)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -154,7 +175,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.tabGroup.setCurrentIndex(0) + self.tabGroup.setCurrentIndex(2) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -162,8 +183,11 @@ class Ui_MainWindow(object): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.fftSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8)) self.filePosBox.setTitle(QtGui.QApplication.translate("MainWindow", "File Position", None, QtGui.QApplication.UnicodeUTF8)) self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) self.filePosStopLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index f298735c4..62125962b 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -1,8 +1,7 @@ - - + MainWindow - - + + 0 0 @@ -10,93 +9,149 @@ 696 - + MainWindow - - - - - + + + + + Qt::Horizontal - - - - 0 + + + + 2 - - + + Time Domain - + - + - - + + Frequency Domain - + - - + + 160 0 - + FFT Properties - - - - 0 - 20 - 151 - 191 - + + + QFormLayout::AllNonFixedFieldsGrow - - - - - FFT Size - - - - - - - - + + + + + 96 + 0 + + + + + 96 + 16777215 + + + + + + + + FFT Size + + + + + formLayoutWidget + psdFFTComboBox + psdFFTSizeLabel + + + + + + + + + + Spectrogram + + + + + + Spectrogram Properties + + + + + + FFT Size + + + + + + + + 96 + 0 + + + + + 96 + 16777215 + + + + + + specFFTLabel + specFFTComboBox + specFFTComboBox - + + specPlot + groupBox - - - + + + 0 120 - + File Position - - + + 0 20 @@ -104,41 +159,41 @@ 92 - - - - + + + + Start - - + + - - - + + + Stop - - + + - - - + + + Length - - + + - - + + 180 20 @@ -146,41 +201,41 @@ 92 - - - - + + + + time start (sec) - - + + - - - + + + time stop (sec) - - + + - - - + + + time length (sec) - - + + - - + + 530 0 @@ -188,17 +243,17 @@ 120 - + 200 0 - + System Properties - - + + 0 20 @@ -206,17 +261,17 @@ 91 - - - - + + + + Sample Rate - - - + + + 0 0 @@ -227,8 +282,8 @@ - - + + 730 0 @@ -236,17 +291,17 @@ 120 - + 170 0 - + Display Properties - - + + 0 20 @@ -254,16 +309,16 @@ 91 - + - + - - + + Qt::Vertical - + 20 40 @@ -278,35 +333,35 @@ - - + + 0 0 927 - 25 + 24 - - + + &File - - + + - + - - - + + + &Open - + Ctrl+O - - + + E&xit @@ -326,11 +381,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From ab88e3c4fcf96093637eaadeae360df0d04282fa Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 17:54:36 -0400 Subject: Fixed spectrogram plotting axis. --- gr-utils/src/python/gr_plot_qt.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 958be19ca..5579bbce2 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -26,7 +26,9 @@ class SpectrogramData(Qwt.QwtRasterData): self.sp = data self.freq = xfreq self.time = ytime - boundingBox = Qt.QRectF(0, 0, self.freq.size, self.time.size) + boundingBox = Qt.QRectF(self.freq.min(), self.time.min(), + self.freq.max() - self.freq.min(), + self.time.max() - self.time.min()) self.setBoundingRect(boundingBox) def rasterHint(self, rect): @@ -40,10 +42,9 @@ class SpectrogramData(Qwt.QwtRasterData): return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) def value(self, x, y): - #print x, y - x = int(x) - y = int(y) - return self.sp[x][y-1] + f = int(self.freq.searchsorted(x)) + t = int(self.time.searchsorted(y)) + return self.sp[f][t-1] class gr_plot_qt(QtGui.QMainWindow): @@ -68,6 +69,8 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)") self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, "Frequency (Hz)") self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)") + self.gui.specPlot.setAxisTitle(self.gui.specPlot.xBottom, "Frequency (Hz)") + self.gui.specPlot.setAxisTitle(self.gui.specPlot.yLeft, "Time (sec)") # Set up FFT size combo box self.fftsizes = ["128", "256", "512", "1024", "2048", @@ -199,6 +202,7 @@ class gr_plot_qt(QtGui.QMainWindow): # Set up initial color scheme self.color_modes["Blue on Black"]() + # Connect a signal for when the sample rate changes self.set_sample_rate(self.sample_rate) self.connect(self.gui.sampleRateLineEdit, Qt.SIGNAL("editingFinished()"), @@ -338,6 +342,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_specgram() self.update_time_curves() self.update_psd_curves() + self.update_specgram_curves() def set_file_pos_box(self, start, end): tstart = start / self.sample_rate @@ -483,6 +488,13 @@ class gr_plot_qt(QtGui.QMainWindow): # since this is taken care of in the SpectrogramData class self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec) + self.gui.specPlot.setAxisScale(self.gui.specPlot.xBottom, + min(self.spec_f), + max(self.spec_f)) + self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft, + min(self.spec_t), + max(self.spec_t)) + # Set the zoomer base to unzoom to the new axis self.specZoomer.setZoomBase() -- cgit From 785cacd477d50aba8a412bae16c57681c52a7fd2 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 18:22:06 -0400 Subject: Added colorbar to spectrogram for magnitude measurement. --- gr-utils/src/python/gr_plot_qt.py | 18 ++++++++++++++++-- gr-utils/src/python/pyqt_plot.py | 4 ++-- gr-utils/src/python/pyqt_plot.ui | 8 +------- 3 files changed, 19 insertions(+), 11 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 5579bbce2..a5e3463c8 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -195,10 +195,16 @@ class gr_plot_qt(QtGui.QMainWindow): self.spec = Qwt.QwtPlotSpectrogram() self.spec.setColorMap(colorMap) self.spec.attach(self.gui.specPlot) - self.spec.setContourLevels([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) self.spec.setDisplayMode(Qwt.QwtPlotSpectrogram.ImageMode, True) self.spec.setData(self.specdata) + self.rightAxis = self.gui.specPlot.axisWidget(Qwt.QwtPlot.yRight) + self.rightAxis.setTitle("Magnitude (dBm)") + self.rightAxis.setColorBarEnabled(True) + self.rightAxis.setColorMap(self.spec.data().range(), + self.spec.colorMap()) + self.gui.specPlot.enableAxis(Qwt.QwtPlot.yRight) + # Set up initial color scheme self.color_modes["Blue on Black"]() @@ -488,13 +494,21 @@ class gr_plot_qt(QtGui.QMainWindow): # since this is taken care of in the SpectrogramData class self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec) + # Set the color map based on the new data + self.rightAxis.setColorMap(self.spec.data().range(), + self.spec.colorMap()) + + # Set the new axis base; include right axis for the intenisty color bar self.gui.specPlot.setAxisScale(self.gui.specPlot.xBottom, min(self.spec_f), max(self.spec_f)) self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft, min(self.spec_t), max(self.spec_t)) - + self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight, + self.iq_spec.min(), + self.iq_spec.max()) + # Set the zoomer base to unzoom to the new axis self.specZoomer.setZoomBase() diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 2724d8546..74c43c3eb 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Aug 25 15:28:55 2009 +# Created: Tue Aug 25 18:18:14 2009 # by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -175,7 +175,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.tabGroup.setCurrentIndex(2) + self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index 62125962b..19a62adf5 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -24,7 +24,7 @@ - 2 + 0 @@ -80,9 +80,6 @@ - formLayoutWidget - psdFFTComboBox - psdFFTSizeLabel @@ -125,9 +122,6 @@ - specFFTLabel - specFFTComboBox - specFFTComboBox -- cgit From 5314163f36b010c386a545512366aeb1f075f602 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 25 Aug 2009 18:43:52 -0400 Subject: Added files to Makefile.am for distribution. --- gr-utils/src/python/Makefile.am | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index b58faa9bf..0c8240fe4 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -23,12 +23,16 @@ include $(top_srcdir)/Makefile.common EXTRA_DIST = \ $(bin_SCRIPTS) \ - README.plot + README.plot \ + pyqt_plot.ui \ + pyqt_filter.ui ourpythondir = $(grpythondir) ourpython_PYTHON = \ - plot_data.py + plot_data.py \ + pyqt_plot.py \ + pyqt_filter.py bin_SCRIPTS = \ gr_plot_char.py \ @@ -43,6 +47,8 @@ bin_SCRIPTS = \ gr_plot_int.py \ gr_plot_iq.py \ gr_plot_short.py \ + gr_plot_qt.py \ + gr_filter_design.py \ lsusrp \ usrp_fft.py \ usrp_oscope.py \ @@ -56,3 +62,4 @@ bin_SCRIPTS = \ usrp2_rx_cfile.py \ usrp2_siggen.py \ usrp2_siggen_gui.py + -- cgit From db8bc5c7a5e701734810d0aabd8b774eda6f6839 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 1 Sep 2009 21:49:13 -0400 Subject: Adding a Reload option (Ctrl+R) option to quickly reread the file and reset the state. --- gr-utils/src/python/gr_plot_qt.py | 75 ++++++++++++++++++++++++++++----------- gr-utils/src/python/pyqt_plot.py | 6 +++- gr-utils/src/python/pyqt_plot.ui | 6 ++++ 3 files changed, 66 insertions(+), 21 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index a5e3463c8..36c0da485 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -7,14 +7,36 @@ except ImportError: print "Please install SciPy to run this script (http://www.scipy.org/)" raise SystemExit, 1 +try: + from matplotlib import mlab +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net)" + raise SystemExit, 1 + +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + # FIXME: reenable this before committing + #from gnuradio.pyqt_plot import Ui_MainWindow + from pyqt_plot import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_plot. Please build with \"pyuic4 pyqt_plot.ui -o pyqt_plot.py\"" + raise SystemExit, 1 + import sys, os -from PyQt4 import Qt, QtCore, QtGui -import PyQt4.Qwt5 as Qwt -from matplotlib import mlab from optparse import OptionParser from gnuradio import eng_notation -from pyqt_plot import Ui_MainWindow class SpectrogramData(Qwt.QwtRasterData): @@ -53,6 +75,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui = Ui_MainWindow() self.gui.setupUi(self) + self.filename = None self.block_length = options.block_length self.start = options.start self.sample_rate = options.sample_rate @@ -121,15 +144,15 @@ class gr_plot_qt(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.specPlot.canvas()) - self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, - self.gui.timePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPlotPicker.CrossRubberBand, - Qwt.QwtPicker.AlwaysOn, - self.gui.timePlot.canvas()) - self.picker.connect(self.picker, - Qt.SIGNAL('selected(const QwtDoublePoint&)'), - self.clickMe) + #self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, + # self.gui.timePlot.yLeft, + # Qwt.QwtPicker.PointSelection, + # Qwt.QwtPlotPicker.CrossRubberBand, + # Qwt.QwtPicker.AlwaysOn, + # self.gui.timePlot.canvas()) + #self.picker.connect(self.picker, + # Qt.SIGNAL('selected(const QwtDoublePoint&)'), + # self.clickMe) # Set up action when tab is changed self.connect(self.gui.tabGroup, @@ -153,7 +176,14 @@ class gr_plot_qt(QtGui.QMainWindow): self.connect(self.gui.action_open, Qt.SIGNAL("activated()"), self.open_file) - + + # Connect Reload action to reload the file + self.connect(self.gui.action_reload, + Qt.SIGNAL("activated()"), + self.reload_file) + self.gui.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", + None, QtGui.QApplication.UnicodeUTF8)) + # Set up file position boxes to update current figure self.connect(self.gui.filePosStartLineEdit, Qt.SIGNAL("editingFinished()"), @@ -222,10 +252,15 @@ class gr_plot_qt(QtGui.QMainWindow): def open_file(self): filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") if(filename != ""): - print filename + #print filename self.initialize(filename) + def reload_file(self): + if(self.filename): + self.initialize(self.filename) + def initialize(self, filename): + self.filename = filename self.hfile = open(filename, "r") self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) @@ -253,7 +288,7 @@ class gr_plot_qt(QtGui.QMainWindow): def init_data_input(self): self.hfile.seek(0, os.SEEK_END) self.signal_size = self.hfile.tell()/self.sizeof_data - print "Sizeof File: ", self.signal_size + #print "Sizeof File: ", self.signal_size self.hfile.seek(0, os.SEEK_SET) def get_data(self, start, end): @@ -528,7 +563,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) + #self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) @@ -550,7 +585,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) @@ -573,7 +608,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) @@ -595,7 +630,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) + #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 74c43c3eb..22492b0d0 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Aug 25 18:18:14 2009 +# Created: Tue Sep 1 21:40:08 2009 # by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -170,7 +170,10 @@ class Ui_MainWindow(object): self.action_open.setObjectName("action_open") self.action_exit = QtGui.QAction(MainWindow) self.action_exit.setObjectName("action_exit") + self.action_reload = QtGui.QAction(MainWindow) + self.action_reload.setObjectName("action_reload") self.menu_File.addAction(self.action_open) + self.menu_File.addAction(self.action_reload) self.menu_File.addAction(self.action_exit) self.menubar.addAction(self.menu_File.menuAction()) @@ -202,5 +205,6 @@ class Ui_MainWindow(object): self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + self.action_reload.setText(QtGui.QApplication.translate("MainWindow", "&Reload", None, QtGui.QApplication.UnicodeUTF8)) from PyQt4 import Qwt5 diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index 19a62adf5..023010f8c 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -341,6 +341,7 @@ &File + @@ -359,6 +360,11 @@ E&xit + + + &Reload + + -- cgit From 74c747cc9c9115d3d19d627eb5d3a39e6a15714c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 1 Sep 2009 21:59:44 -0400 Subject: Removing plot picker that addd nothing to the interface. --- gr-utils/src/python/gr_plot_qt.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 36c0da485..906bb2d33 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -144,16 +144,6 @@ class gr_plot_qt(QtGui.QMainWindow): Qwt.QwtPicker.AlwaysOn, self.gui.specPlot.canvas()) - #self.picker = Qwt.QwtPlotPicker(self.gui.timePlot.xBottom, - # self.gui.timePlot.yLeft, - # Qwt.QwtPicker.PointSelection, - # Qwt.QwtPlotPicker.CrossRubberBand, - # Qwt.QwtPicker.AlwaysOn, - # self.gui.timePlot.canvas()) - #self.picker.connect(self.picker, - # Qt.SIGNAL('selected(const QwtDoublePoint&)'), - # self.clickMe) - # Set up action when tab is changed self.connect(self.gui.tabGroup, Qt.SIGNAL("currentChanged (int)"), @@ -214,6 +204,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.psdcurve = Qwt.QwtPlotCurve("PSD") self.psdcurve.attach(self.gui.freqPlot) + # Set up specTab plot as a spectrogram self.specdata = SpectrogramData(range(0, 10), range(0, 10)) @@ -340,9 +331,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.spec_f = f self.spec_t = t - def clickMe(self, qPoint): - print qPoint.x() - def psdFFTComboBoxEdit(self, fftSize): self.psdfftsize = fftSize.toInt()[0] self.get_psd() @@ -563,7 +551,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - #self.picker.setTrackerPen(Qt.QPen(blackBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) @@ -585,7 +572,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) @@ -608,7 +594,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) @@ -630,7 +615,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - #self.picker.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) -- cgit From 3a27d463adaf6784b9abfe1d5f5828a0429f838b Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 1 Sep 2009 22:46:16 -0400 Subject: Adding ability to change line width and style (only a handful of current styles enabled). --- gr-utils/src/python/gr_plot_qt.py | 112 +++++++++++++++++++++++++++----------- gr-utils/src/python/pyqt_plot.py | 33 +++++++---- gr-utils/src/python/pyqt_plot.ui | 57 +++++++++---------- 3 files changed, 128 insertions(+), 74 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 906bb2d33..3d77787d4 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -84,6 +84,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.winfunc = scipy.blackman self.sizeof_data = 8 self.datatype = scipy.complex64 + self.pen_width = 1 self.iq = list() self.time = list() @@ -125,6 +126,18 @@ class gr_plot_qt(QtGui.QMainWindow): self.colorComboBoxEdit) + # Set up line style combo box + self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, + "Circle" : Qwt.QwtSymbol.Ellipse, + "Diamond" : Qwt.QwtSymbol.Rect, + "Triangle" : Qwt.QwtSymbol.Triangle} + self.gui.lineStyleComboBox.addItems(self.line_styles.keys()) + pos = self.gui.lineStyleComboBox.findText("None") + self.gui.lineStyleComboBox.setCurrentIndex(pos) + self.connect(self.gui.lineStyleComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.lineStyleComboBoxEdit) + # Create zoom functionality for the plots self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, self.gui.timePlot.yLeft, @@ -195,8 +208,20 @@ class gr_plot_qt(QtGui.QMainWindow): Qt.SIGNAL("editingFinished()"), self.file_time_length_changed) + stylestr = str(self.gui.lineStyleComboBox.currentText().toAscii()) + style = self.line_styles[stylestr] + self.rcurve = Qwt.QwtPlotCurve("Real") self.icurve = Qwt.QwtPlotCurve("Imaginary") + self.rsym = Qwt.QwtSymbol() + self.rsym.setStyle(style) + self.rsym.setSize(10) + self.isym = Qwt.QwtSymbol() + self.isym.setStyle(style) + self.isym.setSize(10) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.icurve.attach(self.gui.timePlot) self.rcurve.attach(self.gui.timePlot) @@ -204,7 +229,6 @@ class gr_plot_qt(QtGui.QMainWindow): self.psdcurve = Qwt.QwtPlotCurve("PSD") self.psdcurve.attach(self.gui.freqPlot) - # Set up specTab plot as a spectrogram self.specdata = SpectrogramData(range(0, 10), range(0, 10)) @@ -229,6 +253,13 @@ class gr_plot_qt(QtGui.QMainWindow): # Set up initial color scheme self.color_modes["Blue on Black"]() + # When line width spin box changes, update the pen size + self.connect(self.gui.lineWidthSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_pen_width) + self.gui.lineWidthSpinBox.setRange(1, 10) + + # Connect a signal for when the sample rate changes self.set_sample_rate(self.sample_rate) self.connect(self.gui.sampleRateLineEdit, @@ -346,6 +377,14 @@ class gr_plot_qt(QtGui.QMainWindow): color_func = self.color_modes[colorstr] color_func() + def lineStyleComboBoxEdit(self, styleSelection): + stylestr = str(styleSelection.toAscii()) + self.rsym.setStyle(self.line_styles[stylestr]) + self.isym.setStyle(self.line_styles[stylestr]) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def sliderMoved(self, value): pos_start = value pos_end = value + self.gui.plotHBar.pageStep() @@ -540,24 +579,33 @@ class gr_plot_qt(QtGui.QMainWindow): def tabChanged(self, index): self.gui.timePlot.replot() self.gui.freqPlot.replot() + self.gui.specPlot.replot() + + def change_pen_width(self, width): + self.pen_width = width + colormode = str(self.gui.colorComboBox.currentText().toAscii()) + color_func = self.color_modes[colormode]() def color_black_on_white(self): blue = QtGui.qRgb(0x00, 0x00, 0xFF) red = QtGui.qRgb(0xFF, 0x00, 0x00) - blackBrush = Qt.QBrush(Qt.QColor("black")) - blueBrush = Qt.QBrush(Qt.QColor(blue)) - redBrush = Qt.QBrush(Qt.QColor(red)) + blackPen = Qt.QPen(Qt.QBrush(Qt.QColor("black")), self.pen_width) + bluePen = Qt.QPen(Qt.QBrush(Qt.QColor(blue)), self.pen_width) + redPen = Qt.QPen(Qt.QBrush(Qt.QColor(red)), self.pen_width) self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - self.timeZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(blackBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(blackBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(blackPen) + self.timeZoomer.setRubberBandPen(blackPen) + self.freqZoomer.setTrackerPen(blackPen) + self.freqZoomer.setRubberBandPen(blackPen) + self.psdcurve.setPen(bluePen) + self.rcurve.setPen(bluePen) + self.icurve.setPen(redPen) + + self.rsym.setPen(bluePen) + self.isym.setPen(redPen) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -572,13 +620,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(whiteBrush, 1)) - self.rcurve.setPen(Qt.QPen(whiteBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -594,13 +642,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(greenBrush, 1)) - self.rcurve.setPen(Qt.QPen(greenBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() @@ -615,13 +663,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, 2)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, 2)) - self.psdcurve.setPen(Qt.QPen(blueBrush, 1)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) self.gui.timePlot.replot() self.gui.freqPlot.replot() diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 22492b0d0..c6e7fd5a2 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Sep 1 21:40:08 2009 +# Created: Tue Sep 1 22:46:04 2009 # by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -12,7 +12,7 @@ from PyQt4 import QtCore, QtGui class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(927, 696) + MainWindow.resize(927, 693) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtGui.QGridLayout(self.centralwidget) @@ -142,19 +142,26 @@ class Ui_MainWindow(object): self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) self.displayGroupBox = QtGui.QGroupBox(self.filePosBox) - self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 120)) + self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 142)) self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) self.displayGroupBox.setObjectName("displayGroupBox") - self.verticalLayoutWidget = QtGui.QWidget(self.displayGroupBox) - self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 20, 160, 91)) - self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget) - self.verticalLayout.setObjectName("verticalLayout") - self.colorComboBox = QtGui.QComboBox(self.verticalLayoutWidget) + self.gridLayout_2 = QtGui.QGridLayout(self.displayGroupBox) + self.gridLayout_2.setObjectName("gridLayout_2") + self.colorComboBox = QtGui.QComboBox(self.displayGroupBox) self.colorComboBox.setObjectName("colorComboBox") - self.verticalLayout.addWidget(self.colorComboBox) - spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - self.verticalLayout.addItem(spacerItem) + self.gridLayout_2.addWidget(self.colorComboBox, 0, 0, 1, 2) + self.lineWidthSpinBox = QtGui.QSpinBox(self.displayGroupBox) + self.lineWidthSpinBox.setObjectName("lineWidthSpinBox") + self.gridLayout_2.addWidget(self.lineWidthSpinBox, 1, 1, 1, 1) + self.lineWidthLabel = QtGui.QLabel(self.displayGroupBox) + self.lineWidthLabel.setObjectName("lineWidthLabel") + self.gridLayout_2.addWidget(self.lineWidthLabel, 1, 0, 1, 1) + self.label = QtGui.QLabel(self.displayGroupBox) + self.label.setObjectName("label") + self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1) + self.lineStyleComboBox = QtGui.QComboBox(self.displayGroupBox) + self.lineStyleComboBox.setObjectName("lineStyleComboBox") + self.gridLayout_2.addWidget(self.lineStyleComboBox, 2, 1, 1, 1) self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) @@ -201,6 +208,8 @@ class Ui_MainWindow(object): self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8)) self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8)) self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.lineWidthLabel.setText(QtGui.QApplication.translate("MainWindow", "Line Width", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("MainWindow", "Line Style", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index 023010f8c..df3d61197 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -6,7 +6,7 @@ 0 0 927 - 696 + 693 @@ -282,7 +282,7 @@ 730 0 170 - 120 + 142 @@ -294,34 +294,31 @@ Display Properties - - - - 0 - 20 - 160 - 91 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + + + + + + + + + + + Line Width + + + + + + + Line Style + + + + + + + -- cgit From e4c161f16aecd82f3cfc0a8aff4e1d16afaa2791 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 1 Sep 2009 23:02:47 -0400 Subject: Can now change the size of the symbols. Also fixes some layout issues. --- gr-utils/src/python/gr_plot_qt.py | 14 + gr-utils/src/python/pyqt_plot.py | 242 ++++++++------ gr-utils/src/python/pyqt_plot.ui | 670 ++++++++++++++++++++++---------------- 3 files changed, 546 insertions(+), 380 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 3d77787d4..267737fd0 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -259,6 +259,13 @@ class gr_plot_qt(QtGui.QMainWindow): self.change_pen_width) self.gui.lineWidthSpinBox.setRange(1, 10) + # When style size spin box changes, update the pen size + self.connect(self.gui.styleSizeSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_style_size) + self.gui.styleSizeSpinBox.setRange(1, 20) + self.gui.styleSizeSpinBox.setValue(5) + # Connect a signal for when the sample rate changes self.set_sample_rate(self.sample_rate) @@ -586,6 +593,13 @@ class gr_plot_qt(QtGui.QMainWindow): colormode = str(self.gui.colorComboBox.currentText().toAscii()) color_func = self.color_modes[colormode]() + def change_style_size(self, size): + self.rsym.setSize(size) + self.isym.setSize(size) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + def color_black_on_white(self): blue = QtGui.qRgb(0x00, 0x00, 0xFF) red = QtGui.qRgb(0xFF, 0x00, 0x00) diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index c6e7fd5a2..98977da97 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Sep 1 22:46:04 2009 +# Created: Tue Sep 1 23:02:36 2009 # by: PyQt4 UI code generator 4.4.3 # # WARNING! All changes made in this file will be lost! @@ -12,7 +12,7 @@ from PyQt4 import QtCore, QtGui class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(927, 693) + MainWindow.resize(927, 718) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtGui.QGridLayout(self.centralwidget) @@ -20,8 +20,123 @@ class Ui_MainWindow(object): self.plotHBar = QtGui.QScrollBar(self.centralwidget) self.plotHBar.setOrientation(QtCore.Qt.Horizontal) self.plotHBar.setObjectName("plotHBar") - self.gridLayout.addWidget(self.plotHBar, 2, 0, 1, 2) - self.tabGroup = QtGui.QTabWidget(self.centralwidget) + self.gridLayout.addWidget(self.plotHBar, 1, 0, 1, 3) + self.filePosBox = QtGui.QGroupBox(self.centralwidget) + self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) + self.filePosBox.setObjectName("filePosBox") + self.gridLayout_4 = QtGui.QGridLayout(self.filePosBox) + self.gridLayout_4.setObjectName("gridLayout_4") + self.filePosLayout = QtGui.QFormLayout() + self.filePosLayout.setObjectName("filePosLayout") + self.filePosStartLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosStartLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosStartLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosStartLineEdit.setObjectName("filePosStartLineEdit") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit) + self.filePosStopLabel = QtGui.QLabel(self.filePosBox) + self.filePosStopLabel.setObjectName("filePosStopLabel") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel) + self.filePosStopLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosStopLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosStopLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosStopLineEdit.setObjectName("filePosStopLineEdit") + self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit) + self.filePosLengthLabel = QtGui.QLabel(self.filePosBox) + self.filePosLengthLabel.setObjectName("filePosLengthLabel") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel) + self.filePosLengthLineEdit = QtGui.QLineEdit(self.filePosBox) + self.filePosLengthLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.filePosLengthLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit") + self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit) + self.filePosStartLabel = QtGui.QLabel(self.filePosBox) + self.filePosStartLabel.setObjectName("filePosStartLabel") + self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel) + self.gridLayout_4.addLayout(self.filePosLayout, 0, 0, 1, 1) + self.fileTimeLayout = QtGui.QFormLayout() + self.fileTimeLayout.setObjectName("fileTimeLayout") + self.fileTimeStartLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeStartLabel.setObjectName("fileTimeStartLabel") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel) + self.fileTimeStartLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeStartLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeStartLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit") + self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit) + self.fileTimeStopLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeStopLabel.setObjectName("fileTimeStopLabel") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel) + self.fileTimeStopLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeStopLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeStopLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit") + self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit) + self.fileTimeLengthLabel = QtGui.QLabel(self.filePosBox) + self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel) + self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.filePosBox) + self.fileTimeLengthLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.fileTimeLengthLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit") + self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit) + self.gridLayout_4.addLayout(self.fileTimeLayout, 0, 1, 1, 1) + self.gridLayout.addWidget(self.filePosBox, 2, 0, 1, 1) + self.displayGroupBox = QtGui.QGroupBox(self.centralwidget) + self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) + self.displayGroupBox.setObjectName("displayGroupBox") + self.gridLayout_2 = QtGui.QGridLayout(self.displayGroupBox) + self.gridLayout_2.setObjectName("gridLayout_2") + self.colorComboBox = QtGui.QComboBox(self.displayGroupBox) + self.colorComboBox.setObjectName("colorComboBox") + self.gridLayout_2.addWidget(self.colorComboBox, 0, 0, 1, 2) + self.lineWidthSpinBox = QtGui.QSpinBox(self.displayGroupBox) + self.lineWidthSpinBox.setMinimumSize(QtCore.QSize(100, 0)) + self.lineWidthSpinBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.lineWidthSpinBox.setObjectName("lineWidthSpinBox") + self.gridLayout_2.addWidget(self.lineWidthSpinBox, 1, 1, 1, 1) + self.lineWidthLabel = QtGui.QLabel(self.displayGroupBox) + self.lineWidthLabel.setObjectName("lineWidthLabel") + self.gridLayout_2.addWidget(self.lineWidthLabel, 1, 0, 1, 1) + self.lineStyleLabel = QtGui.QLabel(self.displayGroupBox) + self.lineStyleLabel.setObjectName("lineStyleLabel") + self.gridLayout_2.addWidget(self.lineStyleLabel, 2, 0, 1, 1) + self.lineStyleComboBox = QtGui.QComboBox(self.displayGroupBox) + self.lineStyleComboBox.setMinimumSize(QtCore.QSize(100, 0)) + self.lineStyleComboBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.lineStyleComboBox.setObjectName("lineStyleComboBox") + self.gridLayout_2.addWidget(self.lineStyleComboBox, 2, 1, 1, 1) + self.styleSizeLabel = QtGui.QLabel(self.displayGroupBox) + self.styleSizeLabel.setObjectName("styleSizeLabel") + self.gridLayout_2.addWidget(self.styleSizeLabel, 3, 0, 1, 1) + self.styleSizeSpinBox = QtGui.QSpinBox(self.displayGroupBox) + self.styleSizeSpinBox.setMinimumSize(QtCore.QSize(100, 0)) + self.styleSizeSpinBox.setMaximumSize(QtCore.QSize(100, 16777215)) + self.styleSizeSpinBox.setObjectName("styleSizeSpinBox") + self.gridLayout_2.addWidget(self.styleSizeSpinBox, 3, 1, 1, 1) + self.gridLayout.addWidget(self.displayGroupBox, 2, 2, 1, 1) + self.sysGroupBox = QtGui.QGroupBox(self.centralwidget) + self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0)) + self.sysGroupBox.setObjectName("sysGroupBox") + self.formLayout = QtGui.QFormLayout(self.sysGroupBox) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.sampleRateLabel = QtGui.QLabel(self.sysGroupBox) + self.sampleRateLabel.setObjectName("sampleRateLabel") + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) + self.sampleRateLineEdit = QtGui.QLineEdit(self.sysGroupBox) + self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(50, 0)) + self.sampleRateLineEdit.setMaximumSize(QtCore.QSize(100, 16777215)) + self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) + self.gridLayout.addWidget(self.sysGroupBox, 2, 1, 1, 1) + self.frame = QtGui.QFrame(self.centralwidget) + self.frame.setFrameShape(QtGui.QFrame.StyledPanel) + self.frame.setFrameShadow(QtGui.QFrame.Raised) + self.frame.setObjectName("frame") + self.gridLayout_3 = QtGui.QGridLayout(self.frame) + self.gridLayout_3.setObjectName("gridLayout_3") + self.tabGroup = QtGui.QTabWidget(self.frame) + self.tabGroup.setMinimumSize(QtCore.QSize(0, 0)) self.tabGroup.setObjectName("tabGroup") self.timeTab = QtGui.QWidget() self.timeTab.setObjectName("timeTab") @@ -41,14 +156,14 @@ class Ui_MainWindow(object): self.formLayout_4 = QtGui.QFormLayout(self.fftPropBox) self.formLayout_4.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_4.setObjectName("formLayout_4") + self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox) + self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel") + self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel) self.psdFFTComboBox = QtGui.QComboBox(self.fftPropBox) self.psdFFTComboBox.setMinimumSize(QtCore.QSize(96, 0)) self.psdFFTComboBox.setMaximumSize(QtCore.QSize(96, 16777215)) self.psdFFTComboBox.setObjectName("psdFFTComboBox") self.formLayout_4.setWidget(0, QtGui.QFormLayout.FieldRole, self.psdFFTComboBox) - self.psdFFTSizeLabel = QtGui.QLabel(self.fftPropBox) - self.psdFFTSizeLabel.setObjectName("psdFFTSizeLabel") - self.formLayout_4.setWidget(0, QtGui.QFormLayout.LabelRole, self.psdFFTSizeLabel) self.horizontalLayout_2.addWidget(self.fftPropBox) self.freqPlot = Qwt5.QwtPlot(self.freqTab) self.freqPlot.setObjectName("freqPlot") @@ -75,94 +190,8 @@ class Ui_MainWindow(object): self.specPlot.setObjectName("specPlot") self.horizontalLayout_3.addWidget(self.specPlot) self.tabGroup.addTab(self.specTab, "") - self.gridLayout.addWidget(self.tabGroup, 1, 0, 1, 1) - self.filePosBox = QtGui.QGroupBox(self.centralwidget) - self.filePosBox.setMinimumSize(QtCore.QSize(0, 120)) - self.filePosBox.setObjectName("filePosBox") - self.formLayoutWidget_2 = QtGui.QWidget(self.filePosBox) - self.formLayoutWidget_2.setGeometry(QtCore.QRect(0, 20, 160, 92)) - self.formLayoutWidget_2.setObjectName("formLayoutWidget_2") - self.filePosLayout = QtGui.QFormLayout(self.formLayoutWidget_2) - self.filePosLayout.setObjectName("filePosLayout") - self.filePosStartLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosStartLabel.setObjectName("filePosStartLabel") - self.filePosLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.filePosStartLabel) - self.filePosStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosStartLineEdit.setObjectName("filePosStartLineEdit") - self.filePosLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.filePosStartLineEdit) - self.filePosStopLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosStopLabel.setObjectName("filePosStopLabel") - self.filePosLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.filePosStopLabel) - self.filePosStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosStopLineEdit.setObjectName("filePosStopLineEdit") - self.filePosLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.filePosStopLineEdit) - self.filePosLengthLabel = QtGui.QLabel(self.formLayoutWidget_2) - self.filePosLengthLabel.setObjectName("filePosLengthLabel") - self.filePosLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.filePosLengthLabel) - self.filePosLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_2) - self.filePosLengthLineEdit.setObjectName("filePosLengthLineEdit") - self.filePosLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.filePosLengthLineEdit) - self.formLayoutWidget_4 = QtGui.QWidget(self.filePosBox) - self.formLayoutWidget_4.setGeometry(QtCore.QRect(180, 20, 231, 92)) - self.formLayoutWidget_4.setObjectName("formLayoutWidget_4") - self.fileTimeLayout = QtGui.QFormLayout(self.formLayoutWidget_4) - self.fileTimeLayout.setObjectName("fileTimeLayout") - self.fileTimeStartLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeStartLabel.setObjectName("fileTimeStartLabel") - self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.fileTimeStartLabel) - self.fileTimeStartLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeStartLineEdit.setObjectName("fileTimeStartLineEdit") - self.fileTimeLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.fileTimeStartLineEdit) - self.fileTimeStopLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeStopLabel.setObjectName("fileTimeStopLabel") - self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.fileTimeStopLabel) - self.fileTimeStopLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeStopLineEdit.setObjectName("fileTimeStopLineEdit") - self.fileTimeLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.fileTimeStopLineEdit) - self.fileTimeLengthLabel = QtGui.QLabel(self.formLayoutWidget_4) - self.fileTimeLengthLabel.setObjectName("fileTimeLengthLabel") - self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.fileTimeLengthLabel) - self.fileTimeLengthLineEdit = QtGui.QLineEdit(self.formLayoutWidget_4) - self.fileTimeLengthLineEdit.setObjectName("fileTimeLengthLineEdit") - self.fileTimeLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.fileTimeLengthLineEdit) - self.sysGroupBox = QtGui.QGroupBox(self.filePosBox) - self.sysGroupBox.setGeometry(QtCore.QRect(530, 0, 200, 120)) - self.sysGroupBox.setMinimumSize(QtCore.QSize(200, 0)) - self.sysGroupBox.setObjectName("sysGroupBox") - self.formLayoutWidget_3 = QtGui.QWidget(self.sysGroupBox) - self.formLayoutWidget_3.setGeometry(QtCore.QRect(0, 20, 191, 91)) - self.formLayoutWidget_3.setObjectName("formLayoutWidget_3") - self.formLayout_2 = QtGui.QFormLayout(self.formLayoutWidget_3) - self.formLayout_2.setObjectName("formLayout_2") - self.sampleRateLabel = QtGui.QLabel(self.formLayoutWidget_3) - self.sampleRateLabel.setObjectName("sampleRateLabel") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.sampleRateLabel) - self.sampleRateLineEdit = QtGui.QLineEdit(self.formLayoutWidget_3) - self.sampleRateLineEdit.setMinimumSize(QtCore.QSize(0, 0)) - self.sampleRateLineEdit.setObjectName("sampleRateLineEdit") - self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.sampleRateLineEdit) - self.displayGroupBox = QtGui.QGroupBox(self.filePosBox) - self.displayGroupBox.setGeometry(QtCore.QRect(730, 0, 170, 142)) - self.displayGroupBox.setMinimumSize(QtCore.QSize(170, 0)) - self.displayGroupBox.setObjectName("displayGroupBox") - self.gridLayout_2 = QtGui.QGridLayout(self.displayGroupBox) - self.gridLayout_2.setObjectName("gridLayout_2") - self.colorComboBox = QtGui.QComboBox(self.displayGroupBox) - self.colorComboBox.setObjectName("colorComboBox") - self.gridLayout_2.addWidget(self.colorComboBox, 0, 0, 1, 2) - self.lineWidthSpinBox = QtGui.QSpinBox(self.displayGroupBox) - self.lineWidthSpinBox.setObjectName("lineWidthSpinBox") - self.gridLayout_2.addWidget(self.lineWidthSpinBox, 1, 1, 1, 1) - self.lineWidthLabel = QtGui.QLabel(self.displayGroupBox) - self.lineWidthLabel.setObjectName("lineWidthLabel") - self.gridLayout_2.addWidget(self.lineWidthLabel, 1, 0, 1, 1) - self.label = QtGui.QLabel(self.displayGroupBox) - self.label.setObjectName("label") - self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1) - self.lineStyleComboBox = QtGui.QComboBox(self.displayGroupBox) - self.lineStyleComboBox.setObjectName("lineStyleComboBox") - self.gridLayout_2.addWidget(self.lineStyleComboBox, 2, 1, 1, 1) - self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) + self.gridLayout_3.addWidget(self.tabGroup, 0, 0, 1, 1) + self.gridLayout.addWidget(self.frame, 0, 0, 1, 3) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 24)) @@ -191,25 +220,26 @@ class Ui_MainWindow(object): def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) - self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) - self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) - self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8)) self.filePosBox.setTitle(QtGui.QApplication.translate("MainWindow", "File Position", None, QtGui.QApplication.UnicodeUTF8)) - self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) self.filePosStopLabel.setText(QtGui.QApplication.translate("MainWindow", "Stop", None, QtGui.QApplication.UnicodeUTF8)) self.filePosLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "Length", None, QtGui.QApplication.UnicodeUTF8)) + self.filePosStartLabel.setText(QtGui.QApplication.translate("MainWindow", "Start", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeStartLabel.setText(QtGui.QApplication.translate("MainWindow", "time start (sec)", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeStopLabel.setText(QtGui.QApplication.translate("MainWindow", "time stop (sec)", None, QtGui.QApplication.UnicodeUTF8)) self.fileTimeLengthLabel.setText(QtGui.QApplication.translate("MainWindow", "time length (sec)", None, QtGui.QApplication.UnicodeUTF8)) - self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8)) - self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8)) self.displayGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Display Properties", None, QtGui.QApplication.UnicodeUTF8)) self.lineWidthLabel.setText(QtGui.QApplication.translate("MainWindow", "Line Width", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("MainWindow", "Line Style", None, QtGui.QApplication.UnicodeUTF8)) + self.lineStyleLabel.setText(QtGui.QApplication.translate("MainWindow", "Line Style", None, QtGui.QApplication.UnicodeUTF8)) + self.styleSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "Style Size", None, QtGui.QApplication.UnicodeUTF8)) + self.sysGroupBox.setTitle(QtGui.QApplication.translate("MainWindow", "System Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.sampleRateLabel.setText(QtGui.QApplication.translate("MainWindow", "Sample Rate", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.timeTab), QtGui.QApplication.translate("MainWindow", "Time Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.fftPropBox.setTitle(QtGui.QApplication.translate("MainWindow", "FFT Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.psdFFTSizeLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.freqTab), QtGui.QApplication.translate("MainWindow", "Frequency Domain", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Spectrogram Properties", None, QtGui.QApplication.UnicodeUTF8)) + self.specFFTLabel.setText(QtGui.QApplication.translate("MainWindow", "FFT Size", None, QtGui.QApplication.UnicodeUTF8)) + self.tabGroup.setTabText(self.tabGroup.indexOf(self.specTab), QtGui.QApplication.translate("MainWindow", "Spectrogram", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index df3d61197..7244d24c9 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -6,7 +6,7 @@ 0 0 927 - 693 + 718 @@ -14,126 +14,14 @@ - + Qt::Horizontal - - - - 0 - - - - Time Domain - - - - - - - - - - Frequency Domain - - - - - - - 160 - 0 - - - - FFT Properties - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - 96 - 0 - - - - - 96 - 16777215 - - - - - - - - FFT Size - - - - - - - - - - - - - - Spectrogram - - - - - - Spectrogram Properties - - - - - - FFT Size - - - - - - - - 96 - 0 - - - - - 96 - 16777215 - - - - - - - - - - - - specPlot - groupBox - - - - + @@ -144,182 +32,416 @@ File Position - - - - 0 - 20 - 160 - 92 - - - - - - - Start - - - - - - - - - - Stop - - - - - - - - - - Length - - - - - - - - - - - - 180 - 20 - 231 - 92 - - - - - - - time start (sec) - - - - - - - - - - time stop (sec) - - - - - - - - - - time length (sec) - - - - - - - - - - - - 530 - 0 - 200 - 120 - - - - - 200 - 0 - - - - System Properties - - - - - 0 - 20 - 191 - 91 - - - + + + + + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + Stop + + + + + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + Length + + + + + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + Start + + + + + + + - + - Sample Rate + time start (sec) - + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + time stop (sec) + + + + + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + time length (sec) + + + + + - 0 + 50 0 + + + 100 + 16777215 + + - - - - - - 730 - 0 - 170 - 142 - - - - - 170 - 0 - - - - Display Properties + + + + + + + + + 170 + 0 + + + + Display Properties + + + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + + + + + Line Width + + + + + + + Line Style + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + + + + + Style Size + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + + + + + + + + + 200 + 0 + + + + System Properties + + + + QFormLayout::AllNonFixedFieldsGrow - - - - - - - - - - - Line Width - + + + + Sample Rate + + + + + + + + 50 + 0 + + + + + 100 + 16777215 + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + 0 + + + + Time Domain + + + + + + + timePlot + + + + Frequency Domain + + + + + + + 160 + 0 + + + + FFT Properties + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + FFT Size + + + + + + + + 96 + 0 + + + + + 96 + 16777215 + + + + + + psdFFTSizeLabel + psdFFTComboBox + + + + + + - - - - - Line Style - + + + Spectrogram + + + + + + Spectrogram Properties + + + + + + FFT Size + + + + + + + + 96 + 0 + + + + + 96 + 16777215 + + + + + + + + + + + + specPlot + groupBox - - - - - - + + + + tabGroup -- cgit From 4b3c5eced9a5b03a0077b6f7897a2157fca9a8dd Mon Sep 17 00:00:00 2001 From: Eric Blossom Date: Tue, 8 Sep 2009 12:40:05 -0700 Subject: removed qr_fft.py from gr-utils --- gr-utils/src/python/Makefile.am | 1 - gr-utils/src/python/qr_fft.py | 505 ---------------------------------------- 2 files changed, 506 deletions(-) delete mode 100755 gr-utils/src/python/qr_fft.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 59ca215a7..0c8240fe4 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -50,7 +50,6 @@ bin_SCRIPTS = \ gr_plot_qt.py \ gr_filter_design.py \ lsusrp \ - qr_fft.py \ usrp_fft.py \ usrp_oscope.py \ usrp_print_db.py \ diff --git a/gr-utils/src/python/qr_fft.py b/gr-utils/src/python/qr_fft.py deleted file mode 100755 index c2f06d715..000000000 --- a/gr-utils/src/python/qr_fft.py +++ /dev/null @@ -1,505 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio.wxgui import forms -from gnuradio import gr, gru -from gnuradio import vrt -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider -from gnuradio.gr import pubsub -from optparse import OptionParser -import wx -import sys -import numpy -import time - -class app_top_block(stdgui2.std_top_block, pubsub.pubsub): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - pubsub.pubsub.__init__(self) - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - #parser.add_option("-e", "--interface", type="string", default="eth0", - # help="select Ethernet interface, default is eth0") - #parser.add_option("-m", "--mac-addr", type="string", default="", - # help="select USRP by MAC address, default is auto-select") - #parser.add_option("-A", "--antenna", default=None, - # help="select Rx Antenna (only on RFX-series boards)") - #parser.add_option("-d", "--decim", type="int", default=16, - # help="set fgpa decimation rate to DECIM [default=%default]") - #parser.add_option("-f", "--freq", type="eng_float", default=None, - # help="set frequency to FREQ", metavar="FREQ") - #parser.add_option("-g", "--gain", type="eng_float", default=None, - # help="set gain in dB (default is midpoint)") - parser.add_option("-W", "--waterfall", action="store_true", default=False, - help="Enable waterfall display") - parser.add_option("-S", "--oscilloscope", action="store_true", default=False, - help="Enable oscilloscope display") - parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, default=[%default]") - parser.add_option("", "--ref-scale", type="eng_float", default=1.0, - help="Set dBFS=0dB input value, default=[%default]") - parser.add_option("--fft-size", type="int", default=1024, - help="Set number of FFT bins [default=%default]") - parser.add_option("--samples-per-pkt", type="int", default=0, - help="Set number of SAMPLES-PER-PKT [default=%default]") - parser.add_option("", "--ip-addr", type="string", default="192.168.10.2", - help="IP address 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.u = vrt.quadradio_source_32fc(options.ip_addr, - int(62.5e6), options.samples_per_pkt) - #self.u.set_decim(options.decim) - - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = int(120e6/4) - - if options.waterfall: - self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) - elif options.oscilloscope: - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) - else: - self.scope = fftsink2.fft_sink_c (panel, - fft_size=options.fft_size, - sample_rate=input_rate, - ref_scale=options.ref_scale, - ref_level=20.0, - y_divs = 12, - avg_alpha=options.avg_alpha) - - self.connect(self.u, self.scope) - - self._build_gui(vbox) - self._setup_events() - - # set initial values - - #if options.gain is None: - # # if no gain was specified, use the mid-point in dB - # g = self.u.gain_range() - # options.gain = float(g[0]+g[1])/2 - - #if options.freq is None: - # # if no freq was specified, use the mid-point - # r = self.u.freq_range() - # options.freq = float(r[0]+r[1])/2 - - #self.set_gain(options.gain) - - #if options.antenna is not None: - # print "Selecting antenna %s" % (options.antenna,) - # self.subdev.select_rx_antenna(options.antenna) - - if self.show_debug_info: - # self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - # self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - - #if not(self.set_freq(options.freq)): - # self._set_status_msg("Failed to set initial frequency") - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,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((5,0), 0, 0) - #g = self.u.gain_range() - - # some configurations don't have gain control - if 0 and g[1] > g[0]: - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,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_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@gbe'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@GbE") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - ##### db control stuff ##### - self.subscribe('cal_div_lo_freq', lambda x: self.u.set_lo_freq(x) and time.sleep(0.01)) - self.subscribe('cal_div_lo_freq', self.u.set_center_freq) #TODO should be combined with set lo freq - self.subscribe('cal_div_cal_freq', lambda x: self.u.set_cal_freq(x) and time.sleep(0.01)) - self.subscribe('db_ctrl_atten0', self.u.set_attenuation0) - self.subscribe('db_ctrl_atten1', self.u.set_attenuation1) - self.subscribe('sys_beaming', self.u.set_beamforming) - #self.subscribe('db_ctrl_10db', self.u.set_10dB_atten) - self.subscribe('db_ctrl_adcgain', self.u.set_adc_gain) - self.subscribe('db_ctrl_diggain', self.u.set_digital_gain) - self.subscribe('db_ctrl_dcoffset', self.u.set_dc_offset_comp) - self.subscribe('db_ctrl_bandsel', self.u.set_band_select) - self.subscribe('db_ctrl_type', self.u.select_rx_antenna) - self.subscribe('db_test_signal', self.u.set_test_signal) - self['db_ctrl_bandsel'] = 'A' - self['cal_div_lo_freq'] = 2.1e9 - self['cal_div_cal_freq'] = 2.102e9 - self['db_ctrl_atten0'] = 0 - self['db_ctrl_atten1'] = 0 - #self['db_ctrl_10db'] = False - self['db_ctrl_adcgain'] = False - self['db_ctrl_dcoffset'] = False - self['db_ctrl_diggain'] = 0.0 - self['db_ctrl_type'] = 'rf' - self['db_test_signal'] = vrt.VRT_TEST_SIG_NORMAL - self['sys_beaming'] = [16.7e6, 0, 0, 0] - #slider and box for freqs - for key, name in (('cal_div_lo_freq', 'LO Freq'), ('cal_div_cal_freq', 'Cal Freq')): - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - forms.text_box( - label=name, - ps=self, - key=key, - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key=key, - minimum=0, #TODO get bounds from cal_div, from vrt... - maximum=int(3.5e9), - step_size=int(5e6), - cast=float, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - ############################################ - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create slider for atten - atten0_txt_box = forms.static_text( - label='Attenuation (0)', - ps=self, - key='db_ctrl_atten0', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - atten0_slider = forms.slider( - ps=self, - key='db_ctrl_atten0', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - #create slider for atten - forms.static_text( - label='Attenuation (1)', - ps=self, - key='db_ctrl_atten1', - sizer=hbox, - parent=panel, - proportion=0, - converter=forms.int_converter() - ) - hbox.AddSpacer(20) - forms.slider( - ps=self, - key='db_ctrl_atten1', - minimum=0, - maximum=31, - step_size=1, - cast=int, - sizer=hbox, - parent=panel, - proportion=2, - ) - hbox.AddSpacer(10) - def update_atten0(*args): - for form_obj in (atten0_txt_box, atten0_slider): form_obj.Enable(self['db_ctrl_bandsel'] > 'B') - update_atten0() - self.subscribe('db_ctrl_bandsel', update_atten0) - #create checkbox for 10dB att - #forms.check_box( - # label='10dB Attenuation', - # ps=self, - # key='db_ctrl_10db', - # sizer=hbox, - # parent=panel, - # proportion=1, - #) - #hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - hbox2 = wx.BoxSizer(wx.HORIZONTAL) - hbox2.AddSpacer(10) - forms.static_text( - label='ADC Controls', - ps=self, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=0, - converter=forms.float_converter() - ) - hbox2.AddSpacer(20) - #create checkbox for ADC digital gain - forms.slider( - #label='ADC Digital Gain', - ps=self, - minimum=0, - maximum=6, - step_size=0.5, - key='db_ctrl_diggain', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - #create checkbox for 3.5dB ADC gain - forms.check_box( - label='3.5dB ADC Gain', - ps=self, - key='db_ctrl_adcgain', - sizer=hbox2, - parent=panel, - proportion=1, - ) - hbox2.AddSpacer(10) - #create checkbox for DC Offset Correction in ADC - forms.check_box( - label='DC Offset Correction', - ps=self, - key='db_ctrl_dcoffset', - sizer=hbox2, - parent=panel, - proportion=2, - ) - hbox2.AddSpacer(10) - vbox.Add(hbox2, 0, wx.EXPAND) - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.AddSpacer(10) - #create radio buttons for band sel - forms.radio_buttons( - label='Band Select', - ps=self, - key='db_ctrl_bandsel', - choices=['A', 'B', 'C', 'D'], - labels=['A', 'B', 'C', 'D'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - forms.radio_buttons( - label='RF Input', - ps=self, - key='db_ctrl_type', - choices=['rf', 'cal'], - labels=['Main RF', 'Calibrator'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for band sel - types = sorted( - filter(lambda x: x.startswith('VRT_TEST_SIG_'), dir(vrt)), - lambda x, y: cmp(getattr(vrt, x), getattr(vrt, y)), - ) - forms.drop_down( - label='Test Signal', - ps=self, - key='db_test_signal', - choices=map(lambda a: getattr(vrt, a), types), - labels=types, - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - #create radio buttons for type - forms.drop_down( - label='Beamformer', - ps=self, - key='sys_beaming', - choices=[[16.7e6, 0, 0, 0], [0, 16.7e6, 0, 0], [0, 0, 16.7e6, 0], [0, 0, 0, 16.7e6], [4.19e6]*4], - labels=['Ant0', 'Ant1', 'Ant2', 'Ant3', 'Equal Gain'], - sizer=hbox, - parent=panel, - proportion=0, - ) - hbox.AddSpacer(10) - vbox.Add(hbox, 0, wx.EXPAND) - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - return True - - r = self.u.set_center_freq(target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.oscilloscope: - self.scope.win.set_baseband_freq(target_freq) - return True - - return False - - def set_gain(self, gain): - return True - - if self.myform.has_key('gain'): - self.myform['gain'].set_value(gain) # update displayed value - self.u.set_gain(gain) - - def set_decim(self, decim): - return True - - ok = self.u.set_decim(decim) - if not ok: - print "set_decim failed" - #input_rate = self.u.adc_rate() / self.u.decim() - input_rate = 120e6/4 - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - return ok - - def _setup_events(self): - if not self.options.waterfall and not self.options.oscilloscope: - self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) - - def evt_left_dclick(self, event): - (ux, uy) = self.scope.win.GetXY(event) - if event.CmdDown(): - # Re-center on maximum power - points = self.scope.win._points - if self.scope.win.peak_hold: - if self.scope.win.peak_vals is not None: - ind = numpy.argmax(self.scope.win.peak_vals) - else: - ind = int(points.shape()[0]/2) - else: - ind = numpy.argmax(points[:,1]) - (freq, pwr) = points[ind] - target_freq = freq/self.scope.win._scale_factor - print ind, freq, pwr - self.set_freq(target_freq) - else: - # Re-center on clicked frequency - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) - - -def main (): - app = stdgui2.stdapp(app_top_block, "QuadRadio FFT", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () -- cgit From f0bf96fad3e02e494fa8ae3edde548844342569b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 9 Sep 2009 12:33:10 -0700 Subject: copied usrp_siggen stuff from experimental gui into gnuradio tree --- gr-utils/src/python/Makefile.am | 5 +- gr-utils/src/python/usrp2_siggen.py | 389 -------------------------- gr-utils/src/python/usrp2_siggen_gui.py | 275 ------------------- gr-utils/src/python/usrp_siggen.py | 471 ++++++++++++++++++++------------ gr-utils/src/python/usrp_siggen_gui.py | 310 +++++++++++++++++++++ 5 files changed, 601 insertions(+), 849 deletions(-) delete mode 100755 gr-utils/src/python/usrp2_siggen.py delete mode 100755 gr-utils/src/python/usrp2_siggen_gui.py create mode 100755 gr-utils/src/python/usrp_siggen_gui.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 0c8240fe4..fb21e4f44 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -56,10 +56,9 @@ bin_SCRIPTS = \ usrp_rx_cfile.py \ usrp_rx_nogui.py \ usrp_siggen.py \ + usrp_siggen_gui.py \ usrp_test_counting.py \ usrp_test_loopback.py \ usrp2_fft.py \ - usrp2_rx_cfile.py \ - usrp2_siggen.py \ - usrp2_siggen_gui.py + usrp2_rx_cfile.py diff --git a/gr-utils/src/python/usrp2_siggen.py b/gr-utils/src/python/usrp2_siggen.py deleted file mode 100755 index 9ade933c7..000000000 --- a/gr-utils/src/python/usrp2_siggen.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio import gr, eng_notation, usrp2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys -import math - -n2s = eng_notation.num_to_str - -waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", - gr.GR_CONST_WAVE : "Constant", - gr.GR_GAUSSIAN : "Gaussian Noise", - gr.GR_UNIFORM : "Uniform Noise", - "2tone" : "Two Tone", - "sweep" : "Sweep" } - -# -# GUI-unaware GNU Radio flowgraph. This may be used either with command -# line applications or GUI applications. -# -class top_block(gr.top_block): - def __init__(self, options, args): - gr.top_block.__init__(self) - self._verbose = options.verbose - - self._interp = 0 - self._gain = 0 - self._freq = None # Indicates frequency hasn't been successfully set yet - self._bb_freq = 0 - self._ddc_freq = 0 - self._amplitude = 0 - self._type = None # Indicates waveform flowgraph not created yet - self._offset = options.offset - - self.set_usrp2(options.interface, options.mac_addr) - self.set_interp(options.interp) - self.set_gain(options.gain) - self.set_freq(options.tx_freq, options.lo_offset) - self.set_amplitude(options.amplitude) - - self.set_waveform_freq(options.waveform_freq) - self.set_waveform2_freq(options.waveform2_freq) - self.set_waveform(options.type) - - def set_usrp2(self, interface, mac_addr): - self._u = usrp2.sink_32fc(interface, mac_addr) - self._dac_rate = self._u.dac_rate() - if self._verbose: - print "Network interface:", interface - print "Network address:", self._u.mac_addr() - print "Daughterboard ID:", hex(self._u.daughterboard_id()) - - def set_interp(self, interp): - if interp < 4 or interp > 512: # FIXME get from flowgraph - if self._verbose: print "Interpolation rate out of range:", interp - return False - - if not self._u.set_interp(interp): - raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - - self._interp = interp - self._eth_rate = self._dac_rate/self._interp - if self._verbose: - print "USRP2 interpolation rate:", self._interp - print "USRP2 IF bandwidth: %sHz" % (n2s(self._eth_rate),) - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE): - self._src.set_sampling_freq(self._eth_rate) - elif self._type == "2tone": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._eth_rate) - elif self._type == "sweep": - self._src1.set_sampling_freq(self._eth_rate) - self._src1.set_sampling_freq(self._waveform_freq*2*math.pi/self._eth_rate) - else: - return True # Waveform not yet set - - if self._verbose: print "Set interpolation rate to:", interp - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - def set_gain(self, gain): - if gain is None: - g = self._u.gain_range() - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self._u.set_gain(gain) - self._gain = gain - if self._verbose: - print "Set TX gain to:", self._gain - - def set_freq(self, target_freq, lo_offset=None): - if lo_offset is not None: - self._lo_offset = lo_offset - self._u.set_lo_offset(self._lo_offset) - if self._verbose: - print "Set LO offset frequency to: %sHz" % (n2s(lo_offset),) - - if target_freq is None: - f = self._u.freq_range() - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - self._ddc_freq = tr.dxc_freq - self._bb_freq = tr.baseband_freq - if self._verbose: - print "Set center frequency to", fs - print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) - print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) - print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) - - return tr - - def set_waveform_freq(self, freq): - self._waveform_freq = freq - if self._type == gr.GR_SIN_WAVE: - self._src.set_frequency(freq) - elif self._type == "2tone" or self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform2_freq(self, freq): - self._waveform2_freq = freq - if self._type == "2tone": - self._src2.set_frequency(freq) - elif self._type == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform(self, type): - self.lock() - self.disconnect_all() - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(self._eth_rate, # Sample rate - type, # Waveform type - self._waveform_freq, # Waveform frequency - self._amplitude, # Waveform amplitude - self._offset) # Waveform offset - elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(type, self._amplitude) - elif type == "2tone": - self._src1 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform_freq, - self._amplitude/2.0, - 0) - if(self._waveform2_freq is None): - self._waveform2_freq = -self._waveform_freq - - self._src2 = gr.sig_source_c(self._eth_rate, - gr.GR_SIN_WAVE, - self._waveform2_freq, - self._amplitude/2.0, - 0) - self._src = gr.add_cc() - self.connect(self._src1,(self._src,0)) - self.connect(self._src2,(self._src,1)) - elif type == "sweep": - # rf freq is center frequency - # waveform_freq is total swept width - # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - if self._waveform2_freq is None: - self._waveform2_freq = 0.1 - - self._src1 = gr.sig_source_f(self._eth_rate, - gr.GR_TRI_WAVE, - self._waveform2_freq, - 1.0, - -0.5) - self._src2 = gr.frequency_modulator_fc(self._waveform_freq*2*math.pi/self._eth_rate) - self._src = gr.multiply_const_cc(self._amplitude) - self.connect(self._src1,self._src2,self._src) - else: - raise RuntimeError("Unknown waveform type") - - self.connect(self._src, self._u) - self._type = type - self.unlock() - - if self._verbose: - print "Set baseband modulation to:", waveforms[self._type] - if type == gr.GR_SIN_WAVE: - print "Modulation frequency: %sHz" % (n2s(self._waveform_freq),) - print "Initial phase:", self._offset - elif type == "2tone": - print "Tone 1: %sHz" % (n2s(self._waveform_freq),) - print "Tone 2: %sHz" % (n2s(self._waveform2_freq),) - elif type == "sweep": - print "Sweeping across %sHz to %sHz" % (n2s(-self._waveform_freq/2.0),n2s(self._waveform_freq/2.0)) - print "Sweep rate: %sHz" % (n2s(self._waveform2_freq),) - print "TX amplitude:", self._amplitude - - - def set_amplitude(self, amplitude): - if amplitude < 0.0 or amplitude > 1.0: - if self._verbose: print "Amplitude out of range:", amplitude - return False - - self._amplitude = amplitude - - if (self._type == gr.GR_SIN_WAVE or - self._type == gr.GR_CONST_WAVE or - self._type == gr.GR_GAUSSIAN or - self._type == gr.GR_UNIFORM): - self._src.set_amplitude(amplitude) - elif self._type == "2tone": - self._src1.set_amplitude(amplitude/2.0) - self._src2.set_amplitude(amplitude/2.0) - elif self._type == "sweep": - self._src.set_k(amplitude) - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - - - # Property getters - - def mac_addr(self): - return self._u.mac_addr() - - def interface_name(self): - return self._u.interface_name() - - def daughterboard_id(self): - return self._u.daughterboard_id() - - def interp_rate(self): - return self._interp - - def eth_rate(self): - return self._eth_rate - - def freq(self): - return self._freq - - def freq_range(self): - return self._u.freq_range() - - def ddc_freq(self): - return self._ddc_freq - - def baseband_freq(self): - return self._bb_freq - - def amplitude(self): - return self._amplitude - - def waveform_type(self): - return self._type - - def waveform_freq(self): - return self._waveform_freq - - def waveform2_freq(self): - if self._waveform2_freq is None: - return -self._waveform_freq - else: - return self._waveform2_freq - -def get_options(): - usage="%prog: [options]" - - parser = OptionParser(option_class=eng_option, usage=usage) - - parser.add_option("-e", "--interface", type="string", default="eth0", - help="Use specified Ethernet interface [default=%default]") - parser.add_option("-m", "--mac-addr", type="string", default="", - help="Use USRP2 at specified MAC address [default=None]") - parser.add_option("-i", "--interp", type="int", default=16, metavar="INTERP", - help="Set FPGA interpolation rate of INTERP [default=%default]") - parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") - parser.add_option("--lo-offset", type="eng_float", default=None, - help="set daughterboard LO offset to OFFSET [default=hw default]") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="Set TX gain to GAIN [default=mid-point]") - parser.add_option("-w", "--waveform-freq", type="eng_float", default=0, - help="Set baseband waveform frequency to FREQ [default=%default]") - parser.add_option("-x", "--waveform2-freq", type="eng_float", default=None, - help="Set 2nd waveform frequency to FREQ [default=%default]") - parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) - parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="Generate a constant carrier") - parser.add_option("--offset", type="eng_float", default=0, - help="Set waveform phase offset to OFFSET [default=%default]") - parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="Generate Gaussian random output") - parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="Generate Uniform random output") - parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - help="Generate Two Tone signal for IMD testing") - parser.add_option("--sweep", dest="type", action="store_const", const="sweep", - help="Generate a swept sine wave") - parser.add_option("-a", "--amplitude", type="eng_float", default=0.1, - help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="Use verbose console output [default=%default]") - - (options, args) = parser.parse_args() - - return (options, args) - -# If this script is executed, the following runs. If it is imported, the below does not run. -if __name__ == "__main__": - if gr.enable_realtime_scheduling() != gr.RT_OK: - print "Note: failed to enable realtime scheduling, continuing" - - # Grab command line options and create top block - try: - (options, args) = get_options() - tb = top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - - # Run it - try: - tb.run() - - except KeyboardInterrupt: - pass diff --git a/gr-utils/src/python/usrp2_siggen_gui.py b/gr-utils/src/python/usrp2_siggen_gui.py deleted file mode 100755 index 89bc6e589..000000000 --- a/gr-utils/src/python/usrp2_siggen_gui.py +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import wx -from gnuradio.wxgui import form, slider, gui -import usrp2_siggen -import sys, math - -class app_gui(object): - def __init__(self, frame, panel, vbox, top_block, options, args): - self.frame = frame # Use for top-level application window frame - self.panel = panel # Use as parent class for created windows - self.vbox = vbox # Use as sizer for created windows - self.tb = top_block # GUI-unaware flowgraph class - self.options = options # Supplied command-line options - self.args = args # Supplied command-line arguments - - freq_range = self.tb.freq_range() - self.min_freq = freq_range[0] - self.max_freq = freq_range[1] - self.freq_step = (self.max_freq-self.min_freq)/100.0 - self._types = dict([v, k] for k, v in usrp2_siggen.waveforms.items()) - - self.build_gui() - - # TODO: turn these into listeners - self.myform['ifc'].set_value(self.tb.interface_name()) - self.myform['mac'].set_value(self.tb.mac_addr()) - dbid = self.tb.daughterboard_id() - self.myform['dbid'].set_value("%04x" % (dbid,)) - - w = usrp2_siggen.waveforms[self.tb.waveform_type()] - self.myform['type'].set_value(w) - self.myform['w1freq'].set_value(self.tb.waveform_freq()) - self.myform['w2freq'].set_value(self.tb.waveform2_freq()) - - freq = self.tb.freq() - if freq is None: - self.evt_set_status_msg("Failed to set initial frequency") - else: - self.myform['freq'].set_value(freq) - self.myform['freq_slider'].set_value(self.tb.freq()) - - amp = self.tb.amplitude() - if (amp > 0.0): - db = 20*math.log10(amp) - else: - db = -100.0 - self.myform['amp'].set_value(amp) - self.myform['amp_slider'].set_value(db) - self.myform['eth'].set_value(self.tb.eth_rate()) - self.myform['gbe'].set_value(self.tb.eth_rate()*32) - self.myform['interp'].set_value(self.tb.interp_rate()) - self.myform['DDC'].set_value(self.tb.ddc_freq()) - self.myform['analog'].set_value(self.tb.baseband_freq()) - - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) - - def evt_set_freq1(self, kv): - return self.tb.set_waveform_freq(kv['w1freq']) - - def evt_set_freq2(self, kv): - return self.tb.set_waveform2_freq(kv['w2freq']) - - def evt_set_freq(self, kv): - if type(kv) == type(0.0): # Set from slider - tr = self.tb.set_freq(kv) - if tr is not None: - self.myform['freq'].set_value(kv) - else: # Set from edit box - f = kv['freq'] - tr = self.tb.set_freq(f) - if tr is not None: - self.myform['freq_slider'].set_value(f) - - if tr is not None: - self.myform['DDC'].set_value(tr.dxc_freq) - self.myform['analog'].set_value(tr.baseband_freq) - - return (tr is not None) - - def evt_set_amplitude(self, kv): - if type(kv) == type(0.0): # Set from slider - amp = math.pow(10, kv/20.0) - self.myform['amp'].set_value(amp) - return self.tb.set_amplitude(amp) - else: # Set from edit box - amp = kv['amp'] - if amp < 0.0 or amp > 1.0: - return False - if amp == 0.0: - db = -100.0 - else: - db = 20*math.log10(amp) - self.myform['amp_slider'].set_value(db) - return self.tb.set_amplitude(amp) - - def evt_set_interp(self): - interp = self.myform['interp'].get_value() - if self.tb.set_interp(interp): - eth_rate = self.tb.eth_rate() - self.myform['eth'].set_value(eth_rate) - self.myform['gbe'].set_value(eth_rate*32) - return True - return False - - def evt_set_waveform_type(self, type): - # TODO: update frequency labels - return self.tb.set_waveform(self._types[type]) - - # GUI construction - def build_gui(self): - self.myform = myform = form.form() - - # Baseband controls - bb_sbox = wx.StaticBox(parent=self.panel, label="Baseband Modulation") - bb_vbox = wx.StaticBoxSizer(bb_sbox, wx.VERTICAL) # Holds all baseband controls as unit - - # First row of baseband controls (modulation type) - mod_hbox = wx.BoxSizer(wx.HORIZONTAL) - mod_hbox.Add((10,0), 0, 0) - myform['type'] = form.radiobox_field( - parent=self.panel, label="Type", sizer=mod_hbox, value=None, - callback=self.evt_set_waveform_type, weight=1, major_dimension=0, - choices=usrp2_siggen.waveforms.values() ) - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(mod_hbox, 0, wx.EXPAND) - - # Second row of baseband controls (frequencies) - bbf_hbox = wx.BoxSizer(wx.HORIZONTAL) - bbf_hbox.Add((10,0), 0, 0) - myform['w1freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 1 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq1, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - myform['w2freq'] = form.float_field( - parent=self.panel, sizer=bbf_hbox, label="Frequency 2 (Hz)", weight=1, - callback=myform.check_input_and_call(self.evt_set_freq2, self.evt_set_status_msg) ) - bbf_hbox.Add((10,0), 0, 0) - - bb_vbox.Add((0,10), 0, 0) - bb_vbox.Add(bbf_hbox, 0, wx.EXPAND) - - # Add baseband controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - - # Frequency controls - fc_sbox = wx.StaticBox(parent=self.panel, label="Center Frequency") - fc_vbox = wx.StaticBoxSizer(fc_sbox, wx.VERTICAL) # Holds all frequency controls as unit - - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - freq_hbox.Add((10,0), 0, 0) - myform['freq'] = form.float_field( - parent=self.panel, sizer=freq_hbox, label=None, weight=1, - callback=myform.check_input_and_call(self.evt_set_freq, self.evt_set_status_msg) ) - freq_hbox.Add((10,0), 0, 0) - myform['freq_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=freq_hbox, label="Min-Max", weight=4, - range = (self.min_freq, self.max_freq, self.freq_step), - callback=self.evt_set_freq) - freq_hbox.Add((10,0), 0, 0) - - fc_vbox.Add((10,0), 0, 0) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - tr_hbox.Add((10,0), 0, 0) - myform['analog'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="Daughterboard: (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - myform['DDC'] = form.static_float_field( - parent=self.panel, sizer=tr_hbox, label="USRP2 DDC (Hz)", weight=1) - tr_hbox.Add((10,0), 0, 0) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - - # Add frequency controls to top window sizer - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - - # Amplitude row - amp_sbox = wx.StaticBox(parent=self.panel, label="Amplitude") - amp_hbox = wx.StaticBoxSizer(amp_sbox, wx.HORIZONTAL) - amp_hbox.Add((10,0), 0, 0) - myform['amp'] = form.float_field( - parent=self.panel, sizer=amp_hbox, label="Linear\n(0.0-1.0)", weight=1, - callback=myform.check_input_and_call(self.evt_set_amplitude, self.evt_set_status_msg) ) - amp_hbox.Add((10,0), 0, 0) - myform['amp_slider'] = form.quantized_slider_field( - parent=self.panel, sizer=amp_hbox, label="dB Full Scale\n(-100-0)", weight=4, - range=(-100.0, 0.0, 1), callback=self.evt_set_amplitude) - amp_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - - # Sample rate row - sam_sbox = wx.StaticBox(parent=self.panel, label="Sample Rate") - sam_hbox = wx.StaticBoxSizer(sam_sbox, wx.HORIZONTAL) - sam_hbox.Add((10,0), 0, 0) - myform['interp'] = form.int_field( - parent=self.panel, sizer=sam_hbox, label="Interpolation", weight=1, - callback=self.evt_set_interp) - sam_hbox.Add((10,0), 0, 0) - myform['eth'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="Sample Rate (sps)", weight=1) - sam_hbox.Add((10,0), 0, 0) - myform['gbe'] = form.static_float_field( - parent=self.panel, sizer=sam_hbox, label="GbE Rate (bits/sec)", weight=1) - sam_hbox.Add((10,0), 0, 0) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - - # USRP2 row - u2_sbox = wx.StaticBox(parent=self.panel, label="USRP2 Hardware") - u2_hbox = wx.StaticBoxSizer(u2_sbox, wx.HORIZONTAL) - u2_hbox.Add((10,0), 0, 0) - myform['ifc'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Interface", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['mac'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="MAC Address", weight=2) - u2_hbox.Add((10,0), 0, 0) - myform['dbid'] = form.static_text_field(parent=self.panel, sizer=u2_hbox, - label="Daughterboard ID", weight=1) - self.vbox.Add((0,10), 0, 0) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.Add((0,20), 0, 0) - -if __name__ == "__main__": - try: - # Get command line parameters - (options, args) = usrp2_siggen.get_options() - - # Create the top block using these - tb = usrp2_siggen.top_block(options, args) - - # Create the GUI application - app = gui.app(top_block=tb, # Constructed top block - gui=app_gui, # User interface class - options=options, # Command line options - args=args, # Command line args - title="USRP2 Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 8ae2fbfbf..8ee8cfd2a 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2008,2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,200 +20,307 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru -from gnuradio import usrp +DESC_KEY = 'desc' +SAMP_RATE_KEY = 'samp_rate' +LINK_RATE_KEY = 'link_rate' +DAC_RATE_KEY = 'dac_rate' +INTERP_KEY = 'interp' +GAIN_KEY = 'gain' +TX_FREQ_KEY = 'tx_freq' +DDC_FREQ_KEY = 'ddc_freq' +BB_FREQ_KEY = 'bb_freq' +AMPLITUDE_KEY = 'amplitude' +AMPL_RANGE_KEY = 'ampl_range' +WAVEFORM_FREQ_KEY = 'waveform_freq' +WAVEFORM_OFFSET_KEY = 'waveform_offset' +WAVEFORM2_FREQ_KEY = 'waveform2_freq' +FREQ_RANGE_KEY = 'freq_range' +GAIN_RANGE_KEY = 'gain_range' +TYPE_KEY = 'type' + +def setter(ps, key, val): ps[key] = val + +from gnuradio import gr, eng_notation +from gnuradio.gr.pubsub import pubsub from gnuradio.eng_option import eng_option -from gnuradio import eng_notation +from gnuradio import usrp_options from optparse import OptionParser import sys +import math +n2s = eng_notation.num_to_str -class my_top_block(gr.top_block): - def __init__ (self, nsamples): +waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", + gr.GR_CONST_WAVE : "Constant", + gr.GR_GAUSSIAN : "Gaussian Noise", + gr.GR_UNIFORM : "Uniform Noise", + "2tone" : "Two Tone", + "sweep" : "Sweep" } + +# +# GUI-unaware GNU Radio flowgraph. This may be used either with command +# line applications or GUI applications. +# +class top_block(gr.top_block, pubsub): + def __init__(self, options, args): gr.top_block.__init__(self) + pubsub.__init__(self) + self._verbose = options.verbose + #initialize values from options + self._setup_usrpx(options) + self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i)) + self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32)) + self[INTERP_KEY] = options.interp or 16 + self[TX_FREQ_KEY] = options.tx_freq + self[AMPLITUDE_KEY] = options.amplitude + self[WAVEFORM_FREQ_KEY] = options.waveform_freq + self[WAVEFORM_OFFSET_KEY] = options.offset + self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq + self[BB_FREQ_KEY] = 0 + self[DDC_FREQ_KEY] = 0 + #subscribe set methods + self.subscribe(INTERP_KEY, self.set_interp) + self.subscribe(GAIN_KEY, self.set_gain) + self.subscribe(TX_FREQ_KEY, self.set_freq) + self.subscribe(AMPLITUDE_KEY, self.set_amplitude) + self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) + self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) + self.subscribe(TYPE_KEY, self.set_waveform) + #force update on pubsub keys + for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY, + AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): + self[key] = self[key] + self[TYPE_KEY] = options.type #set type last + + def _setup_usrpx(self, options): + self._u = usrp_options.create_usrp_sink(options) + self.publish(DESC_KEY, lambda: str(self._u)) + self.publish(DAC_RATE_KEY, self._u.dac_rate) + self.publish(FREQ_RANGE_KEY, self._u.freq_range) + self.publish(GAIN_RANGE_KEY, self._u.gain_range) + self.publish(GAIN_KEY, self._u.gain) + if self._verbose: print str(self._u) + + def _set_tx_amplitude(self, ampl): + """ + Sets the transmit amplitude sent to the USRP + @param ampl the amplitude or None for automatic + """ + ampl_range = self[AMPL_RANGE_KEY] + if ampl is None: ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0] + self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) + + def set_interp(self, interp): + if not self._u.set_interp(interp): + raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) + + if self._verbose: + print "USRP interpolation rate:", interp + print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),) + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): + self._src.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "2tone": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[SAMP_RATE_KEY]) + elif self[TYPE_KEY] == "sweep": + self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) + self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + else: + return True # Waveform not yet set - # controllable values - self.interp = 64 - self.waveform_type = gr.GR_SIN_WAVE - self.waveform_ampl = 16000 - self.waveform_freq = 100.12345e3 - self.waveform_offset = 0 - self.nsamples = nsamples - self._instantiate_blocks () - self.set_waveform_type (self.waveform_type) - - def usb_freq (self): - return self.u.dac_freq() / self.interp - - def usb_throughput (self): - return self.usb_freq () * 4 - - def set_waveform_type (self, type): - ''' - valid waveform types are: gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, - gr.GR_UNIFORM and gr.GR_GAUSSIAN - ''' - self._configure_graph (type) - self.waveform_type = type - - def set_waveform_ampl (self, ampl): - self.waveform_ampl = ampl - self.siggen.set_amplitude (ampl) - self.noisegen.set_amplitude (ampl) - - def set_waveform_freq (self, freq): - self.waveform_freq = freq - self.siggen.set_frequency (freq) - - def set_waveform_offset (self, offset): - self.waveform_offset = offset - self.siggen.set_offset (offset) - - def set_interpolator (self, interp): - self.interp = interp - self.siggen.set_sampling_freq (self.usb_freq ()) - self.u.set_interp_rate (interp) - - def _instantiate_blocks (self): - self.src = None - self.u = usrp.sink_c (0, self.interp) - - self.siggen = gr.sig_source_c (self.usb_freq (), - gr.GR_SIN_WAVE, - self.waveform_freq, - self.waveform_ampl, - self.waveform_offset) - - self.noisegen = gr.noise_source_c (gr.GR_UNIFORM, - self.waveform_ampl) - - self.head = None - if self.nsamples > 0: - self.head = gr.head(gr.sizeof_gr_complex, int(self.nsamples)) - - # self.file_sink = gr.file_sink (gr.sizeof_gr_complex, "siggen.dat") - - def _configure_graph (self, type): - try: - self.lock() - self.disconnect_all () - - if self.head: - self.connect(self.head, self.u) - tail = self.head - else: - tail = self.u - - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self.connect (self.siggen, tail) - # self.connect (self.siggen, self.file_sink) - self.siggen.set_waveform (type) - self.src = self.siggen - elif type == gr.GR_UNIFORM or type == gr.GR_GAUSSIAN: - self.connect (self.noisegen, tail) - self.noisegen.set_type (type) - self.src = self.noisegen - else: - raise ValueError, type - finally: - self.unlock() + if self._verbose: print "Set interpolation rate to:", interp + return True + + def set_gain(self, gain): + if gain is None: + g = self[GAIN_RANGE_KEY] + gain = float(g[0]+g[1])/2 + if self._verbose: + print "Using auto-calculated mid-point TX gain" + self[GAIN_KEY] = gain + return + self._u.set_gain(gain) + if self._verbose: + print "Set TX gain to:", gain def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital up converter. - """ - r = self.u.tune(self.subdev.which(), self.subdev, target_freq) - if r: - #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) - #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) - #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) - #print "r.inverted =", r.inverted - return True - - return False - - - -def main (): - parser = OptionParser (option_class=eng_option) - parser.add_option ("-T", "--tx-subdev-spec", type="subdev", default=(0, 0), - help="select USRP Tx side A or B") - parser.add_option ("-f", "--rf-freq", type="eng_float", default=None, - help="set RF center frequency to FREQ") - parser.add_option ("-i", "--interp", type="int", default=64, - help="set fgpa interpolation rate to INTERP [default=%default]") - - parser.add_option ("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="generate a complex sinusoid [default]", default=gr.GR_SIN_WAVE) - parser.add_option ("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="generate a constant output") - parser.add_option ("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="generate Gaussian random output") - parser.add_option ("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="generate Uniform random output") - - parser.add_option ("-w", "--waveform-freq", type="eng_float", default=0, - help="set waveform frequency to FREQ [default=%default]") - parser.add_option ("-a", "--amplitude", type="eng_float", default=16e3, - help="set waveform amplitude to AMPLITUDE [default=%default]", metavar="AMPL") - parser.add_option ("-g", "--gain", type="eng_float", default=None, - help="set output gain to GAIN [default=%default]") - parser.add_option ("-o", "--offset", type="eng_float", default=0, - help="set waveform offset to OFFSET [default=%default]") - parser.add_option ("-N", "--nsamples", type="eng_float", default=0, - help="set number of samples to transmit [default=+inf]") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - raise SystemExit - - if options.rf_freq is None: - sys.stderr.write("usrp_siggen: must specify RF center frequency with -f RF_FREQ\n") - parser.print_help() - raise SystemExit - - tb = my_top_block(options.nsamples) - tb.set_interpolator (options.interp) - tb.set_waveform_type (options.type) - tb.set_waveform_freq (options.waveform_freq) - tb.set_waveform_ampl (options.amplitude) - tb.set_waveform_offset (options.offset) - - # determine the daughterboard subdevice we're using - if options.tx_subdev_spec is None: - options.tx_subdev_spec = usrp.pick_tx_subdevice(tb.u) - - m = usrp.determine_tx_mux_value(tb.u, options.tx_subdev_spec) - #print "mux = %#04x" % (m,) - tb.u.set_mux(m) - tb.subdev = usrp.selected_subdev(tb.u, options.tx_subdev_spec) - print "Using TX d'board %s" % (tb.subdev.side_and_name(),) - - if options.gain is None: - tb.subdev.set_gain(tb.subdev.gain_range()[1]) # set max Tx gain - else: - tb.subdev.set_gain(options.gain) # set max Tx gain - - if not tb.set_freq(options.rf_freq): - sys.stderr.write('Failed to set RF frequency\n') - raise SystemExit + if target_freq is None: + f = self[FREQ_RANGE_KEY] + target_freq = float(f[0]+f[1])/2.0 + if self._verbose: + print "Using auto-calculated mid-point frequency" + self[TX_FREQ_KEY] = target_freq + return + + tr = self._u.set_center_freq(target_freq) + fs = "%sHz" % (n2s(target_freq),) + if tr is not None: + self._freq = target_freq + self[DDC_FREQ_KEY] = tr.dxc_freq + self[BB_FREQ_KEY] = tr.baseband_freq + if self._verbose: + print "Set center frequency to", fs + print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) + print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) + print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) + elif self._verbose: print "Failed to set freq." + return tr + + def set_waveform_freq(self, freq): + if self[TYPE_KEY] == gr.GR_SIN_WAVE: + self._src.set_frequency(freq) + elif self[TYPE_KEY] == "2tone": + self._src1.set_frequency(freq) + elif self[TYPE_KEY] == 'sweep': + #there is no set sensitivity, redo fg + self[TYPE_KEY] = self[TYPE_KEY] + return True + + def set_waveform2_freq(self, freq): + if freq is None: + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + return + if self[TYPE_KEY] == "2tone": + self._src2.set_frequency(freq) + elif self[TYPE_KEY] == "sweep": + self._src1.set_frequency(freq) + return True + + def set_waveform(self, type): + self.lock() + self.disconnect_all() + if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: + self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate + type, # Waveform type + self[WAVEFORM_FREQ_KEY], # Waveform frequency + self[AMPLITUDE_KEY], # Waveform amplitude + self[WAVEFORM_OFFSET_KEY]) # Waveform offset + elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: + self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) + elif type == "2tone": + self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + if(self[WAVEFORM2_FREQ_KEY] is None): + self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] + + self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], + gr.GR_SIN_WAVE, + self[WAVEFORM2_FREQ_KEY], + self[AMPLITUDE_KEY]/2.0, + 0) + self._src = gr.add_cc() + self.connect(self._src1,(self._src,0)) + self.connect(self._src2,(self._src,1)) + elif type == "sweep": + # rf freq is center frequency + # waveform_freq is total swept width + # waveform2_freq is sweep rate + # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) + if self[WAVEFORM2_FREQ_KEY] is None: + self[WAVEFORM2_FREQ_KEY] = 0.1 + + self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], + gr.GR_TRI_WAVE, + self[WAVEFORM2_FREQ_KEY], + 1.0, + -0.5) + self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) + self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) + self.connect(self._src1,self._src2,self._src) + else: + raise RuntimeError("Unknown waveform type") + + self.connect(self._src, self._u) + self.unlock() + + if self._verbose: + print "Set baseband modulation to:", waveforms[type] + if type == gr.GR_SIN_WAVE: + print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Initial phase:", self[WAVEFORM_OFFSET_KEY] + elif type == "2tone": + print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) + print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + elif type == "sweep": + print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) + print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) + print "TX amplitude:", self[AMPLITUDE_KEY] + + + def set_amplitude(self, amplitude): + if amplitude < 0.0 or amplitude > 1.0: + if self._verbose: print "Amplitude out of range:", amplitude + return False + + if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM): + self._src.set_amplitude(amplitude) + elif self[TYPE_KEY] == "2tone": + self._src1.set_amplitude(amplitude/2.0) + self._src2.set_amplitude(amplitude/2.0) + elif self[TYPE_KEY] == "sweep": + self._src.set_k(amplitude) + else: + return True # Waveform not yet set + + if self._verbose: print "Set amplitude to:", amplitude + return True + +def get_options(): + usage="%prog: [options]" + + parser = OptionParser(option_class=eng_option, usage=usage) + usrp_options.add_tx_options(parser) + parser.add_option("-f", "--tx-freq", type="eng_float", default=None, + help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") + parser.add_option("-x", "--waveform-freq", type="eng_float", default=0, + help="Set baseband waveform frequency to FREQ [default=%default]") + parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None, + help="Set 2nd waveform frequency to FREQ [default=%default]") + parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, + help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) + parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, + help="Generate a constant carrier") + parser.add_option("--offset", type="eng_float", default=0, + help="Set waveform phase offset to OFFSET [default=%default]") + parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, + help="Generate Gaussian random output") + parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, + help="Generate Uniform random output") + parser.add_option("--2tone", dest="type", action="store_const", const="2tone", + help="Generate Two Tone signal for IMD testing") + parser.add_option("--sweep", dest="type", action="store_const", const="sweep", + help="Generate a swept sine wave") + parser.add_option("-A", "--amplitude", type="eng_float", default=0.15, + help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Use verbose console output [default=%default]") + + (options, args) = parser.parse_args() + + return (options, args) + +# If this script is executed, the following runs. If it is imported, the below does not run. +if __name__ == "__main__": + if gr.enable_realtime_scheduling() != gr.RT_OK: + print "Note: failed to enable realtime scheduling, continuing" - tb.subdev.set_enable(True) # enable transmitter + # Grab command line options and create top block + try: + (options, args) = get_options() + tb = top_block(options, args) + except RuntimeError, e: + print e + sys.exit(1) + + # Run it try: tb.run() + except KeyboardInterrupt: pass - - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py new file mode 100755 index 000000000..5ac2369fb --- /dev/null +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from gnuradio import gr +from gnuradio.gr.pubsub import pubsub +from gnuradio.wxgui import gui, forms +import usrp_siggen +import sys, math + +class app_gui(pubsub): + def __init__(self, frame, panel, vbox, top_block, options, args): + pubsub.__init__(self) + self.frame = frame # Use for top-level application window frame + self.panel = panel # Use as parent class for created windows + self.vbox = vbox # Use as sizer for created windows + self.tb = top_block # GUI-unaware flowgraph class + self.options = options # Supplied command-line options + self.args = args # Supplied command-line arguments + self.build_gui() + + # Event response handlers + def evt_set_status_msg(self, msg): + self.frame.SetStatusText(msg, 0) + + # GUI construction + def build_gui(self): + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + ################################################## + # Baseband controls + ################################################## + bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True) + self.vbox.Add(bb_vbox, 0, wx.EXPAND) + sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + #callback to show/hide forms + def set_type(type): + sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE) + sweep_bb_hbox.ShowItems(type == 'sweep') + tone_bb_hbox.ShowItems(type == '2tone') + self.vbox.Layout() + self.tb.subscribe(usrp_siggen.TYPE_KEY, set_type) + #create sine forms + sine_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sine_bb_hbox, + label='Frequency (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sine_bb_hbox.AddStretchSpacer() + #create sweep forms + sweep_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Width (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=sweep_bb_hbox, + label='Sweep Rate (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + sweep_bb_hbox.AddStretchSpacer() + #create 2tone forms + tone_bb_hbox.AddSpacer(10) + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 1 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.text_box( + parent=self.panel, sizer=tone_bb_hbox, + label='Tone 2 (Hz)', + ps=self.tb, + key=usrp_siggen.WAVEFORM2_FREQ_KEY, + converter=forms.float_converter(), + ) + tone_bb_hbox.AddStretchSpacer() + forms.radio_buttons( + parent=self.panel, sizer=bb_vbox, + choices=usrp_siggen.waveforms.keys(), + labels=usrp_siggen.waveforms.values(), + ps=self.tb, + key=usrp_siggen.TYPE_KEY, + style=wx.NO_BORDER | wx.RA_HORIZONTAL, + ) + bb_vbox.AddSpacer(10) + bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND) + bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND) + set_type(self.tb[usrp_siggen.TYPE_KEY]) + ################################################## + # Frequency controls + ################################################## + fc_vbox = forms.static_box_sizer(parent=self.panel, label="Center Frequency", orient=wx.VERTICAL, bold=True) + fc_vbox.AddSpacer(5) + # First row of frequency controls (center frequency) + freq_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(freq_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(10) + # Second row of frequency controls (results) + tr_hbox = wx.BoxSizer(wx.HORIZONTAL) + fc_vbox.Add(tr_hbox, 0, wx.EXPAND) + fc_vbox.AddSpacer(5) + # Add frequency controls to top window sizer + self.vbox.Add(fc_vbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + freq_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=freq_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + ) + freq_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=freq_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.TX_FREQ_KEY, + minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1], + num_steps=100, + ) + freq_hbox.AddSpacer(5) + tr_hbox.AddSpacer(5) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='Daughterboard (Hz)', + ps=self.tb, + key=usrp_siggen.BB_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=tr_hbox, + label='USRP DDC (Hz)', + ps=self.tb, + key=usrp_siggen.DDC_FREQ_KEY, + converter=forms.float_converter(), + proportion=1, + ) + tr_hbox.AddSpacer(5) + ################################################## + # Amplitude controls + ################################################## + amp_hbox = forms.static_box_sizer(parent=self.panel, label="Amplitude", orient=wx.VERTICAL, bold=True) + amp_hbox.AddSpacer(5) + # First row of amp controls (ampl) + lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(lvl_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(10) + # Second row of amp controls (tx gain) + gain_hbox = wx.BoxSizer(wx.HORIZONTAL) + amp_hbox.Add(gain_hbox, 0, wx.EXPAND) + amp_hbox.AddSpacer(5) + self.vbox.Add(amp_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + lvl_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=lvl_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + label="Level (0.0-1.0)", + ) + lvl_hbox.AddSpacer(10) + forms.log_slider( + parent=self.panel, sizer=lvl_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.AMPLITUDE_KEY, + min_exp=-5, + max_exp=0, + base=10, + step_size=1, + ) + lvl_hbox.AddSpacer(5) + if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: + gain_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=gain_hbox, + proportion=1, + converter=forms.float_converter(), + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + label="TX Gain (dB)", + ) + gain_hbox.AddSpacer(10) + forms.slider( + parent=self.panel, sizer=gain_hbox, + proportion=2, + ps=self.tb, + key=usrp_siggen.GAIN_KEY, + minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0], + maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1], + step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2], + ) + gain_hbox.AddSpacer(5) + ################################################## + # Sample Rate controls + ################################################## + sam_hbox = forms.static_box_sizer(parent=self.panel, label="Sample Rate", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(sam_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + sam_hbox.AddSpacer(5) + forms.text_box( + parent=self.panel, sizer=sam_hbox, + converter=forms.int_converter(), + ps=self.tb, + key=usrp_siggen.INTERP_KEY, + label="Interpolation", + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Sample Rate (sps)', + ps=self.tb, + key=usrp_siggen.SAMP_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddStretchSpacer(20) + forms.static_text( + parent=self.panel, sizer=sam_hbox, + label='Link Rate (bits/sec)', + ps=self.tb, + key=usrp_siggen.LINK_RATE_KEY, + converter=forms.float_converter(), + ) + sam_hbox.AddSpacer(5) + ################################################## + # USRP status + ################################################## + u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", orient=wx.HORIZONTAL, bold=True) + self.vbox.Add(u2_hbox, 0, wx.EXPAND) + self.vbox.AddSpacer(10) + self.vbox.AddStretchSpacer() + u2_hbox.AddSpacer(10) + forms.static_text( + parent=self.panel, sizer=u2_hbox, + ps=self.tb, + key=usrp_siggen.DESC_KEY, + converter=forms.str_converter(), + ) + self.vbox.AddSpacer(5) + self.vbox.AddStretchSpacer() + +if __name__ == "__main__": + try: + # Get command line parameters + (options, args) = usrp_siggen.get_options() + + # Create the top block using these + tb = usrp_siggen.top_block(options, args) + + # Create the GUI application + app = gui.app(top_block=tb, # Constructed top block + gui=app_gui, # User interface class + options=options, # Command line options + args=args, # Command line args + title="USRP Signal Generator", # Top window title + nstatus=1, # Number of status lines + start=True, # Whether to start flowgraph + realtime=True) # Whether to set realtime priority + + # And run it + app.MainLoop() + + except RuntimeError, e: + print e + sys.exit(1) -- cgit From 5acd0b6b42d2b939daf61ec0e26008a83b883c57 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 9 Sep 2009 14:13:52 -0700 Subject: tweaked ampl slider params --- gr-utils/src/python/usrp_siggen_gui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py index 5ac2369fb..40848fbee 100755 --- a/gr-utils/src/python/usrp_siggen_gui.py +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -208,10 +208,10 @@ class app_gui(pubsub): proportion=2, ps=self.tb, key=usrp_siggen.AMPLITUDE_KEY, - min_exp=-5, + min_exp=-6, max_exp=0, base=10, - step_size=1, + num_steps=100, ) lvl_hbox.AddSpacer(5) if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: -- cgit From 70b35690d96a1af9799ddf43ab9bd69abca448a1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 16 Sep 2009 10:03:29 -0400 Subject: Handling a few exceptions when no file is loaded. --- gr-utils/src/python/gr_plot_qt.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 267737fd0..581dc6d33 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -64,9 +64,12 @@ class SpectrogramData(Qwt.QwtRasterData): return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) def value(self, x, y): - f = int(self.freq.searchsorted(x)) - t = int(self.time.searchsorted(y)) - return self.sp[f][t-1] + try: + f = int(self.freq.searchsorted(x)) + t = int(self.time.searchsorted(y)) + return self.sp[f][t-1] + except AttributeError: # if no file loaded yet + return 0 class gr_plot_qt(QtGui.QMainWindow): @@ -451,7 +454,11 @@ class gr_plot_qt(QtGui.QMainWindow): # If there's a non-digit character, reset box else: - self.set_file_pos_box(self.cur_start, self.cur_stop) + try: + self.set_file_pos_box(self.cur_start, self.cur_stop) + except AttributeError: + pass + def file_time_changed(self): tstart = self.gui.fileTimeStartLineEdit.text().toDouble() -- cgit From af30f69055b08d484123b50bd07649bb34edb4d1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 16 Sep 2009 10:17:31 -0400 Subject: Fixed slider behavior when the end of the file is reached. --- gr-utils/src/python/gr_plot_qt.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index 581dc6d33..f3dc472f5 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -310,7 +310,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.get_psd() self.get_specgram() self.gui.plotHBar.setSliderPosition(0) - self.gui.plotHBar.setMaximum(self.signal_size) + self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) self.update_time_curves() @@ -332,10 +332,8 @@ class gr_plot_qt(QtGui.QMainWindow): count=end-start) if(len(iq) < (end-start)): - end = len(iq) - self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end)) - self.gui.plotHBar.setMaximum(end) - self.gui.plotHBar.setSingleStep(end) + end = start + len(iq) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq))) self.file_length_changed() tstep = 1.0 / self.sample_rate -- cgit From cf015f49e79e9f5add28121516418eb39c46cad4 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 5 Oct 2009 14:55:28 -0400 Subject: Adding ability to easily reload/reset file --- gr-utils/src/python/gr_plot_qt.py | 8 ++ gr-utils/src/python/pyqt_plot.py | 11 +- gr-utils/src/python/pyqt_plot.ui | 262 ++++++++++++++++++++------------------ 3 files changed, 152 insertions(+), 129 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py index a5e3463c8..5e2b3065c 100755 --- a/gr-utils/src/python/gr_plot_qt.py +++ b/gr-utils/src/python/gr_plot_qt.py @@ -154,6 +154,10 @@ class gr_plot_qt(QtGui.QMainWindow): Qt.SIGNAL("activated()"), self.open_file) + self.connect(self.gui.action_reload, + Qt.SIGNAL("activated()"), + self.reload_file) + # Set up file position boxes to update current figure self.connect(self.gui.filePosStartLineEdit, Qt.SIGNAL("editingFinished()"), @@ -225,7 +229,11 @@ class gr_plot_qt(QtGui.QMainWindow): print filename self.initialize(filename) + def reload_file(self): + initialize(self.filename) + def initialize(self, filename): + self.filename = filename self.hfile = open(filename, "r") self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) diff --git a/gr-utils/src/python/pyqt_plot.py b/gr-utils/src/python/pyqt_plot.py index 74c43c3eb..3b8b4c9e8 100644 --- a/gr-utils/src/python/pyqt_plot.py +++ b/gr-utils/src/python/pyqt_plot.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_plot.ui' # -# Created: Tue Aug 25 18:18:14 2009 -# by: PyQt4 UI code generator 4.4.3 +# Created: Mon Aug 31 22:12:05 2009 +# by: PyQt4 UI code generator 4.4.4 # # WARNING! All changes made in this file will be lost! @@ -158,7 +158,7 @@ class Ui_MainWindow(object): self.gridLayout.addWidget(self.filePosBox, 3, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 24)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 927, 25)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -170,7 +170,10 @@ class Ui_MainWindow(object): self.action_open.setObjectName("action_open") self.action_exit = QtGui.QAction(MainWindow) self.action_exit.setObjectName("action_exit") + self.action_reload = QtGui.QAction(MainWindow) + self.action_reload.setObjectName("action_reload") self.menu_File.addAction(self.action_open) + self.menu_File.addAction(self.action_reload) self.menu_File.addAction(self.action_exit) self.menubar.addAction(self.menu_File.menuAction()) @@ -202,5 +205,7 @@ class Ui_MainWindow(object): self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + self.action_reload.setText(QtGui.QApplication.translate("MainWindow", "&Reload", None, QtGui.QApplication.UnicodeUTF8)) + self.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", None, QtGui.QApplication.UnicodeUTF8)) from PyQt4 import Qwt5 diff --git a/gr-utils/src/python/pyqt_plot.ui b/gr-utils/src/python/pyqt_plot.ui index 19a62adf5..55c72fda2 100644 --- a/gr-utils/src/python/pyqt_plot.ui +++ b/gr-utils/src/python/pyqt_plot.ui @@ -1,7 +1,8 @@ - + + MainWindow - - + + 0 0 @@ -9,62 +10,62 @@ 696 - + MainWindow - - - - - + + + + + Qt::Horizontal - - - + + + 0 - - + + Time Domain - + - + - - + + Frequency Domain - + - - + + 160 0 - + FFT Properties - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 96 0 - + 96 16777215 @@ -72,9 +73,9 @@ - - - + + + FFT Size @@ -83,37 +84,37 @@ - + - - + + Spectrogram - + - - + + Spectrogram Properties - - - - + + + + FFT Size - - - + + + 96 0 - + 96 16777215 @@ -125,7 +126,7 @@ - + specPlot @@ -133,19 +134,19 @@ - - - + + + 0 120 - + File Position - - + + 0 20 @@ -153,41 +154,41 @@ 92 - - - - + + + + Start - - + + - - - + + + Stop - - + + - - - + + + Length - - + + - - + + 180 20 @@ -195,41 +196,41 @@ 92 - - - - + + + + time start (sec) - - + + - - - + + + time stop (sec) - - + + - - - + + + time length (sec) - - + + - - + + 530 0 @@ -237,17 +238,17 @@ 120 - + 200 0 - + System Properties - - + + 0 20 @@ -255,17 +256,17 @@ 91 - - - - + + + + Sample Rate - - - + + + 0 0 @@ -276,8 +277,8 @@ - - + + 730 0 @@ -285,17 +286,17 @@ 120 - + 170 0 - + Display Properties - - + + 0 20 @@ -303,16 +304,16 @@ 91 - + - + - - + + Qt::Vertical - + 20 40 @@ -327,38 +328,47 @@ - - + + 0 0 927 - 24 + 25 - - + + &File - - + + + - + - - - + + + &Open - + Ctrl+O - - + + E&xit + + + &Reload + + + Ctrl+R + + @@ -375,11 +385,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From c6fe89eb039b13afb65a09980837063cdd61c810 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 29 Oct 2009 13:00:44 -0700 Subject: modified flowgraph cleanup --- gr-utils/src/python/usrp_siggen.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 8ee8cfd2a..69925fd0e 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -318,9 +318,6 @@ if __name__ == "__main__": print e sys.exit(1) - # Run it - try: - tb.run() - - except KeyboardInterrupt: - pass + tb.start() + raw_input('Press Enter to quit: ') + tb.stop() -- cgit From a0ffbc6d5c39bf605cf6e9f3c09de9f95ee6c6e6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 29 Oct 2009 14:28:56 -0700 Subject: fixed issue where usrp siggen continued to transmit after program exit --- gr-utils/src/python/usrp_siggen.py | 10 +++++++++- gr-utils/src/python/usrp_siggen_gui.py | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py index 69925fd0e..da83da770 100755 --- a/gr-utils/src/python/usrp_siggen.py +++ b/gr-utils/src/python/usrp_siggen.py @@ -305,7 +305,7 @@ def get_options(): return (options, args) # If this script is executed, the following runs. If it is imported, the below does not run. -if __name__ == "__main__": +def main(): if gr.enable_realtime_scheduling() != gr.RT_OK: print "Note: failed to enable realtime scheduling, continuing" @@ -321,3 +321,11 @@ if __name__ == "__main__": 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() diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py index 40848fbee..47d47bdb3 100755 --- a/gr-utils/src/python/usrp_siggen_gui.py +++ b/gr-utils/src/python/usrp_siggen_gui.py @@ -284,7 +284,7 @@ class app_gui(pubsub): self.vbox.AddSpacer(5) self.vbox.AddStretchSpacer() -if __name__ == "__main__": +def main(): try: # Get command line parameters (options, args) = usrp_siggen.get_options() @@ -308,3 +308,10 @@ if __name__ == "__main__": 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 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() -- cgit From a549bd11646f60d425a74d530b8f3ddfc4774202 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 10 Jan 2010 01:03:11 -0800 Subject: fixed issue 387: removed uses of win.set for wx sinks --- gr-utils/src/python/usrp2_fft.py | 4 ++-- gr-utils/src/python/usrp_fft.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py index 1e8cf89ea..4276e389a 100755 --- a/gr-utils/src/python/usrp2_fft.py +++ b/gr-utils/src/python/usrp2_fft.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2004,2005,2007,2008,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -218,7 +218,7 @@ class app_top_block(stdgui2.std_top_block): self.myform['baseband'].set_value(r.baseband_freq) self.myform['ddc'].set_value(r.dxc_freq) if not self.options.oscilloscope: - self.scope.win.set_baseband_freq(target_freq) + self.scope.set_baseband_freq(target_freq) return True return False diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index 4aa70adab..ab7fb4462 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2004,2005,2007,2008 Free Software Foundation, Inc. +# Copyright 2004,2005,2007,2008,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -255,7 +255,7 @@ class app_top_block(stdgui2.std_top_block): self.myform['baseband'].set_value(r.baseband_freq) self.myform['ddc'].set_value(r.dxc_freq) if not self.options.oscilloscope: - self.scope.win.set_baseband_freq(target_freq) + self.scope.set_baseband_freq(target_freq) return True return False -- cgit From 6b1bcb301ff4cb20ac62bf5400fa3001182cb069 Mon Sep 17 00:00:00 2001 From: Eric Blossom Date: Thu, 4 Feb 2010 11:37:00 -0800 Subject: Fix pick_subdevice. Patch from Alexander Chemeris --- gr-utils/src/python/usrp_fft.py | 2 +- gr-utils/src/python/usrp_oscope.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py index ab7fb4462..eda9bd57c 100755 --- a/gr-utils/src/python/usrp_fft.py +++ b/gr-utils/src/python/usrp_fft.py @@ -39,7 +39,7 @@ def pick_subdevice(u): """ if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db(0, 0).dbid() >= 0: + if u.db(1, 0).dbid() >= 0: return (1, 0) return (0, 0) diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py index f4a539dd5..9921e9873 100755 --- a/gr-utils/src/python/usrp_oscope.py +++ b/gr-utils/src/python/usrp_oscope.py @@ -42,7 +42,7 @@ def pick_subdevice(u): """ if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem return (0, 0) - if u.db(0, 0).dbid() >= 0: + if u.db(1, 0).dbid() >= 0: return (1, 0) return (0, 0) -- cgit From 901e0ad28d1f65eb10362fffd00693426db84ed4 Mon Sep 17 00:00:00 2001 From: Eric Blossom Date: Thu, 4 Mar 2010 17:00:20 -0800 Subject: Add command that builds a new 'out-of-tree' project. --- gr-utils/src/python/Makefile.am | 1 + .../src/python/create-gnuradio-out-of-tree-project | 69 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100755 gr-utils/src/python/create-gnuradio-out-of-tree-project (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index fb21e4f44..9c4e222c8 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -35,6 +35,7 @@ ourpython_PYTHON = \ pyqt_filter.py bin_SCRIPTS = \ + create-gnuradio-out-of-tree-project \ gr_plot_char.py \ gr_plot_const.py \ gr_plot_fft.py \ diff --git a/gr-utils/src/python/create-gnuradio-out-of-tree-project b/gr-utils/src/python/create-gnuradio-out-of-tree-project new file mode 100755 index 000000000..1f512b219 --- /dev/null +++ b/gr-utils/src/python/create-gnuradio-out-of-tree-project @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +from optparse import OptionParser +import os +import re +import sys +import subprocess + +tarball_url="http://gnuradio.org/releases/gnuradio/gr-howto-write-a-block-3.3git-651-g642252d8.tar.gz" + +def open_tarball(tarball_name=None): + """Return a readable fileobject that references the tarball. + If tarball_name is None, download from the net + """ + if tarball_name: + return open(tarball_name, 'r') + p = subprocess.Popen(["wget", "-O", "-", tarball_url], + close_fds=True, stdout=subprocess.PIPE) + return p.stdout + +def extract_and_rename_files(tarball, module_name): + # Requires GNU tar. + tar_cmd = 'tar xz --strip-components=1 --transform="s/howto/%s/g"' % (module_name,) + p = subprocess.Popen(tar_cmd, shell=True, stdin=tarball, close_fds=True) + sts = os.waitpid(p.pid, 0) + return sts == 0 + +def main(): + usage = "%prog: [options] new_module_name" + description="Create a prototype 'out of tree' GNU Radio project" + parser = OptionParser(usage=usage, description=description) + parser.add_option("-T", "--tarball", type="string", default=None, + help="path to gr-howto-build-a-block gzipped tarball [default=]") + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + raise SystemExit,2 + module_name = args[0] + if not re.match(r'[_a-z][_a-z0-9]*$', module_name): + sys.stderr.write("module_name '%s' may only contain [a-z0-9_]\n" % (module_name)) + raise SystemExit, 1 + + # Ensure there's no file or directory called + if os.path.exists(module_name): + sys.stderr.write("A file or directory named '%s' already exists\n" % (module_name,)) + raise SystemExit, 1 + + os.mkdir(module_name) + os.chdir(module_name) + + ok = extract_and_rename_files(open_tarball(options.tarball), module_name) + + # rename file contents + upper_module_name = module_name.upper() + sed_cmd = 'sed -i -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, + upper_module_name) + os.system('find . -type f -print0 | xargs -0 ' + sed_cmd) + + sys.stdout.write(""" +Project '%s' is now ready to build. + + $ ./bootstrap + $ ./configure --prefix=/home/[user]/install + $ (make && make check && make install) 2>&1 | tee make.log + +""" % (module_name,)) + +if __name__ == '__main__': + main() -- cgit From 272c44f10ebf9e2d7ac76fe00c87382a1c0f4f29 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Mon, 5 Jul 2010 11:55:56 -0700 Subject: gr-utils: fix out of tree project generator to properly update tarfile name --- gr-utils/src/python/create-gnuradio-out-of-tree-project | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/create-gnuradio-out-of-tree-project b/gr-utils/src/python/create-gnuradio-out-of-tree-project index 1f512b219..d5e32c92b 100755 --- a/gr-utils/src/python/create-gnuradio-out-of-tree-project +++ b/gr-utils/src/python/create-gnuradio-out-of-tree-project @@ -52,8 +52,8 @@ def main(): # rename file contents upper_module_name = module_name.upper() - sed_cmd = 'sed -i -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, - upper_module_name) + sed_cmd = 'sed -i -e "s/howto-write-a-block/%s/g" -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, module_name, \ + upper_module_name) os.system('find . -type f -print0 | xargs -0 ' + sed_cmd) sys.stdout.write(""" -- cgit From 8e39df793623ed62a1d4f23a05548a81914ad959 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 21 Nov 2010 19:41:59 -0500 Subject: Updating PSD function for some newer matplotlib interfacing. --- gr-utils/src/python/gr_plot_psd.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 0e3dbecd9..f3535d321 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -35,6 +35,7 @@ except ImportError: from optparse import OptionParser from scipy import log10 +from gnuradio.eng_option import eng_option class gr_plot_psd: def __init__(self, datatype, filename, options): @@ -100,10 +101,10 @@ class gr_plot_psd: ''' Need to do this here and plot later so we can do the fftshift ''' overlap = self.psdfftsize/4 winfunc = scipy.blackman - psd,freq = self.sp_psd.psd(iq, self.psdfftsize, self.sample_rate, - window = lambda d: d*winfunc(self.psdfftsize), - noverlap = overlap, visible=False) - psd = 10.0*log10(abs(fftpack.fftshift(psd))) + psd,freq = mlab.psd(iq, self.psdfftsize, self.sample_rate, + window = lambda d: d*winfunc(self.psdfftsize), + noverlap = overlap) + psd = 10.0*log10(abs(psd)) return (psd, freq) def make_plots(self): @@ -159,6 +160,7 @@ class gr_plot_psd: def draw_psd(self): self.plot_psd[0].set_data([self.freq, self.iq_psd]) self.sp_psd.set_ylim([min(self.iq_psd)-10, max(self.iq_psd)+10]) + self.sp_psd.set_xlim([min(self.freq), max(self.freq)]) def draw_spec(self): overlap = self.specfftsize/4 @@ -236,14 +238,15 @@ def setup_options(): usage="%prog: [options] input_filename" description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec." - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser = OptionParser(option_class=eng_option, conflict_handler="resolve", + usage=usage, description=description) parser.add_option("-d", "--data-type", type="string", default="complex64", help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") parser.add_option("-B", "--block", type="int", default=8192, help="Specify the block size [default=%default]") parser.add_option("-s", "--start", type="int", default=0, help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, + parser.add_option("-R", "--sample-rate", type="eng_float", default=1.0, help="Set the sampler rate of the data [default=%default]") parser.add_option("", "--psd-size", type="int", default=1024, help="Set the size of the PSD FFT [default=%default]") -- cgit From d692a41f98e7b888c745efbb9fcbbb0400f39025 Mon Sep 17 00:00:00 2001 From: Eric Blossom Date: Wed, 24 Nov 2010 17:29:11 -0800 Subject: Major Makefile.am housecleaning. Passes distcheck. Move all occurrences of swig_built_sources out of Makefile.am's. Move all SWIG related use of BUILT_SOURCES out of Makefile.am's. Clean up 'if PYTHON' conditionalization in gr-* Still left to do: fix Makefile.swig CLEANFILES and no_dist_files such that they remove exactly the generated files. --- gr-utils/src/python/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 9c4e222c8..450032266 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common -EXTRA_DIST = \ +EXTRA_DIST += \ $(bin_SCRIPTS) \ README.plot \ pyqt_plot.ui \ -- cgit From 91ca107edc1e4cad69f102d947471d2c0adfc354 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 30 Dec 2010 17:12:26 -0500 Subject: Fixes to psd plotting tool. Trying to keep up with the changing API; this should be backwards compatible. --- gr-utils/src/python/gr_plot_psd.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index f3535d321..e3ecabd6a 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -87,13 +87,13 @@ class gr_plot_psd: def get_data(self): self.position = self.hfile.tell()/self.sizeof_data self.text_file_pos.set_text("File Position: %d" % self.position) - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.iq) - if(len(self.iq) == 0): + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: tstep = 1.0 / self.sample_rate - self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) self.iq_psd, self.freq = self.dopsd(self.iq) @@ -153,14 +153,14 @@ class gr_plot_psd: imags = self.iq.imag self.plot_iq[0].set_data([self.time, reals]) self.plot_iq[1].set_data([self.time, imags]) - self.sp_iq.set_xlim(min(self.time), max(self.time)) - self.sp_iq.set_ylim([1.5*min([min(reals), min(imags)]), - 1.5*max([max(reals), max(imags)])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), + 1.5*max([reals.max(), imags.max()])]) def draw_psd(self): self.plot_psd[0].set_data([self.freq, self.iq_psd]) - self.sp_psd.set_ylim([min(self.iq_psd)-10, max(self.iq_psd)+10]) - self.sp_psd.set_xlim([min(self.freq), max(self.freq)]) + self.sp_psd.set_ylim([self.iq_psd.min()-10, self.iq_psd.max()+10]) + self.sp_psd.set_xlim([self.freq.min(), self.freq.max()]) def draw_spec(self): overlap = self.specfftsize/4 @@ -168,7 +168,7 @@ class gr_plot_psd: self.sp_spec.clear() self.sp_spec.specgram(self.iq, self.specfftsize, self.sample_rate, window = lambda d: d*winfunc(self.specfftsize), - noverlap = overlap, xextent=[min(self.time), max(self.time)]) + noverlap = overlap, xextent=[self.time.min(), self.time.max()]) def update_plots(self): self.draw_time() @@ -188,14 +188,14 @@ class gr_plot_psd: xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) - iq = self.iq[xmin : xmax] - time = self.time[xmin : xmax] + iq = scipy.array(self.iq[xmin : xmax]) + time = scipy.array(self.time[xmin : xmax]) iq_psd, freq = self.dopsd(iq) self.plot_psd[0].set_data(freq, iq_psd) - self.sp_psd.axis([min(freq), max(freq), - min(iq_psd)-10, max(iq_psd)+10]) + self.sp_psd.axis([freq.min(), freq.max(), + iq_psd.min()-10, iq_psd.max()+10]) draw() -- cgit From 3ad8f8ed993cccae7492bf0fa8519ebe15567101 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 15 Jan 2011 17:15:11 -0500 Subject: Fix how the end of a file is handled. --- gr-utils/src/python/gr_plot_psd.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 0e3dbecd9..b386d35ab 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -60,8 +60,10 @@ class gr_plot_psd: rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.92, "File Position: ", weight="heavy", size=self.text_size) + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), + weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.92, "File Position: ", + weight="heavy", size=self.text_size) self.text_block = figtext(0.35, 0.92, ("Block Size: %d" % self.block_length), weight="heavy", size=self.text_size) self.text_sr = figtext(0.60, 0.915, ("Sample Rate: %.2f" % self.sample_rate), @@ -86,9 +88,9 @@ class gr_plot_psd: def get_data(self): self.position = self.hfile.tell()/self.sizeof_data self.text_file_pos.set_text("File Position: %d" % self.position) - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.iq) - if(len(self.iq) == 0): + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: tstep = 1.0 / self.sample_rate -- cgit From 7b5095514204a524afbf6fd97bb70511519e5b35 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 15 Jan 2011 17:21:14 -0500 Subject: Using .min and .max on scipy arrays instead of min() max(); seems to be more portable. --- gr-utils/src/python/gr_plot_psd.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index b386d35ab..1b653d61a 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -94,7 +94,7 @@ class gr_plot_psd: print "End of File" else: tstep = 1.0 / self.sample_rate - self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) self.iq_psd, self.freq = self.dopsd(self.iq) @@ -154,13 +154,14 @@ class gr_plot_psd: imags = self.iq.imag self.plot_iq[0].set_data([self.time, reals]) self.plot_iq[1].set_data([self.time, imags]) - self.sp_iq.set_xlim(min(self.time), max(self.time)) - self.sp_iq.set_ylim([1.5*min([min(reals), min(imags)]), - 1.5*max([max(reals), max(imags)])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), + 1.5*max([reals.max(), imags.max()])]) def draw_psd(self): self.plot_psd[0].set_data([self.freq, self.iq_psd]) - self.sp_psd.set_ylim([min(self.iq_psd)-10, max(self.iq_psd)+10]) + self.sp_psd.set_ylim([self.iq_psd.min()-10, self.iq_psd.max()+10]) + self.sp_psd.set_xlim([self.freq.min(), self.freq.max()]) def draw_spec(self): overlap = self.specfftsize/4 @@ -168,7 +169,7 @@ class gr_plot_psd: self.sp_spec.clear() self.sp_spec.specgram(self.iq, self.specfftsize, self.sample_rate, window = lambda d: d*winfunc(self.specfftsize), - noverlap = overlap, xextent=[min(self.time), max(self.time)]) + noverlap = overlap, xextent=[self.time.min(), self.time.max()]) def update_plots(self): self.draw_time() @@ -194,8 +195,8 @@ class gr_plot_psd: iq_psd, freq = self.dopsd(iq) self.plot_psd[0].set_data(freq, iq_psd) - self.sp_psd.axis([min(freq), max(freq), - min(iq_psd)-10, max(iq_psd)+10]) + self.sp_psd.axis([freq.min(), freq.max(), + iq_psd.min()-10, iq_psd.max()+10]) draw() -- cgit From 4f4268311488f88c2f20f31ba9d4615b522b946a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 15 Jan 2011 17:48:02 -0500 Subject: Fixing up other plotting tools for data read errors. --- gr-utils/src/python/gr_plot_const.py | 26 +++++++++++++------------- gr-utils/src/python/gr_plot_fft.py | 28 ++++++++++++++-------------- gr-utils/src/python/gr_plot_iq.py | 25 +++++++++++++------------ gr-utils/src/python/gr_plot_psd.py | 2 +- gr-utils/src/python/plot_data.py | 20 ++++++++++---------- 5 files changed, 51 insertions(+), 50 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index ec2272c74..9e4920776 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -80,15 +80,15 @@ class draw_constellation: def get_data(self): self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(iq) - if(len(iq) == 0): + try: + iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: - self.reals = [r.real for r in iq] - self.imags = [i.imag for i in iq] + self.reals = scipy.array([r.real for r in iq]) + self.imags = scipy.array([i.imag for i in iq]) - self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) def make_plots(self): # if specified on the command-line, set file pointer @@ -117,9 +117,9 @@ class draw_constellation: self.plot_const += self.sp_const.plot([self.reals[self.indx],], [self.imags[self.indx],], 'mo', ms=12) # Adjust axis - self.sp_iq.axis([min(self.time), max(self.time), - 1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) + self.sp_iq.axis([self.time.min(), self.time.max(), + 1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) self.sp_const.axis([-2, 2, -2, 2]) draw() @@ -127,9 +127,9 @@ class draw_constellation: def update_plots(self): self.plot_iq[0].set_data([self.time, self.reals]) self.plot_iq[1].set_data([self.time, self.imags]) - self.sp_iq.axis([min(self.time), max(self.time), - 1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) + self.sp_iq.axis([self.time.min(), self.time.max(), + 1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) self.plot_const[0].set_data([self.reals, self.imags]) self.sp_const.axis([-2, 2, -2, 2]) diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py index a9c1417f9..bb21f3dcd 100755 --- a/gr-utils/src/python/gr_plot_fft.py +++ b/gr-utils/src/python/gr_plot_fft.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -81,15 +81,15 @@ class gr_plot_fft: def get_data(self): self.position = self.hfile.tell()/self.sizeof_data self.text_file_pos.set_text("File Position: %d" % (self.position)) - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.iq) - if(len(self.iq) == 0): + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: self.iq_fft = self.dofft(self.iq) tstep = 1.0 / self.sample_rate - self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) self.freq = self.calc_freq(self.time, self.sample_rate) @@ -102,9 +102,9 @@ class gr_plot_fft: def calc_freq(self, time, sample_rate): N = len(time) - Fs = 1.0 / (max(time) - min(time)) + Fs = 1.0 / (time.max() - time.min()) Fn = 0.5 * sample_rate - freq = [-Fn + i*Fs for i in xrange(N)] + freq = scipy.array([-Fn + i*Fs for i in xrange(N)]) return freq def make_plots(self): @@ -139,14 +139,14 @@ class gr_plot_fft: imags = self.iq.imag self.plot_iq[0].set_data([self.time, reals]) self.plot_iq[1].set_data([self.time, imags]) - self.sp_iq.set_xlim(min(self.time), max(self.time)) - self.sp_iq.set_ylim([1.5*min([min(reals), min(imags)]), - 1.5*max([max(reals), max(imags)])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), + 1.5*max([reals.max(), imags.max()])]) def draw_fft(self): self.plot_fft[0].set_data([self.freq, self.iq_fft]) - self.sp_fft.set_xlim(min(self.freq), max(self.freq)) - self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10]) + self.sp_fft.set_xlim(self.freq.min(), self.freq.max()) + self.sp_fft.set_ylim([self.iq_fft.min()-10, self.iq_fft.max()+10]) def update_plots(self): self.draw_time() @@ -170,8 +170,8 @@ class gr_plot_fft: freq = self.calc_freq(time, self.sample_rate) self.plot_fft[0].set_data(freq, iq_fft) - self.sp_fft.axis([min(freq), max(freq), - min(iq_fft)-10, max(iq_fft)+10]) + self.sp_fft.axis([freq.min(), freq.max(), + iq_fft.min()-10, iq_fftmax()+10]) draw() diff --git a/gr-utils/src/python/gr_plot_iq.py b/gr-utils/src/python/gr_plot_iq.py index 371ce3b79..316e60a75 100755 --- a/gr-utils/src/python/gr_plot_iq.py +++ b/gr-utils/src/python/gr_plot_iq.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -78,14 +78,14 @@ class draw_iq: def get_data(self): self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.iq) - if(len(self.iq) == 0): + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: - self.reals = [r.real for r in self.iq] - self.imags = [i.imag for i in self.iq] - self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))] + self.reals = scipy.array([r.real for r in self.iq]) + self.imags = scipy.array([i.imag for i in self.iq]) + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) def make_plots(self): # if specified on the command-line, set file pointer @@ -99,16 +99,17 @@ class draw_iq: self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') - self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) - + self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) draw() def update_plots(self): self.plot_iq[0].set_data([self.time, self.reals]) self.plot_iq[1].set_data([self.time, self.imags]) - self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]), - 1.5*max([max(self.reals), max(self.imags)])]) + self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) draw() def click(self, event): diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 1b653d61a..d5bfca389 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # diff --git a/gr-utils/src/python/plot_data.py b/gr-utils/src/python/plot_data.py index 08cdd6030..15012e589 100644 --- a/gr-utils/src/python/plot_data.py +++ b/gr-utils/src/python/plot_data.py @@ -1,5 +1,5 @@ # -# Copyright 2007,2008 Free Software Foundation, Inc. +# Copyright 2007,2008,2011 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -81,13 +81,13 @@ class plot_data: def get_data(self, hfile): self.text_file_pos.set_text("File Position: %d" % (hfile.tell()//self.sizeof_data)) - f = scipy.fromfile(hfile, dtype=self.datatype, count=self.block_length) - #print "Read in %d items" % len(self.f) - if(len(f) == 0): + try: + f = scipy.fromfile(hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: print "End of File" else: - self.f = f - self.time = [i*(1/self.sample_rate) for i in range(len(self.f))] + self.f = scipy.array(f) + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.f))]) def make_plots(self): self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6]) @@ -107,8 +107,8 @@ class plot_data: # Subplot for real and imaginary parts of signal self.plot_f += plot(self.time, self.f, 'o-') - maxval = max(maxval, max(self.f)) - minval = min(minval, min(self.f)) + maxval = max(maxval, self.f.max()) + minval = min(minval, self.f.min()) self.sp_f.set_ylim([1.5*minval, 1.5*maxval]) @@ -122,8 +122,8 @@ class plot_data: for hf,p in zip(self.hfile,self.plot_f): self.get_data(hf) p.set_data([self.time, self.f]) - maxval = max(maxval, max(self.f)) - minval = min(minval, min(self.f)) + maxval = max(maxval, self.f.max()) + minval = min(minval, self.f.min()) self.sp_f.set_ylim([1.5*minval, 1.5*maxval]) -- cgit From a8e021e949fca067cf2df5a7cbb7c68ac21b8935 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 16 Jan 2011 13:34:42 -0500 Subject: Fixing zooming capabilities. Time axis does not track any longer due to what looks like a matplotlib bug that resets the xlims after the zoom occurs. --- gr-utils/src/python/gr_plot_psd.py | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index d5bfca389..e88995b72 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -78,7 +78,7 @@ class gr_plot_psd: self.button_right = Button(self.button_right_axes, ">") self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - self.xlim = self.sp_iq.get_xlim() + self.xlim = scipy.array(self.sp_iq.get_xlim()) self.manager = get_current_fig_manager() connect('draw_event', self.zoom) @@ -94,10 +94,11 @@ class gr_plot_psd: print "End of File" else: tstep = 1.0 / self.sample_rate - self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) self.iq_psd, self.freq = self.dopsd(self.iq) - + def dopsd(self, iq): ''' Need to do this here and plot later so we can do the fftshift ''' overlap = self.psdfftsize/4 @@ -132,10 +133,10 @@ class gr_plot_psd: self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags - self.draw_time() # draw the plot + self.draw_time(self.time, self.iq) # draw the plot self.plot_psd = self.sp_psd.plot([], 'b') # make plot for PSD - self.draw_psd() # draw the plot + self.draw_psd(self.freq, self.iq_psd) # draw the plot if self.dospec: @@ -145,58 +146,59 @@ class gr_plot_psd: self.sp_spec.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - self.draw_spec() + self.draw_spec(self.time, self.iq) draw() - def draw_time(self): - reals = self.iq.real - imags = self.iq.imag - self.plot_iq[0].set_data([self.time, reals]) - self.plot_iq[1].set_data([self.time, imags]) - self.sp_iq.set_xlim(self.time.min(), self.time.max()) + def draw_time(self, t, iq): + reals = iq.real + imags = iq.imag + self.plot_iq[0].set_data([t, reals]) + self.plot_iq[1].set_data([t, imags]) + self.sp_iq.set_xlim(t.min(), t.max()) self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), 1.5*max([reals.max(), imags.max()])]) - def draw_psd(self): - self.plot_psd[0].set_data([self.freq, self.iq_psd]) - self.sp_psd.set_ylim([self.iq_psd.min()-10, self.iq_psd.max()+10]) - self.sp_psd.set_xlim([self.freq.min(), self.freq.max()]) + def draw_psd(self, f, p): + self.plot_psd[0].set_data([f, p]) + self.sp_psd.set_ylim([p.min()-10, p.max()+10]) + self.sp_psd.set_xlim([f.min(), f.max()]) - def draw_spec(self): + def draw_spec(self, t, s): overlap = self.specfftsize/4 winfunc = scipy.blackman self.sp_spec.clear() - self.sp_spec.specgram(self.iq, self.specfftsize, self.sample_rate, + self.sp_spec.specgram(s, self.specfftsize, self.sample_rate, window = lambda d: d*winfunc(self.specfftsize), - noverlap = overlap, xextent=[self.time.min(), self.time.max()]) + noverlap = overlap, xextent=[t.min(), t.max()]) def update_plots(self): - self.draw_time() - self.draw_psd() + self.draw_time(self.time, self.iq) + self.draw_psd(self.freq, self.iq_psd) if self.dospec: - self.draw_spec() + self.draw_spec(self.time, self.iq) - self.xlim = self.sp_iq.get_xlim() # so zoom doesn't get called + self.xlim = scipy.array(self.sp_iq.get_xlim()) # so zoom doesn't get called + draw() def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) - if(newxlim.all() != curxlim.all()): - self.xlim = newxlim - xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) - xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): + #xmin = max(0, int(ceil(self.sample_rate*(newxlim[0] - self.position)))) + #xmax = min(int(ceil(self.sample_rate*(newxlim[1] - self.position))), len(self.iq)) + xmin = max(0, int(ceil(self.sample_rate*(newxlim[0])))) + xmax = min(int(ceil(self.sample_rate*(newxlim[1]))), len(self.iq)) iq = self.iq[xmin : xmax] time = self.time[xmin : xmax] iq_psd, freq = self.dopsd(iq) - self.plot_psd[0].set_data(freq, iq_psd) - self.sp_psd.axis([freq.min(), freq.max(), - iq_psd.min()-10, iq_psd.max()+10]) + self.draw_psd(freq, iq_psd) + self.xlim = scipy.array(self.sp_iq.get_xlim()) draw() -- cgit From ead0819388bc03555c9182f27176aac6ea2a8bbc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 16 Jan 2011 13:40:20 -0500 Subject: Fixing up fft and constellation plot to better handle zooming. --- gr-utils/src/python/gr_plot_const.py | 2 +- gr-utils/src/python/gr_plot_fft.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 9e4920776..5dd08c9a0 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -138,7 +138,7 @@ class draw_constellation: def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) - if(newxlim.all() != curxlim.all()): + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): self.xlim = newxlim r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py index bb21f3dcd..ba3901e03 100755 --- a/gr-utils/src/python/gr_plot_fft.py +++ b/gr-utils/src/python/gr_plot_fft.py @@ -89,7 +89,8 @@ class gr_plot_fft: self.iq_fft = self.dofft(self.iq) tstep = 1.0 / self.sample_rate - self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) self.freq = self.calc_freq(self.time, self.sample_rate) @@ -158,10 +159,12 @@ class gr_plot_fft: def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) - if(newxlim.all() != curxlim.all()): + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): self.xlim = newxlim - xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) - xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) + #xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) + #xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) + xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0])))) + xmax = min(int(ceil(self.sample_rate*(self.xlim[1]))), len(self.iq)) iq = self.iq[xmin : xmax] time = self.time[xmin : xmax] @@ -171,7 +174,7 @@ class gr_plot_fft: self.plot_fft[0].set_data(freq, iq_fft) self.sp_fft.axis([freq.min(), freq.max(), - iq_fft.min()-10, iq_fftmax()+10]) + iq_fft.min()-10, iq_fft.max()+10]) draw() -- cgit From 04a2f7d44984ebce10c27ae5271d5fe9782cb6f0 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 9 Mar 2011 23:08:42 -0500 Subject: Fixing gr_filter_design program to import from gnuradio Python package. --- gr-utils/src/python/gr_filter_design.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index bf83cf69f..56ca84d78 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -24,7 +24,7 @@ except ImportError: raise SystemExit, 1 try: - from pyqt_filter import Ui_MainWindow + from gnuradio.pyqt_filter import Ui_MainWindow except ImportError: print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" raise SystemExit, 1 -- cgit From cc4cd11bb3443f79771b6b18aaf40105a2f9f088 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 17 Mar 2011 11:11:56 -0700 Subject: gr-utils: Adding save and open actions to filter designer. --- gr-utils/src/python/gr_filter_design.py | 105 ++++++- gr-utils/src/python/pyqt_filter.py | 61 ++-- gr-utils/src/python/pyqt_filter.ui | 505 ++++++++++++++++---------------- 3 files changed, 385 insertions(+), 286 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 56ca84d78..265bb3a03 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import sys, os +import sys, os, csv from optparse import OptionParser from gnuradio import gr, blks2, eng_notation @@ -24,7 +24,7 @@ except ImportError: raise SystemExit, 1 try: - from gnuradio.pyqt_filter import Ui_MainWindow + from pyqt_filter import Ui_MainWindow except ImportError: print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" raise SystemExit, 1 @@ -36,6 +36,14 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui = Ui_MainWindow() self.gui.setupUi(self) + self.connect(self.gui.action_save, + Qt.SIGNAL("activated()"), + self.action_save_dialog) + self.connect(self.gui.action_open, + Qt.SIGNAL("activated()"), + self.action_open_dialog) + + self.connect(self.gui.filterTypeComboBox, Qt.SIGNAL("currentIndexChanged(const QString&)"), self.changed_filter_type) @@ -306,17 +314,10 @@ class gr_plot_filter(QtGui.QMainWindow): "Root Raised Cosine" : self.design_win_rrc, "Gaussian" : self.design_win_gaus} wintype = self.filterWindows[winstr] - taps,r = designer[ftype](fs, gain, wintype) + taps,design,r = designer[ftype](fs, gain, wintype) if(r): - self.taps = scipy.array(taps) - self.get_fft(fs, self.taps, self.nfftpts) - self.update_time_curves() - self.update_freq_curves() - self.update_phase_curves() - self.update_group_curves() - - self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) + self.draw_plots(taps, design) # Filter design functions using a window @@ -334,9 +335,12 @@ class gr_plot_filter(QtGui.QMainWindow): taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, wintype) - return (taps, ret) + design = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "lpf", "passband": pb, "stopband": sb, + "atten": atten} + return (taps, design, ret) else: - return ([], ret) + return ([], [], ret) def design_win_bpf(self, fs, gain, wintype): ret = True @@ -651,6 +655,81 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.groupPlot.replot() + def action_save_dialog(self): + filename = QtGui.QFileDialog.getSaveFileName(self, "Save CSV Filter File", ".", "") + handle = open(filename, "wb") + csvhandle = csv.writer(handle, delimiter=",") + for k in self.design.keys(): + csvhandle.writerow([k, self.design[k]]) + csvhandle.writerow(["taps",] + self.taps.tolist()) + handle.close() + + def action_open_dialog(self): + filename = QtGui.QFileDialog.getOpenFileName(self, "Open CSV Filter File", ".", "") + handle = open(filename, "rb") + csvhandle = csv.reader(handle, delimiter=",") + taps = [] + design = {} + for row in csvhandle: + if(row[0] != "taps"): + try: # if it's not a float, its a string + design[row[0]] = float(row[1]) + except ValueError: + design[row[0]] = row[1] + else: + taps = [float(r) for r in row[1:]] + handle.close() + self.draw_plots(taps, design) + + self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(design["fs"])) + self.gui.filterGainEdit.setText(Qt.QString("%1").arg(design["gain"])) + + #FIXME: work on setting filter type and window type dropdown boxes + #FIXME: enable this and design for all other filt types + if(design["filttype"] == "lpf"): + self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(design["passband"])) + self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(design["stopband"])) + self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(design["atten"])) + elif(design["filttype"] == "bpf"): + self.gui.startofBpfPassBandEdit + self.gui.endofBpfPassBandEdit + self.gui.bpfTransitionEdit + self.gui.bpfStopBandAttenEdit + elif(design["filttype"] == "cbpf"): + self.gui.startofBpfPassBandEdit + self.gui.endofBpfPassBandEdit + self.gui.bpfTransitionEdit + self.gui.bpfStopBandAttenEdit + elif(design["filttype"] == "bnf"): + self.gui.startofBnfStopBandEdit + self.gui.endofBnfStopBandEdit + self.gui.bnfTransitionEdit + self.gui.bnfStopBandAttenEdit + elif(design["filttype"] == "hpf"): + self.gui.endofHpfStopBandEdit + self.gui.startofHpfPassBandEdit + self.gui.hpfStopBandAttenEdit + elif(design["filttype"] == "rrc"): + self.gui.rrcSymbolRateEdit + self.gui.rrcAlphaEdit + self.gui.rrcNumTapsEdit + elif(design["filttype"] == "gauss"): + self.gui.gausSymbolRateEdit + self.gui.gausBTEdit + self.gui.gausNumTapsEdit + + + def draw_plots(self, taps, design): + self.design = design + self.taps = scipy.array(taps) + self.get_fft(self.design["fs"], self.taps, self.nfftpts) + self.update_time_curves() + self.update_freq_curves() + self.update_phase_curves() + self.update_group_curves() + + self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) + def setup_options(): usage="%prog: [options] (input_filename)" diff --git a/gr-utils/src/python/pyqt_filter.py b/gr-utils/src/python/pyqt_filter.py index 12ad183b0..0c781f234 100644 --- a/gr-utils/src/python/pyqt_filter.py +++ b/gr-utils/src/python/pyqt_filter.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'pyqt_filter.ui' # -# Created: Tue Aug 25 11:13:57 2009 -# by: PyQt4 UI code generator 4.4.3 +# Created: Thu Mar 17 10:51:17 2011 +# by: PyQt4 UI code generator 4.7.4 # # WARNING! All changes made in this file will be lost! @@ -27,23 +27,23 @@ class Ui_MainWindow(object): self.verticalLayout.setObjectName("verticalLayout") self.filterTypeComboBox = QtGui.QComboBox(self.filterFrame) self.filterTypeComboBox.setObjectName("filterTypeComboBox") - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) - self.filterTypeComboBox.addItem(QtCore.QString()) + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") + self.filterTypeComboBox.addItem("") self.verticalLayout.addWidget(self.filterTypeComboBox) self.filterDesignTypeComboBox = QtGui.QComboBox(self.filterFrame) self.filterDesignTypeComboBox.setObjectName("filterDesignTypeComboBox") - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) - self.filterDesignTypeComboBox.addItem(QtCore.QString()) + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") + self.filterDesignTypeComboBox.addItem("") self.verticalLayout.addWidget(self.filterDesignTypeComboBox) self.globalParamsLayout = QtGui.QFormLayout() self.globalParamsLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) @@ -255,6 +255,7 @@ class Ui_MainWindow(object): self.nTapsEdit.setMaximumSize(QtCore.QSize(100, 16777215)) self.nTapsEdit.setFrameShape(QtGui.QFrame.Box) self.nTapsEdit.setFrameShadow(QtGui.QFrame.Raised) + self.nTapsEdit.setText("") self.nTapsEdit.setObjectName("nTapsEdit") self.formLayout_8.setWidget(1, QtGui.QFormLayout.FieldRole, self.nTapsEdit) self.verticalLayout.addWidget(self.filterPropsBox) @@ -285,7 +286,7 @@ class Ui_MainWindow(object): self.freqTab.setObjectName("freqTab") self.horizontalLayout_2 = QtGui.QHBoxLayout(self.freqTab) self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.freqPlot = Qwt5.QwtPlot(self.freqTab) + self.freqPlot = QwtPlot(self.freqTab) self.freqPlot.setObjectName("freqPlot") self.horizontalLayout_2.addWidget(self.freqPlot) self.tabGroup.addTab(self.freqTab, "") @@ -293,7 +294,7 @@ class Ui_MainWindow(object): self.timeTab.setObjectName("timeTab") self.horizontalLayout = QtGui.QHBoxLayout(self.timeTab) self.horizontalLayout.setObjectName("horizontalLayout") - self.timePlot = Qwt5.QwtPlot(self.timeTab) + self.timePlot = QwtPlot(self.timeTab) self.timePlot.setObjectName("timePlot") self.horizontalLayout.addWidget(self.timePlot) self.tabGroup.addTab(self.timeTab, "") @@ -301,7 +302,7 @@ class Ui_MainWindow(object): self.phaseTab.setObjectName("phaseTab") self.horizontalLayout_3 = QtGui.QHBoxLayout(self.phaseTab) self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.phasePlot = Qwt5.QwtPlot(self.phaseTab) + self.phasePlot = QwtPlot(self.phaseTab) self.phasePlot.setObjectName("phasePlot") self.horizontalLayout_3.addWidget(self.phasePlot) self.tabGroup.addTab(self.phaseTab, "") @@ -309,14 +310,14 @@ class Ui_MainWindow(object): self.groupTab.setObjectName("groupTab") self.horizontalLayout_4 = QtGui.QHBoxLayout(self.groupTab) self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.groupPlot = Qwt5.QwtPlot(self.groupTab) + self.groupPlot = QwtPlot(self.groupTab) self.groupPlot.setObjectName("groupPlot") self.horizontalLayout_4.addWidget(self.groupPlot) self.tabGroup.addTab(self.groupTab, "") self.gridLayout.addWidget(self.tabGroup, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 24)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1124, 27)) self.menubar.setObjectName("menubar") self.menu_File = QtGui.QMenu(self.menubar) self.menu_File.setObjectName("menu_File") @@ -324,15 +325,19 @@ class Ui_MainWindow(object): self.statusbar = QtGui.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) - self.action_open = QtGui.QAction(MainWindow) - self.action_open.setObjectName("action_open") self.action_exit = QtGui.QAction(MainWindow) self.action_exit.setObjectName("action_exit") + self.action_save = QtGui.QAction(MainWindow) + self.action_save.setObjectName("action_save") + self.action_open = QtGui.QAction(MainWindow) + self.action_open.setObjectName("action_open") + self.menu_File.addAction(self.action_open) + self.menu_File.addAction(self.action_save) self.menu_File.addAction(self.action_exit) self.menubar.addAction(self.menu_File.menuAction()) self.retranslateUi(MainWindow) - self.filterTypeWidget.setCurrentIndex(0) + self.filterTypeWidget.setCurrentIndex(5) self.tabGroup.setCurrentIndex(0) QtCore.QObject.connect(self.action_exit, QtCore.SIGNAL("activated()"), MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -419,8 +424,12 @@ class Ui_MainWindow(object): self.tabGroup.setTabText(self.tabGroup.indexOf(self.phaseTab), QtGui.QApplication.translate("MainWindow", "Phase", None, QtGui.QApplication.UnicodeUTF8)) self.tabGroup.setTabText(self.tabGroup.indexOf(self.groupTab), QtGui.QApplication.translate("MainWindow", "Group Delay", None, QtGui.QApplication.UnicodeUTF8)) self.menu_File.setTitle(QtGui.QApplication.translate("MainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8)) + self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) + self.action_save.setText(QtGui.QApplication.translate("MainWindow", "&Save", None, QtGui.QApplication.UnicodeUTF8)) + self.action_save.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+S", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setText(QtGui.QApplication.translate("MainWindow", "&Open", None, QtGui.QApplication.UnicodeUTF8)) self.action_open.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8)) - self.action_exit.setText(QtGui.QApplication.translate("MainWindow", "E&xit", None, QtGui.QApplication.UnicodeUTF8)) -from PyQt4 import Qwt5 +#from qwt_plot import QwtPlot +from PyQt4.Qwt5 import QwtPlot + diff --git a/gr-utils/src/python/pyqt_filter.ui b/gr-utils/src/python/pyqt_filter.ui index 9b31112e8..9853352e2 100644 --- a/gr-utils/src/python/pyqt_filter.ui +++ b/gr-utils/src/python/pyqt_filter.ui @@ -1,7 +1,8 @@ - + + MainWindow - - + + 0 0 @@ -9,131 +10,131 @@ 696 - + GNU Radio Filter Design Tool - - - - - + + + + + 300 0 - + 300 16777215 - + QFrame::StyledPanel - + QFrame::Raised - + - + - + Low Pass - + Band Pass - + Complex Band Pass - + Band Notch - + High Pass - + Root Raised Cosine - + Gaussian - + - + Hamming Window - + Hann Window - + Blackman Window - + Rectangular Window - + Kaiser Window - + Blackman-harris Window - + Equiripple - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 16777215 30 - + Sample Rate (sps) - - - + + + 16777215 30 @@ -141,332 +142,332 @@ - - - + + + Filter Gain - - + + - - - 0 + + + 5 - - - - - + + + + + End of Pass Band (Hz) - - + + - - - + + + Start of Stop Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - - - + + + + + Start of Pass Band (Hz) - - + + - - - + + + End of Pass Band (Hz) - - + + - - + + - - - + + + Stop Band Attenuation (dB) - - - + + + Transition Width (Hz) - - + + - - + + - - - + + + Pass Band Ripple (dB) - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + Start of Stop Band (Hz) - - + + - - - + + + End of Stop Band (Hz) - - + + - - - + + + Transition Width (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - + + + QFormLayout::AllNonFixedFieldsGrow - - - + + + End of Stop Band (Hz) - - + + - - - + + + Start of Pass Band (Hz) - - + + - - - + + + Stop Band Attenuation (dB) - - + + - - - + + + Pass Band Ripple (dB) - - + + - - - - - + + + + + Symbol Rate (sps) - - - + + + Roll-off Factor - - - + + + Number of Taps - - + + - - + + - - + + - - - - - + + + + + Symbol Rate (sps) - - + + - - - + + + Roll-off Factor - - + + - - - + + + Number of Taps - - + + - - + + Filter Properties - - + + QFormLayout::AllNonFixedFieldsGrow - - - + + + 150 0 - + Number of Taps: - - - + + + 100 16777215 - + QFrame::Box - + QFrame::Raised - + @@ -475,23 +476,23 @@ - - + + System Parameters - - - + + + - - - + + + 150 0 - + Num FFT points @@ -500,26 +501,26 @@ - - + + 0 0 - + 200 16777215 - + Design - + true - + true @@ -527,54 +528,54 @@ - - - + + + 800 0 - + 0 - - + + Frequency Domain - + - + - - + + Time Domain - + - + - - + + Phase - + - + - - + + Group Delay - + - + @@ -582,35 +583,45 @@ - - + + 0 0 1124 - 24 + 27 - - + + &File - + + + - + - - - - &Open + + + + E&xit - - Ctrl+O + + + + &Save + + + Ctrl+S - - - E&xit + + + &Open + + + Ctrl+O @@ -662,11 +673,11 @@ MainWindow close() - + -1 -1 - + 399 347 -- cgit From cec3834a9da5e8b96be438f078fbd3a93ea230d6 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 17 Mar 2011 11:15:50 -0700 Subject: gr-utils: way to break something you just fixed a few days ago... --- gr-utils/src/python/gr_filter_design.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 265bb3a03..d0ef44d8a 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -24,7 +24,7 @@ except ImportError: raise SystemExit, 1 try: - from pyqt_filter import Ui_MainWindow + from gnuradio.pyqt_filter import Ui_MainWindow except ImportError: print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" raise SystemExit, 1 -- cgit From add43f24de20d3fbf6b94920e142d636c4769d5a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 17 Mar 2011 23:19:53 -0700 Subject: gr-utils: refactoring design parameters from 'design' to 'params' to not conflict with design function. --- gr-utils/src/python/gr_filter_design.py | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index d0ef44d8a..091af0092 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -314,10 +314,10 @@ class gr_plot_filter(QtGui.QMainWindow): "Root Raised Cosine" : self.design_win_rrc, "Gaussian" : self.design_win_gaus} wintype = self.filterWindows[winstr] - taps,design,r = designer[ftype](fs, gain, wintype) + taps,params,r = designer[ftype](fs, gain, wintype) if(r): - self.draw_plots(taps, design) + self.draw_plots(taps, params) # Filter design functions using a window @@ -335,10 +335,10 @@ class gr_plot_filter(QtGui.QMainWindow): taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, wintype) - design = {"fs": fs, "gain": gain, "wintype": wintype, + params = {"fs": fs, "gain": gain, "wintype": wintype, "filttype": "lpf", "passband": pb, "stopband": sb, "atten": atten} - return (taps, design, ret) + return (taps, params, ret) else: return ([], [], ret) @@ -659,8 +659,8 @@ class gr_plot_filter(QtGui.QMainWindow): filename = QtGui.QFileDialog.getSaveFileName(self, "Save CSV Filter File", ".", "") handle = open(filename, "wb") csvhandle = csv.writer(handle, delimiter=",") - for k in self.design.keys(): - csvhandle.writerow([k, self.design[k]]) + for k in self.params.keys(): + csvhandle.writerow([k, self.params[k]]) csvhandle.writerow(["taps",] + self.taps.tolist()) handle.close() @@ -669,60 +669,60 @@ class gr_plot_filter(QtGui.QMainWindow): handle = open(filename, "rb") csvhandle = csv.reader(handle, delimiter=",") taps = [] - design = {} + params = {} for row in csvhandle: if(row[0] != "taps"): try: # if it's not a float, its a string - design[row[0]] = float(row[1]) + params[row[0]] = float(row[1]) except ValueError: - design[row[0]] = row[1] + params[row[0]] = row[1] else: taps = [float(r) for r in row[1:]] handle.close() - self.draw_plots(taps, design) + self.draw_plots(taps, params) - self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(design["fs"])) - self.gui.filterGainEdit.setText(Qt.QString("%1").arg(design["gain"])) + self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(params["fs"])) + self.gui.filterGainEdit.setText(Qt.QString("%1").arg(params["gain"])) #FIXME: work on setting filter type and window type dropdown boxes #FIXME: enable this and design for all other filt types - if(design["filttype"] == "lpf"): - self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(design["passband"])) - self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(design["stopband"])) - self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(design["atten"])) - elif(design["filttype"] == "bpf"): + if(params["filttype"] == "lpf"): + self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["passband"])) + self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["stopband"])) + self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + elif(params["filttype"] == "bpf"): self.gui.startofBpfPassBandEdit self.gui.endofBpfPassBandEdit self.gui.bpfTransitionEdit self.gui.bpfStopBandAttenEdit - elif(design["filttype"] == "cbpf"): + elif(params["filttype"] == "cbpf"): self.gui.startofBpfPassBandEdit self.gui.endofBpfPassBandEdit self.gui.bpfTransitionEdit self.gui.bpfStopBandAttenEdit - elif(design["filttype"] == "bnf"): + elif(params["filttype"] == "bnf"): self.gui.startofBnfStopBandEdit self.gui.endofBnfStopBandEdit self.gui.bnfTransitionEdit self.gui.bnfStopBandAttenEdit - elif(design["filttype"] == "hpf"): + elif(params["filttype"] == "hpf"): self.gui.endofHpfStopBandEdit self.gui.startofHpfPassBandEdit self.gui.hpfStopBandAttenEdit - elif(design["filttype"] == "rrc"): + elif(params["filttype"] == "rrc"): self.gui.rrcSymbolRateEdit self.gui.rrcAlphaEdit self.gui.rrcNumTapsEdit - elif(design["filttype"] == "gauss"): + elif(params["filttype"] == "gauss"): self.gui.gausSymbolRateEdit self.gui.gausBTEdit self.gui.gausNumTapsEdit - def draw_plots(self, taps, design): - self.design = design + def draw_plots(self, taps, params): + self.params = params self.taps = scipy.array(taps) - self.get_fft(self.design["fs"], self.taps, self.nfftpts) + self.get_fft(self.params["fs"], self.taps, self.nfftpts) self.update_time_curves() self.update_freq_curves() self.update_phase_curves() -- cgit From 831ca406706ec4c4cdcd2c5f36dc74fb658a3d26 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 18 Mar 2011 00:39:25 -0700 Subject: gr-utils: handling parameters and GUI updates when loading filters from file. Only for windowed filters. --- gr-utils/src/python/gr_filter_design.py | 144 ++++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 46 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 091af0092..ffd67528d 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import sys, os, csv +import sys, os, re, csv from optparse import OptionParser from gnuradio import gr, blks2, eng_notation @@ -190,6 +190,12 @@ class gr_plot_filter(QtGui.QMainWindow): "Rectangular Window" : gr.firdes.WIN_RECTANGULAR, "Kaiser Window" : gr.firdes.WIN_KAISER, "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS} + self.filterWindowsMap = ["Hamming Window", + "Hann Window", + "Blackman Window", + "Rectangular Window", + "Kaiser Window", + "Blackman-harris Window"] self.show() @@ -336,8 +342,8 @@ class gr_plot_filter(QtGui.QMainWindow): taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, wintype) params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "lpf", "passband": pb, "stopband": sb, - "atten": atten} + "filttype": "lpf", "pbend": pb, "sbstart": sb, + "atten": atten, "ntaps": len(taps)} return (taps, params, ret) else: return ([], [], ret) @@ -356,9 +362,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): taps = gr.firdes.band_pass_2(gain, fs, pb1, pb2, tb, atten, wintype) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "bpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_win_cbpf(self, fs, gain, wintype): ret = True @@ -374,9 +383,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): taps = gr.firdes.complex_band_pass_2(gain, fs, pb1, pb2, tb, atten, wintype) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_win_bnf(self, fs, gain, wintype): ret = True @@ -392,9 +404,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): taps = gr.firdes.band_reject_2(gain, fs, pb1, pb2, tb, atten, wintype) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "bnf", "sbstart": pb1, "sbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_win_hpf(self, fs, gain, wintype): ret = True @@ -409,9 +424,12 @@ class gr_plot_filter(QtGui.QMainWindow): tb = pb - sb taps = gr.firdes.high_pass_2(gain, fs, pb, tb, atten, wintype) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "hpf", "sbend": sb, "pbstart": pb, + "atten": atten, "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_win_rrc(self, fs, gain, wintype): ret = True @@ -425,9 +443,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): taps = gr.firdes.root_raised_cosine(gain, fs, sr, alpha, ntaps) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "rrc", "srate": sr, "alpha": alpha, + "ntaps": ntaps} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_win_gaus(self, fs, gain, wintype): ret = True @@ -441,9 +462,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): spb = fs / sr taps = gr.firdes.gaussian(gain, spb, bt, ntaps) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "gaus", "srate": sr, "bt": bt, + "ntaps": ntaps} + return (taps,params,r) else: - return ([],r) + return ([],[],r) # Design Functions for Equiripple Filters def design_opt_lpf(self, fs, gain): @@ -672,51 +696,79 @@ class gr_plot_filter(QtGui.QMainWindow): params = {} for row in csvhandle: if(row[0] != "taps"): - try: # if it's not a float, its a string - params[row[0]] = float(row[1]) - except ValueError: - params[row[0]] = row[1] + testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) + if(len(testcpx) > 0): # it's a complex + params[row[0]] = complex(row[1]) + else: # assume it's a float + try: # if it's not a float, its a string + params[row[0]] = float(row[1]) + except ValueError: + params[row[0]] = row[1] else: - taps = [float(r) for r in row[1:]] + testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) + if(len(testcpx) > 0): # it's a complex + taps = [complex(r) for r in row[1:]] + else: + taps = [float(r) for r in row[1:]] handle.close() self.draw_plots(taps, params) self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(params["fs"])) self.gui.filterGainEdit.setText(Qt.QString("%1").arg(params["gain"])) - #FIXME: work on setting filter type and window type dropdown boxes - #FIXME: enable this and design for all other filt types + # Set up GUI parameters for each filter type if(params["filttype"] == "lpf"): - self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["passband"])) - self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["stopband"])) + self.gui.filterTypeComboBox.setCurrentIndex(0) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) elif(params["filttype"] == "bpf"): - self.gui.startofBpfPassBandEdit - self.gui.endofBpfPassBandEdit - self.gui.bpfTransitionEdit - self.gui.bpfStopBandAttenEdit + self.gui.filterTypeComboBox.setCurrentIndex(1) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) elif(params["filttype"] == "cbpf"): - self.gui.startofBpfPassBandEdit - self.gui.endofBpfPassBandEdit - self.gui.bpfTransitionEdit - self.gui.bpfStopBandAttenEdit + self.gui.filterTypeComboBox.setCurrentIndex(2) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) elif(params["filttype"] == "bnf"): - self.gui.startofBnfStopBandEdit - self.gui.endofBnfStopBandEdit - self.gui.bnfTransitionEdit - self.gui.bnfStopBandAttenEdit + self.gui.filterTypeComboBox.setCurrentIndex(3) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) + self.gui.endofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) + self.gui.bnfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bnfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) elif(params["filttype"] == "hpf"): - self.gui.endofHpfStopBandEdit - self.gui.startofHpfPassBandEdit - self.gui.hpfStopBandAttenEdit + self.gui.filterTypeComboBox.setCurrentIndex(4) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.endofHpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) + self.gui.startofHpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.hpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) elif(params["filttype"] == "rrc"): - self.gui.rrcSymbolRateEdit - self.gui.rrcAlphaEdit - self.gui.rrcNumTapsEdit - elif(params["filttype"] == "gauss"): - self.gui.gausSymbolRateEdit - self.gui.gausBTEdit - self.gui.gausNumTapsEdit + self.gui.filterTypeComboBox.setCurrentIndex(5) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.rrcSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) + self.gui.rrcAlphaEdit.setText(Qt.QString("%1").arg(params["alpha"])) + self.gui.rrcNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) + elif(params["filttype"] == "gaus"): + self.gui.filterTypeComboBox.setCurrentIndex(6) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.gausSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) + self.gui.gausBTEdit.setText(Qt.QString("%1").arg(params["bt"])) + self.gui.gausNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) def draw_plots(self, taps, params): -- cgit From b0856456d63a7f50ad852bcdf4512606a1cfb34e Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 25 Mar 2011 19:37:39 -0400 Subject: gr-utils: adding save/open capabilities to equiripple filters. Also added some error checking on opening and saving files. --- gr-utils/src/python/gr_filter_design.py | 81 ++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 21 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index ffd67528d..7b5fa1305 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -190,13 +190,7 @@ class gr_plot_filter(QtGui.QMainWindow): "Rectangular Window" : gr.firdes.WIN_RECTANGULAR, "Kaiser Window" : gr.firdes.WIN_KAISER, "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS} - self.filterWindowsMap = ["Hamming Window", - "Hann Window", - "Blackman Window", - "Rectangular Window", - "Kaiser Window", - "Blackman-harris Window"] - + self.EQUIRIPPLE_FILT = 6 # const for equiripple filter window types self.show() def changed_filter_type(self, ftype): @@ -309,7 +303,7 @@ class gr_plot_filter(QtGui.QMainWindow): "Complex Band Pass" : self.design_opt_cbpf, "Band Notch" : self.design_opt_bnf, "High Pass" : self.design_opt_hpf} - taps,r = designer[ftype](fs, gain) + taps,params,r = designer[ftype](fs, gain) else: designer = {"Low Pass" : self.design_win_lpf, @@ -484,9 +478,12 @@ class gr_plot_filter(QtGui.QMainWindow): if(ret): taps = blks2.optfir.low_pass(gain, fs, pb, sb, ripple, atten) - return (taps, ret) + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "lpf", "pbend": pb, "sbstart": sb, + "atten": atten, "ripple": ripple, "ntaps": len(taps)} + return (taps, params, ret) else: - return ([], ret) + return ([], [], ret) def design_opt_bpf(self, fs, gain): ret = True @@ -506,9 +503,13 @@ class gr_plot_filter(QtGui.QMainWindow): sb2 = pb2 + tb taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, ripple, atten) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_opt_cbpf(self, fs, gain): ret = True @@ -528,9 +529,13 @@ class gr_plot_filter(QtGui.QMainWindow): sb2 = pb2 + tb taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, ripple, atten) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_opt_bnf(self, fs, gain): ret = True @@ -550,9 +555,13 @@ class gr_plot_filter(QtGui.QMainWindow): pb2 = sb2 + tb taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, ripple, atten) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bnf", "sbstart": pb1, "sbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def design_opt_hpf(self, fs, gain): ret = True @@ -568,9 +577,13 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): taps = blks2.optfir.high_pass(gain, fs, sb, pb, atten, ripple) - return (taps,r) + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "hpf", "sbend": sb, "pbstart": pb, + "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: - return ([],r) + return ([],[],r) def nfft_edit_changed(self, nfft): infft,r = nfft.toInt() @@ -681,7 +694,14 @@ class gr_plot_filter(QtGui.QMainWindow): def action_save_dialog(self): filename = QtGui.QFileDialog.getSaveFileName(self, "Save CSV Filter File", ".", "") - handle = open(filename, "wb") + try: + handle = open(filename, "wb") + except IOError: + reply = QtGui.QMessageBox.information(self, 'File Name', + ("Could not save to file: %s" % filename), + "&Ok") + return + csvhandle = csv.writer(handle, delimiter=",") for k in self.params.keys(): csvhandle.writerow([k, self.params[k]]) @@ -690,7 +710,17 @@ class gr_plot_filter(QtGui.QMainWindow): def action_open_dialog(self): filename = QtGui.QFileDialog.getOpenFileName(self, "Open CSV Filter File", ".", "") - handle = open(filename, "rb") + if(len(filename) == 0): + return + + try: + handle = open(filename, "rb") + except IOError: + reply = QtGui.QMessageBox.information(self, 'File Name', + ("Could not open file: %s" % filename), + "&Ok") + return + csvhandle = csv.reader(handle, delimiter=",") taps = [] params = {} @@ -724,6 +754,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.lpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) elif(params["filttype"] == "bpf"): self.gui.filterTypeComboBox.setCurrentIndex(1) self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) @@ -732,6 +764,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) elif(params["filttype"] == "cbpf"): self.gui.filterTypeComboBox.setCurrentIndex(2) self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) @@ -740,6 +774,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) elif(params["filttype"] == "bnf"): self.gui.filterTypeComboBox.setCurrentIndex(3) self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) @@ -748,6 +784,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.endofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) self.gui.bnfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) self.gui.bnfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bnfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) elif(params["filttype"] == "hpf"): self.gui.filterTypeComboBox.setCurrentIndex(4) self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) @@ -755,6 +793,8 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.endofHpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) self.gui.startofHpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) self.gui.hpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.hpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) elif(params["filttype"] == "rrc"): self.gui.filterTypeComboBox.setCurrentIndex(5) self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) @@ -770,7 +810,6 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.gausBTEdit.setText(Qt.QString("%1").arg(params["bt"])) self.gui.gausNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) - def draw_plots(self, taps, params): self.params = params self.taps = scipy.array(taps) -- cgit From 511e31d4fcd7341b5f1fb56aeba497f0ba36159c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 25 Mar 2011 19:55:03 -0400 Subject: gr-utils: more error checking on filter designer. --- gr-utils/src/python/gr_filter_design.py | 99 ++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 34 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py index 7b5fa1305..e8703db4f 100755 --- a/gr-utils/src/python/gr_filter_design.py +++ b/gr-utils/src/python/gr_filter_design.py @@ -476,12 +476,18 @@ class gr_plot_filter(QtGui.QMainWindow): ret = r and ret if(ret): - taps = blks2.optfir.low_pass(gain, fs, pb, sb, - ripple, atten) - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "lpf", "pbend": pb, "sbstart": sb, - "atten": atten, "ripple": ripple, "ntaps": len(taps)} - return (taps, params, ret) + try: + taps = blks2.optfir.low_pass(gain, fs, pb, sb, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "lpf", "pbend": pb, "sbstart": sb, + "atten": atten, "ripple": ripple, "ntaps": len(taps)} + return (taps, params, ret) else: return ([], [], ret) @@ -501,13 +507,20 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): sb1 = pb1 - tb sb2 = pb2 + tb - taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, - ripple, atten) - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "bpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) + try: + taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: return ([],[],r) @@ -527,13 +540,19 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): sb1 = pb1 - tb sb2 = pb2 + tb - taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, - ripple, atten) - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) + try: + taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: return ([],[],r) @@ -553,13 +572,19 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): pb1 = sb1 - tb pb2 = sb2 + tb - taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, - ripple, atten) - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "bnf", "sbstart": pb1, "sbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) + try: + taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bnf", "sbstart": pb1, "sbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: return ([],[],r) @@ -575,13 +600,19 @@ class gr_plot_filter(QtGui.QMainWindow): ret = r and ret if(r): - taps = blks2.optfir.high_pass(gain, fs, sb, pb, - atten, ripple) - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "hpf", "sbend": sb, "pbstart": pb, - "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) + try: + taps = blks2.optfir.high_pass(gain, fs, sb, pb, + atten, ripple) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "hpf", "sbend": sb, "pbstart": pb, + "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) else: return ([],[],r) -- cgit From e896fec51f576a169c8751573af3dcd90c80669f Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 24 May 2011 12:07:39 +0100 Subject: gr-utils: updating gr_plot_psd.py to protect against zero-length arrays in get_data. --- gr-utils/src/python/gr_plot_psd.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py index 3f90a7104..3dab0535a 100755 --- a/gr-utils/src/python/gr_plot_psd.py +++ b/gr-utils/src/python/gr_plot_psd.py @@ -93,12 +93,20 @@ class gr_plot_psd: self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) except MemoryError: print "End of File" + return False else: - tstep = 1.0 / self.sample_rate - #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) - self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) - - self.iq_psd, self.freq = self.dopsd(self.iq) + # retesting length here as newer version of scipy does not throw a MemoryError, just + # returns a zero-length array + if(len(self.iq) > 0): + tstep = 1.0 / self.sample_rate + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) + + self.iq_psd, self.freq = self.dopsd(self.iq) + return True + else: + print "End of File" + return False def dopsd(self, iq): ''' Need to do this here and plot later so we can do the fftshift ''' @@ -130,7 +138,7 @@ class gr_plot_psd: self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") - self.get_data() + r = self.get_data() self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags @@ -220,8 +228,9 @@ class gr_plot_psd: self.step_forward() def step_forward(self): - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def step_backward(self): # Step back in file position @@ -229,8 +238,9 @@ class gr_plot_psd: self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) else: self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def find(item_in, list_search): try: -- cgit From 2930812784e1b2d9325efccc163448e14118af7c Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sun, 3 Jul 2011 17:51:24 -0700 Subject: gr-utils: move non-GUI apps using old libusrp(2) into gr-usrp or gr-usrp2 One step (of many) to convert GNU Radio to use new Ettus Research UHD driver. --- gr-utils/src/python/Makefile.am | 9 +- gr-utils/src/python/lsusrp | 75 ---------------- gr-utils/src/python/usrp2_rx_cfile.py | 144 ------------------------------ gr-utils/src/python/usrp_print_db.py | 42 --------- gr-utils/src/python/usrp_rx_cfile.py | 108 ---------------------- gr-utils/src/python/usrp_test_counting.py | 53 ----------- gr-utils/src/python/usrp_test_loopback.py | 65 -------------- 7 files changed, 1 insertion(+), 495 deletions(-) delete mode 100755 gr-utils/src/python/lsusrp delete mode 100755 gr-utils/src/python/usrp2_rx_cfile.py delete mode 100755 gr-utils/src/python/usrp_print_db.py delete mode 100755 gr-utils/src/python/usrp_rx_cfile.py delete mode 100755 gr-utils/src/python/usrp_test_counting.py delete mode 100755 gr-utils/src/python/usrp_test_loopback.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index 450032266..b422bfd05 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -50,16 +50,9 @@ bin_SCRIPTS = \ gr_plot_short.py \ gr_plot_qt.py \ gr_filter_design.py \ - lsusrp \ usrp_fft.py \ usrp_oscope.py \ - usrp_print_db.py \ - usrp_rx_cfile.py \ usrp_rx_nogui.py \ usrp_siggen.py \ usrp_siggen_gui.py \ - usrp_test_counting.py \ - usrp_test_loopback.py \ - usrp2_fft.py \ - usrp2_rx_cfile.py - + usrp2_fft.py diff --git a/gr-utils/src/python/lsusrp b/gr-utils/src/python/lsusrp deleted file mode 100755 index d2eab33fe..000000000 --- a/gr-utils/src/python/lsusrp +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008 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. -# - -MAX_USRPS = 8 - -from gnuradio import usrp -from optparse import OptionParser - -def disp_usrp(which, serial=None): - u_source = usrp.source_c(which=which) - u_sink = usrp.sink_c(which=which) - u_serial = u_source.serial_number() - - if serial is not None: - if serial != u_serial: - raise ValueError - - print "USRP", which, "serial number", u_source.serial_number() - subdev_A_rx = usrp.selected_subdev(u_source, (0,0)) - subdev_B_rx = usrp.selected_subdev(u_source, (1,0)) - subdev_A_tx = usrp.selected_subdev(u_sink, (0,0)) - subdev_B_tx = usrp.selected_subdev(u_sink, (1,0)) - print " RX d'board %s" % (subdev_A_rx.side_and_name(),) - print " RX d'board %s" % (subdev_B_rx.side_and_name(),) - print " TX d'board %s" % (subdev_A_tx.side_and_name(),) - print " TX d'board %s" % (subdev_B_tx.side_and_name(),) - -if __name__ == "__main__": - parser = OptionParser() - parser.add_option("-w", "--which", type="int", default=None, - help="select which USRP (0, 1, ...) default is all found", - metavar="NUM") - parser.add_option("-s", "--serial", default=None, - help="select USRP by serial number", - metavar="SER") - (options, args) = parser.parse_args() - if len(args) > 0: - print parser.print_help() - raise SystemExit, 1 - - if options.serial is not None and options.which is not None: - print "Use of --which or --serial is exclusive" - raise SystemExit, 1 - - if options.which is not None: - try: - disp_usrp(options.which) - except: - print "USRP", options.which, "not found." - else: - for n in range(MAX_USRPS): - try: - disp_usrp(n, options.serial) - except: - pass - diff --git a/gr-utils/src/python/usrp2_rx_cfile.py b/gr-utils/src/python/usrp2_rx_cfile.py deleted file mode 100755 index 1f23eee4e..000000000 --- a/gr-utils/src/python/usrp2_rx_cfile.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -""" -Read samples from the USRP2 and write to file formatted as binary -outputs single precision complex float values or complex short values -(interleaved 16 bit signed short integers). -""" - -from gnuradio import gr, eng_notation -from gnuradio import usrp2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys - -n2s = eng_notation.num_to_str - -class rx_cfile_block(gr.top_block): - - def __init__(self, options, filename): - gr.top_block.__init__(self) - - # Create a USRP2 source - if options.output_shorts: - self._u = usrp2.source_16sc(options.interface, options.mac_addr) - self._sink = gr.file_sink(gr.sizeof_short*2, filename) - else: - self._u = usrp2.source_32fc(options.interface, options.mac_addr) - self._sink = gr.file_sink(gr.sizeof_gr_complex, filename) - - # Set receiver decimation rate - self._u.set_decim(options.decim) - - # Set receive daughterboard gain - if options.gain is None: - g = self._u.gain_range() - options.gain = float(g[0]+g[1])/2 - print "Using mid-point gain of", options.gain, "(", g[0], "-", g[1], ")" - self._u.set_gain(options.gain) - - # Set receive frequency - if options.lo_offset is not None: - self._u.set_lo_offset(options.lo_offset) - - tr = self._u.set_center_freq(options.freq) - if tr == None: - sys.stderr.write('Failed to set center frequency\n') - raise SystemExit, 1 - - # Create head block if needed and wire it up - if options.nsamples is None: - self.connect(self._u, self._sink) - else: - if options.output_shorts: - self._head = gr.head(gr.sizeof_short*2, int(options.nsamples)) - else: - self._head = gr.head(gr.sizeof_gr_complex, int(options.nsamples)) - - self.connect(self._u, self._head, self._sink) - - input_rate = self._u.adc_rate()/self._u.decim() - - if options.verbose: - print "Network interface:", options.interface - print "USRP2 address:", self._u.mac_addr() - print "Using RX d'board id 0x%04X" % (self._u.daughterboard_id(),) - print "Rx gain:", options.gain - print "Rx baseband frequency:", n2s(tr.baseband_freq) - print "Rx DDC frequency:", n2s(tr.dxc_freq) - print "Rx residual frequency:", n2s(tr.residual_freq) - print "Rx decimation rate:", options.decim - print "Rx sample rate:", n2s(input_rate) - if options.nsamples is None: - print "Receiving samples until Ctrl-C" - else: - print "Receving", n2s(options.nsamples), "samples" - if options.output_shorts: - print "Writing 16-bit complex shorts" - else: - print "Writing 32-bit complex floats" - print "Output filename:", filename - -def get_options(): - usage="%prog: [options] output_filename" - parser = OptionParser(option_class=eng_option, usage=usage) - parser.add_option("-e", "--interface", type="string", default="eth0", - help="use specified Ethernet interface [default=%default]") - parser.add_option("-m", "--mac-addr", type="string", default="", - help="use USRP2 at specified MAC address [default=None]") - parser.add_option("-d", "--decim", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-f", "--freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") - parser.add_option( "-s","--output-shorts", action="store_true", default=False, - help="output interleaved shorts instead of complex floats") - parser.add_option("-N", "--nsamples", type="eng_float", default=None, - help="number of samples to collect [default=+inf]") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="verbose output") - parser.add_option("", "--lo-offset", type="eng_float", default=None, - help="set daughterboard LO offset to OFFSET [default=hw default]") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - - if options.freq is None: - parser.print_help() - sys.stderr.write('You must specify the frequency with -f FREQ\n'); - raise SystemExit, 1 - - return (options, args[0]) - - -if __name__ == '__main__': - (options, filename) = get_options() - tb = rx_cfile_block(options, filename) - - try: - tb.run() - except KeyboardInterrupt: - pass diff --git a/gr-utils/src/python/usrp_print_db.py b/gr-utils/src/python/usrp_print_db.py deleted file mode 100755 index b082cb073..000000000 --- a/gr-utils/src/python/usrp_print_db.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006,2007 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. -# - -#!/usr/bin/env python - -from gnuradio import gr -from gnuradio import usrp -from optparse import OptionParser -from usrpm import usrp_dbid - -u_source = usrp.source_c() -u_sink = usrp.sink_c() - -subdev_Ar = usrp.selected_subdev(u_source, (0,0)) -subdev_Br = usrp.selected_subdev(u_source, (1,0)) -subdev_At = usrp.selected_subdev(u_sink, (0,0)) -subdev_Bt = usrp.selected_subdev(u_sink, (1,0)) - -print "RX d'board %s" % (subdev_Ar.side_and_name(),) -print "RX d'board %s" % (subdev_Br.side_and_name(),) -print "TX d'board %s" % (subdev_At.side_and_name(),) -print "TX d'board %s" % (subdev_Bt.side_and_name(),) - diff --git a/gr-utils/src/python/usrp_rx_cfile.py b/gr-utils/src/python/usrp_rx_cfile.py deleted file mode 100755 index 3ac9fb56f..000000000 --- a/gr-utils/src/python/usrp_rx_cfile.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python - -""" -Read samples from the USRP and write to file formatted as binary -outputs single precision complex float values or complex short values (interleaved 16 bit signed short integers). - -""" - -from gnuradio import gr, eng_notation -from gnuradio import audio -from gnuradio import usrp -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys - -class my_top_block(gr.top_block): - - def __init__(self): - gr.top_block.__init__(self) - - usage="%prog: [options] output_filename" - parser = OptionParser(option_class=eng_option, usage=usage) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0, 0), - help="select USRP Rx side A or B (default=A)") - parser.add_option("-d", "--decim", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-f", "--freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") - parser.add_option("-8", "--width-8", action="store_true", default=False, - help="Enable 8-bit samples across USB") - parser.add_option( "--no-hb", action="store_true", default=False, - help="don't use halfband filter in usrp") - parser.add_option( "-s","--output-shorts", action="store_true", default=False, - help="output interleaved shorts in stead of complex floats") - parser.add_option("-N", "--nsamples", type="eng_float", default=None, - help="number of samples to collect [default=+inf]") - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - if options.freq is None: - parser.print_help() - sys.stderr.write('You must specify the frequency with -f FREQ\n'); - raise SystemExit, 1 - - # build the graph - if options.no_hb or (options.decim<8): - self.fpga_filename="std_4rx_0tx.rbf" #Min decimation of this firmware is 4. contains 4 Rx paths without halfbands and 0 tx paths. - if options.output_shorts: - self.u = usrp.source_s(decim_rate=options.decim,fpga_filename=self.fpga_filename) - else: - self.u = usrp.source_c(decim_rate=options.decim,fpga_filename=self.fpga_filename) - else: - #standard fpga firmware "std_2rxhb_2tx.rbf" contains 2 Rx paths with halfband filters and 2 tx paths (the default) min decimation 8 - if options.output_shorts: - self.u = usrp.source_s(decim_rate=options.decim) - else: - self.u = usrp.source_c(decim_rate=options.decim) - if options.width_8: - sample_width = 8 - sample_shift = 8 - format = self.u.make_format(sample_width, sample_shift) - r = self.u.set_format(format) - if options.output_shorts: - self.dst = gr.file_sink(gr.sizeof_short, filename) - else: - self.dst = gr.file_sink(gr.sizeof_gr_complex, filename) - if options.nsamples is None: - self.connect(self.u, self.dst) - else: - if options.output_shorts: - self.head = gr.head(gr.sizeof_short, int(options.nsamples)*2) - else: - self.head = gr.head(gr.sizeof_gr_complex, int(options.nsamples)) - self.connect(self.u, self.head, self.dst) - - if options.rx_subdev_spec is None: - options.rx_subdev_spec = usrp.pick_rx_subdevice(self.u) - self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) - - # determine the daughterboard subdevice we're using - self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) - print "Using RX d'board %s" % (self.subdev.side_and_name(),) - input_rate = self.u.adc_freq() / self.u.decim_rate() - print "USB sample rate %s" % (eng_notation.num_to_str(input_rate)) - - if options.gain is None: - # if no gain was specified, use the mid-point in dB - g = self.subdev.gain_range() - options.gain = float(g[0]+g[1])/2 - - self.subdev.set_gain(options.gain) - - r = self.u.tune(0, self.subdev, options.freq) - if not r: - sys.stderr.write('Failed to set frequency\n') - raise SystemExit, 1 - - -if __name__ == '__main__': - try: - my_top_block().run() - except KeyboardInterrupt: - pass diff --git a/gr-utils/src/python/usrp_test_counting.py b/gr-utils/src/python/usrp_test_counting.py deleted file mode 100755 index a8300afe2..000000000 --- a/gr-utils/src/python/usrp_test_counting.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2007 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. -# - -""" -Check Rx path or USRP Rev 1. - -This configures the USRP to return a periodic sequence of integers -""" - -from gnuradio import gr -from gnuradio import usrp - -def build_graph (): - rx_decim = 32 - - tb = gr.top_block () - usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_COUNTING) - sink = gr.check_counting_s () - tb.connect (usrp_rx, sink) - - # file_sink = gr.file_sink (gr.sizeof_short, 'counting.dat') - # tb.connect (usrp_rx, file_sink) - - return tb - -def main (): - tb = build_graph () - try: - tb.run() - except KeyboardInterrupt: - pass - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_test_loopback.py b/gr-utils/src/python/usrp_test_loopback.py deleted file mode 100755 index b58ac06ae..000000000 --- a/gr-utils/src/python/usrp_test_loopback.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2007 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. -# - -""" -Digital loopback (Tx to Rx) for the USRP Rev1. -""" - - -from gnuradio import gr -from gnuradio import usrp - - -def ramp_source (tb): - period = 2**16 - src = gr.vector_source_s (range (-period/2, period/2, 1), True) - return src - -def build_graph (): - tx_interp = 32 # tx should be twice rx - rx_decim = 16 - - tb = gr.top_block () - - data_src = ramp_source (tb) - # usrp_tx = usrp.sink_s (0, tx_interp, 1, 0x98) - usrp_tx = usrp.sink_s (0, tx_interp) - tb.connect (data_src, usrp_tx) - - usrp_rx = usrp.source_s (0, rx_decim, 1, 0x32103210, usrp.FPGA_MODE_LOOPBACK) - sink = gr.check_counting_s () - tb.connect (usrp_rx, sink) - - # file_sink = gr.file_sink (gr.sizeof_short, "loopback.dat") - # tb.connect (usrp_rx, file_sink) - - return tb - -def main (): - tb = build_graph () - try: - tb.run() - except KeyboardInterrupt: - pass - -if __name__ == '__main__': - main () -- cgit From 25a0f8cc6aeb4ce8d11d643f6f8b2d9552002709 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 10 Aug 2011 22:38:13 -0400 Subject: fixing constellation plotter to gracefully handle the end of a file. --- gr-utils/src/python/gr_plot_const.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 5dd08c9a0..0c52899b2 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -85,16 +85,23 @@ class draw_constellation: except MemoryError: print "End of File" else: - self.reals = scipy.array([r.real for r in iq]) - self.imags = scipy.array([i.imag for i in iq]) + # retesting length here as newer version of scipy does not throw a MemoryError, just + # returns a zero-length array + if(len(iq) > 0): + self.reals = scipy.array([r.real for r in iq]) + self.imags = scipy.array([i.imag for i in iq]) + + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) + return Tr + else: + print "End of File" + return False - self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - def make_plots(self): # if specified on the command-line, set file pointer self.hfile.seek(self.sizeof_data*self.start, 1) - self.get_data() + r = self.get_data() # Subplot for real and imaginary parts of signal self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) @@ -175,8 +182,9 @@ class draw_constellation: self.step_forward() def step_forward(self): - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def step_backward(self): # Step back in file position @@ -184,8 +192,9 @@ class draw_constellation: self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) else: self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() + r = self.get_data() + if(r): + self.update_plots() def mouse_button_callback(self, event): -- cgit From 8af791009ad280f8830dada145a78292a19dde81 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 22 Aug 2011 20:13:13 -0400 Subject: utils: fixed typo --- gr-utils/src/python/gr_plot_const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py index 0c52899b2..8873e5b7e 100755 --- a/gr-utils/src/python/gr_plot_const.py +++ b/gr-utils/src/python/gr_plot_const.py @@ -92,7 +92,7 @@ class draw_constellation: self.imags = scipy.array([i.imag for i in iq]) self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - return Tr + return True else: print "End of File" return False -- cgit From 3b1a26e6e610aed2aa8dee3bb747184f51447cf6 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 7 Oct 2011 17:40:59 -0400 Subject: uhd: removing old USRP util files that have been replaced in gr-uhd/apps. --- gr-utils/src/python/Makefile.am | 8 +- gr-utils/src/python/usrp2_fft.py | 273 -------------------------- gr-utils/src/python/usrp_fft.py | 309 ----------------------------- gr-utils/src/python/usrp_oscope.py | 349 --------------------------------- gr-utils/src/python/usrp_rx_nogui.py | 213 -------------------- gr-utils/src/python/usrp_siggen.py | 331 ------------------------------- gr-utils/src/python/usrp_siggen_gui.py | 317 ------------------------------ 7 files changed, 1 insertion(+), 1799 deletions(-) delete mode 100755 gr-utils/src/python/usrp2_fft.py delete mode 100755 gr-utils/src/python/usrp_fft.py delete mode 100755 gr-utils/src/python/usrp_oscope.py delete mode 100755 gr-utils/src/python/usrp_rx_nogui.py delete mode 100755 gr-utils/src/python/usrp_siggen.py delete mode 100755 gr-utils/src/python/usrp_siggen_gui.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index b422bfd05..11fb038f6 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -49,10 +49,4 @@ bin_SCRIPTS = \ gr_plot_iq.py \ gr_plot_short.py \ gr_plot_qt.py \ - gr_filter_design.py \ - usrp_fft.py \ - usrp_oscope.py \ - usrp_rx_nogui.py \ - usrp_siggen.py \ - usrp_siggen_gui.py \ - usrp2_fft.py + gr_filter_design.py diff --git a/gr-utils/src/python/usrp2_fft.py b/gr-utils/src/python/usrp2_fft.py deleted file mode 100755 index 4276e389a..000000000 --- a/gr-utils/src/python/usrp2_fft.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2010 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, gru -from gnuradio import usrp2 -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider -from optparse import OptionParser -import wx -import sys -import numpy - -class app_top_block(stdgui2.std_top_block): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - parser.add_option("-e", "--interface", type="string", default="eth0", - help="select Ethernet interface, default is eth0") - parser.add_option("-m", "--mac-addr", type="string", default="", - help="select USRP by MAC address, default is auto-select") - #parser.add_option("-A", "--antenna", default=None, - # help="select Rx Antenna (only on RFX-series boards)") - parser.add_option("-d", "--decim", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-f", "--freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") - parser.add_option("-W", "--waterfall", action="store_true", default=False, - help="Enable waterfall display") - parser.add_option("-S", "--oscilloscope", action="store_true", default=False, - help="Enable oscilloscope display") - parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, default=[%default]") - parser.add_option("", "--ref-scale", type="eng_float", default=1.0, - help="Set dBFS=0dB input value, default=[%default]") - parser.add_option("--fft-size", type="int", default=1024, - help="Set number of FFT bins [default=%default]") - (options, args) = parser.parse_args() - if len(args) != 0: - parser.print_help() - sys.exit(1) - self.options = options - self.show_debug_info = True - - self.u = usrp2.source_32fc(options.interface, options.mac_addr) - self.u.set_decim(options.decim) - - input_rate = self.u.adc_rate() / self.u.decim() - - if options.waterfall: - self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=1024, sample_rate=input_rate) - elif options.oscilloscope: - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) - else: - self.scope = fftsink2.fft_sink_c (panel, - fft_size=options.fft_size, - sample_rate=input_rate, - ref_scale=options.ref_scale, - ref_level=20.0, - y_divs = 12, - avg_alpha=options.avg_alpha) - - self.connect(self.u, self.scope) - - self._build_gui(vbox) - self._setup_events() - - # set initial values - - if options.gain is None: - # if no gain was specified, use the mid-point in dB - g = self.u.gain_range() - options.gain = float(g[0]+g[1])/2 - - if options.freq is None: - # if no freq was specified, use the mid-point - r = self.u.freq_range() - options.freq = float(r[0]+r[1])/2 - - self.set_gain(options.gain) - - #if options.antenna is not None: - # print "Selecting antenna %s" % (options.antenna,) - # self.subdev.select_rx_antenna(options.antenna) - - if self.show_debug_info: - self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - self.myform['dbname'].set_value("0x%04X" % (self.u.daughterboard_id(),)) # FIXME: add text name - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - - if not(self.set_freq(options.freq)): - self._set_status_msg("Failed to set initial frequency") - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,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((5,0), 0, 0) - g = self.u.gain_range() - - # some configurations don't have gain control - if g[1] > g[0]: - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,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_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@gbe'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@GbE") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - r = self.u.set_center_freq(target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.oscilloscope: - self.scope.set_baseband_freq(target_freq) - return True - - return False - - def set_gain(self, gain): - if self.myform.has_key('gain'): - self.myform['gain'].set_value(gain) # update displayed value - self.u.set_gain(gain) - - def set_decim(self, decim): - ok = self.u.set_decim(decim) - if not ok: - print "set_decim failed" - input_rate = self.u.adc_rate() / self.u.decim() - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim()) - self.myform['fs@gbe'].set_value(input_rate) - return ok - - def _setup_events(self): - if not self.options.waterfall and not self.options.oscilloscope: - self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) - - def evt_left_dclick(self, event): - (ux, uy) = self.scope.win.GetXY(event) - if event.CmdDown(): - # Re-center on maximum power - points = self.scope.win._points - if self.scope.win.peak_hold: - if self.scope.win.peak_vals is not None: - ind = numpy.argmax(self.scope.win.peak_vals) - else: - ind = int(points.shape()[0]/2) - else: - ind = numpy.argmax(points[:,1]) - (freq, pwr) = points[ind] - target_freq = freq/self.scope.win._scale_factor - print ind, freq, pwr - self.set_freq(target_freq) - else: - # Re-center on clicked frequency - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) - - -def main (): - app = stdgui2.stdapp(app_top_block, "USRP2 FFT", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_fft.py b/gr-utils/src/python/usrp_fft.py deleted file mode 100755 index eda9bd57c..000000000 --- a/gr-utils/src/python/usrp_fft.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2007,2008,2010 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, gru -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, fftsink2, waterfallsink2, scopesink2, form, slider -from optparse import OptionParser -import wx -import sys -import numpy - -def pick_subdevice(u): - """ - The user didn't specify a subdevice on the command line. - If there's a daughterboard on A, select A. - If there's a daughterboard on B, select B. - Otherwise, select A. - """ - if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem - return (0, 0) - if u.db(1, 0).dbid() >= 0: - return (1, 0) - return (0, 0) - - -class app_top_block(stdgui2.std_top_block): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - parser.add_option("-w", "--which", type="int", default=0, - help="select which USRP (0, 1, ...) default is %default", - metavar="NUM") - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B (default=first one with a daughterboard)") - parser.add_option("-A", "--antenna", default=None, - help="select Rx Antenna (only on RFX-series boards)") - parser.add_option("-d", "--decim", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-f", "--freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB [default is midpoint]") - parser.add_option("-W", "--waterfall", action="store_true", default=False, - help="Enable waterfall display") - parser.add_option("-8", "--width-8", action="store_true", default=False, - help="Enable 8-bit samples across USB") - parser.add_option( "--no-hb", action="store_true", default=False, - help="don't use halfband filter in usrp") - parser.add_option("-S", "--oscilloscope", action="store_true", default=False, - help="Enable oscilloscope display") - parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, - help="Set fftsink averaging factor, [default=%default]") - parser.add_option("", "--ref-scale", type="eng_float", default=13490.0, - help="Set dBFS=0dB input value, [default=%default]") - parser.add_option("", "--fft-size", type="int", default=1024, - help="Set FFT frame size, [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 - - # build the graph - if options.no_hb or (options.decim<8): - #Min decimation of this firmware is 4. - #contains 4 Rx paths without halfbands and 0 tx paths. - self.fpga_filename="std_4rx_0tx.rbf" - self.u = usrp.source_c(which=options.which, decim_rate=options.decim, fpga_filename=self.fpga_filename) - else: - #Min decimation of standard firmware is 8. - #standard fpga firmware "std_2rxhb_2tx.rbf" - #contains 2 Rx paths with halfband filters and 2 tx paths (the default) - self.u = usrp.source_c(which=options.which, decim_rate=options.decim) - - if options.rx_subdev_spec is None: - options.rx_subdev_spec = pick_subdevice(self.u) - self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) - - if options.width_8: - width = 8 - shift = 8 - format = self.u.make_format(width, shift) - print "format =", hex(format) - r = self.u.set_format(format) - print "set_format =", r - - # determine the daughterboard subdevice we're using - self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) - - input_rate = self.u.adc_freq() / self.u.decim_rate() - - if options.waterfall: - self.scope = \ - waterfallsink2.waterfall_sink_c (panel, fft_size=options.fft_size, sample_rate=input_rate) - elif options.oscilloscope: - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate) - else: - self.scope = fftsink2.fft_sink_c (panel, fft_size=options.fft_size, sample_rate=input_rate, - ref_scale=options.ref_scale, ref_level=0.0, y_divs = 10, - avg_alpha=options.avg_alpha) - - self.connect(self.u, self.scope) - - self._build_gui(vbox) - self._setup_events() - - # set initial values - - if options.gain is None: - # if no gain was specified, use the mid-point in dB - g = self.subdev.gain_range() - options.gain = float(g[0]+g[1])/2 - - if options.freq is None: - # if no freq was specified, use the mid-point - r = self.subdev.freq_range() - options.freq = float(r[0]+r[1])/2 - - self.set_gain(options.gain) - - if options.antenna is not None: - print "Selecting antenna %s" % (options.antenna,) - self.subdev.select_rx_antenna(options.antenna) - - if self.show_debug_info: - self.myform['decim'].set_value(self.u.decim_rate()) - self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) - self.myform['dbname'].set_value(self.subdev.name()) - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - - if not(self.set_freq(options.freq)): - self._set_status_msg("Failed to set initial frequency") - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,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((5,0), 0, 0) - g = self.subdev.gain_range() - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,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_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@usb'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@USB") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - r = self.u.tune(0, self.subdev, target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - if not self.options.oscilloscope: - self.scope.set_baseband_freq(target_freq) - return True - - return False - - def set_gain(self, gain): - self.myform['gain'].set_value(gain) # update displayed value - self.subdev.set_gain(gain) - - def set_decim(self, decim): - ok = self.u.set_decim_rate(decim) - if not ok: - print "set_decim failed" - input_rate = self.u.adc_freq() / self.u.decim_rate() - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim_rate()) - self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) - return ok - - def _setup_events(self): - if not self.options.waterfall and not self.options.oscilloscope: - self.scope.win.Bind(wx.EVT_LEFT_DCLICK, self.evt_left_dclick) - - def evt_left_dclick(self, event): - (ux, uy) = self.scope.win.GetXY(event) - if event.CmdDown(): - # Re-center on maximum power - points = self.scope.win._points - if self.scope.win.peak_hold: - if self.scope.win.peak_vals is not None: - ind = numpy.argmax(self.scope.win.peak_vals) - else: - ind = int(points.shape()[0]/2) - else: - ind = numpy.argmax(points[:,1]) - (freq, pwr) = points[ind] - target_freq = freq/self.scope.win._scale_factor - print ind, freq, pwr - self.set_freq(target_freq) - else: - # Re-center on clicked frequency - target_freq = ux/self.scope.win._scale_factor - self.set_freq(target_freq) - - -def main (): - app = stdgui2.stdapp(app_top_block, "USRP FFT", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_oscope.py b/gr-utils/src/python/usrp_oscope.py deleted file mode 100755 index 9921e9873..000000000 --- a/gr-utils/src/python/usrp_oscope.py +++ /dev/null @@ -1,349 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004,2005,2006,2007 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. -# - -# print "Loading revised usrp_oscope with additional options for scopesink..." - -from gnuradio import gr, gru -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui2, scopesink2, form, slider -from optparse import OptionParser -import wx -import sys -from usrpm import usrp_dbid - - -def pick_subdevice(u): - """ - The user didn't specify a subdevice on the command line. - If there's a daughterboard on A, select A. - If there's a daughterboard on B, select B. - Otherwise, select A. - """ - if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem - return (0, 0) - if u.db(1, 0).dbid() >= 0: - return (1, 0) - return (0, 0) - - -class app_top_block(stdgui2.std_top_block): - def __init__(self, frame, panel, vbox, argv): - stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) - - self.frame = frame - self.panel = panel - - parser = OptionParser(option_class=eng_option) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B (default=first one with a daughterboard)") - parser.add_option("-d", "--decim", type="int", default=16, - help="set fgpa decimation rate to DECIM [default=%default]") - parser.add_option("-f", "--freq", type="eng_float", default=None, - help="set frequency to FREQ", metavar="FREQ") - parser.add_option("-g", "--gain", type="eng_float", default=None, - help="set gain in dB (default is midpoint)") - parser.add_option("-8", "--width-8", action="store_true", default=False, - help="Enable 8-bit samples across USB") - parser.add_option( "--no-hb", action="store_true", default=False, - help="don't use halfband filter in usrp") - parser.add_option("-C", "--basic-complex", action="store_true", default=False, - help="Use both inputs of a basicRX or LFRX as a single Complex input channel") - parser.add_option("-D", "--basic-dualchan", action="store_true", default=False, - help="Use both inputs of a basicRX or LFRX as seperate Real input channels") - parser.add_option("-n", "--frame-decim", type="int", default=1, - help="set oscope frame decimation factor to n [default=1]") - parser.add_option("-v", "--v-scale", type="eng_float", default=1000, - help="set oscope initial V/div to SCALE [default=%default]") - parser.add_option("-t", "--t-scale", type="eng_float", default=49e-6, - help="set oscope initial s/div to SCALE [default=50us]") - (options, args) = parser.parse_args() - if len(args) != 0: - parser.print_help() - sys.exit(1) - - self.show_debug_info = True - - # build the graph - if options.basic_dualchan: - self.num_inputs=2 - else: - self.num_inputs=1 - if options.no_hb or (options.decim<8): - #Min decimation of this firmware is 4. - #contains 4 Rx paths without halfbands and 0 tx paths. - self.fpga_filename="std_4rx_0tx.rbf" - self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim, fpga_filename=self.fpga_filename) - else: - #Min decimation of standard firmware is 8. - #standard fpga firmware "std_2rxhb_2tx.rbf" - #contains 2 Rx paths with halfband filters and 2 tx paths (the default) - self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim) - - if options.rx_subdev_spec is None: - options.rx_subdev_spec = pick_subdevice(self.u) - - if options.width_8: - width = 8 - shift = 8 - format = self.u.make_format(width, shift) - #print "format =", hex(format) - r = self.u.set_format(format) - #print "set_format =", r - - # determine the daughterboard subdevice we're using - self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec) - if (options.basic_complex or options.basic_dualchan ): - if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)): - side = options.rx_subdev_spec[0] # side A = 0, side B = 1 - if options.basic_complex: - #force Basic_RX and LF_RX in complex mode (use both I and Q channel) - print "Receiver daughterboard forced in complex mode. Both inputs will combined to form a single complex channel." - self.dualchan=False - if side==0: - self.u.set_mux(0x00000010) #enable adc 0 and 1 to form a single complex input on side A - else: #side ==1 - self.u.set_mux(0x00000032) #enable adc 3 and 2 to form a single complex input on side B - elif options.basic_dualchan: - #force Basic_RX and LF_RX in dualchan mode (use input A for channel 0 and input B for channel 1) - print "Receiver daughterboard forced in dualchannel mode. Each input will be used to form a seperate channel." - self.dualchan=True - if side==0: - self.u.set_mux(gru.hexint(0xf0f0f1f0)) #enable adc 0, side A to form a real input on channel 0 and adc1,side A to form a real input on channel 1 - else: #side ==1 - self.u.set_mux(0xf0f0f3f2) #enable adc 2, side B to form a real input on channel 0 and adc3,side B to form a real input on channel 1 - else: - sys.stderr.write('options basic_dualchan or basic_complex is only supported for Basic Rx or LFRX at the moment\n') - sys.exit(1) - else: - self.dualchan=False - self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec)) - - input_rate = self.u.adc_freq() / self.u.decim_rate() - - self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate, - frame_decim=options.frame_decim, - v_scale=options.v_scale, - t_scale=options.t_scale, - num_inputs=self.num_inputs) - if self.dualchan: - # deinterleave two channels from FPGA - self.di = gr.deinterleave(gr.sizeof_gr_complex) - self.connect(self.u,self.di) - self.connect((self.di,0),(self.scope,0)) - self.connect((self.di,1),(self.scope,1)) - else: - self.connect(self.u, self.scope) - - self._build_gui(vbox) - - # set initial values - - if options.gain is None: - # if no gain was specified, use the mid-point in dB - g = self.subdev.gain_range() - options.gain = float(g[0]+g[1])/2 - - if options.freq is None: - if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)): - #for Basic RX and LFRX if no freq is specified you probably want 0.0 Hz and not 45 GHz - options.freq=0.0 - else: - # if no freq was specified, use the mid-point - r = self.subdev.freq_range() - options.freq = float(r[0]+r[1])/2 - - self.set_gain(options.gain) - - if self.show_debug_info: - self.myform['decim'].set_value(self.u.decim_rate()) - self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) - self.myform['dbname'].set_value(self.subdev.name()) - self.myform['baseband'].set_value(0) - self.myform['ddc'].set_value(0) - if self.num_inputs==2: - self.myform['baseband2'].set_value(0) - self.myform['ddc2'].set_value(0) - - if not(self.set_freq(options.freq)): - self._set_status_msg("Failed to set initial frequency") - if self.num_inputs==2: - if not(self.set_freq2(options.freq)): - self._set_status_msg("Failed to set initial frequency for channel 2") - - - def _set_status_msg(self, msg): - self.frame.GetStatusBar().SetStatusText(msg, 0) - - def _build_gui(self, vbox): - - def _form_set_freq(kv): - return self.set_freq(kv['freq']) - - def _form_set_freq2(kv): - return self.set_freq2(kv['freq2']) - vbox.Add(self.scope.win, 10, wx.EXPAND) - - # add control area at the bottom - self.myform = myform = form.form() - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,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)) - if self.num_inputs==2: - myform['freq2'] = form.float_field( - parent=self.panel, sizer=hbox, label="Center freq2", weight=1, - callback=myform.check_input_and_call(_form_set_freq2, self._set_status_msg)) - hbox.Add((5,0), 0, 0) - g = self.subdev.gain_range() - myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain", - weight=3, - min=int(g[0]), max=int(g[1]), - callback=self.set_gain) - - hbox.Add((5,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_decim(kv): - return self.set_decim(kv['decim']) - - if not(self.show_debug_info): - return - - panel = self.panel - vbox = vbox_arg - myform = self.myform - - #panel = wx.Panel(self.panel, -1) - #vbox = wx.BoxSizer(wx.VERTICAL) - - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add((5,0), 0) - - myform['decim'] = form.int_field( - parent=panel, sizer=hbox, label="Decim", - callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg)) - - hbox.Add((5,0), 1) - myform['fs@usb'] = form.static_float_field( - parent=panel, sizer=hbox, label="Fs@USB") - - hbox.Add((5,0), 1) - myform['dbname'] = form.static_text_field( - parent=panel, sizer=hbox) - - hbox.Add((5,0), 1) - myform['baseband'] = form.static_float_field( - parent=panel, sizer=hbox, label="Analog BB") - - hbox.Add((5,0), 1) - myform['ddc'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC") - if self.num_inputs==2: - hbox.Add((1,0), 1) - myform['baseband2'] = form.static_float_field( - parent=panel, sizer=hbox, label="BB2") - hbox.Add((1,0), 1) - myform['ddc2'] = form.static_float_field( - parent=panel, sizer=hbox, label="DDC2") - - hbox.Add((5,0), 0) - vbox.Add(hbox, 0, wx.EXPAND) - - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - r = usrp.tune(self.u, 0, self.subdev, target_freq) - - if r: - self.myform['freq'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband'].set_value(r.baseband_freq) - self.myform['ddc'].set_value(r.dxc_freq) - return True - - return False - - def set_freq2(self, target_freq): - """ - Set the center frequency of we're interested in for the second channel. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital down converter. - """ - r = usrp.tune(self.u, 1, self.subdev, target_freq) - - if r: - self.myform['freq2'].set_value(target_freq) # update displayed value - if self.show_debug_info: - self.myform['baseband2'].set_value(r.baseband_freq) - self.myform['ddc2'].set_value(r.dxc_freq) - return True - - return False - - def set_gain(self, gain): - self.myform['gain'].set_value(gain) # update displayed value - self.subdev.set_gain(gain) - - def set_decim(self, decim): - ok = self.u.set_decim_rate(decim) - if not ok: - print "set_decim failed" - input_rate = self.u.adc_freq() / self.u.decim_rate() - self.scope.set_sample_rate(input_rate) - if self.show_debug_info: # update displayed values - self.myform['decim'].set_value(self.u.decim_rate()) - self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate()) - return ok - -def main (): - app = stdgui2.stdapp(app_top_block, "USRP O'scope", nstatus=1) - app.MainLoop() - -if __name__ == '__main__': - main () diff --git a/gr-utils/src/python/usrp_rx_nogui.py b/gr-utils/src/python/usrp_rx_nogui.py deleted file mode 100755 index a5d792c8b..000000000 --- a/gr-utils/src/python/usrp_rx_nogui.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006,2007 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, gru, usrp, optfir, audio, eng_notation, blks2 -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys - -""" -This example application demonstrates receiving and demodulating -different types of signals using the USRP. - -A receive chain is built up of the following signal processing -blocks: - -USRP - Daughter board source generating complex baseband signal. -CHAN - Low pass filter to select channel bandwidth -RFSQL - RF squelch zeroing output when input power below threshold -AGC - Automatic gain control leveling signal at [-1.0, +1.0] -DEMOD - Demodulation block appropriate to selected signal type. - This converts the complex baseband to real audio frequencies, - and applies an appropriate low pass decimating filter. -CTCSS - Optional tone squelch zeroing output when tone is not present. -RSAMP - Resampler block to convert audio sample rate to user specified - sound card output rate. -AUDIO - Audio sink for playing final output to speakers. - -The following are required command line parameters: - --f FREQ USRP receive frequency --m MOD Modulation type, select from AM, FM, or WFM - -The following are optional command line parameters: - --R SUBDEV Daughter board specification, defaults to first found --c FREQ Calibration offset. Gets added to receive frequency. - Defaults to 0.0 Hz. --g GAIN Daughterboard gain setting. Defaults to mid-range. --o RATE Sound card output rate. Defaults to 32000. Useful if - your sound card only accepts particular sample rates. --r RFSQL RF squelch in db. Defaults to -50.0. --p FREQ CTCSS frequency. Opens squelch when tone is present. - -Once the program is running, ctrl-break (Ctrl-C) stops operation. - -Please see fm_demod.py and am_demod.py for details of the demodulation -blocks. -""" - -# (usrp_decim, channel_decim, audio_decim, channel_pass, channel_stop, demod) -demod_params = { - 'AM' : (250, 16, 1, 5000, 8000, blks2.demod_10k0a3e_cf), - 'FM' : (250, 8, 4, 8000, 9000, blks2.demod_20k0f3e_cf), - 'WFM' : (250, 1, 8, 90000, 100000, blks2.demod_200kf3e_cf) - } - -class usrp_src(gr.hier_block2): - """ - Create a USRP source object supplying complex floats. - - Selects user supplied subdevice or chooses first available one. - - Calibration value is the offset from the tuned frequency to - the actual frequency. - """ - def __init__(self, subdev_spec, decim, gain=None, calibration=0.0): - gr.hier_block2.__init__(self, "usrp_src", - gr.io_signature(0, 0, 0), # Input signature - gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature - - self._decim = decim - self._src = usrp.source_c() - if subdev_spec is None: - subdev_spec = usrp.pick_rx_subdevice(self._src) - self._subdev = usrp.selected_subdev(self._src, subdev_spec) - self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec)) - self._src.set_decim_rate(self._decim) - - # If no gain specified, set to midrange - if gain is None: - g = self._subdev.gain_range() - gain = (g[0]+g[1])/2.0 - - self._subdev.set_gain(gain) - self._cal = calibration - self.connect(self._src, self) - - def tune(self, freq): - result = usrp.tune(self._src, 0, self._subdev, freq+self._cal) - # TODO: deal with residual - - def rate(self): - return self._src.adc_rate()/self._decim - -class app_top_block(gr.top_block): - def __init__(self, options): - gr.top_block.__init__(self) - self.options = options - - (usrp_decim, channel_decim, audio_decim, - channel_pass, channel_stop, demod) = demod_params[options.modulation] - - USRP = usrp_src(options.rx_subdev_spec, # Daugherboard spec - usrp_decim, # IF decimation ratio - options.gain, # Receiver gain - options.calibration) # Frequency offset - USRP.tune(options.frequency) - - if_rate = USRP.rate() - channel_rate = if_rate // channel_decim - audio_rate = channel_rate // audio_decim - - CHAN_taps = optfir.low_pass(1.0, # Filter gain - if_rate, # Sample rate - channel_pass, # One sided modulation bandwidth - channel_stop, # One sided channel bandwidth - 0.1, # Passband ripple - 60) # Stopband attenuation - - CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate - CHAN_taps, # Filter taps - 0.0, # Offset frequency - if_rate) # Sample rate - - RFSQL = gr.pwr_squelch_cc(options.rf_squelch, # Power threshold - 125.0/channel_rate, # Time constant - channel_rate/20, # 50ms rise/fall - False) # Zero, not gate output - - AGC = gr.agc_cc(1.0/channel_rate, # Time constant - 1.0, # Reference power - 1.0, # Initial gain - 1.0) # Maximum gain - - DEMOD = demod(channel_rate, audio_decim) - - # From RF to audio - self.connect(USRP, CHAN, RFSQL, AGC, DEMOD) - - # Optionally add CTCSS and RSAMP if needed - tail = DEMOD - if options.ctcss != None and options.ctcss > 60.0: - CTCSS = gr.ctcss_squelch_ff(audio_rate, # Sample rate - options.ctcss) # Squelch tone - self.connect(DEMOD, CTCSS) - tail = CTCSS - - if options.output_rate != audio_rate: - out_lcm = gru.lcm(audio_rate, options.output_rate) - out_interp = int(out_lcm // audio_rate) - out_decim = int(out_lcm // options.output_rate) - RSAMP = blks2.rational_resampler_fff(out_interp, out_decim) - self.connect(tail, RSAMP) - tail = RSAMP - - # Send to default audio output - AUDIO = audio.sink(options.output_rate, "") - self.connect(tail, AUDIO) - -def main(): - parser = OptionParser(option_class=eng_option) - parser.add_option("-f", "--frequency", type="eng_float", default=None, - help="set receive frequency to Hz", metavar="Hz") - parser.add_option("-R", "--rx-subdev-spec", type="subdev", - help="select USRP Rx side A or B", metavar="SUBDEV") - parser.add_option("-c", "--calibration", type="eng_float", default=0.0, - help="set frequency offset to Hz", metavar="Hz") - parser.add_option("-g", "--gain", type="int", default=None, - help="set RF gain", metavar="dB") - parser.add_option("-m", "--modulation", type="choice", choices=('AM','FM','WFM'), - help="set modulation type (AM,FM)", metavar="TYPE") - parser.add_option("-o", "--output-rate", type="int", default=32000, - help="set audio output rate to RATE", metavar="RATE") - parser.add_option("-r", "--rf-squelch", type="eng_float", default=-50.0, - help="set RF squelch to dB", metavar="dB") - parser.add_option("-p", "--ctcss", type="float", - help="set CTCSS squelch to FREQ", metavar="FREQ") - (options, args) = parser.parse_args() - - if options.frequency is None: - print "Must supply receive frequency with -f" - sys.exit(1) - - if options.frequency < 1e6: - options.frequency *= 1e6 - - tb = app_top_block(options) - try: - tb.run() - except KeyboardInterrupt: - pass - -if __name__ == "__main__": - main() diff --git a/gr-utils/src/python/usrp_siggen.py b/gr-utils/src/python/usrp_siggen.py deleted file mode 100755 index da83da770..000000000 --- a/gr-utils/src/python/usrp_siggen.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -DESC_KEY = 'desc' -SAMP_RATE_KEY = 'samp_rate' -LINK_RATE_KEY = 'link_rate' -DAC_RATE_KEY = 'dac_rate' -INTERP_KEY = 'interp' -GAIN_KEY = 'gain' -TX_FREQ_KEY = 'tx_freq' -DDC_FREQ_KEY = 'ddc_freq' -BB_FREQ_KEY = 'bb_freq' -AMPLITUDE_KEY = 'amplitude' -AMPL_RANGE_KEY = 'ampl_range' -WAVEFORM_FREQ_KEY = 'waveform_freq' -WAVEFORM_OFFSET_KEY = 'waveform_offset' -WAVEFORM2_FREQ_KEY = 'waveform2_freq' -FREQ_RANGE_KEY = 'freq_range' -GAIN_RANGE_KEY = 'gain_range' -TYPE_KEY = 'type' - -def setter(ps, key, val): ps[key] = val - -from gnuradio import gr, eng_notation -from gnuradio.gr.pubsub import pubsub -from gnuradio.eng_option import eng_option -from gnuradio import usrp_options -from optparse import OptionParser -import sys -import math - -n2s = eng_notation.num_to_str - -waveforms = { gr.GR_SIN_WAVE : "Complex Sinusoid", - gr.GR_CONST_WAVE : "Constant", - gr.GR_GAUSSIAN : "Gaussian Noise", - gr.GR_UNIFORM : "Uniform Noise", - "2tone" : "Two Tone", - "sweep" : "Sweep" } - -# -# GUI-unaware GNU Radio flowgraph. This may be used either with command -# line applications or GUI applications. -# -class top_block(gr.top_block, pubsub): - def __init__(self, options, args): - gr.top_block.__init__(self) - pubsub.__init__(self) - self._verbose = options.verbose - #initialize values from options - self._setup_usrpx(options) - self.subscribe(INTERP_KEY, lambda i: setter(self, SAMP_RATE_KEY, self[DAC_RATE_KEY]/i)) - self.subscribe(SAMP_RATE_KEY, lambda e: setter(self, LINK_RATE_KEY, e*32)) - self[INTERP_KEY] = options.interp or 16 - self[TX_FREQ_KEY] = options.tx_freq - self[AMPLITUDE_KEY] = options.amplitude - self[WAVEFORM_FREQ_KEY] = options.waveform_freq - self[WAVEFORM_OFFSET_KEY] = options.offset - self[WAVEFORM2_FREQ_KEY] = options.waveform2_freq - self[BB_FREQ_KEY] = 0 - self[DDC_FREQ_KEY] = 0 - #subscribe set methods - self.subscribe(INTERP_KEY, self.set_interp) - self.subscribe(GAIN_KEY, self.set_gain) - self.subscribe(TX_FREQ_KEY, self.set_freq) - self.subscribe(AMPLITUDE_KEY, self.set_amplitude) - self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) - self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) - self.subscribe(TYPE_KEY, self.set_waveform) - #force update on pubsub keys - for key in (INTERP_KEY, GAIN_KEY, TX_FREQ_KEY, - AMPLITUDE_KEY, WAVEFORM_FREQ_KEY, WAVEFORM_OFFSET_KEY, WAVEFORM2_FREQ_KEY): - self[key] = self[key] - self[TYPE_KEY] = options.type #set type last - - def _setup_usrpx(self, options): - self._u = usrp_options.create_usrp_sink(options) - self.publish(DESC_KEY, lambda: str(self._u)) - self.publish(DAC_RATE_KEY, self._u.dac_rate) - self.publish(FREQ_RANGE_KEY, self._u.freq_range) - self.publish(GAIN_RANGE_KEY, self._u.gain_range) - self.publish(GAIN_KEY, self._u.gain) - if self._verbose: print str(self._u) - - def _set_tx_amplitude(self, ampl): - """ - Sets the transmit amplitude sent to the USRP - @param ampl the amplitude or None for automatic - """ - ampl_range = self[AMPL_RANGE_KEY] - if ampl is None: ampl = (ampl_range[1] - ampl_range[0])*0.15 + ampl_range[0] - self[AMPLITUDE_KEY] = max(ampl_range[0], min(ampl, ampl_range[1])) - - def set_interp(self, interp): - if not self._u.set_interp(interp): - raise RuntimeError("Failed to set interpolation rate %i" % (interp,)) - - if self._verbose: - print "USRP interpolation rate:", interp - print "USRP IF bandwidth: %sHz" % (n2s(self[SAMP_RATE_KEY]),) - - if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE): - self._src.set_sampling_freq(self[SAMP_RATE_KEY]) - elif self[TYPE_KEY] == "2tone": - self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) - self._src2.set_sampling_freq(self[SAMP_RATE_KEY]) - elif self[TYPE_KEY] == "sweep": - self._src1.set_sampling_freq(self[SAMP_RATE_KEY]) - self._src2.set_sampling_freq(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) - else: - return True # Waveform not yet set - - if self._verbose: print "Set interpolation rate to:", interp - return True - - def set_gain(self, gain): - if gain is None: - g = self[GAIN_RANGE_KEY] - gain = float(g[0]+g[1])/2 - if self._verbose: - print "Using auto-calculated mid-point TX gain" - self[GAIN_KEY] = gain - return - self._u.set_gain(gain) - if self._verbose: - print "Set TX gain to:", gain - - def set_freq(self, target_freq): - - if target_freq is None: - f = self[FREQ_RANGE_KEY] - target_freq = float(f[0]+f[1])/2.0 - if self._verbose: - print "Using auto-calculated mid-point frequency" - self[TX_FREQ_KEY] = target_freq - return - - tr = self._u.set_center_freq(target_freq) - fs = "%sHz" % (n2s(target_freq),) - if tr is not None: - self._freq = target_freq - self[DDC_FREQ_KEY] = tr.dxc_freq - self[BB_FREQ_KEY] = tr.baseband_freq - if self._verbose: - print "Set center frequency to", fs - print "Tx baseband frequency: %sHz" % (n2s(tr.baseband_freq),) - print "Tx DDC frequency: %sHz" % (n2s(tr.dxc_freq),) - print "Tx residual frequency: %sHz" % (n2s(tr.residual_freq),) - elif self._verbose: print "Failed to set freq." - return tr - - def set_waveform_freq(self, freq): - if self[TYPE_KEY] == gr.GR_SIN_WAVE: - self._src.set_frequency(freq) - elif self[TYPE_KEY] == "2tone": - self._src1.set_frequency(freq) - elif self[TYPE_KEY] == 'sweep': - #there is no set sensitivity, redo fg - self[TYPE_KEY] = self[TYPE_KEY] - return True - - def set_waveform2_freq(self, freq): - if freq is None: - self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] - return - if self[TYPE_KEY] == "2tone": - self._src2.set_frequency(freq) - elif self[TYPE_KEY] == "sweep": - self._src1.set_frequency(freq) - return True - - def set_waveform(self, type): - self.lock() - self.disconnect_all() - if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: - self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate - type, # Waveform type - self[WAVEFORM_FREQ_KEY], # Waveform frequency - self[AMPLITUDE_KEY], # Waveform amplitude - self[WAVEFORM_OFFSET_KEY]) # Waveform offset - elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: - self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) - elif type == "2tone": - self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], - gr.GR_SIN_WAVE, - self[WAVEFORM_FREQ_KEY], - self[AMPLITUDE_KEY]/2.0, - 0) - if(self[WAVEFORM2_FREQ_KEY] is None): - self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] - - self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], - gr.GR_SIN_WAVE, - self[WAVEFORM2_FREQ_KEY], - self[AMPLITUDE_KEY]/2.0, - 0) - self._src = gr.add_cc() - self.connect(self._src1,(self._src,0)) - self.connect(self._src2,(self._src,1)) - elif type == "sweep": - # rf freq is center frequency - # waveform_freq is total swept width - # waveform2_freq is sweep rate - # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) - if self[WAVEFORM2_FREQ_KEY] is None: - self[WAVEFORM2_FREQ_KEY] = 0.1 - - self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], - gr.GR_TRI_WAVE, - self[WAVEFORM2_FREQ_KEY], - 1.0, - -0.5) - self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) - self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) - self.connect(self._src1,self._src2,self._src) - else: - raise RuntimeError("Unknown waveform type") - - self.connect(self._src, self._u) - self.unlock() - - if self._verbose: - print "Set baseband modulation to:", waveforms[type] - if type == gr.GR_SIN_WAVE: - print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) - print "Initial phase:", self[WAVEFORM_OFFSET_KEY] - elif type == "2tone": - print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) - print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) - elif type == "sweep": - print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) - print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) - print "TX amplitude:", self[AMPLITUDE_KEY] - - - def set_amplitude(self, amplitude): - if amplitude < 0.0 or amplitude > 1.0: - if self._verbose: print "Amplitude out of range:", amplitude - return False - - if self[TYPE_KEY] in (gr.GR_SIN_WAVE, gr.GR_CONST_WAVE, gr.GR_GAUSSIAN, gr.GR_UNIFORM): - self._src.set_amplitude(amplitude) - elif self[TYPE_KEY] == "2tone": - self._src1.set_amplitude(amplitude/2.0) - self._src2.set_amplitude(amplitude/2.0) - elif self[TYPE_KEY] == "sweep": - self._src.set_k(amplitude) - else: - return True # Waveform not yet set - - if self._verbose: print "Set amplitude to:", amplitude - return True - -def get_options(): - usage="%prog: [options]" - - parser = OptionParser(option_class=eng_option, usage=usage) - usrp_options.add_tx_options(parser) - parser.add_option("-f", "--tx-freq", type="eng_float", default=None, - help="Set carrier frequency to FREQ [default=mid-point]", metavar="FREQ") - parser.add_option("-x", "--waveform-freq", type="eng_float", default=0, - help="Set baseband waveform frequency to FREQ [default=%default]") - parser.add_option("-y", "--waveform2-freq", type="eng_float", default=None, - help="Set 2nd waveform frequency to FREQ [default=%default]") - parser.add_option("--sine", dest="type", action="store_const", const=gr.GR_SIN_WAVE, - help="Generate a carrier modulated by a complex sine wave", default=gr.GR_SIN_WAVE) - parser.add_option("--const", dest="type", action="store_const", const=gr.GR_CONST_WAVE, - help="Generate a constant carrier") - parser.add_option("--offset", type="eng_float", default=0, - help="Set waveform phase offset to OFFSET [default=%default]") - parser.add_option("--gaussian", dest="type", action="store_const", const=gr.GR_GAUSSIAN, - help="Generate Gaussian random output") - parser.add_option("--uniform", dest="type", action="store_const", const=gr.GR_UNIFORM, - help="Generate Uniform random output") - parser.add_option("--2tone", dest="type", action="store_const", const="2tone", - help="Generate Two Tone signal for IMD testing") - parser.add_option("--sweep", dest="type", action="store_const", const="sweep", - help="Generate a swept sine wave") - parser.add_option("-A", "--amplitude", type="eng_float", default=0.15, - help="Set output amplitude to AMPL (0.0-1.0) [default=%default]", metavar="AMPL") - parser.add_option("-v", "--verbose", action="store_true", default=False, - help="Use verbose console output [default=%default]") - - (options, args) = parser.parse_args() - - return (options, args) - -# If this script is executed, the following runs. If it is imported, the below does not run. -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) = get_options() - tb = top_block(options, args) - - except RuntimeError, e: - print e - sys.exit(1) - - tb.start() - raw_input('Press Enter to quit: ') - tb.stop() - tb.wait() - -# Make sure to create the top block (tb) within a function: -# That code in main will allow tb to go out of scope on return, -# which will call the decontructor on 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() diff --git a/gr-utils/src/python/usrp_siggen_gui.py b/gr-utils/src/python/usrp_siggen_gui.py deleted file mode 100755 index 47d47bdb3..000000000 --- a/gr-utils/src/python/usrp_siggen_gui.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import wx -from gnuradio import gr -from gnuradio.gr.pubsub import pubsub -from gnuradio.wxgui import gui, forms -import usrp_siggen -import sys, math - -class app_gui(pubsub): - def __init__(self, frame, panel, vbox, top_block, options, args): - pubsub.__init__(self) - self.frame = frame # Use for top-level application window frame - self.panel = panel # Use as parent class for created windows - self.vbox = vbox # Use as sizer for created windows - self.tb = top_block # GUI-unaware flowgraph class - self.options = options # Supplied command-line options - self.args = args # Supplied command-line arguments - self.build_gui() - - # Event response handlers - def evt_set_status_msg(self, msg): - self.frame.SetStatusText(msg, 0) - - # GUI construction - def build_gui(self): - self.vbox.AddSpacer(5) - self.vbox.AddStretchSpacer() - ################################################## - # Baseband controls - ################################################## - bb_vbox = forms.static_box_sizer(parent=self.panel, label="Baseband Modulation", orient=wx.VERTICAL, bold=True) - self.vbox.Add(bb_vbox, 0, wx.EXPAND) - sine_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - sweep_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - tone_bb_hbox = wx.BoxSizer(wx.HORIZONTAL) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - #callback to show/hide forms - def set_type(type): - sine_bb_hbox.ShowItems(type == gr.GR_SIN_WAVE) - sweep_bb_hbox.ShowItems(type == 'sweep') - tone_bb_hbox.ShowItems(type == '2tone') - self.vbox.Layout() - self.tb.subscribe(usrp_siggen.TYPE_KEY, set_type) - #create sine forms - sine_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=sine_bb_hbox, - label='Frequency (Hz)', - ps=self.tb, - key=usrp_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), - ) - sine_bb_hbox.AddStretchSpacer() - #create sweep forms - sweep_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=sweep_bb_hbox, - label='Sweep Width (Hz)', - ps=self.tb, - key=usrp_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), - ) - sweep_bb_hbox.AddStretchSpacer() - forms.text_box( - parent=self.panel, sizer=sweep_bb_hbox, - label='Sweep Rate (Hz)', - ps=self.tb, - key=usrp_siggen.WAVEFORM2_FREQ_KEY, - converter=forms.float_converter(), - ) - sweep_bb_hbox.AddStretchSpacer() - #create 2tone forms - tone_bb_hbox.AddSpacer(10) - forms.text_box( - parent=self.panel, sizer=tone_bb_hbox, - label='Tone 1 (Hz)', - ps=self.tb, - key=usrp_siggen.WAVEFORM_FREQ_KEY, - converter=forms.float_converter(), - ) - tone_bb_hbox.AddStretchSpacer() - forms.text_box( - parent=self.panel, sizer=tone_bb_hbox, - label='Tone 2 (Hz)', - ps=self.tb, - key=usrp_siggen.WAVEFORM2_FREQ_KEY, - converter=forms.float_converter(), - ) - tone_bb_hbox.AddStretchSpacer() - forms.radio_buttons( - parent=self.panel, sizer=bb_vbox, - choices=usrp_siggen.waveforms.keys(), - labels=usrp_siggen.waveforms.values(), - ps=self.tb, - key=usrp_siggen.TYPE_KEY, - style=wx.NO_BORDER | wx.RA_HORIZONTAL, - ) - bb_vbox.AddSpacer(10) - bb_vbox.Add(sine_bb_hbox, 0, wx.EXPAND) - bb_vbox.Add(sweep_bb_hbox, 0, wx.EXPAND) - bb_vbox.Add(tone_bb_hbox, 0, wx.EXPAND) - set_type(self.tb[usrp_siggen.TYPE_KEY]) - ################################################## - # Frequency controls - ################################################## - fc_vbox = forms.static_box_sizer(parent=self.panel, label="Center Frequency", orient=wx.VERTICAL, bold=True) - fc_vbox.AddSpacer(5) - # First row of frequency controls (center frequency) - freq_hbox = wx.BoxSizer(wx.HORIZONTAL) - fc_vbox.Add(freq_hbox, 0, wx.EXPAND) - fc_vbox.AddSpacer(10) - # Second row of frequency controls (results) - tr_hbox = wx.BoxSizer(wx.HORIZONTAL) - fc_vbox.Add(tr_hbox, 0, wx.EXPAND) - fc_vbox.AddSpacer(5) - # Add frequency controls to top window sizer - self.vbox.Add(fc_vbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - freq_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=freq_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=usrp_siggen.TX_FREQ_KEY, - ) - freq_hbox.AddSpacer(10) - forms.slider( - parent=self.panel, sizer=freq_hbox, - proportion=2, - ps=self.tb, - key=usrp_siggen.TX_FREQ_KEY, - minimum=self.tb[usrp_siggen.FREQ_RANGE_KEY][0], - maximum=self.tb[usrp_siggen.FREQ_RANGE_KEY][1], - num_steps=100, - ) - freq_hbox.AddSpacer(5) - tr_hbox.AddSpacer(5) - forms.static_text( - parent=self.panel, sizer=tr_hbox, - label='Daughterboard (Hz)', - ps=self.tb, - key=usrp_siggen.BB_FREQ_KEY, - converter=forms.float_converter(), - proportion=1, - ) - tr_hbox.AddSpacer(10) - forms.static_text( - parent=self.panel, sizer=tr_hbox, - label='USRP DDC (Hz)', - ps=self.tb, - key=usrp_siggen.DDC_FREQ_KEY, - converter=forms.float_converter(), - proportion=1, - ) - tr_hbox.AddSpacer(5) - ################################################## - # Amplitude controls - ################################################## - amp_hbox = forms.static_box_sizer(parent=self.panel, label="Amplitude", orient=wx.VERTICAL, bold=True) - amp_hbox.AddSpacer(5) - # First row of amp controls (ampl) - lvl_hbox = wx.BoxSizer(wx.HORIZONTAL) - amp_hbox.Add(lvl_hbox, 0, wx.EXPAND) - amp_hbox.AddSpacer(10) - # Second row of amp controls (tx gain) - gain_hbox = wx.BoxSizer(wx.HORIZONTAL) - amp_hbox.Add(gain_hbox, 0, wx.EXPAND) - amp_hbox.AddSpacer(5) - self.vbox.Add(amp_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - lvl_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=lvl_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=usrp_siggen.AMPLITUDE_KEY, - label="Level (0.0-1.0)", - ) - lvl_hbox.AddSpacer(10) - forms.log_slider( - parent=self.panel, sizer=lvl_hbox, - proportion=2, - ps=self.tb, - key=usrp_siggen.AMPLITUDE_KEY, - min_exp=-6, - max_exp=0, - base=10, - num_steps=100, - ) - lvl_hbox.AddSpacer(5) - if self.tb[usrp_siggen.GAIN_RANGE_KEY][0] < self.tb[usrp_siggen.GAIN_RANGE_KEY][1]: - gain_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=gain_hbox, - proportion=1, - converter=forms.float_converter(), - ps=self.tb, - key=usrp_siggen.GAIN_KEY, - label="TX Gain (dB)", - ) - gain_hbox.AddSpacer(10) - forms.slider( - parent=self.panel, sizer=gain_hbox, - proportion=2, - ps=self.tb, - key=usrp_siggen.GAIN_KEY, - minimum=self.tb[usrp_siggen.GAIN_RANGE_KEY][0], - maximum=self.tb[usrp_siggen.GAIN_RANGE_KEY][1], - step_size=self.tb[usrp_siggen.GAIN_RANGE_KEY][2], - ) - gain_hbox.AddSpacer(5) - ################################################## - # Sample Rate controls - ################################################## - sam_hbox = forms.static_box_sizer(parent=self.panel, label="Sample Rate", orient=wx.HORIZONTAL, bold=True) - self.vbox.Add(sam_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - sam_hbox.AddSpacer(5) - forms.text_box( - parent=self.panel, sizer=sam_hbox, - converter=forms.int_converter(), - ps=self.tb, - key=usrp_siggen.INTERP_KEY, - label="Interpolation", - ) - sam_hbox.AddStretchSpacer(20) - forms.static_text( - parent=self.panel, sizer=sam_hbox, - label='Sample Rate (sps)', - ps=self.tb, - key=usrp_siggen.SAMP_RATE_KEY, - converter=forms.float_converter(), - ) - sam_hbox.AddStretchSpacer(20) - forms.static_text( - parent=self.panel, sizer=sam_hbox, - label='Link Rate (bits/sec)', - ps=self.tb, - key=usrp_siggen.LINK_RATE_KEY, - converter=forms.float_converter(), - ) - sam_hbox.AddSpacer(5) - ################################################## - # USRP status - ################################################## - u2_hbox = forms.static_box_sizer(parent=self.panel, label="USRP Status", orient=wx.HORIZONTAL, bold=True) - self.vbox.Add(u2_hbox, 0, wx.EXPAND) - self.vbox.AddSpacer(10) - self.vbox.AddStretchSpacer() - u2_hbox.AddSpacer(10) - forms.static_text( - parent=self.panel, sizer=u2_hbox, - ps=self.tb, - key=usrp_siggen.DESC_KEY, - converter=forms.str_converter(), - ) - self.vbox.AddSpacer(5) - self.vbox.AddStretchSpacer() - -def main(): - try: - # Get command line parameters - (options, args) = usrp_siggen.get_options() - - # Create the top block using these - tb = usrp_siggen.top_block(options, args) - - # Create the GUI application - app = gui.app(top_block=tb, # Constructed top block - gui=app_gui, # User interface class - options=options, # Command line options - args=args, # Command line args - title="USRP Signal Generator", # Top window title - nstatus=1, # Number of status lines - start=True, # Whether to start flowgraph - realtime=True) # Whether to set realtime priority - - # And run it - app.MainLoop() - - except RuntimeError, e: - print e - sys.exit(1) - -# 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() -- cgit From f4ed279bba9924bf63b9b883906e7c83887fb3fe Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 20 Oct 2011 14:40:15 -0700 Subject: utils: added cmake support for the gr-utils --- gr-utils/src/python/CMakeLists.txt | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 gr-utils/src/python/CMakeLists.txt (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/CMakeLists.txt b/gr-utils/src/python/CMakeLists.txt new file mode 100644 index 000000000..fba0d57a5 --- /dev/null +++ b/gr-utils/src/python/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright 2011 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. + +######################################################################## +# Install python files and apps +######################################################################## +include(GrPython) + +GR_PYTHON_INSTALL( + FILES + plot_data.py + pyqt_plot.py + pyqt_filter.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio + COMPONENT "utils" +) + +GR_PYTHON_INSTALL( + PROGRAMS + create-gnuradio-out-of-tree-project + gr_plot_char.py + gr_plot_const.py + gr_plot_fft.py + gr_plot_fft_c.py + gr_plot_fft_f.py + gr_plot_psd.py + gr_plot_psd_c.py + gr_plot_psd_f.py + gr_plot_float.py + gr_plot_int.py + gr_plot_iq.py + gr_plot_short.py + gr_plot_qt.py + gr_filter_design.py + DESTINATION ${GR_RUNTIME_DIR} + COMPONENT "utils" +) -- cgit From 00420d32081d8252bb37142b2be19a8a7c4dc4c4 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Thu, 8 Dec 2011 13:48:48 -0800 Subject: Removed autotools, gr-waveform, some cleanup Nick Foster owes Nick Corgan a six-pack of beer! --- gr-utils/src/python/.gitignore | 3 --- gr-utils/src/python/Makefile.am | 52 ----------------------------------------- 2 files changed, 55 deletions(-) delete mode 100644 gr-utils/src/python/.gitignore delete mode 100644 gr-utils/src/python/Makefile.am (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/.gitignore b/gr-utils/src/python/.gitignore deleted file mode 100644 index b6950912c..000000000 --- a/gr-utils/src/python/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/Makefile -/Makefile.in -/*.pyc diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am deleted file mode 100644 index 11fb038f6..000000000 --- a/gr-utils/src/python/Makefile.am +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright 2007,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/Makefile.common - -EXTRA_DIST += \ - $(bin_SCRIPTS) \ - README.plot \ - pyqt_plot.ui \ - pyqt_filter.ui - -ourpythondir = $(grpythondir) - -ourpython_PYTHON = \ - plot_data.py \ - pyqt_plot.py \ - pyqt_filter.py - -bin_SCRIPTS = \ - create-gnuradio-out-of-tree-project \ - gr_plot_char.py \ - gr_plot_const.py \ - gr_plot_fft.py \ - gr_plot_fft_c.py \ - gr_plot_fft_f.py \ - gr_plot_psd.py \ - gr_plot_psd_c.py \ - gr_plot_psd_f.py \ - gr_plot_float.py \ - gr_plot_int.py \ - gr_plot_iq.py \ - gr_plot_short.py \ - gr_plot_qt.py \ - gr_filter_design.py -- cgit From 1ca78cb621cbd60f25c5ce4373fa727114a86cee Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 1 Apr 2012 17:16:41 -0400 Subject: build: removed .py extensions from installed Python plot programs. The fft and psd bases have been moved into the Python packages directory and new wrappers for data-type independent programs have been created. --- gr-utils/src/python/CMakeLists.txt | 30 +- gr-utils/src/python/README.plot | 95 +++- gr-utils/src/python/gr_filter_design | 874 ++++++++++++++++++++++++++++++++ gr-utils/src/python/gr_filter_design.py | 874 -------------------------------- gr-utils/src/python/gr_plot_char | 58 +++ gr-utils/src/python/gr_plot_char.py | 58 --- gr-utils/src/python/gr_plot_const | 250 +++++++++ gr-utils/src/python/gr_plot_const.py | 250 --------- gr-utils/src/python/gr_plot_fft | 42 ++ gr-utils/src/python/gr_plot_fft.py | 248 --------- gr-utils/src/python/gr_plot_fft_c | 46 ++ gr-utils/src/python/gr_plot_fft_c.py | 44 -- gr-utils/src/python/gr_plot_fft_f | 46 ++ gr-utils/src/python/gr_plot_fft_f.py | 44 -- gr-utils/src/python/gr_plot_float | 58 +++ gr-utils/src/python/gr_plot_float.py | 58 --- gr-utils/src/python/gr_plot_int | 58 +++ gr-utils/src/python/gr_plot_int.py | 58 --- gr-utils/src/python/gr_plot_iq | 178 +++++++ gr-utils/src/python/gr_plot_iq.py | 178 ------- gr-utils/src/python/gr_plot_psd | 42 ++ gr-utils/src/python/gr_plot_psd.py | 291 ----------- gr-utils/src/python/gr_plot_psd_c | 47 ++ gr-utils/src/python/gr_plot_psd_c.py | 47 -- gr-utils/src/python/gr_plot_psd_f | 47 ++ gr-utils/src/python/gr_plot_psd_f.py | 47 -- gr-utils/src/python/gr_plot_qt | 729 ++++++++++++++++++++++++++ gr-utils/src/python/gr_plot_qt.py | 729 -------------------------- gr-utils/src/python/gr_plot_short | 58 +++ gr-utils/src/python/gr_plot_short.py | 58 --- gr-utils/src/python/plot_fft_base.py | 249 +++++++++ gr-utils/src/python/plot_psd_base.py | 292 +++++++++++ 32 files changed, 3166 insertions(+), 3017 deletions(-) create mode 100755 gr-utils/src/python/gr_filter_design delete mode 100755 gr-utils/src/python/gr_filter_design.py create mode 100755 gr-utils/src/python/gr_plot_char delete mode 100755 gr-utils/src/python/gr_plot_char.py create mode 100755 gr-utils/src/python/gr_plot_const delete mode 100755 gr-utils/src/python/gr_plot_const.py create mode 100644 gr-utils/src/python/gr_plot_fft delete mode 100755 gr-utils/src/python/gr_plot_fft.py create mode 100755 gr-utils/src/python/gr_plot_fft_c delete mode 100755 gr-utils/src/python/gr_plot_fft_c.py create mode 100755 gr-utils/src/python/gr_plot_fft_f delete mode 100755 gr-utils/src/python/gr_plot_fft_f.py create mode 100755 gr-utils/src/python/gr_plot_float delete mode 100755 gr-utils/src/python/gr_plot_float.py create mode 100755 gr-utils/src/python/gr_plot_int delete mode 100755 gr-utils/src/python/gr_plot_int.py create mode 100755 gr-utils/src/python/gr_plot_iq delete mode 100755 gr-utils/src/python/gr_plot_iq.py create mode 100644 gr-utils/src/python/gr_plot_psd delete mode 100755 gr-utils/src/python/gr_plot_psd.py create mode 100755 gr-utils/src/python/gr_plot_psd_c delete mode 100755 gr-utils/src/python/gr_plot_psd_c.py create mode 100755 gr-utils/src/python/gr_plot_psd_f delete mode 100755 gr-utils/src/python/gr_plot_psd_f.py create mode 100755 gr-utils/src/python/gr_plot_qt delete mode 100755 gr-utils/src/python/gr_plot_qt.py create mode 100755 gr-utils/src/python/gr_plot_short delete mode 100755 gr-utils/src/python/gr_plot_short.py create mode 100755 gr-utils/src/python/plot_fft_base.py create mode 100755 gr-utils/src/python/plot_psd_base.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/CMakeLists.txt b/gr-utils/src/python/CMakeLists.txt index fba0d57a5..90caeb234 100644 --- a/gr-utils/src/python/CMakeLists.txt +++ b/gr-utils/src/python/CMakeLists.txt @@ -25,6 +25,8 @@ include(GrPython) GR_PYTHON_INSTALL( FILES plot_data.py + plot_fft_base.py + plot_psd_base.py pyqt_plot.py pyqt_filter.py DESTINATION ${GR_PYTHON_DIR}/gnuradio @@ -34,20 +36,20 @@ GR_PYTHON_INSTALL( GR_PYTHON_INSTALL( PROGRAMS create-gnuradio-out-of-tree-project - gr_plot_char.py - gr_plot_const.py - gr_plot_fft.py - gr_plot_fft_c.py - gr_plot_fft_f.py - gr_plot_psd.py - gr_plot_psd_c.py - gr_plot_psd_f.py - gr_plot_float.py - gr_plot_int.py - gr_plot_iq.py - gr_plot_short.py - gr_plot_qt.py - gr_filter_design.py + gr_plot_char + gr_plot_const + gr_plot_fft + gr_plot_fft_c + gr_plot_fft_f + gr_plot_psd + gr_plot_psd_c + gr_plot_psd_f + gr_plot_float + gr_plot_int + gr_plot_iq + gr_plot_short + gr_plot_qt + gr_filter_design DESTINATION ${GR_RUNTIME_DIR} COMPONENT "utils" ) diff --git a/gr-utils/src/python/README.plot b/gr-utils/src/python/README.plot index 0c4657ba9..60f14c669 100644 --- a/gr-utils/src/python/README.plot +++ b/gr-utils/src/python/README.plot @@ -1,40 +1,97 @@ -* gr_plot_*.py: -These are a collection of Python scripts to enable viewing and analysis of files produced by GNU Radio flow graphs. Most of them work off complex data produced by digital waveforms. +* gr_plot_*: +These are a collection of Python scripts to enable viewing and +analysis of files produced by GNU Radio flow graphs. Most of them work +off complex data produced by digital waveforms. -** gr_plot_float.py: -Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. +** gr_plot_float: +Takes a GNU Radio floating point binary file and displays the samples +versus time. You can set the block size to specify how many points to +read in at a time and the start position in the file. -By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time axis, +set the sample rate (-R or --sample-rate) to the sample rate used when +capturing the samples. -** gr_plot_iq.py: -Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. +** gr_plot_iq: +Takes a GNU Radio complex binary file and displays the I&Q data versus +time. You can set the block size to specify how many points to read in +at a time and the start position in the file. -By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time axis, +set the sample rate (-R or --sample-rate) to the sample rate used when +capturing the samples. -** gr_plot_const.py: -Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. +** gr_plot_const: +Takes a GNU Radio complex binary file and displays the I&Q data versus +time and the constellation plot (I vs. Q). You can set the block size +to specify how many points to read in at a time and the start position +in the file. -By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time axis, +set the sample rate (-R or --sample-rate) to the sample rate used when +capturing the samples. -** gr_plot_fft_c.py: -Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). +** gr_plot_fft_c: +Takes a GNU Radio complex binary file and displays the I&Q data versus +time as well as the frequency domain (FFT) plot. The y-axis values are +plotted assuming volts as the amplitude of the I&Q streams and +converted into dBm in the frequency domain (the 1/N power adjustment +out of the FFT is performed internally). -The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). +The script plots a certain block of data at a time, specified on the +command line as -B or --block. This value defaults to 1000. The start +position in the file can be set by specifying -s or --start and +defaults to 0 (the start of the file). -By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time and +frequency axis, set the sample rate (-R or --sample-rate) to the +sample rate used when capturing the samples. -** gr_plot_fft_f.py: -Takes a GNU Radio floating point binary file and displays the samples versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). +** gr_plot_fft_f: +Takes a GNU Radio floating point binary file and displays the samples +versus time as well as the frequency domain (FFT) plot. The y-axis +values are plotted assuming volts as the amplitude of the I&Q streams +and converted into dBm in the frequency domain (the 1/N power +adjustment out of the FFT is performed internally). -The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). +The script plots a certain block of data at a time, specified on the +command line as -B or --block. This value defaults to 1000. The start +position in the file can be set by specifying -s or --start and +defaults to 0 (the start of the file). -By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time and +frequency axis, set the sample rate (-R or --sample-rate) to the +sample rate used when capturing the samples. + + +** gr_plot_fft: +Takes a GNU Radio binary file (the datatype is specified using the -d +option and defaults to complex64) and displays the samples versus time +as well as the frequency domain (FFT) plot. The y-axis values are +plotted assuming volts as the amplitude of the I&Q streams and +converted into dBm in the frequency domain (the 1/N power adjustment +out of the FFT is performed internally). + +The script plots a certain block of data at a time, specified on the +command line as -B or --block. This value defaults to 1000. The start +position in the file can be set by specifying -s or --start and +defaults to 0 (the start of the file). + +By default, the system assumes a sample rate of 1, so in time, each +sample is plotted versus the sample number. To set a true time and +frequency axis, set the sample rate (-R or --sample-rate) to the +sample rate used when capturing the samples. diff --git a/gr-utils/src/python/gr_filter_design b/gr-utils/src/python/gr_filter_design new file mode 100755 index 000000000..e8703db4f --- /dev/null +++ b/gr-utils/src/python/gr_filter_design @@ -0,0 +1,874 @@ +#!/usr/bin/env python + +import sys, os, re, csv +from optparse import OptionParser +from gnuradio import gr, blks2, eng_notation + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + from gnuradio.pyqt_filter import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" + raise SystemExit, 1 + + +class gr_plot_filter(QtGui.QMainWindow): + def __init__(self, qapp, options): + QtGui.QWidget.__init__(self, None) + self.gui = Ui_MainWindow() + self.gui.setupUi(self) + + self.connect(self.gui.action_save, + Qt.SIGNAL("activated()"), + self.action_save_dialog) + self.connect(self.gui.action_open, + Qt.SIGNAL("activated()"), + self.action_open_dialog) + + + self.connect(self.gui.filterTypeComboBox, + Qt.SIGNAL("currentIndexChanged(const QString&)"), + self.changed_filter_type) + self.connect(self.gui.filterDesignTypeComboBox, + Qt.SIGNAL("currentIndexChanged(const QString&)"), + self.changed_filter_design_type) + + self.connect(self.gui.designButton, + Qt.SIGNAL("released()"), + self.design) + + self.connect(self.gui.tabGroup, + Qt.SIGNAL("currentChanged(int)"), + self.tab_changed) + + self.connect(self.gui.nfftEdit, + Qt.SIGNAL("textEdited(QString)"), + self.nfft_edit_changed) + + self.gui.designButton.setShortcut(QtCore.Qt.Key_Return) + + self.taps = [] + self.fftdB = [] + self.fftDeg = [] + self.groupDelay = [] + self.nfftpts = int(10000) + self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts)) + + self.firFilters = ("Low Pass", "Band Pass", "Complex Band Pass", "Band Notch", + "High Pass", "Root Raised Cosine", "Gaussian") + self.optFilters = ("Low Pass", "Band Pass", "Complex Band Pass", + "Band Notch", "High Pass") + + self.set_windowed() + + # Initialize to LPF + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + + # Set Axis labels + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, + "Frequency (Hz)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, + "Magnitude (dB)") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, + "Tap number") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, + "Amplitude") + self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.xBottom, + "Frequency (Hz)") + self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.yLeft, + "Phase (Radians)") + self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.xBottom, + "Frequency (Hz)") + self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.yLeft, + "Delay (sec)") + + # Set up plot curves + self.rcurve = Qwt.QwtPlotCurve("Real") + self.rcurve.attach(self.gui.timePlot) + self.icurve = Qwt.QwtPlotCurve("Imag") + self.icurve.attach(self.gui.timePlot) + + self.freqcurve = Qwt.QwtPlotCurve("PSD") + self.freqcurve.attach(self.gui.freqPlot) + + self.phasecurve = Qwt.QwtPlotCurve("Phase") + self.phasecurve.attach(self.gui.phasePlot) + + self.groupcurve = Qwt.QwtPlotCurve("Group Delay") + self.groupcurve.attach(self.gui.groupPlot) + + # Create zoom functionality for the plots + self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, + self.gui.timePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.timePlot.canvas()) + + self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, + self.gui.freqPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.freqPlot.canvas()) + + self.phaseZoomer = Qwt.QwtPlotZoomer(self.gui.phasePlot.xBottom, + self.gui.phasePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.phasePlot.canvas()) + + self.groupZoomer = Qwt.QwtPlotZoomer(self.gui.groupPlot.xBottom, + self.gui.groupPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.groupPlot.canvas()) + + # Set up pen for colors and line width + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + blueBrush = Qt.QBrush(Qt.QColor(blue)) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + redBrush = Qt.QBrush(Qt.QColor(red)) + self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) + self.rcurve.setPen(Qt.QPen(blueBrush, 2)) + self.icurve.setPen(Qt.QPen(redBrush, 2)) + self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) + self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) + + # Set up validators for edit boxes + self.intVal = Qt.QIntValidator(None) + self.dblVal = Qt.QDoubleValidator(None) + self.gui.nfftEdit.setValidator(self.intVal) + self.gui.sampleRateEdit.setValidator(self.dblVal) + self.gui.filterGainEdit.setValidator(self.dblVal) + self.gui.endofLpfPassBandEdit.setValidator(self.dblVal) + self.gui.startofLpfStopBandEdit.setValidator(self.dblVal) + self.gui.lpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.lpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.startofBpfPassBandEdit.setValidator(self.dblVal) + self.gui.endofBpfPassBandEdit.setValidator(self.dblVal) + self.gui.bpfTransitionEdit.setValidator(self.dblVal) + self.gui.bpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.bpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.startofBnfStopBandEdit.setValidator(self.dblVal) + self.gui.endofBnfStopBandEdit.setValidator(self.dblVal) + self.gui.bnfTransitionEdit.setValidator(self.dblVal) + self.gui.bnfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.bnfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.endofHpfStopBandEdit.setValidator(self.dblVal) + self.gui.startofHpfPassBandEdit.setValidator(self.dblVal) + self.gui.hpfStopBandAttenEdit.setValidator(self.dblVal) + self.gui.hpfPassBandRippleEdit.setValidator(self.dblVal) + self.gui.rrcSymbolRateEdit.setValidator(self.dblVal) + self.gui.rrcAlphaEdit.setValidator(self.dblVal) + self.gui.rrcNumTapsEdit.setValidator(self.dblVal) + self.gui.gausSymbolRateEdit.setValidator(self.dblVal) + self.gui.gausBTEdit.setValidator(self.dblVal) + self.gui.gausNumTapsEdit.setValidator(self.dblVal) + + self.gui.nTapsEdit.setText("0") + + self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING, + "Hann Window" : gr.firdes.WIN_HANN, + "Blackman Window" : gr.firdes.WIN_BLACKMAN, + "Rectangular Window" : gr.firdes.WIN_RECTANGULAR, + "Kaiser Window" : gr.firdes.WIN_KAISER, + "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS} + self.EQUIRIPPLE_FILT = 6 # const for equiripple filter window types + self.show() + + def changed_filter_type(self, ftype): + strftype = str(ftype.toAscii()) + if(ftype == "Low Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) + elif(ftype == "Band Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) + elif(ftype == "Complex Band Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) + elif(ftype == "Band Notch"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbnfPage) + elif(ftype == "High Pass"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) + elif(ftype == "Root Raised Cosine"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.rrcPage) + elif(ftype == "Gaussian"): + self.gui.filterTypeWidget.setCurrentWidget(self.gui.gausPage) + + self.design() + + def changed_filter_design_type(self, design): + if(design == "Equiripple"): + self.set_equiripple() + else: + self.set_windowed() + + self.design() + + def set_equiripple(self): + # Stop sending the signal for this function + self.gui.filterTypeComboBox.blockSignals(True) + + self.equiripple = True + self.gui.lpfPassBandRippleLabel.setVisible(True) + self.gui.lpfPassBandRippleEdit.setVisible(True) + self.gui.bpfPassBandRippleLabel.setVisible(True) + self.gui.bpfPassBandRippleEdit.setVisible(True) + self.gui.bnfPassBandRippleLabel.setVisible(True) + self.gui.bnfPassBandRippleEdit.setVisible(True) + self.gui.hpfPassBandRippleLabel.setVisible(True) + self.gui.hpfPassBandRippleEdit.setVisible(True) + + # Save current type and repopulate the combo box for + # filters this window type can handle + currenttype = self.gui.filterTypeComboBox.currentText() + items = self.gui.filterTypeComboBox.count() + for i in xrange(items): + self.gui.filterTypeComboBox.removeItem(0) + self.gui.filterTypeComboBox.addItems(self.optFilters) + + # If the last filter type was valid for this window type, + # go back to it; otherwise, reset + try: + index = self.optFilters.index(currenttype) + self.gui.filterTypeComboBox.setCurrentIndex(index) + except ValueError: + pass + + # Tell gui its ok to start sending this signal again + self.gui.filterTypeComboBox.blockSignals(False) + + def set_windowed(self): + # Stop sending the signal for this function + self.gui.filterTypeComboBox.blockSignals(True) + + self.equiripple = False + self.gui.lpfPassBandRippleLabel.setVisible(False) + self.gui.lpfPassBandRippleEdit.setVisible(False) + self.gui.bpfPassBandRippleLabel.setVisible(False) + self.gui.bpfPassBandRippleEdit.setVisible(False) + self.gui.bnfPassBandRippleLabel.setVisible(False) + self.gui.bnfPassBandRippleEdit.setVisible(False) + self.gui.hpfPassBandRippleLabel.setVisible(False) + self.gui.hpfPassBandRippleEdit.setVisible(False) + + # Save current type and repopulate the combo box for + # filters this window type can handle + currenttype = self.gui.filterTypeComboBox.currentText() + items = self.gui.filterTypeComboBox.count() + for i in xrange(items): + self.gui.filterTypeComboBox.removeItem(0) + self.gui.filterTypeComboBox.addItems(self.firFilters) + + # If the last filter type was valid for this window type, + # go back to it; otherwise, reset + try: + index = self.optFilters.index(currenttype) + self.gui.filterTypeComboBox.setCurrentIndex(index) + except ValueError: + pass + + # Tell gui its ok to start sending this signal again + self.gui.filterTypeComboBox.blockSignals(False) + + def design(self): + ret = True + fs,r = self.gui.sampleRateEdit.text().toDouble() + ret = r and ret + gain,r = self.gui.filterGainEdit.text().toDouble() + ret = r and ret + + if(ret): + winstr = str(self.gui.filterDesignTypeComboBox.currentText().toAscii()) + ftype = str(self.gui.filterTypeComboBox.currentText().toAscii()) + + if(winstr == "Equiripple"): + designer = {"Low Pass" : self.design_opt_lpf, + "Band Pass" : self.design_opt_bpf, + "Complex Band Pass" : self.design_opt_cbpf, + "Band Notch" : self.design_opt_bnf, + "High Pass" : self.design_opt_hpf} + taps,params,r = designer[ftype](fs, gain) + + else: + designer = {"Low Pass" : self.design_win_lpf, + "Band Pass" : self.design_win_bpf, + "Complex Band Pass" : self.design_win_cbpf, + "Band Notch" : self.design_win_bnf, + "High Pass" : self.design_win_hpf, + "Root Raised Cosine" : self.design_win_rrc, + "Gaussian" : self.design_win_gaus} + wintype = self.filterWindows[winstr] + taps,params,r = designer[ftype](fs, gain, wintype) + + if(r): + self.draw_plots(taps, params) + + + # Filter design functions using a window + def design_win_lpf(self, fs, gain, wintype): + ret = True + pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() + ret = r and ret + sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(ret): + tb = sb - pb + + taps = gr.firdes.low_pass_2(gain, fs, pb, tb, + atten, wintype) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "lpf", "pbend": pb, "sbstart": sb, + "atten": atten, "ntaps": len(taps)} + return (taps, params, ret) + else: + return ([], [], ret) + + def design_win_bpf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.band_pass_2(gain, fs, pb1, pb2, tb, + atten, wintype) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "bpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_win_cbpf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.complex_band_pass_2(gain, fs, pb1, pb2, tb, + atten, wintype) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_win_bnf(self, fs, gain, wintype): + ret = True + pb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bnfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + taps = gr.firdes.band_reject_2(gain, fs, pb1, pb2, tb, + atten, wintype) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "bnf", "sbstart": pb1, "sbend": pb2, + "tb": tb, "atten": atten, "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_win_hpf(self, fs, gain, wintype): + ret = True + sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() + ret = r and ret + pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() + ret = r and ret + + if(r): + tb = pb - sb + taps = gr.firdes.high_pass_2(gain, fs, pb, tb, + atten, wintype) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "hpf", "sbend": sb, "pbstart": pb, + "atten": atten, "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_win_rrc(self, fs, gain, wintype): + ret = True + sr,r = self.gui.rrcSymbolRateEdit.text().toDouble() + ret = r and ret + alpha,r = self.gui.rrcAlphaEdit.text().toDouble() + ret = r and ret + ntaps,r = self.gui.rrcNumTapsEdit.text().toInt() + ret = r and ret + + if(r): + taps = gr.firdes.root_raised_cosine(gain, fs, sr, + alpha, ntaps) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "rrc", "srate": sr, "alpha": alpha, + "ntaps": ntaps} + return (taps,params,r) + else: + return ([],[],r) + + def design_win_gaus(self, fs, gain, wintype): + ret = True + sr,r = self.gui.gausSymbolRateEdit.text().toDouble() + ret = r and ret + bt,r = self.gui.gausBTEdit.text().toDouble() + ret = r and ret + ntaps,r = self.gui.gausNumTapsEdit.text().toInt() + ret = r and ret + + if(r): + spb = fs / sr + taps = gr.firdes.gaussian(gain, spb, bt, ntaps) + params = {"fs": fs, "gain": gain, "wintype": wintype, + "filttype": "gaus", "srate": sr, "bt": bt, + "ntaps": ntaps} + return (taps,params,r) + else: + return ([],[],r) + + # Design Functions for Equiripple Filters + def design_opt_lpf(self, fs, gain): + ret = True + pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() + ret = r and ret + sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.lpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(ret): + try: + taps = blks2.optfir.low_pass(gain, fs, pb, sb, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "lpf", "pbend": pb, "sbstart": sb, + "atten": atten, "ripple": ripple, "ntaps": len(taps)} + return (taps, params, ret) + else: + return ([], [], ret) + + def design_opt_bpf(self, fs, gain): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + sb1 = pb1 - tb + sb2 = pb2 + tb + try: + taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_opt_cbpf(self, fs, gain): + ret = True + pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() + ret = r and ret + pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bpfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + sb1 = pb1 - tb + sb2 = pb2 + tb + try: + taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_opt_bnf(self, fs, gain): + ret = True + sb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() + ret = r and ret + sb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() + ret = r and ret + tb,r = self.gui.bnfTransitionEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.bnfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + pb1 = sb1 - tb + pb2 = sb2 + tb + try: + taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, + ripple, atten) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "bnf", "sbstart": pb1, "sbend": pb2, + "tb": tb, "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def design_opt_hpf(self, fs, gain): + ret = True + sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() + ret = r and ret + pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() + ret = r and ret + atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() + ret = r and ret + ripple,r = self.gui.hpfPassBandRippleEdit.text().toDouble() + ret = r and ret + + if(r): + try: + taps = blks2.optfir.high_pass(gain, fs, sb, pb, + atten, ripple) + except RuntimeError, e: + reply = QtGui.QMessageBox.information(self, "Filter did not converge", + e.args[0], "&Ok") + return ([],[],False) + else: + params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, + "filttype": "hpf", "sbend": sb, "pbstart": pb, + "atten": atten, "ripple": ripple, + "ntaps": len(taps)} + return (taps,params,r) + else: + return ([],[],r) + + def nfft_edit_changed(self, nfft): + infft,r = nfft.toInt() + if(r and (infft != self.nfftpts)): + self.nfftpts = infft + self.update_freq_curves() + + def tab_changed(self, tab): + if(tab == 0): + self.update_freq_curves() + if(tab == 1): + self.update_time_curves() + if(tab == 2): + self.update_phase_curves() + if(tab == 3): + self.update_group_curves() + + def get_fft(self, fs, taps, Npts): + Ts = 1.0/fs + fftpts = fftpack.fft(taps, Npts) + self.freq = scipy.arange(0, fs, 1.0/(Npts*Ts)) + self.fftdB = 20.0*scipy.log10(abs(fftpts)) + self.fftDeg = scipy.unwrap(scipy.angle(fftpts)) + self.groupDelay = -scipy.diff(self.fftDeg) + + def update_time_curves(self): + ntaps = len(self.taps) + if(ntaps > 0): + if(type(self.taps[0]) == scipy.complex128): + self.rcurve.setData(scipy.arange(ntaps), self.taps.real) + self.icurve.setData(scipy.arange(ntaps), self.taps.imag) + else: + self.rcurve.setData(scipy.arange(ntaps), self.taps) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.taps) + ymin = 1.5 * min(self.taps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, + 0, ntaps) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.timeZoomer.setZoomBase() + + self.gui.timePlot.replot() + + def update_freq_curves(self): + npts = len(self.fftdB) + if(npts > 0): + self.freqcurve.setData(self.freq, self.fftdB) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.fftdB[0:npts/2]) + ymin = 1.1 * min(self.fftdB[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, + xmin, xmax) + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.freqZoomer.setZoomBase() + + self.gui.freqPlot.replot() + + + def update_phase_curves(self): + npts = len(self.fftDeg) + if(npts > 0): + self.phasecurve.setData(self.freq, self.fftDeg) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.fftDeg[0:npts/2]) + ymin = 1.1 * min(self.fftDeg[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] + self.gui.phasePlot.setAxisScale(self.gui.phasePlot.xBottom, + xmin, xmax) + self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.phaseZoomer.setZoomBase() + + self.gui.phasePlot.replot() + + def update_group_curves(self): + npts = len(self.groupDelay) + if(npts > 0): + self.groupcurve.setData(self.freq, self.groupDelay) + + # Reset the x-axis to the new time scale + ymax = 1.5 * max(self.groupDelay[0:npts/2]) + ymin = 1.1 * min(self.groupDelay[0:npts/2]) + xmax = self.freq[npts/2] + xmin = self.freq[0] + self.gui.groupPlot.setAxisScale(self.gui.groupPlot.xBottom, + xmin, xmax) + self.gui.groupPlot.setAxisScale(self.gui.groupPlot.yLeft, + ymin, ymax) + + # Set the zoomer base to unzoom to the new axis + self.groupZoomer.setZoomBase() + + self.gui.groupPlot.replot() + + def action_save_dialog(self): + filename = QtGui.QFileDialog.getSaveFileName(self, "Save CSV Filter File", ".", "") + try: + handle = open(filename, "wb") + except IOError: + reply = QtGui.QMessageBox.information(self, 'File Name', + ("Could not save to file: %s" % filename), + "&Ok") + return + + csvhandle = csv.writer(handle, delimiter=",") + for k in self.params.keys(): + csvhandle.writerow([k, self.params[k]]) + csvhandle.writerow(["taps",] + self.taps.tolist()) + handle.close() + + def action_open_dialog(self): + filename = QtGui.QFileDialog.getOpenFileName(self, "Open CSV Filter File", ".", "") + if(len(filename) == 0): + return + + try: + handle = open(filename, "rb") + except IOError: + reply = QtGui.QMessageBox.information(self, 'File Name', + ("Could not open file: %s" % filename), + "&Ok") + return + + csvhandle = csv.reader(handle, delimiter=",") + taps = [] + params = {} + for row in csvhandle: + if(row[0] != "taps"): + testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) + if(len(testcpx) > 0): # it's a complex + params[row[0]] = complex(row[1]) + else: # assume it's a float + try: # if it's not a float, its a string + params[row[0]] = float(row[1]) + except ValueError: + params[row[0]] = row[1] + else: + testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) + if(len(testcpx) > 0): # it's a complex + taps = [complex(r) for r in row[1:]] + else: + taps = [float(r) for r in row[1:]] + handle.close() + self.draw_plots(taps, params) + + self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(params["fs"])) + self.gui.filterGainEdit.setText(Qt.QString("%1").arg(params["gain"])) + + # Set up GUI parameters for each filter type + if(params["filttype"] == "lpf"): + self.gui.filterTypeComboBox.setCurrentIndex(0) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) + self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.lpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) + elif(params["filttype"] == "bpf"): + self.gui.filterTypeComboBox.setCurrentIndex(1) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) + elif(params["filttype"] == "cbpf"): + self.gui.filterTypeComboBox.setCurrentIndex(2) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) + self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) + elif(params["filttype"] == "bnf"): + self.gui.filterTypeComboBox.setCurrentIndex(3) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.startofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) + self.gui.endofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) + self.gui.bnfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) + self.gui.bnfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.bnfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) + elif(params["filttype"] == "hpf"): + self.gui.filterTypeComboBox.setCurrentIndex(4) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.endofHpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) + self.gui.startofHpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) + self.gui.hpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) + if(params["wintype"] == self.EQUIRIPPLE_FILT): + self.gui.hpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) + elif(params["filttype"] == "rrc"): + self.gui.filterTypeComboBox.setCurrentIndex(5) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.rrcSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) + self.gui.rrcAlphaEdit.setText(Qt.QString("%1").arg(params["alpha"])) + self.gui.rrcNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) + elif(params["filttype"] == "gaus"): + self.gui.filterTypeComboBox.setCurrentIndex(6) + self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) + + self.gui.gausSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) + self.gui.gausBTEdit.setText(Qt.QString("%1").arg(params["bt"])) + self.gui.gausNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) + + def draw_plots(self, taps, params): + self.params = params + self.taps = scipy.array(taps) + self.get_fft(self.params["fs"], self.taps, self.nfftpts) + self.update_time_curves() + self.update_freq_curves() + self.update_phase_curves() + self.update_group_curves() + + self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) + + +def setup_options(): + usage="%prog: [options] (input_filename)" + description = "" + + parser = OptionParser(conflict_handler="resolve", + usage=usage, description=description) + return parser + +def main(args): + parser = setup_options() + (options, args) = parser.parse_args () + + app = Qt.QApplication(args) + gplt = gr_plot_filter(app, options) + app.exec_() + +if __name__ == '__main__': + main(sys.argv) + diff --git a/gr-utils/src/python/gr_filter_design.py b/gr-utils/src/python/gr_filter_design.py deleted file mode 100755 index e8703db4f..000000000 --- a/gr-utils/src/python/gr_filter_design.py +++ /dev/null @@ -1,874 +0,0 @@ -#!/usr/bin/env python - -import sys, os, re, csv -from optparse import OptionParser -from gnuradio import gr, blks2, eng_notation - -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from PyQt4 import Qt, QtCore, QtGui -except ImportError: - print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" - raise SystemExit, 1 - -try: - import PyQt4.Qwt5 as Qwt -except ImportError: - print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" - raise SystemExit, 1 - -try: - from gnuradio.pyqt_filter import Ui_MainWindow -except ImportError: - print "Could not import from pyqt_filter. Please build with \"pyuic4 pyqt_filter.ui -o pyqt_filter.py\"" - raise SystemExit, 1 - - -class gr_plot_filter(QtGui.QMainWindow): - def __init__(self, qapp, options): - QtGui.QWidget.__init__(self, None) - self.gui = Ui_MainWindow() - self.gui.setupUi(self) - - self.connect(self.gui.action_save, - Qt.SIGNAL("activated()"), - self.action_save_dialog) - self.connect(self.gui.action_open, - Qt.SIGNAL("activated()"), - self.action_open_dialog) - - - self.connect(self.gui.filterTypeComboBox, - Qt.SIGNAL("currentIndexChanged(const QString&)"), - self.changed_filter_type) - self.connect(self.gui.filterDesignTypeComboBox, - Qt.SIGNAL("currentIndexChanged(const QString&)"), - self.changed_filter_design_type) - - self.connect(self.gui.designButton, - Qt.SIGNAL("released()"), - self.design) - - self.connect(self.gui.tabGroup, - Qt.SIGNAL("currentChanged(int)"), - self.tab_changed) - - self.connect(self.gui.nfftEdit, - Qt.SIGNAL("textEdited(QString)"), - self.nfft_edit_changed) - - self.gui.designButton.setShortcut(QtCore.Qt.Key_Return) - - self.taps = [] - self.fftdB = [] - self.fftDeg = [] - self.groupDelay = [] - self.nfftpts = int(10000) - self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts)) - - self.firFilters = ("Low Pass", "Band Pass", "Complex Band Pass", "Band Notch", - "High Pass", "Root Raised Cosine", "Gaussian") - self.optFilters = ("Low Pass", "Band Pass", "Complex Band Pass", - "Band Notch", "High Pass") - - self.set_windowed() - - # Initialize to LPF - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) - - # Set Axis labels - self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, - "Frequency (Hz)") - self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, - "Magnitude (dB)") - self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, - "Tap number") - self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, - "Amplitude") - self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.xBottom, - "Frequency (Hz)") - self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.yLeft, - "Phase (Radians)") - self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.xBottom, - "Frequency (Hz)") - self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.yLeft, - "Delay (sec)") - - # Set up plot curves - self.rcurve = Qwt.QwtPlotCurve("Real") - self.rcurve.attach(self.gui.timePlot) - self.icurve = Qwt.QwtPlotCurve("Imag") - self.icurve.attach(self.gui.timePlot) - - self.freqcurve = Qwt.QwtPlotCurve("PSD") - self.freqcurve.attach(self.gui.freqPlot) - - self.phasecurve = Qwt.QwtPlotCurve("Phase") - self.phasecurve.attach(self.gui.phasePlot) - - self.groupcurve = Qwt.QwtPlotCurve("Group Delay") - self.groupcurve.attach(self.gui.groupPlot) - - # Create zoom functionality for the plots - self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, - self.gui.timePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.timePlot.canvas()) - - self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, - self.gui.freqPlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.freqPlot.canvas()) - - self.phaseZoomer = Qwt.QwtPlotZoomer(self.gui.phasePlot.xBottom, - self.gui.phasePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.phasePlot.canvas()) - - self.groupZoomer = Qwt.QwtPlotZoomer(self.gui.groupPlot.xBottom, - self.gui.groupPlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.groupPlot.canvas()) - - # Set up pen for colors and line width - blue = QtGui.qRgb(0x00, 0x00, 0xFF) - blueBrush = Qt.QBrush(Qt.QColor(blue)) - red = QtGui.qRgb(0xFF, 0x00, 0x00) - redBrush = Qt.QBrush(Qt.QColor(red)) - self.freqcurve.setPen(Qt.QPen(blueBrush, 2)) - self.rcurve.setPen(Qt.QPen(blueBrush, 2)) - self.icurve.setPen(Qt.QPen(redBrush, 2)) - self.phasecurve.setPen(Qt.QPen(blueBrush, 2)) - self.groupcurve.setPen(Qt.QPen(blueBrush, 2)) - - # Set up validators for edit boxes - self.intVal = Qt.QIntValidator(None) - self.dblVal = Qt.QDoubleValidator(None) - self.gui.nfftEdit.setValidator(self.intVal) - self.gui.sampleRateEdit.setValidator(self.dblVal) - self.gui.filterGainEdit.setValidator(self.dblVal) - self.gui.endofLpfPassBandEdit.setValidator(self.dblVal) - self.gui.startofLpfStopBandEdit.setValidator(self.dblVal) - self.gui.lpfStopBandAttenEdit.setValidator(self.dblVal) - self.gui.lpfPassBandRippleEdit.setValidator(self.dblVal) - self.gui.startofBpfPassBandEdit.setValidator(self.dblVal) - self.gui.endofBpfPassBandEdit.setValidator(self.dblVal) - self.gui.bpfTransitionEdit.setValidator(self.dblVal) - self.gui.bpfStopBandAttenEdit.setValidator(self.dblVal) - self.gui.bpfPassBandRippleEdit.setValidator(self.dblVal) - self.gui.startofBnfStopBandEdit.setValidator(self.dblVal) - self.gui.endofBnfStopBandEdit.setValidator(self.dblVal) - self.gui.bnfTransitionEdit.setValidator(self.dblVal) - self.gui.bnfStopBandAttenEdit.setValidator(self.dblVal) - self.gui.bnfPassBandRippleEdit.setValidator(self.dblVal) - self.gui.endofHpfStopBandEdit.setValidator(self.dblVal) - self.gui.startofHpfPassBandEdit.setValidator(self.dblVal) - self.gui.hpfStopBandAttenEdit.setValidator(self.dblVal) - self.gui.hpfPassBandRippleEdit.setValidator(self.dblVal) - self.gui.rrcSymbolRateEdit.setValidator(self.dblVal) - self.gui.rrcAlphaEdit.setValidator(self.dblVal) - self.gui.rrcNumTapsEdit.setValidator(self.dblVal) - self.gui.gausSymbolRateEdit.setValidator(self.dblVal) - self.gui.gausBTEdit.setValidator(self.dblVal) - self.gui.gausNumTapsEdit.setValidator(self.dblVal) - - self.gui.nTapsEdit.setText("0") - - self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING, - "Hann Window" : gr.firdes.WIN_HANN, - "Blackman Window" : gr.firdes.WIN_BLACKMAN, - "Rectangular Window" : gr.firdes.WIN_RECTANGULAR, - "Kaiser Window" : gr.firdes.WIN_KAISER, - "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS} - self.EQUIRIPPLE_FILT = 6 # const for equiripple filter window types - self.show() - - def changed_filter_type(self, ftype): - strftype = str(ftype.toAscii()) - if(ftype == "Low Pass"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) - elif(ftype == "Band Pass"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) - elif(ftype == "Complex Band Pass"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage) - elif(ftype == "Band Notch"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbnfPage) - elif(ftype == "High Pass"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage) - elif(ftype == "Root Raised Cosine"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.rrcPage) - elif(ftype == "Gaussian"): - self.gui.filterTypeWidget.setCurrentWidget(self.gui.gausPage) - - self.design() - - def changed_filter_design_type(self, design): - if(design == "Equiripple"): - self.set_equiripple() - else: - self.set_windowed() - - self.design() - - def set_equiripple(self): - # Stop sending the signal for this function - self.gui.filterTypeComboBox.blockSignals(True) - - self.equiripple = True - self.gui.lpfPassBandRippleLabel.setVisible(True) - self.gui.lpfPassBandRippleEdit.setVisible(True) - self.gui.bpfPassBandRippleLabel.setVisible(True) - self.gui.bpfPassBandRippleEdit.setVisible(True) - self.gui.bnfPassBandRippleLabel.setVisible(True) - self.gui.bnfPassBandRippleEdit.setVisible(True) - self.gui.hpfPassBandRippleLabel.setVisible(True) - self.gui.hpfPassBandRippleEdit.setVisible(True) - - # Save current type and repopulate the combo box for - # filters this window type can handle - currenttype = self.gui.filterTypeComboBox.currentText() - items = self.gui.filterTypeComboBox.count() - for i in xrange(items): - self.gui.filterTypeComboBox.removeItem(0) - self.gui.filterTypeComboBox.addItems(self.optFilters) - - # If the last filter type was valid for this window type, - # go back to it; otherwise, reset - try: - index = self.optFilters.index(currenttype) - self.gui.filterTypeComboBox.setCurrentIndex(index) - except ValueError: - pass - - # Tell gui its ok to start sending this signal again - self.gui.filterTypeComboBox.blockSignals(False) - - def set_windowed(self): - # Stop sending the signal for this function - self.gui.filterTypeComboBox.blockSignals(True) - - self.equiripple = False - self.gui.lpfPassBandRippleLabel.setVisible(False) - self.gui.lpfPassBandRippleEdit.setVisible(False) - self.gui.bpfPassBandRippleLabel.setVisible(False) - self.gui.bpfPassBandRippleEdit.setVisible(False) - self.gui.bnfPassBandRippleLabel.setVisible(False) - self.gui.bnfPassBandRippleEdit.setVisible(False) - self.gui.hpfPassBandRippleLabel.setVisible(False) - self.gui.hpfPassBandRippleEdit.setVisible(False) - - # Save current type and repopulate the combo box for - # filters this window type can handle - currenttype = self.gui.filterTypeComboBox.currentText() - items = self.gui.filterTypeComboBox.count() - for i in xrange(items): - self.gui.filterTypeComboBox.removeItem(0) - self.gui.filterTypeComboBox.addItems(self.firFilters) - - # If the last filter type was valid for this window type, - # go back to it; otherwise, reset - try: - index = self.optFilters.index(currenttype) - self.gui.filterTypeComboBox.setCurrentIndex(index) - except ValueError: - pass - - # Tell gui its ok to start sending this signal again - self.gui.filterTypeComboBox.blockSignals(False) - - def design(self): - ret = True - fs,r = self.gui.sampleRateEdit.text().toDouble() - ret = r and ret - gain,r = self.gui.filterGainEdit.text().toDouble() - ret = r and ret - - if(ret): - winstr = str(self.gui.filterDesignTypeComboBox.currentText().toAscii()) - ftype = str(self.gui.filterTypeComboBox.currentText().toAscii()) - - if(winstr == "Equiripple"): - designer = {"Low Pass" : self.design_opt_lpf, - "Band Pass" : self.design_opt_bpf, - "Complex Band Pass" : self.design_opt_cbpf, - "Band Notch" : self.design_opt_bnf, - "High Pass" : self.design_opt_hpf} - taps,params,r = designer[ftype](fs, gain) - - else: - designer = {"Low Pass" : self.design_win_lpf, - "Band Pass" : self.design_win_bpf, - "Complex Band Pass" : self.design_win_cbpf, - "Band Notch" : self.design_win_bnf, - "High Pass" : self.design_win_hpf, - "Root Raised Cosine" : self.design_win_rrc, - "Gaussian" : self.design_win_gaus} - wintype = self.filterWindows[winstr] - taps,params,r = designer[ftype](fs, gain, wintype) - - if(r): - self.draw_plots(taps, params) - - - # Filter design functions using a window - def design_win_lpf(self, fs, gain, wintype): - ret = True - pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() - ret = r and ret - sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() - ret = r and ret - - if(ret): - tb = sb - pb - - taps = gr.firdes.low_pass_2(gain, fs, pb, tb, - atten, wintype) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "lpf", "pbend": pb, "sbstart": sb, - "atten": atten, "ntaps": len(taps)} - return (taps, params, ret) - else: - return ([], [], ret) - - def design_win_bpf(self, fs, gain, wintype): - ret = True - pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() - ret = r and ret - pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bpfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() - ret = r and ret - - if(r): - taps = gr.firdes.band_pass_2(gain, fs, pb1, pb2, tb, - atten, wintype) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "bpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_win_cbpf(self, fs, gain, wintype): - ret = True - pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() - ret = r and ret - pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bpfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() - ret = r and ret - - if(r): - taps = gr.firdes.complex_band_pass_2(gain, fs, pb1, pb2, tb, - atten, wintype) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_win_bnf(self, fs, gain, wintype): - ret = True - pb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() - ret = r and ret - pb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bnfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() - ret = r and ret - - if(r): - taps = gr.firdes.band_reject_2(gain, fs, pb1, pb2, tb, - atten, wintype) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "bnf", "sbstart": pb1, "sbend": pb2, - "tb": tb, "atten": atten, "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_win_hpf(self, fs, gain, wintype): - ret = True - sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() - ret = r and ret - pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() - ret = r and ret - - if(r): - tb = pb - sb - taps = gr.firdes.high_pass_2(gain, fs, pb, tb, - atten, wintype) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "hpf", "sbend": sb, "pbstart": pb, - "atten": atten, "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_win_rrc(self, fs, gain, wintype): - ret = True - sr,r = self.gui.rrcSymbolRateEdit.text().toDouble() - ret = r and ret - alpha,r = self.gui.rrcAlphaEdit.text().toDouble() - ret = r and ret - ntaps,r = self.gui.rrcNumTapsEdit.text().toInt() - ret = r and ret - - if(r): - taps = gr.firdes.root_raised_cosine(gain, fs, sr, - alpha, ntaps) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "rrc", "srate": sr, "alpha": alpha, - "ntaps": ntaps} - return (taps,params,r) - else: - return ([],[],r) - - def design_win_gaus(self, fs, gain, wintype): - ret = True - sr,r = self.gui.gausSymbolRateEdit.text().toDouble() - ret = r and ret - bt,r = self.gui.gausBTEdit.text().toDouble() - ret = r and ret - ntaps,r = self.gui.gausNumTapsEdit.text().toInt() - ret = r and ret - - if(r): - spb = fs / sr - taps = gr.firdes.gaussian(gain, spb, bt, ntaps) - params = {"fs": fs, "gain": gain, "wintype": wintype, - "filttype": "gaus", "srate": sr, "bt": bt, - "ntaps": ntaps} - return (taps,params,r) - else: - return ([],[],r) - - # Design Functions for Equiripple Filters - def design_opt_lpf(self, fs, gain): - ret = True - pb,r = self.gui.endofLpfPassBandEdit.text().toDouble() - ret = r and ret - sb,r = self.gui.startofLpfStopBandEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble() - ret = r and ret - ripple,r = self.gui.lpfPassBandRippleEdit.text().toDouble() - ret = r and ret - - if(ret): - try: - taps = blks2.optfir.low_pass(gain, fs, pb, sb, - ripple, atten) - except RuntimeError, e: - reply = QtGui.QMessageBox.information(self, "Filter did not converge", - e.args[0], "&Ok") - return ([],[],False) - else: - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "lpf", "pbend": pb, "sbstart": sb, - "atten": atten, "ripple": ripple, "ntaps": len(taps)} - return (taps, params, ret) - else: - return ([], [], ret) - - def design_opt_bpf(self, fs, gain): - ret = True - pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() - ret = r and ret - pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bpfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() - ret = r and ret - ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() - ret = r and ret - - if(r): - sb1 = pb1 - tb - sb2 = pb2 + tb - try: - taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2, - ripple, atten) - except RuntimeError, e: - reply = QtGui.QMessageBox.information(self, "Filter did not converge", - e.args[0], "&Ok") - return ([],[],False) - - else: - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "bpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_opt_cbpf(self, fs, gain): - ret = True - pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() - ret = r and ret - pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bpfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble() - ret = r and ret - ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble() - ret = r and ret - - if(r): - sb1 = pb1 - tb - sb2 = pb2 + tb - try: - taps = blks2.optfir.complex_band_pass(gain, fs, sb1, pb1, pb2, sb2, - ripple, atten) - except RuntimeError, e: - reply = QtGui.QMessageBox.information(self, "Filter did not converge", - e.args[0], "&Ok") - return ([],[],False) - else: - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "cbpf", "pbstart": pb1, "pbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_opt_bnf(self, fs, gain): - ret = True - sb1,r = self.gui.startofBnfStopBandEdit.text().toDouble() - ret = r and ret - sb2,r = self.gui.endofBnfStopBandEdit.text().toDouble() - ret = r and ret - tb,r = self.gui.bnfTransitionEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.bnfStopBandAttenEdit.text().toDouble() - ret = r and ret - ripple,r = self.gui.bnfPassBandRippleEdit.text().toDouble() - ret = r and ret - - if(r): - pb1 = sb1 - tb - pb2 = sb2 + tb - try: - taps = blks2.optfir.band_reject(gain, fs, pb1, sb1, sb2, pb2, - ripple, atten) - except RuntimeError, e: - reply = QtGui.QMessageBox.information(self, "Filter did not converge", - e.args[0], "&Ok") - return ([],[],False) - else: - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "bnf", "sbstart": pb1, "sbend": pb2, - "tb": tb, "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def design_opt_hpf(self, fs, gain): - ret = True - sb,r = self.gui.endofHpfStopBandEdit.text().toDouble() - ret = r and ret - pb,r = self.gui.startofHpfPassBandEdit.text().toDouble() - ret = r and ret - atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble() - ret = r and ret - ripple,r = self.gui.hpfPassBandRippleEdit.text().toDouble() - ret = r and ret - - if(r): - try: - taps = blks2.optfir.high_pass(gain, fs, sb, pb, - atten, ripple) - except RuntimeError, e: - reply = QtGui.QMessageBox.information(self, "Filter did not converge", - e.args[0], "&Ok") - return ([],[],False) - else: - params = {"fs": fs, "gain": gain, "wintype": self.EQUIRIPPLE_FILT, - "filttype": "hpf", "sbend": sb, "pbstart": pb, - "atten": atten, "ripple": ripple, - "ntaps": len(taps)} - return (taps,params,r) - else: - return ([],[],r) - - def nfft_edit_changed(self, nfft): - infft,r = nfft.toInt() - if(r and (infft != self.nfftpts)): - self.nfftpts = infft - self.update_freq_curves() - - def tab_changed(self, tab): - if(tab == 0): - self.update_freq_curves() - if(tab == 1): - self.update_time_curves() - if(tab == 2): - self.update_phase_curves() - if(tab == 3): - self.update_group_curves() - - def get_fft(self, fs, taps, Npts): - Ts = 1.0/fs - fftpts = fftpack.fft(taps, Npts) - self.freq = scipy.arange(0, fs, 1.0/(Npts*Ts)) - self.fftdB = 20.0*scipy.log10(abs(fftpts)) - self.fftDeg = scipy.unwrap(scipy.angle(fftpts)) - self.groupDelay = -scipy.diff(self.fftDeg) - - def update_time_curves(self): - ntaps = len(self.taps) - if(ntaps > 0): - if(type(self.taps[0]) == scipy.complex128): - self.rcurve.setData(scipy.arange(ntaps), self.taps.real) - self.icurve.setData(scipy.arange(ntaps), self.taps.imag) - else: - self.rcurve.setData(scipy.arange(ntaps), self.taps) - - # Reset the x-axis to the new time scale - ymax = 1.5 * max(self.taps) - ymin = 1.5 * min(self.taps) - self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, - 0, ntaps) - self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, - ymin, ymax) - - # Set the zoomer base to unzoom to the new axis - self.timeZoomer.setZoomBase() - - self.gui.timePlot.replot() - - def update_freq_curves(self): - npts = len(self.fftdB) - if(npts > 0): - self.freqcurve.setData(self.freq, self.fftdB) - - # Reset the x-axis to the new time scale - ymax = 1.5 * max(self.fftdB[0:npts/2]) - ymin = 1.1 * min(self.fftdB[0:npts/2]) - xmax = self.freq[npts/2] - xmin = self.freq[0] - self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, - xmin, xmax) - self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft, - ymin, ymax) - - # Set the zoomer base to unzoom to the new axis - self.freqZoomer.setZoomBase() - - self.gui.freqPlot.replot() - - - def update_phase_curves(self): - npts = len(self.fftDeg) - if(npts > 0): - self.phasecurve.setData(self.freq, self.fftDeg) - - # Reset the x-axis to the new time scale - ymax = 1.5 * max(self.fftDeg[0:npts/2]) - ymin = 1.1 * min(self.fftDeg[0:npts/2]) - xmax = self.freq[npts/2] - xmin = self.freq[0] - self.gui.phasePlot.setAxisScale(self.gui.phasePlot.xBottom, - xmin, xmax) - self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft, - ymin, ymax) - - # Set the zoomer base to unzoom to the new axis - self.phaseZoomer.setZoomBase() - - self.gui.phasePlot.replot() - - def update_group_curves(self): - npts = len(self.groupDelay) - if(npts > 0): - self.groupcurve.setData(self.freq, self.groupDelay) - - # Reset the x-axis to the new time scale - ymax = 1.5 * max(self.groupDelay[0:npts/2]) - ymin = 1.1 * min(self.groupDelay[0:npts/2]) - xmax = self.freq[npts/2] - xmin = self.freq[0] - self.gui.groupPlot.setAxisScale(self.gui.groupPlot.xBottom, - xmin, xmax) - self.gui.groupPlot.setAxisScale(self.gui.groupPlot.yLeft, - ymin, ymax) - - # Set the zoomer base to unzoom to the new axis - self.groupZoomer.setZoomBase() - - self.gui.groupPlot.replot() - - def action_save_dialog(self): - filename = QtGui.QFileDialog.getSaveFileName(self, "Save CSV Filter File", ".", "") - try: - handle = open(filename, "wb") - except IOError: - reply = QtGui.QMessageBox.information(self, 'File Name', - ("Could not save to file: %s" % filename), - "&Ok") - return - - csvhandle = csv.writer(handle, delimiter=",") - for k in self.params.keys(): - csvhandle.writerow([k, self.params[k]]) - csvhandle.writerow(["taps",] + self.taps.tolist()) - handle.close() - - def action_open_dialog(self): - filename = QtGui.QFileDialog.getOpenFileName(self, "Open CSV Filter File", ".", "") - if(len(filename) == 0): - return - - try: - handle = open(filename, "rb") - except IOError: - reply = QtGui.QMessageBox.information(self, 'File Name', - ("Could not open file: %s" % filename), - "&Ok") - return - - csvhandle = csv.reader(handle, delimiter=",") - taps = [] - params = {} - for row in csvhandle: - if(row[0] != "taps"): - testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) - if(len(testcpx) > 0): # it's a complex - params[row[0]] = complex(row[1]) - else: # assume it's a float - try: # if it's not a float, its a string - params[row[0]] = float(row[1]) - except ValueError: - params[row[0]] = row[1] - else: - testcpx = re.findall("[+-]?\d+\.*\d*[Ee]?[-+]?\d+j", row[1]) - if(len(testcpx) > 0): # it's a complex - taps = [complex(r) for r in row[1:]] - else: - taps = [float(r) for r in row[1:]] - handle.close() - self.draw_plots(taps, params) - - self.gui.sampleRateEdit.setText(Qt.QString("%1").arg(params["fs"])) - self.gui.filterGainEdit.setText(Qt.QString("%1").arg(params["gain"])) - - # Set up GUI parameters for each filter type - if(params["filttype"] == "lpf"): - self.gui.filterTypeComboBox.setCurrentIndex(0) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.endofLpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) - self.gui.startofLpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) - self.gui.lpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) - if(params["wintype"] == self.EQUIRIPPLE_FILT): - self.gui.lpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) - elif(params["filttype"] == "bpf"): - self.gui.filterTypeComboBox.setCurrentIndex(1) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) - self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) - self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) - self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) - if(params["wintype"] == self.EQUIRIPPLE_FILT): - self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) - elif(params["filttype"] == "cbpf"): - self.gui.filterTypeComboBox.setCurrentIndex(2) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.startofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) - self.gui.endofBpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbend"])) - self.gui.bpfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) - self.gui.bpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) - if(params["wintype"] == self.EQUIRIPPLE_FILT): - self.gui.bpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) - elif(params["filttype"] == "bnf"): - self.gui.filterTypeComboBox.setCurrentIndex(3) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.startofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbstart"])) - self.gui.endofBnfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) - self.gui.bnfTransitionEdit.setText(Qt.QString("%1").arg(params["tb"])) - self.gui.bnfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) - if(params["wintype"] == self.EQUIRIPPLE_FILT): - self.gui.bnfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) - elif(params["filttype"] == "hpf"): - self.gui.filterTypeComboBox.setCurrentIndex(4) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.endofHpfStopBandEdit.setText(Qt.QString("%1").arg(params["sbend"])) - self.gui.startofHpfPassBandEdit.setText(Qt.QString("%1").arg(params["pbstart"])) - self.gui.hpfStopBandAttenEdit.setText(Qt.QString("%1").arg(params["atten"])) - if(params["wintype"] == self.EQUIRIPPLE_FILT): - self.gui.hpfPassBandRippleEdit.setText(Qt.QString("%1").arg(params["ripple"])) - elif(params["filttype"] == "rrc"): - self.gui.filterTypeComboBox.setCurrentIndex(5) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.rrcSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) - self.gui.rrcAlphaEdit.setText(Qt.QString("%1").arg(params["alpha"])) - self.gui.rrcNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) - elif(params["filttype"] == "gaus"): - self.gui.filterTypeComboBox.setCurrentIndex(6) - self.gui.filterDesignTypeComboBox.setCurrentIndex(int(params["wintype"])) - - self.gui.gausSymbolRateEdit.setText(Qt.QString("%1").arg(params["srate"])) - self.gui.gausBTEdit.setText(Qt.QString("%1").arg(params["bt"])) - self.gui.gausNumTapsEdit.setText(Qt.QString("%1").arg(params["ntaps"])) - - def draw_plots(self, taps, params): - self.params = params - self.taps = scipy.array(taps) - self.get_fft(self.params["fs"], self.taps, self.nfftpts) - self.update_time_curves() - self.update_freq_curves() - self.update_phase_curves() - self.update_group_curves() - - self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) - - -def setup_options(): - usage="%prog: [options] (input_filename)" - description = "" - - parser = OptionParser(conflict_handler="resolve", - usage=usage, description=description) - return parser - -def main(args): - parser = setup_options() - (options, args) = parser.parse_args () - - app = Qt.QApplication(args) - gplt = gr_plot_filter(app, options) - app.exec_() - -if __name__ == '__main__': - main(sys.argv) - diff --git a/gr-utils/src/python/gr_plot_char b/gr-utils/src/python/gr_plot_char new file mode 100755 index 000000000..87a323c9c --- /dev/null +++ b/gr-utils/src/python/gr_plot_char @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio byte/char binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int8 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_char.py b/gr-utils/src/python/gr_plot_char.py deleted file mode 100755 index 87a323c9c..000000000 --- a/gr-utils/src/python/gr_plot_char.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -from optparse import OptionParser -from gnuradio.plot_data import plot_data - -def main(): - usage="%prog: [options] input_filenames" - description = "Takes a GNU Radio byte/char binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) < 1: - parser.print_help() - raise SystemExit, 1 - filenames = args - - datatype=scipy.int8 - dc = plot_data(datatype, filenames, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - diff --git a/gr-utils/src/python/gr_plot_const b/gr-utils/src/python/gr_plot_const new file mode 100755 index 000000000..8873e5b7e --- /dev/null +++ b/gr-utils/src/python/gr_plot_const @@ -0,0 +1,250 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008,2011 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * + from matplotlib.font_manager import fontManager, FontProperties +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +class draw_constellation: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16) + self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16) + self.text_block = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length), + weight="heavy", size=16) + self.text_sr = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=16) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + connect('button_press_event', self.mouse_button_callback) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + try: + iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: + print "End of File" + else: + # retesting length here as newer version of scipy does not throw a MemoryError, just + # returns a zero-length array + if(len(iq) > 0): + self.reals = scipy.array([r.real for r in iq]) + self.imags = scipy.array([i.imag for i in iq]) + + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) + return True + else: + print "End of File" + return False + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + r = self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_iq = self.sp_iq.plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') + + # Subplot for constellation plot + self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold") + self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold") + self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold") + self.plot_const = self.sp_const.plot(self.reals, self.imags, 'bo') + + # Add plots to mark current location of point between time and constellation plots + self.indx = 0 + self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.reals[self.indx],], 'mo', ms=8) + self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.imags[self.indx],], 'mo', ms=8) + self.plot_const += self.sp_const.plot([self.reals[self.indx],], [self.imags[self.indx],], 'mo', ms=12) + + # Adjust axis + self.sp_iq.axis([self.time.min(), self.time.max(), + 1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + self.sp_const.axis([-2, 2, -2, 2]) + + draw() + + def update_plots(self): + self.plot_iq[0].set_data([self.time, self.reals]) + self.plot_iq[1].set_data([self.time, self.imags]) + self.sp_iq.axis([self.time.min(), self.time.max(), + 1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + + self.plot_const[0].set_data([self.reals, self.imags]) + self.sp_const.axis([-2, 2, -2, 2]) + draw() + + def zoom(self, event): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): + self.xlim = newxlim + r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] + i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] + + self.plot_const[0].set_data(r, i) + self.sp_const.axis([-2, 2, -2, 2]) + self.manager.canvas.draw() + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + trace_forward_valid_keys = [">",] + trace_backward_valid_keys = ["<",] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + elif(find(event.key, trace_forward_valid_keys)): + self.indx = min(self.indx+1, len(self.time)-1) + self.set_trace(self.indx) + + elif(find(event.key, trace_backward_valid_keys)): + self.indx = max(0, self.indx-1) + self.set_trace(self.indx) + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + r = self.get_data() + if(r): + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + r = self.get_data() + if(r): + self.update_plots() + + + def mouse_button_callback(self, event): + x, y = event.xdata, event.ydata + + if x is not None and y is not None: + if(event.inaxes == self.sp_iq): + self.indx = searchsorted(self.time, [x]) + self.set_trace(self.indx) + + + def set_trace(self, indx): + self.plot_iq[2].set_data(self.time[indx], self.reals[indx]) + self.plot_iq[3].set_data(self.time[indx], self.imags[indx]) + self.plot_const[1].set_data(self.reals[indx], self.imags[indx]) + draw() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_constellation(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py deleted file mode 100755 index 8873e5b7e..000000000 --- a/gr-utils/src/python/gr_plot_const.py +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008,2011 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from pylab import * - from matplotlib.font_manager import fontManager, FontProperties -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser - -class draw_constellation: - def __init__(self, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - - self.datatype = scipy.complex64 - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 9), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16) - self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16) - self.text_block = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length), - weight="heavy", size=16) - self.text_sr = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=16) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = self.sp_iq.get_xlim() - - self.manager = get_current_fig_manager() - connect('draw_event', self.zoom) - connect('key_press_event', self.click) - connect('button_press_event', self.mouse_button_callback) - show() - - def get_data(self): - self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - try: - iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - except MemoryError: - print "End of File" - else: - # retesting length here as newer version of scipy does not throw a MemoryError, just - # returns a zero-length array - if(len(iq) > 0): - self.reals = scipy.array([r.real for r in iq]) - self.imags = scipy.array([i.imag for i in iq]) - - self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - return True - else: - print "End of File" - return False - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - r = self.get_data() - - # Subplot for real and imaginary parts of signal - self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) - self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") - self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - self.plot_iq = self.sp_iq.plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') - - # Subplot for constellation plot - self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6]) - self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold") - self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold") - self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold") - self.plot_const = self.sp_const.plot(self.reals, self.imags, 'bo') - - # Add plots to mark current location of point between time and constellation plots - self.indx = 0 - self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.reals[self.indx],], 'mo', ms=8) - self.plot_iq += self.sp_iq.plot([self.time[self.indx],], [self.imags[self.indx],], 'mo', ms=8) - self.plot_const += self.sp_const.plot([self.reals[self.indx],], [self.imags[self.indx],], 'mo', ms=12) - - # Adjust axis - self.sp_iq.axis([self.time.min(), self.time.max(), - 1.5*min([self.reals.min(), self.imags.min()]), - 1.5*max([self.reals.max(), self.imags.max()])]) - self.sp_const.axis([-2, 2, -2, 2]) - - draw() - - def update_plots(self): - self.plot_iq[0].set_data([self.time, self.reals]) - self.plot_iq[1].set_data([self.time, self.imags]) - self.sp_iq.axis([self.time.min(), self.time.max(), - 1.5*min([self.reals.min(), self.imags.min()]), - 1.5*max([self.reals.max(), self.imags.max()])]) - - self.plot_const[0].set_data([self.reals, self.imags]) - self.sp_const.axis([-2, 2, -2, 2]) - draw() - - def zoom(self, event): - newxlim = scipy.array(self.sp_iq.get_xlim()) - curxlim = scipy.array(self.xlim) - if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): - self.xlim = newxlim - r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] - i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))] - - self.plot_const[0].set_data(r, i) - self.sp_const.axis([-2, 2, -2, 2]) - self.manager.canvas.draw() - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - trace_forward_valid_keys = [">",] - trace_backward_valid_keys = ["<",] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - elif(find(event.key, trace_forward_valid_keys)): - self.indx = min(self.indx+1, len(self.time)-1) - self.set_trace(self.indx) - - elif(find(event.key, trace_backward_valid_keys)): - self.indx = max(0, self.indx-1) - self.set_trace(self.indx) - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - r = self.get_data() - if(r): - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - r = self.get_data() - if(r): - self.update_plots() - - - def mouse_button_callback(self, event): - x, y = event.xdata, event.ydata - - if x is not None and y is not None: - if(event.inaxes == self.sp_iq): - self.indx = searchsorted(self.time, [x]) - self.set_trace(self.indx) - - - def set_trace(self, indx): - self.plot_iq[2].set_data(self.time[indx], self.reals[indx]) - self.plot_iq[3].set_data(self.time[indx], self.imags[indx]) - self.plot_const[1].set_data(self.reals[indx], self.imags[indx]) - draw() - - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False - - -def main(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = draw_constellation(filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_fft b/gr-utils/src/python/gr_plot_fft new file mode 100644 index 000000000..6859ea471 --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio.plot_fft_base import plot_fft_base + +# This is a wrapper program for plot_fft_base. It handles any data +# type and defaults to complex64. + +def main(): + parser = plot_fft_base.setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_fft_base(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass diff --git a/gr-utils/src/python/gr_plot_fft.py b/gr-utils/src/python/gr_plot_fft.py deleted file mode 100755 index ba3901e03..000000000 --- a/gr-utils/src/python/gr_plot_fft.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008,2011 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. -# - -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from pylab import * -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser - -class gr_plot_fft: - def __init__(self, datatype, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - - self.datatype = getattr(scipy, datatype) - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - self.text_size = 22 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 12), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) - self.text_block = figtext(0.35, 0.88, ("Block Size: %d" % self.block_length), - weight="heavy", size=self.text_size) - self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=self.text_size) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = self.sp_iq.get_xlim() - - self.manager = get_current_fig_manager() - connect('draw_event', self.zoom) - connect('key_press_event', self.click) - show() - - def get_data(self): - self.position = self.hfile.tell()/self.sizeof_data - self.text_file_pos.set_text("File Position: %d" % (self.position)) - try: - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - except MemoryError: - print "End of File" - else: - self.iq_fft = self.dofft(self.iq) - - tstep = 1.0 / self.sample_rate - #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) - self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) - - self.freq = self.calc_freq(self.time, self.sample_rate) - - def dofft(self, iq): - N = len(iq) - iq_fft = fftpack.fftshift(scipy.fft(iq)) # fft and shift axis - iq_fft = 20*scipy.log10(abs((iq_fft+1e-15)/N)) # convert to decibels, adjust power - # adding 1e-15 (-300 dB) to protect against value errors if an item in iq_fft is 0 - return iq_fft - - def calc_freq(self, time, sample_rate): - N = len(time) - Fs = 1.0 / (time.max() - time.min()) - Fn = 0.5 * sample_rate - freq = scipy.array([-Fn + i*Fs for i in xrange(N)]) - return freq - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - # Subplot for real and imaginary parts of signal - self.sp_iq = self.fig.add_subplot(2,2,1, position=[0.075, 0.2, 0.4, 0.6]) - self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") - self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - - # Subplot for FFT plot - self.sp_fft = self.fig.add_subplot(2,2,2, position=[0.575, 0.2, 0.4, 0.6]) - self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") - self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - self.sp_fft.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") - - self.get_data() - - self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals - self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags - self.draw_time() # draw the plot - - self.plot_fft = self.sp_fft.plot([], 'bo-') # make plot for FFT - self.draw_fft() # draw the plot - - draw() - - def draw_time(self): - reals = self.iq.real - imags = self.iq.imag - self.plot_iq[0].set_data([self.time, reals]) - self.plot_iq[1].set_data([self.time, imags]) - self.sp_iq.set_xlim(self.time.min(), self.time.max()) - self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), - 1.5*max([reals.max(), imags.max()])]) - - def draw_fft(self): - self.plot_fft[0].set_data([self.freq, self.iq_fft]) - self.sp_fft.set_xlim(self.freq.min(), self.freq.max()) - self.sp_fft.set_ylim([self.iq_fft.min()-10, self.iq_fft.max()+10]) - - def update_plots(self): - self.draw_time() - self.draw_fft() - - self.xlim = self.sp_iq.get_xlim() - draw() - - def zoom(self, event): - newxlim = scipy.array(self.sp_iq.get_xlim()) - curxlim = scipy.array(self.xlim) - if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): - self.xlim = newxlim - #xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) - #xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) - xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0])))) - xmax = min(int(ceil(self.sample_rate*(self.xlim[1]))), len(self.iq)) - - iq = self.iq[xmin : xmax] - time = self.time[xmin : xmax] - - iq_fft = self.dofft(iq) - freq = self.calc_freq(time, self.sample_rate) - - self.plot_fft[0].set_data(freq, iq_fft) - self.sp_fft.axis([freq.min(), freq.max(), - iq_fft.min()-10, iq_fft.max()+10]) - - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - self.get_data() - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False - -def setup_options(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-d", "--data-type", type="string", default="complex64", - help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - return parser - -def main(): - parser = setup_options() - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_fft(options.data_type, filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_fft_c b/gr-utils/src/python/gr_plot_fft_c new file mode 100755 index 000000000..e4ee9c5a9 --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft_c @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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.plot_fft_base import plot_fft_base + +# This is a wrapper program for plot_fft_base specifically for complex data + +def main(): + parser = plot_fft_base.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_fft_base("complex64", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_fft_c.py b/gr-utils/src/python/gr_plot_fft_c.py deleted file mode 100755 index de59b36c9..000000000 --- a/gr-utils/src/python/gr_plot_fft_c.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import gr_plot_fft - -def main(): - parser = gr_plot_fft.setup_options() - parser.remove_option("--data-type") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_fft.gr_plot_fft("complex64", filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_fft_f b/gr-utils/src/python/gr_plot_fft_f new file mode 100755 index 000000000..66c75a8ff --- /dev/null +++ b/gr-utils/src/python/gr_plot_fft_f @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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.plot_fft_base import plot_fft_base + +# This is a wrapper program for plot_fft_base specifically for float data + +def main(): + parser = plot_fft_base.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_fft_base("float32", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_fft_f.py b/gr-utils/src/python/gr_plot_fft_f.py deleted file mode 100755 index f50358f01..000000000 --- a/gr-utils/src/python/gr_plot_fft_f.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -import gr_plot_fft - -def main(): - parser = gr_plot_fft.setup_options() - parser.remove_option("--data-type") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_fft.gr_plot_fft("float32", filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_float b/gr-utils/src/python/gr_plot_float new file mode 100755 index 000000000..e5c22a315 --- /dev/null +++ b/gr-utils/src/python/gr_plot_float @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.float32 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_float.py b/gr-utils/src/python/gr_plot_float.py deleted file mode 100755 index e5c22a315..000000000 --- a/gr-utils/src/python/gr_plot_float.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -from optparse import OptionParser -from gnuradio.plot_data import plot_data - -def main(): - usage="%prog: [options] input_filenames" - description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) < 1: - parser.print_help() - raise SystemExit, 1 - filenames = args - - datatype=scipy.float32 - dc = plot_data(datatype, filenames, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - diff --git a/gr-utils/src/python/gr_plot_int b/gr-utils/src/python/gr_plot_int new file mode 100755 index 000000000..b44d4360a --- /dev/null +++ b/gr-utils/src/python/gr_plot_int @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int32 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_int.py b/gr-utils/src/python/gr_plot_int.py deleted file mode 100755 index b44d4360a..000000000 --- a/gr-utils/src/python/gr_plot_int.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -from optparse import OptionParser -from gnuradio.plot_data import plot_data - -def main(): - usage="%prog: [options] input_filenames" - description = "Takes a GNU Radio integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) < 1: - parser.print_help() - raise SystemExit, 1 - filenames = args - - datatype=scipy.int32 - dc = plot_data(datatype, filenames, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - diff --git a/gr-utils/src/python/gr_plot_iq b/gr-utils/src/python/gr_plot_iq new file mode 100755 index 000000000..316e60a75 --- /dev/null +++ b/gr-utils/src/python/gr_plot_iq @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008,2011 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +class draw_iq: + def __init__(self, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 9), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('key_press_event', self.click) + show() + + def get_data(self): + self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: + print "End of File" + else: + self.reals = scipy.array([r.real for r in self.iq]) + self.imags = scipy.array([i.imag for i in self.iq]) + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + self.get_data() + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') + self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + draw() + + def update_plots(self): + self.plot_iq[0].set_data([self.time, self.reals]) + self.plot_iq[1].set_data([self.time, self.imags]) + self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), + 1.5*max([self.reals.max(), self.imags.max()])]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = draw_iq(filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_iq.py b/gr-utils/src/python/gr_plot_iq.py deleted file mode 100755 index 316e60a75..000000000 --- a/gr-utils/src/python/gr_plot_iq.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008,2011 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from pylab import * -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser - -class draw_iq: - def __init__(self, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - - self.datatype = scipy.complex64 - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - self.text_size = 22 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 9), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) - self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), - weight="heavy", size=self.text_size) - self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=self.text_size) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = self.sp_iq.get_xlim() - - self.manager = get_current_fig_manager() - connect('key_press_event', self.click) - show() - - def get_data(self): - self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//self.sizeof_data)) - try: - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - except MemoryError: - print "End of File" - else: - self.reals = scipy.array([r.real for r in self.iq]) - self.imags = scipy.array([i.imag for i in self.iq]) - self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - self.get_data() - - # Subplot for real and imaginary parts of signal - self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67]) - self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") - self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-') - self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), - 1.5*max([self.reals.max(), self.imags.max()])]) - self.sp_iq.set_xlim(self.time.min(), self.time.max()) - draw() - - def update_plots(self): - self.plot_iq[0].set_data([self.time, self.reals]) - self.plot_iq[1].set_data([self.time, self.imags]) - self.sp_iq.set_ylim([1.5*min([self.reals.min(), self.imags.min()]), - 1.5*max([self.reals.max(), self.imags.max()])]) - self.sp_iq.set_xlim(self.time.min(), self.time.max()) - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - self.get_data() - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - self.get_data() - self.update_plots() - - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False - -def main(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = draw_iq(filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_psd b/gr-utils/src/python/gr_plot_psd new file mode 100644 index 000000000..658e7b297 --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio.plot_psd_base import plot_psd_base + +# This is a wrapper program for plot_psd_base. It handles any data +# type and defaults to complex64. + +def main(): + parser = plot_psd_base.setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_psd_base(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass diff --git a/gr-utils/src/python/gr_plot_psd.py b/gr-utils/src/python/gr_plot_psd.py deleted file mode 100755 index 3dab0535a..000000000 --- a/gr-utils/src/python/gr_plot_psd.py +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008,2010,2011 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. -# - -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from pylab import * -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" - raise SystemExit, 1 - -from optparse import OptionParser -from scipy import log10 -from gnuradio.eng_option import eng_option - -class gr_plot_psd: - def __init__(self, datatype, filename, options): - self.hfile = open(filename, "r") - self.block_length = options.block - self.start = options.start - self.sample_rate = options.sample_rate - self.psdfftsize = options.psd_size - self.specfftsize = options.spec_size - - self.dospec = options.enable_spec # if we want to plot the spectrogram - - self.datatype = getattr(scipy, datatype) #scipy.complex64 - self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file - - self.axis_font_size = 16 - self.label_font_size = 18 - self.title_font_size = 20 - self.text_size = 22 - - # Setup PLOT - self.fig = figure(1, figsize=(16, 12), facecolor='w') - rcParams['xtick.labelsize'] = self.axis_font_size - rcParams['ytick.labelsize'] = self.axis_font_size - - self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), - weight="heavy", size=self.text_size) - self.text_file_pos = figtext(0.10, 0.92, "File Position: ", - weight="heavy", size=self.text_size) - self.text_block = figtext(0.35, 0.92, ("Block Size: %d" % self.block_length), - weight="heavy", size=self.text_size) - self.text_sr = figtext(0.60, 0.915, ("Sample Rate: %.2f" % self.sample_rate), - weight="heavy", size=self.text_size) - self.make_plots() - - self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) - self.button_left = Button(self.button_left_axes, "<") - self.button_left_callback = self.button_left.on_clicked(self.button_left_click) - - self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) - self.button_right = Button(self.button_right_axes, ">") - self.button_right_callback = self.button_right.on_clicked(self.button_right_click) - - self.xlim = scipy.array(self.sp_iq.get_xlim()) - - self.manager = get_current_fig_manager() - connect('draw_event', self.zoom) - connect('key_press_event', self.click) - show() - - def get_data(self): - self.position = self.hfile.tell()/self.sizeof_data - self.text_file_pos.set_text("File Position: %d" % self.position) - try: - self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) - except MemoryError: - print "End of File" - return False - else: - # retesting length here as newer version of scipy does not throw a MemoryError, just - # returns a zero-length array - if(len(self.iq) > 0): - tstep = 1.0 / self.sample_rate - #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) - self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) - - self.iq_psd, self.freq = self.dopsd(self.iq) - return True - else: - print "End of File" - return False - - def dopsd(self, iq): - ''' Need to do this here and plot later so we can do the fftshift ''' - overlap = self.psdfftsize/4 - winfunc = scipy.blackman - psd,freq = mlab.psd(iq, self.psdfftsize, self.sample_rate, - window = lambda d: d*winfunc(self.psdfftsize), - noverlap = overlap) - psd = 10.0*log10(abs(psd)) - return (psd, freq) - - def make_plots(self): - # if specified on the command-line, set file pointer - self.hfile.seek(self.sizeof_data*self.start, 1) - - iqdims = [[0.075, 0.2, 0.4, 0.6], [0.075, 0.55, 0.4, 0.3]] - psddims = [[0.575, 0.2, 0.4, 0.6], [0.575, 0.55, 0.4, 0.3]] - specdims = [0.2, 0.125, 0.6, 0.3] - - # Subplot for real and imaginary parts of signal - self.sp_iq = self.fig.add_subplot(2,2,1, position=iqdims[self.dospec]) - self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") - self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") - - # Subplot for PSD plot - self.sp_psd = self.fig.add_subplot(2,2,2, position=psddims[self.dospec]) - self.sp_psd.set_title(("PSD"), fontsize=self.title_font_size, fontweight="bold") - self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") - - r = self.get_data() - - self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals - self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags - self.draw_time(self.time, self.iq) # draw the plot - - self.plot_psd = self.sp_psd.plot([], 'b') # make plot for PSD - self.draw_psd(self.freq, self.iq_psd) # draw the plot - - - if self.dospec: - # Subplot for spectrogram plot - self.sp_spec = self.fig.add_subplot(2,2,3, position=specdims) - self.sp_spec.set_title(("Spectrogram"), fontsize=self.title_font_size, fontweight="bold") - self.sp_spec.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") - self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") - - self.draw_spec(self.time, self.iq) - - draw() - - def draw_time(self, t, iq): - reals = iq.real - imags = iq.imag - self.plot_iq[0].set_data([t, reals]) - self.plot_iq[1].set_data([t, imags]) - self.sp_iq.set_xlim(t.min(), t.max()) - self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), - 1.5*max([reals.max(), imags.max()])]) - - def draw_psd(self, f, p): - self.plot_psd[0].set_data([f, p]) - self.sp_psd.set_ylim([p.min()-10, p.max()+10]) - self.sp_psd.set_xlim([f.min(), f.max()]) - - def draw_spec(self, t, s): - overlap = self.specfftsize/4 - winfunc = scipy.blackman - self.sp_spec.clear() - self.sp_spec.specgram(s, self.specfftsize, self.sample_rate, - window = lambda d: d*winfunc(self.specfftsize), - noverlap = overlap, xextent=[t.min(), t.max()]) - - def update_plots(self): - self.draw_time(self.time, self.iq) - self.draw_psd(self.freq, self.iq_psd) - - if self.dospec: - self.draw_spec(self.time, self.iq) - - self.xlim = scipy.array(self.sp_iq.get_xlim()) # so zoom doesn't get called - - draw() - - def zoom(self, event): - newxlim = scipy.array(self.sp_iq.get_xlim()) - curxlim = scipy.array(self.xlim) - if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): - #xmin = max(0, int(ceil(self.sample_rate*(newxlim[0] - self.position)))) - #xmax = min(int(ceil(self.sample_rate*(newxlim[1] - self.position))), len(self.iq)) - xmin = max(0, int(ceil(self.sample_rate*(newxlim[0])))) - xmax = min(int(ceil(self.sample_rate*(newxlim[1]))), len(self.iq)) - - iq = scipy.array(self.iq[xmin : xmax]) - time = scipy.array(self.time[xmin : xmax]) - - iq_psd, freq = self.dopsd(iq) - - self.draw_psd(freq, iq_psd) - self.xlim = scipy.array(self.sp_iq.get_xlim()) - - draw() - - def click(self, event): - forward_valid_keys = [" ", "down", "right"] - backward_valid_keys = ["up", "left"] - - if(find(event.key, forward_valid_keys)): - self.step_forward() - - elif(find(event.key, backward_valid_keys)): - self.step_backward() - - def button_left_click(self, event): - self.step_backward() - - def button_right_click(self, event): - self.step_forward() - - def step_forward(self): - r = self.get_data() - if(r): - self.update_plots() - - def step_backward(self): - # Step back in file position - if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): - self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) - else: - self.hfile.seek(-self.hfile.tell(),1) - r = self.get_data() - if(r): - self.update_plots() - -def find(item_in, list_search): - try: - return list_search.index(item_in) != None - except ValueError: - return False - -def setup_options(): - usage="%prog: [options] input_filename" - description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec." - - parser = OptionParser(option_class=eng_option, conflict_handler="resolve", - usage=usage, description=description) - parser.add_option("-d", "--data-type", type="string", default="complex64", - help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") - parser.add_option("-B", "--block", type="int", default=8192, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="eng_float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - parser.add_option("", "--psd-size", type="int", default=1024, - help="Set the size of the PSD FFT [default=%default]") - parser.add_option("", "--spec-size", type="int", default=256, - help="Set the size of the spectrogram FFT [default=%default]") - parser.add_option("-S", "--enable-spec", action="store_true", default=False, - help="Turn on plotting the spectrogram [default=%default]") - - return parser - -def main(): - parser = setup_options() - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_psd(options.data_type, filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_psd_c b/gr-utils/src/python/gr_plot_psd_c new file mode 100755 index 000000000..192f263ec --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd_c @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# Copyright 2008 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 optparse import OptionParser +from gnuradio.plot_psd_base import plot_psd_base + +# This is a wrapper program for plot_psd_base specifically for complex data + +def main(): + parser = plot_psd_base.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_psd_base("complex64", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_psd_c.py b/gr-utils/src/python/gr_plot_psd_c.py deleted file mode 100755 index 1edc04c2b..000000000 --- a/gr-utils/src/python/gr_plot_psd_c.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008 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 optparse import OptionParser -import gr_plot_psd - -# This is a wrapper program for gr_plot_psd specifically for complex data - -def main(): - parser = gr_plot_psd.setup_options() - parser.remove_option("--data-type") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_psd.gr_plot_psd("complex64", filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_psd_f b/gr-utils/src/python/gr_plot_psd_f new file mode 100755 index 000000000..fab312645 --- /dev/null +++ b/gr-utils/src/python/gr_plot_psd_f @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# Copyright 2008 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 optparse import OptionParser +from gnuradio.plot_psd_base import plot_psd_base + +# This is a wrapper program for gr_plot_psd specifically for floating point data + +def main(): + parser = plot_psd_base.setup_options() + parser.remove_option("--data-type") + + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_psd_base("float32", filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/gr_plot_psd_f.py b/gr-utils/src/python/gr_plot_psd_f.py deleted file mode 100755 index bad6788c3..000000000 --- a/gr-utils/src/python/gr_plot_psd_f.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008 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 optparse import OptionParser -import gr_plot_psd - -# This is a wrapper program for gr_plot_psd specifically for floating point data - -def main(): - parser = gr_plot_psd.setup_options() - parser.remove_option("--data-type") - - (options, args) = parser.parse_args () - if len(args) != 1: - parser.print_help() - raise SystemExit, 1 - filename = args[0] - - dc = gr_plot_psd.gr_plot_psd("float32", filename, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - - - diff --git a/gr-utils/src/python/gr_plot_qt b/gr-utils/src/python/gr_plot_qt new file mode 100755 index 000000000..937d0014b --- /dev/null +++ b/gr-utils/src/python/gr_plot_qt @@ -0,0 +1,729 @@ +#!/usr/bin/env python + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from matplotlib import mlab +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net)" + raise SystemExit, 1 + +try: + from PyQt4 import Qt, QtCore, QtGui +except ImportError: + print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" + raise SystemExit, 1 + +try: + import PyQt4.Qwt5 as Qwt +except ImportError: + print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" + raise SystemExit, 1 + +try: + # FIXME: reenable this before committing + #from gnuradio.pyqt_plot import Ui_MainWindow + from gnuradio.pyqt_plot import Ui_MainWindow +except ImportError: + print "Could not import from pyqt_plot. Please build with \"pyuic4 pyqt_plot.ui -o pyqt_plot.py\"" + raise SystemExit, 1 + +import sys, os +from optparse import OptionParser +from gnuradio import eng_notation + + +class SpectrogramData(Qwt.QwtRasterData): + + def __init__(self, f, t): + Qwt.QwtArrayData.__init__(self, Qt.QRectF(0, 0, 0, 0)) + self.sp = scipy.array([[0], [0]]) + + def set_data(self, xfreq, ytime, data): + self.sp = data + self.freq = xfreq + self.time = ytime + boundingBox = Qt.QRectF(self.freq.min(), self.time.min(), + self.freq.max() - self.freq.min(), + self.time.max() - self.time.min()) + self.setBoundingRect(boundingBox) + + def rasterHint(self, rect): + return Qt.QSize(self.sp.shape[0], self.sp.shape[1]) + + def copy(self): + return self + + def range(self): + + return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) + + def value(self, x, y): + try: + f = int(self.freq.searchsorted(x)) + t = int(self.time.searchsorted(y)) + return self.sp[f][t-1] + except AttributeError: # if no file loaded yet + return 0 + + +class gr_plot_qt(QtGui.QMainWindow): + def __init__(self, qapp, filename, options, parent=None): + QtGui.QWidget.__init__(self, parent) + self.gui = Ui_MainWindow() + self.gui.setupUi(self) + + self.filename = None + self.block_length = options.block_length + self.start = options.start + self.sample_rate = options.sample_rate + self.psdfftsize = options.psd_size + self.specfftsize = options.spec_size + self.winfunc = scipy.blackman + self.sizeof_data = 8 + self.datatype = scipy.complex64 + self.pen_width = 1 + self.iq = list() + self.time = list() + + # Set up basic plot attributes + self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, "Time (sec)") + self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, "Frequency (Hz)") + self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)") + self.gui.specPlot.setAxisTitle(self.gui.specPlot.xBottom, "Frequency (Hz)") + self.gui.specPlot.setAxisTitle(self.gui.specPlot.yLeft, "Time (sec)") + + # Set up FFT size combo box + self.fftsizes = ["128", "256", "512", "1024", "2048", + "4096", "8192", "16384", "32768"] + self.gui.psdFFTComboBox.addItems(self.fftsizes) + self.gui.specFFTComboBox.addItems(self.fftsizes) + pos = self.gui.psdFFTComboBox.findText(Qt.QString("%1").arg(self.psdfftsize)) + self.gui.psdFFTComboBox.setCurrentIndex(pos) + pos = self.gui.specFFTComboBox.findText(Qt.QString("%1").arg(self.specfftsize)) + self.gui.specFFTComboBox.setCurrentIndex(pos) + + self.connect(self.gui.psdFFTComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.psdFFTComboBoxEdit) + self.connect(self.gui.specFFTComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.specFFTComboBoxEdit) + + # Set up color scheme box + self.color_modes = {"Black on White" : self.color_black_on_white, + "White on Black" : self.color_white_on_black, + "Blue on Black" : self.color_blue_on_black, + "Green on Black" : self.color_green_on_black} + self.gui.colorComboBox.addItems(self.color_modes.keys()) + pos = self.gui.colorComboBox.findText("Blue on Black") + self.gui.colorComboBox.setCurrentIndex(pos) + self.connect(self.gui.colorComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.colorComboBoxEdit) + + + # Set up line style combo box + self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, + "Circle" : Qwt.QwtSymbol.Ellipse, + "Diamond" : Qwt.QwtSymbol.Rect, + "Triangle" : Qwt.QwtSymbol.Triangle} + self.gui.lineStyleComboBox.addItems(self.line_styles.keys()) + pos = self.gui.lineStyleComboBox.findText("None") + self.gui.lineStyleComboBox.setCurrentIndex(pos) + self.connect(self.gui.lineStyleComboBox, + Qt.SIGNAL("activated (const QString&)"), + self.lineStyleComboBoxEdit) + + # Create zoom functionality for the plots + self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, + self.gui.timePlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.timePlot.canvas()) + + self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, + self.gui.freqPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.freqPlot.canvas()) + + self.specZoomer = Qwt.QwtPlotZoomer(self.gui.specPlot.xBottom, + self.gui.specPlot.yLeft, + Qwt.QwtPicker.PointSelection, + Qwt.QwtPicker.AlwaysOn, + self.gui.specPlot.canvas()) + + # Set up action when tab is changed + self.connect(self.gui.tabGroup, + Qt.SIGNAL("currentChanged (int)"), + self.tabChanged) + + # Add a legend to the Time plot + legend_real = Qwt.QwtLegend() + self.gui.timePlot.insertLegend(legend_real) + + # Set up slider + self.gui.plotHBar.setSingleStep(1) + self.gui.plotHBar.setPageStep(self.block_length) + self.gui.plotHBar.setMinimum(0) + self.gui.plotHBar.setMaximum(self.block_length) + self.connect(self.gui.plotHBar, + Qt.SIGNAL("valueChanged(int)"), + self.sliderMoved) + + # Connect Open action to Open Dialog box + self.connect(self.gui.action_open, + Qt.SIGNAL("activated()"), + self.open_file) + + # Connect Reload action to reload the file + self.connect(self.gui.action_reload, + Qt.SIGNAL("activated()"), + self.reload_file) + self.gui.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", + None, QtGui.QApplication.UnicodeUTF8)) + + # Set up file position boxes to update current figure + self.connect(self.gui.filePosStartLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_position_changed) + self.connect(self.gui.filePosStopLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_position_changed) + self.connect(self.gui.filePosLengthLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_length_changed) + + self.connect(self.gui.fileTimeStartLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_changed) + self.connect(self.gui.fileTimeStopLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_changed) + self.connect(self.gui.fileTimeLengthLineEdit, + Qt.SIGNAL("editingFinished()"), + self.file_time_length_changed) + + stylestr = str(self.gui.lineStyleComboBox.currentText().toAscii()) + style = self.line_styles[stylestr] + + self.rcurve = Qwt.QwtPlotCurve("Real") + self.icurve = Qwt.QwtPlotCurve("Imaginary") + self.rsym = Qwt.QwtSymbol() + self.rsym.setStyle(style) + self.rsym.setSize(10) + self.isym = Qwt.QwtSymbol() + self.isym.setStyle(style) + self.isym.setSize(10) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + + + self.icurve.attach(self.gui.timePlot) + self.rcurve.attach(self.gui.timePlot) + + self.psdcurve = Qwt.QwtPlotCurve("PSD") + self.psdcurve.attach(self.gui.freqPlot) + + # Set up specTab plot as a spectrogram + self.specdata = SpectrogramData(range(0, 10), range(0, 10)) + + colorMap = Qwt.QwtLinearColorMap(Qt.Qt.darkCyan, Qt.Qt.red) + colorMap.addColorStop(0.1, Qt.Qt.cyan) + colorMap.addColorStop(0.6, Qt.Qt.green) + colorMap.addColorStop(0.95, Qt.Qt.yellow) + + self.spec = Qwt.QwtPlotSpectrogram() + self.spec.setColorMap(colorMap) + self.spec.attach(self.gui.specPlot) + self.spec.setDisplayMode(Qwt.QwtPlotSpectrogram.ImageMode, True) + self.spec.setData(self.specdata) + + self.rightAxis = self.gui.specPlot.axisWidget(Qwt.QwtPlot.yRight) + self.rightAxis.setTitle("Magnitude (dBm)") + self.rightAxis.setColorBarEnabled(True) + self.rightAxis.setColorMap(self.spec.data().range(), + self.spec.colorMap()) + self.gui.specPlot.enableAxis(Qwt.QwtPlot.yRight) + + # Set up initial color scheme + self.color_modes["Blue on Black"]() + + # When line width spin box changes, update the pen size + self.connect(self.gui.lineWidthSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_pen_width) + self.gui.lineWidthSpinBox.setRange(1, 10) + + # When style size spin box changes, update the pen size + self.connect(self.gui.styleSizeSpinBox, + Qt.SIGNAL("valueChanged(int)"), + self.change_style_size) + self.gui.styleSizeSpinBox.setRange(1, 20) + self.gui.styleSizeSpinBox.setValue(5) + + + # Connect a signal for when the sample rate changes + self.set_sample_rate(self.sample_rate) + self.connect(self.gui.sampleRateLineEdit, + Qt.SIGNAL("editingFinished()"), + self.sample_rate_changed) + + if(filename is not None): + self.initialize(filename) + + self.show() + + def open_file(self): + filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") + if(filename != ""): + #print filename + self.initialize(filename) + + def reload_file(self): + if(self.filename): + self.initialize(self.filename) + + def initialize(self, filename): + self.filename = filename + self.hfile = open(filename, "r") + + self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) + + self.gui.filePosStartLineEdit.setText("0") + self.gui.filePosStopLineEdit.setText("0") + self.gui.fileTimeStartLineEdit.setText("0") + self.gui.fileTimeStopLineEdit.setText("0") + + self.cur_start = 0 + self.cur_stop = self.block_length + + self.init_data_input() + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.get_specgram() + self.gui.plotHBar.setSliderPosition(0) + self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) + + + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + + def init_data_input(self): + self.hfile.seek(0, os.SEEK_END) + self.signal_size = self.hfile.tell()/self.sizeof_data + #print "Sizeof File: ", self.signal_size + self.hfile.seek(0, os.SEEK_SET) + + def get_data(self, start, end): + if(end > start): + self.hfile.seek(start*self.sizeof_data, os.SEEK_SET) + self.position = start + try: + iq = scipy.fromfile(self.hfile, dtype=self.datatype, + count=end-start) + + if(len(iq) < (end-start)): + end = start + len(iq) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq))) + self.file_length_changed() + + tstep = 1.0 / self.sample_rate + self.iq = iq + self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] + + self.set_file_pos_box(start, end) + except MemoryError: + pass + else: + # Do we want to do anything about this? + pass + + def get_psd(self): + winpoints = self.winfunc(self.psdfftsize) + iq_psd, freq = mlab.psd(self.iq, Fs=self.sample_rate, + NFFT=self.psdfftsize, + noverlap=self.psdfftsize/4.0, + window=winpoints, + scale_by_freq=False) + + self.iq_psd = 10.0*scipy.log10(abs(fftpack.fftshift(iq_psd))) + self.freq = freq - self.sample_rate/2.0 + + def get_specgram(self): + winpoints = self.winfunc(self.specfftsize) + iq_spec, f, t = mlab.specgram(self.iq, Fs=self.sample_rate, + NFFT=self.specfftsize, + noverlap=self.specfftsize/4.0, + window=winpoints, + scale_by_freq=False) + + self.iq_spec = 10.0*scipy.log10(abs(iq_spec)) + self.spec_f = f + self.spec_t = t + + def psdFFTComboBoxEdit(self, fftSize): + self.psdfftsize = fftSize.toInt()[0] + self.get_psd() + self.update_psd_curves() + + def specFFTComboBoxEdit(self, fftSize): + self.specfftsize = fftSize.toInt()[0] + self.get_specgram() + self.update_specgram_curves() + + def colorComboBoxEdit(self, colorSelection): + colorstr = str(colorSelection.toAscii()) + color_func = self.color_modes[colorstr] + color_func() + + def lineStyleComboBoxEdit(self, styleSelection): + stylestr = str(styleSelection.toAscii()) + self.rsym.setStyle(self.line_styles[stylestr]) + self.isym.setStyle(self.line_styles[stylestr]) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + + def sliderMoved(self, value): + pos_start = value + pos_end = value + self.gui.plotHBar.pageStep() + + self.get_data(pos_start, pos_end) + self.get_psd() + self.get_specgram() + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + + def set_sample_rate(self, sr): + self.sample_rate = sr + srstr = eng_notation.num_to_str(self.sample_rate) + self.gui.sampleRateLineEdit.setText(Qt.QString("%1").arg(srstr)) + + def sample_rate_changed(self): + srstr = self.gui.sampleRateLineEdit.text().toAscii() + self.sample_rate = eng_notation.str_to_num(srstr) + self.set_file_pos_box(self.cur_start, self.cur_stop) + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.get_specgram() + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + + def set_file_pos_box(self, start, end): + tstart = start / self.sample_rate + tend = end / self.sample_rate + + self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(start)) + self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(end)) + self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end-start)) + + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tend-tstart)) + + def file_position_changed(self): + start = self.gui.filePosStartLineEdit.text().toInt() + end = self.gui.filePosStopLineEdit.text().toInt() + if((start[1] == True) and (end[1] == True)): + self.cur_start = start[0] + self.cur_stop = end[0] + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + + self.get_data(self.cur_start, self.cur_stop) + + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + + # If there's a non-digit character, reset box + else: + try: + self.set_file_pos_box(self.cur_start, self.cur_stop) + except AttributeError: + pass + + + def file_time_changed(self): + tstart = self.gui.fileTimeStartLineEdit.text().toDouble() + tstop = self.gui.fileTimeStopLineEdit.text().toDouble() + if((tstart[1] == True) and (tstop[1] == True)): + self.cur_start = int(tstart[0] * self.sample_rate) + self.cur_stop = int(tstop[0] * self.sample_rate) + self.get_data(self.cur_start, self.cur_stop) + + self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(self.cur_start)) + self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(self.cur_stop)) + + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + def file_length_changed(self): + start = self.gui.filePosStartLineEdit.text().toInt() + length = self.gui.filePosLengthLineEdit.text().toInt() + + if((start[1] == True) and (length[1] == True)): + self.cur_start = start[0] + self.block_length = length[0] + self.cur_stop = self.cur_start + self.block_length + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + tlen = self.block_length / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) + + self.gui.plotHBar.setPageStep(self.block_length) + + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.get_specgram() + + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + def file_time_length_changed(self): + tstart = self.gui.fileTimeStartLineEdit.text().toDouble() + tlength = self.gui.fileTimeLengthLineEdit.text().toDouble() + if((tstart[1] == True) and (tlength[1] == True)): + self.cur_start = int(tstart[0] * self.sample_rate) + self.block_length = int(tlength[0] * self.sample_rate) + self.cur_stop = self.cur_start + self.block_length + + tstart = self.cur_start / self.sample_rate + tend = self.cur_stop / self.sample_rate + tlen = self.block_length / self.sample_rate + self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) + self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) + self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) + + self.get_data(self.cur_start, self.cur_stop) + self.get_psd() + self.get_specgram() + + self.update_time_curves() + self.update_psd_curves() + self.update_specgram_curves() + # If there's a non-digit character, reset box + else: + self.set_file_pos_box(self.cur_start, self.cur_stop) + + + def update_time_curves(self): + self.icurve.setData(self.time, self.iq.imag) + self.rcurve.setData(self.time, self.iq.real) + + # Reset the x-axis to the new time scale + iqmax = 1.5 * max(max(self.iq.real), max(self.iq.imag)) + iqmin = 1.5 * min(min(self.iq.real), min(self.iq.imag)) + self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, + min(self.time), + max(self.time)) + self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, + iqmin, + iqmax) + + # Set the zoomer base to unzoom to the new axis + self.timeZoomer.setZoomBase() + + self.gui.timePlot.replot() + + def update_psd_curves(self): + self.psdcurve.setData(self.freq, self.iq_psd) + + self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, + min(self.freq), + max(self.freq)) + + # Set the zoomer base to unzoom to the new axis + self.freqZoomer.setZoomBase() + + self.gui.freqPlot.replot() + + def update_specgram_curves(self): + # We don't have to reset the data for the speccurve here + # since this is taken care of in the SpectrogramData class + self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec) + + # Set the color map based on the new data + self.rightAxis.setColorMap(self.spec.data().range(), + self.spec.colorMap()) + + # Set the new axis base; include right axis for the intenisty color bar + self.gui.specPlot.setAxisScale(self.gui.specPlot.xBottom, + min(self.spec_f), + max(self.spec_f)) + self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft, + min(self.spec_t), + max(self.spec_t)) + self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight, + self.iq_spec.min(), + self.iq_spec.max()) + + # Set the zoomer base to unzoom to the new axis + self.specZoomer.setZoomBase() + + self.gui.specPlot.replot() + + def tabChanged(self, index): + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + self.gui.specPlot.replot() + + def change_pen_width(self, width): + self.pen_width = width + colormode = str(self.gui.colorComboBox.currentText().toAscii()) + color_func = self.color_modes[colormode]() + + def change_style_size(self, size): + self.rsym.setSize(size) + self.isym.setSize(size) + self.rcurve.setSymbol(self.rsym) + self.icurve.setSymbol(self.isym) + self.gui.timePlot.replot() + + def color_black_on_white(self): + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + blackPen = Qt.QPen(Qt.QBrush(Qt.QColor("black")), self.pen_width) + bluePen = Qt.QPen(Qt.QBrush(Qt.QColor(blue)), self.pen_width) + redPen = Qt.QPen(Qt.QBrush(Qt.QColor(red)), self.pen_width) + + self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) + self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) + self.timeZoomer.setTrackerPen(blackPen) + self.timeZoomer.setRubberBandPen(blackPen) + self.freqZoomer.setTrackerPen(blackPen) + self.freqZoomer.setRubberBandPen(blackPen) + self.psdcurve.setPen(bluePen) + self.rcurve.setPen(bluePen) + self.icurve.setPen(redPen) + + self.rsym.setPen(bluePen) + self.isym.setPen(redPen) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + def color_white_on_black(self): + white = QtGui.qRgb(0xFF, 0xFF, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + whiteBrush = Qt.QBrush(Qt.QColor(white)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + + def color_green_on_black(self): + green = QtGui.qRgb(0x00, 0xFF, 0x00) + red = QtGui.qRgb(0xFF, 0x00, 0x50) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + greenBrush = Qt.QBrush(Qt.QColor(green)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + + def color_blue_on_black(self): + blue = QtGui.qRgb(0x00, 0x00, 0xFF) + red = QtGui.qRgb(0xFF, 0x00, 0x00) + + whiteBrush = Qt.QBrush(Qt.QColor("white")) + blueBrush = Qt.QBrush(Qt.QColor(blue)) + redBrush = Qt.QBrush(Qt.QColor(red)) + + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) + self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) + self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) + self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) + self.psdcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.rcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) + self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) + + self.gui.timePlot.replot() + self.gui.freqPlot.replot() + +def setup_options(): + usage="%prog: [options] (input_filename)" + description = "" + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block-length", type="int", default=8192, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + parser.add_option("", "--psd-size", type="int", default=2048, + help="Set the size of the PSD FFT [default=%default]") + parser.add_option("", "--spec-size", type="int", default=2048, + help="Set the size of the spectrogram FFT [default=%default]") + + return parser + +def main(args): + parser = setup_options() + (options, args) = parser.parse_args () + + if(len(args) == 1): + filename = args[0] + else: + filename = None + + app = Qt.QApplication(args) + gplt = gr_plot_qt(app, filename, options) + app.exec_() + +if __name__ == '__main__': + main(sys.argv) + diff --git a/gr-utils/src/python/gr_plot_qt.py b/gr-utils/src/python/gr_plot_qt.py deleted file mode 100755 index f3dc472f5..000000000 --- a/gr-utils/src/python/gr_plot_qt.py +++ /dev/null @@ -1,729 +0,0 @@ -#!/usr/bin/env python - -try: - import scipy - from scipy import fftpack -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -try: - from matplotlib import mlab -except ImportError: - print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net)" - raise SystemExit, 1 - -try: - from PyQt4 import Qt, QtCore, QtGui -except ImportError: - print "Please install PyQt4 to run this script (http://www.riverbankcomputing.co.uk/software/pyqt/download)" - raise SystemExit, 1 - -try: - import PyQt4.Qwt5 as Qwt -except ImportError: - print "Please install PyQwt5 to run this script (http://pyqwt.sourceforge.net/)" - raise SystemExit, 1 - -try: - # FIXME: reenable this before committing - #from gnuradio.pyqt_plot import Ui_MainWindow - from pyqt_plot import Ui_MainWindow -except ImportError: - print "Could not import from pyqt_plot. Please build with \"pyuic4 pyqt_plot.ui -o pyqt_plot.py\"" - raise SystemExit, 1 - -import sys, os -from optparse import OptionParser -from gnuradio import eng_notation - - -class SpectrogramData(Qwt.QwtRasterData): - - def __init__(self, f, t): - Qwt.QwtArrayData.__init__(self, Qt.QRectF(0, 0, 0, 0)) - self.sp = scipy.array([[0], [0]]) - - def set_data(self, xfreq, ytime, data): - self.sp = data - self.freq = xfreq - self.time = ytime - boundingBox = Qt.QRectF(self.freq.min(), self.time.min(), - self.freq.max() - self.freq.min(), - self.time.max() - self.time.min()) - self.setBoundingRect(boundingBox) - - def rasterHint(self, rect): - return Qt.QSize(self.sp.shape[0], self.sp.shape[1]) - - def copy(self): - return self - - def range(self): - - return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) - - def value(self, x, y): - try: - f = int(self.freq.searchsorted(x)) - t = int(self.time.searchsorted(y)) - return self.sp[f][t-1] - except AttributeError: # if no file loaded yet - return 0 - - -class gr_plot_qt(QtGui.QMainWindow): - def __init__(self, qapp, filename, options, parent=None): - QtGui.QWidget.__init__(self, parent) - self.gui = Ui_MainWindow() - self.gui.setupUi(self) - - self.filename = None - self.block_length = options.block_length - self.start = options.start - self.sample_rate = options.sample_rate - self.psdfftsize = options.psd_size - self.specfftsize = options.spec_size - self.winfunc = scipy.blackman - self.sizeof_data = 8 - self.datatype = scipy.complex64 - self.pen_width = 1 - self.iq = list() - self.time = list() - - # Set up basic plot attributes - self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom, "Time (sec)") - self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft, "Amplitude (V)") - self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom, "Frequency (Hz)") - self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft, "Magnitude (dB)") - self.gui.specPlot.setAxisTitle(self.gui.specPlot.xBottom, "Frequency (Hz)") - self.gui.specPlot.setAxisTitle(self.gui.specPlot.yLeft, "Time (sec)") - - # Set up FFT size combo box - self.fftsizes = ["128", "256", "512", "1024", "2048", - "4096", "8192", "16384", "32768"] - self.gui.psdFFTComboBox.addItems(self.fftsizes) - self.gui.specFFTComboBox.addItems(self.fftsizes) - pos = self.gui.psdFFTComboBox.findText(Qt.QString("%1").arg(self.psdfftsize)) - self.gui.psdFFTComboBox.setCurrentIndex(pos) - pos = self.gui.specFFTComboBox.findText(Qt.QString("%1").arg(self.specfftsize)) - self.gui.specFFTComboBox.setCurrentIndex(pos) - - self.connect(self.gui.psdFFTComboBox, - Qt.SIGNAL("activated (const QString&)"), - self.psdFFTComboBoxEdit) - self.connect(self.gui.specFFTComboBox, - Qt.SIGNAL("activated (const QString&)"), - self.specFFTComboBoxEdit) - - # Set up color scheme box - self.color_modes = {"Black on White" : self.color_black_on_white, - "White on Black" : self.color_white_on_black, - "Blue on Black" : self.color_blue_on_black, - "Green on Black" : self.color_green_on_black} - self.gui.colorComboBox.addItems(self.color_modes.keys()) - pos = self.gui.colorComboBox.findText("Blue on Black") - self.gui.colorComboBox.setCurrentIndex(pos) - self.connect(self.gui.colorComboBox, - Qt.SIGNAL("activated (const QString&)"), - self.colorComboBoxEdit) - - - # Set up line style combo box - self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, - "Circle" : Qwt.QwtSymbol.Ellipse, - "Diamond" : Qwt.QwtSymbol.Rect, - "Triangle" : Qwt.QwtSymbol.Triangle} - self.gui.lineStyleComboBox.addItems(self.line_styles.keys()) - pos = self.gui.lineStyleComboBox.findText("None") - self.gui.lineStyleComboBox.setCurrentIndex(pos) - self.connect(self.gui.lineStyleComboBox, - Qt.SIGNAL("activated (const QString&)"), - self.lineStyleComboBoxEdit) - - # Create zoom functionality for the plots - self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom, - self.gui.timePlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.timePlot.canvas()) - - self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom, - self.gui.freqPlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.freqPlot.canvas()) - - self.specZoomer = Qwt.QwtPlotZoomer(self.gui.specPlot.xBottom, - self.gui.specPlot.yLeft, - Qwt.QwtPicker.PointSelection, - Qwt.QwtPicker.AlwaysOn, - self.gui.specPlot.canvas()) - - # Set up action when tab is changed - self.connect(self.gui.tabGroup, - Qt.SIGNAL("currentChanged (int)"), - self.tabChanged) - - # Add a legend to the Time plot - legend_real = Qwt.QwtLegend() - self.gui.timePlot.insertLegend(legend_real) - - # Set up slider - self.gui.plotHBar.setSingleStep(1) - self.gui.plotHBar.setPageStep(self.block_length) - self.gui.plotHBar.setMinimum(0) - self.gui.plotHBar.setMaximum(self.block_length) - self.connect(self.gui.plotHBar, - Qt.SIGNAL("valueChanged(int)"), - self.sliderMoved) - - # Connect Open action to Open Dialog box - self.connect(self.gui.action_open, - Qt.SIGNAL("activated()"), - self.open_file) - - # Connect Reload action to reload the file - self.connect(self.gui.action_reload, - Qt.SIGNAL("activated()"), - self.reload_file) - self.gui.action_reload.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+R", - None, QtGui.QApplication.UnicodeUTF8)) - - # Set up file position boxes to update current figure - self.connect(self.gui.filePosStartLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_position_changed) - self.connect(self.gui.filePosStopLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_position_changed) - self.connect(self.gui.filePosLengthLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_length_changed) - - self.connect(self.gui.fileTimeStartLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_time_changed) - self.connect(self.gui.fileTimeStopLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_time_changed) - self.connect(self.gui.fileTimeLengthLineEdit, - Qt.SIGNAL("editingFinished()"), - self.file_time_length_changed) - - stylestr = str(self.gui.lineStyleComboBox.currentText().toAscii()) - style = self.line_styles[stylestr] - - self.rcurve = Qwt.QwtPlotCurve("Real") - self.icurve = Qwt.QwtPlotCurve("Imaginary") - self.rsym = Qwt.QwtSymbol() - self.rsym.setStyle(style) - self.rsym.setSize(10) - self.isym = Qwt.QwtSymbol() - self.isym.setStyle(style) - self.isym.setSize(10) - self.rcurve.setSymbol(self.rsym) - self.icurve.setSymbol(self.isym) - - - self.icurve.attach(self.gui.timePlot) - self.rcurve.attach(self.gui.timePlot) - - self.psdcurve = Qwt.QwtPlotCurve("PSD") - self.psdcurve.attach(self.gui.freqPlot) - - # Set up specTab plot as a spectrogram - self.specdata = SpectrogramData(range(0, 10), range(0, 10)) - - colorMap = Qwt.QwtLinearColorMap(Qt.Qt.darkCyan, Qt.Qt.red) - colorMap.addColorStop(0.1, Qt.Qt.cyan) - colorMap.addColorStop(0.6, Qt.Qt.green) - colorMap.addColorStop(0.95, Qt.Qt.yellow) - - self.spec = Qwt.QwtPlotSpectrogram() - self.spec.setColorMap(colorMap) - self.spec.attach(self.gui.specPlot) - self.spec.setDisplayMode(Qwt.QwtPlotSpectrogram.ImageMode, True) - self.spec.setData(self.specdata) - - self.rightAxis = self.gui.specPlot.axisWidget(Qwt.QwtPlot.yRight) - self.rightAxis.setTitle("Magnitude (dBm)") - self.rightAxis.setColorBarEnabled(True) - self.rightAxis.setColorMap(self.spec.data().range(), - self.spec.colorMap()) - self.gui.specPlot.enableAxis(Qwt.QwtPlot.yRight) - - # Set up initial color scheme - self.color_modes["Blue on Black"]() - - # When line width spin box changes, update the pen size - self.connect(self.gui.lineWidthSpinBox, - Qt.SIGNAL("valueChanged(int)"), - self.change_pen_width) - self.gui.lineWidthSpinBox.setRange(1, 10) - - # When style size spin box changes, update the pen size - self.connect(self.gui.styleSizeSpinBox, - Qt.SIGNAL("valueChanged(int)"), - self.change_style_size) - self.gui.styleSizeSpinBox.setRange(1, 20) - self.gui.styleSizeSpinBox.setValue(5) - - - # Connect a signal for when the sample rate changes - self.set_sample_rate(self.sample_rate) - self.connect(self.gui.sampleRateLineEdit, - Qt.SIGNAL("editingFinished()"), - self.sample_rate_changed) - - if(filename is not None): - self.initialize(filename) - - self.show() - - def open_file(self): - filename = Qt.QFileDialog.getOpenFileName(self, "Open", ".") - if(filename != ""): - #print filename - self.initialize(filename) - - def reload_file(self): - if(self.filename): - self.initialize(self.filename) - - def initialize(self, filename): - self.filename = filename - self.hfile = open(filename, "r") - - self.setWindowTitle(("GNU Radio File Plot Utility: %s" % filename)) - - self.gui.filePosStartLineEdit.setText("0") - self.gui.filePosStopLineEdit.setText("0") - self.gui.fileTimeStartLineEdit.setText("0") - self.gui.fileTimeStopLineEdit.setText("0") - - self.cur_start = 0 - self.cur_stop = self.block_length - - self.init_data_input() - self.get_data(self.cur_start, self.cur_stop) - self.get_psd() - self.get_specgram() - self.gui.plotHBar.setSliderPosition(0) - self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) - - - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - - def init_data_input(self): - self.hfile.seek(0, os.SEEK_END) - self.signal_size = self.hfile.tell()/self.sizeof_data - #print "Sizeof File: ", self.signal_size - self.hfile.seek(0, os.SEEK_SET) - - def get_data(self, start, end): - if(end > start): - self.hfile.seek(start*self.sizeof_data, os.SEEK_SET) - self.position = start - try: - iq = scipy.fromfile(self.hfile, dtype=self.datatype, - count=end-start) - - if(len(iq) < (end-start)): - end = start + len(iq) - self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(len(iq))) - self.file_length_changed() - - tstep = 1.0 / self.sample_rate - self.iq = iq - self.time = [tstep*(self.position + i) for i in xrange(len(self.iq))] - - self.set_file_pos_box(start, end) - except MemoryError: - pass - else: - # Do we want to do anything about this? - pass - - def get_psd(self): - winpoints = self.winfunc(self.psdfftsize) - iq_psd, freq = mlab.psd(self.iq, Fs=self.sample_rate, - NFFT=self.psdfftsize, - noverlap=self.psdfftsize/4.0, - window=winpoints, - scale_by_freq=False) - - self.iq_psd = 10.0*scipy.log10(abs(fftpack.fftshift(iq_psd))) - self.freq = freq - self.sample_rate/2.0 - - def get_specgram(self): - winpoints = self.winfunc(self.specfftsize) - iq_spec, f, t = mlab.specgram(self.iq, Fs=self.sample_rate, - NFFT=self.specfftsize, - noverlap=self.specfftsize/4.0, - window=winpoints, - scale_by_freq=False) - - self.iq_spec = 10.0*scipy.log10(abs(iq_spec)) - self.spec_f = f - self.spec_t = t - - def psdFFTComboBoxEdit(self, fftSize): - self.psdfftsize = fftSize.toInt()[0] - self.get_psd() - self.update_psd_curves() - - def specFFTComboBoxEdit(self, fftSize): - self.specfftsize = fftSize.toInt()[0] - self.get_specgram() - self.update_specgram_curves() - - def colorComboBoxEdit(self, colorSelection): - colorstr = str(colorSelection.toAscii()) - color_func = self.color_modes[colorstr] - color_func() - - def lineStyleComboBoxEdit(self, styleSelection): - stylestr = str(styleSelection.toAscii()) - self.rsym.setStyle(self.line_styles[stylestr]) - self.isym.setStyle(self.line_styles[stylestr]) - self.rcurve.setSymbol(self.rsym) - self.icurve.setSymbol(self.isym) - self.gui.timePlot.replot() - - def sliderMoved(self, value): - pos_start = value - pos_end = value + self.gui.plotHBar.pageStep() - - self.get_data(pos_start, pos_end) - self.get_psd() - self.get_specgram() - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - - def set_sample_rate(self, sr): - self.sample_rate = sr - srstr = eng_notation.num_to_str(self.sample_rate) - self.gui.sampleRateLineEdit.setText(Qt.QString("%1").arg(srstr)) - - def sample_rate_changed(self): - srstr = self.gui.sampleRateLineEdit.text().toAscii() - self.sample_rate = eng_notation.str_to_num(srstr) - self.set_file_pos_box(self.cur_start, self.cur_stop) - self.get_data(self.cur_start, self.cur_stop) - self.get_psd() - self.get_specgram() - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - - def set_file_pos_box(self, start, end): - tstart = start / self.sample_rate - tend = end / self.sample_rate - - self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(start)) - self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(end)) - self.gui.filePosLengthLineEdit.setText(Qt.QString("%1").arg(end-start)) - - self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) - self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) - self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tend-tstart)) - - def file_position_changed(self): - start = self.gui.filePosStartLineEdit.text().toInt() - end = self.gui.filePosStopLineEdit.text().toInt() - if((start[1] == True) and (end[1] == True)): - self.cur_start = start[0] - self.cur_stop = end[0] - - tstart = self.cur_start / self.sample_rate - tend = self.cur_stop / self.sample_rate - self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) - self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) - - self.get_data(self.cur_start, self.cur_stop) - - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - - # If there's a non-digit character, reset box - else: - try: - self.set_file_pos_box(self.cur_start, self.cur_stop) - except AttributeError: - pass - - - def file_time_changed(self): - tstart = self.gui.fileTimeStartLineEdit.text().toDouble() - tstop = self.gui.fileTimeStopLineEdit.text().toDouble() - if((tstart[1] == True) and (tstop[1] == True)): - self.cur_start = int(tstart[0] * self.sample_rate) - self.cur_stop = int(tstop[0] * self.sample_rate) - self.get_data(self.cur_start, self.cur_stop) - - self.gui.filePosStartLineEdit.setText(Qt.QString("%1").arg(self.cur_start)) - self.gui.filePosStopLineEdit.setText(Qt.QString("%1").arg(self.cur_stop)) - - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - # If there's a non-digit character, reset box - else: - self.set_file_pos_box(self.cur_start, self.cur_stop) - - def file_length_changed(self): - start = self.gui.filePosStartLineEdit.text().toInt() - length = self.gui.filePosLengthLineEdit.text().toInt() - - if((start[1] == True) and (length[1] == True)): - self.cur_start = start[0] - self.block_length = length[0] - self.cur_stop = self.cur_start + self.block_length - - tstart = self.cur_start / self.sample_rate - tend = self.cur_stop / self.sample_rate - tlen = self.block_length / self.sample_rate - self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) - self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) - self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) - - self.gui.plotHBar.setPageStep(self.block_length) - - self.get_data(self.cur_start, self.cur_stop) - self.get_psd() - self.get_specgram() - - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - # If there's a non-digit character, reset box - else: - self.set_file_pos_box(self.cur_start, self.cur_stop) - - def file_time_length_changed(self): - tstart = self.gui.fileTimeStartLineEdit.text().toDouble() - tlength = self.gui.fileTimeLengthLineEdit.text().toDouble() - if((tstart[1] == True) and (tlength[1] == True)): - self.cur_start = int(tstart[0] * self.sample_rate) - self.block_length = int(tlength[0] * self.sample_rate) - self.cur_stop = self.cur_start + self.block_length - - tstart = self.cur_start / self.sample_rate - tend = self.cur_stop / self.sample_rate - tlen = self.block_length / self.sample_rate - self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) - self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) - self.gui.fileTimeLengthLineEdit.setText(Qt.QString("%1").arg(tlen)) - - self.get_data(self.cur_start, self.cur_stop) - self.get_psd() - self.get_specgram() - - self.update_time_curves() - self.update_psd_curves() - self.update_specgram_curves() - # If there's a non-digit character, reset box - else: - self.set_file_pos_box(self.cur_start, self.cur_stop) - - - def update_time_curves(self): - self.icurve.setData(self.time, self.iq.imag) - self.rcurve.setData(self.time, self.iq.real) - - # Reset the x-axis to the new time scale - iqmax = 1.5 * max(max(self.iq.real), max(self.iq.imag)) - iqmin = 1.5 * min(min(self.iq.real), min(self.iq.imag)) - self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom, - min(self.time), - max(self.time)) - self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, - iqmin, - iqmax) - - # Set the zoomer base to unzoom to the new axis - self.timeZoomer.setZoomBase() - - self.gui.timePlot.replot() - - def update_psd_curves(self): - self.psdcurve.setData(self.freq, self.iq_psd) - - self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, - min(self.freq), - max(self.freq)) - - # Set the zoomer base to unzoom to the new axis - self.freqZoomer.setZoomBase() - - self.gui.freqPlot.replot() - - def update_specgram_curves(self): - # We don't have to reset the data for the speccurve here - # since this is taken care of in the SpectrogramData class - self.specdata.set_data(self.spec_f, self.spec_t, self.iq_spec) - - # Set the color map based on the new data - self.rightAxis.setColorMap(self.spec.data().range(), - self.spec.colorMap()) - - # Set the new axis base; include right axis for the intenisty color bar - self.gui.specPlot.setAxisScale(self.gui.specPlot.xBottom, - min(self.spec_f), - max(self.spec_f)) - self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft, - min(self.spec_t), - max(self.spec_t)) - self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight, - self.iq_spec.min(), - self.iq_spec.max()) - - # Set the zoomer base to unzoom to the new axis - self.specZoomer.setZoomBase() - - self.gui.specPlot.replot() - - def tabChanged(self, index): - self.gui.timePlot.replot() - self.gui.freqPlot.replot() - self.gui.specPlot.replot() - - def change_pen_width(self, width): - self.pen_width = width - colormode = str(self.gui.colorComboBox.currentText().toAscii()) - color_func = self.color_modes[colormode]() - - def change_style_size(self, size): - self.rsym.setSize(size) - self.isym.setSize(size) - self.rcurve.setSymbol(self.rsym) - self.icurve.setSymbol(self.isym) - self.gui.timePlot.replot() - - def color_black_on_white(self): - blue = QtGui.qRgb(0x00, 0x00, 0xFF) - red = QtGui.qRgb(0xFF, 0x00, 0x00) - - blackPen = Qt.QPen(Qt.QBrush(Qt.QColor("black")), self.pen_width) - bluePen = Qt.QPen(Qt.QBrush(Qt.QColor(blue)), self.pen_width) - redPen = Qt.QPen(Qt.QBrush(Qt.QColor(red)), self.pen_width) - - self.gui.timePlot.setCanvasBackground(Qt.QColor("white")) - self.gui.freqPlot.setCanvasBackground(Qt.QColor("white")) - self.timeZoomer.setTrackerPen(blackPen) - self.timeZoomer.setRubberBandPen(blackPen) - self.freqZoomer.setTrackerPen(blackPen) - self.freqZoomer.setRubberBandPen(blackPen) - self.psdcurve.setPen(bluePen) - self.rcurve.setPen(bluePen) - self.icurve.setPen(redPen) - - self.rsym.setPen(bluePen) - self.isym.setPen(redPen) - - self.gui.timePlot.replot() - self.gui.freqPlot.replot() - - def color_white_on_black(self): - white = QtGui.qRgb(0xFF, 0xFF, 0xFF) - red = QtGui.qRgb(0xFF, 0x00, 0x00) - - whiteBrush = Qt.QBrush(Qt.QColor("white")) - whiteBrush = Qt.QBrush(Qt.QColor(white)) - redBrush = Qt.QBrush(Qt.QColor(red)) - - self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) - self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.psdcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) - self.rcurve.setPen(Qt.QPen(whiteBrush, self.pen_width)) - self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) - - self.gui.timePlot.replot() - self.gui.freqPlot.replot() - - - def color_green_on_black(self): - green = QtGui.qRgb(0x00, 0xFF, 0x00) - red = QtGui.qRgb(0xFF, 0x00, 0x50) - - whiteBrush = Qt.QBrush(Qt.QColor("white")) - greenBrush = Qt.QBrush(Qt.QColor(green)) - redBrush = Qt.QBrush(Qt.QColor(red)) - - self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) - self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.psdcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) - self.rcurve.setPen(Qt.QPen(greenBrush, self.pen_width)) - self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) - - self.gui.timePlot.replot() - self.gui.freqPlot.replot() - - def color_blue_on_black(self): - blue = QtGui.qRgb(0x00, 0x00, 0xFF) - red = QtGui.qRgb(0xFF, 0x00, 0x00) - - whiteBrush = Qt.QBrush(Qt.QColor("white")) - blueBrush = Qt.QBrush(Qt.QColor(blue)) - redBrush = Qt.QBrush(Qt.QColor(red)) - - self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) - self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) - self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.timeZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) - self.freqZoomer.setRubberBandPen(Qt.QPen(whiteBrush, self.pen_width)) - self.psdcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) - self.rcurve.setPen(Qt.QPen(blueBrush, self.pen_width)) - self.icurve.setPen(Qt.QPen(redBrush, self.pen_width)) - - self.gui.timePlot.replot() - self.gui.freqPlot.replot() - -def setup_options(): - usage="%prog: [options] (input_filename)" - description = "" - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block-length", type="int", default=8192, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - parser.add_option("", "--psd-size", type="int", default=2048, - help="Set the size of the PSD FFT [default=%default]") - parser.add_option("", "--spec-size", type="int", default=2048, - help="Set the size of the spectrogram FFT [default=%default]") - - return parser - -def main(args): - parser = setup_options() - (options, args) = parser.parse_args () - - if(len(args) == 1): - filename = args[0] - else: - filename = None - - app = Qt.QApplication(args) - gplt = gr_plot_qt(app, filename, options) - app.exec_() - -if __name__ == '__main__': - main(sys.argv) - diff --git a/gr-utils/src/python/gr_plot_short b/gr-utils/src/python/gr_plot_short new file mode 100755 index 000000000..3466e0b7d --- /dev/null +++ b/gr-utils/src/python/gr_plot_short @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008 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. +# + +try: + import scipy +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +from optparse import OptionParser +from gnuradio.plot_data import plot_data + +def main(): + usage="%prog: [options] input_filenames" + description = "Takes a GNU Radio short integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + + (options, args) = parser.parse_args () + if len(args) < 1: + parser.print_help() + raise SystemExit, 1 + filenames = args + + datatype=scipy.int16 + dc = plot_data(datatype, filenames, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/gr_plot_short.py b/gr-utils/src/python/gr_plot_short.py deleted file mode 100755 index 3466e0b7d..000000000 --- a/gr-utils/src/python/gr_plot_short.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2007,2008 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. -# - -try: - import scipy -except ImportError: - print "Please install SciPy to run this script (http://www.scipy.org/)" - raise SystemExit, 1 - -from optparse import OptionParser -from gnuradio.plot_data import plot_data - -def main(): - usage="%prog: [options] input_filenames" - description = "Takes a GNU Radio short integer binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." - - parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) - parser.add_option("-B", "--block", type="int", default=1000, - help="Specify the block size [default=%default]") - parser.add_option("-s", "--start", type="int", default=0, - help="Specify where to start in the file [default=%default]") - parser.add_option("-R", "--sample-rate", type="float", default=1.0, - help="Set the sampler rate of the data [default=%default]") - - (options, args) = parser.parse_args () - if len(args) < 1: - parser.print_help() - raise SystemExit, 1 - filenames = args - - datatype=scipy.int16 - dc = plot_data(datatype, filenames, options) - -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - pass - diff --git a/gr-utils/src/python/plot_fft_base.py b/gr-utils/src/python/plot_fft_base.py new file mode 100755 index 000000000..0b5df504b --- /dev/null +++ b/gr-utils/src/python/plot_fft_base.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008,2011 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. +# + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser + +class plot_fft_base: + def __init__(self, datatype, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + + self.datatype = getattr(scipy, datatype) + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 12), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) + self.text_block = figtext(0.35, 0.88, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = self.sp_iq.get_xlim() + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.position = self.hfile.tell()/self.sizeof_data + self.text_file_pos.set_text("File Position: %d" % (self.position)) + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: + print "End of File" + else: + self.iq_fft = self.dofft(self.iq) + + tstep = 1.0 / self.sample_rate + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) + + self.freq = self.calc_freq(self.time, self.sample_rate) + + def dofft(self, iq): + N = len(iq) + iq_fft = scipy.fftpack.fftshift(scipy.fft(iq)) # fft and shift axis + iq_fft = 20*scipy.log10(abs((iq_fft+1e-15)/N)) # convert to decibels, adjust power + # adding 1e-15 (-300 dB) to protect against value errors if an item in iq_fft is 0 + return iq_fft + + def calc_freq(self, time, sample_rate): + N = len(time) + Fs = 1.0 / (time.max() - time.min()) + Fn = 0.5 * sample_rate + freq = scipy.array([-Fn + i*Fs for i in xrange(N)]) + return freq + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,2,1, position=[0.075, 0.2, 0.4, 0.6]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + + # Subplot for FFT plot + self.sp_fft = self.fig.add_subplot(2,2,2, position=[0.575, 0.2, 0.4, 0.6]) + self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold") + self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_fft.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") + + self.get_data() + + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals + self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags + self.draw_time() # draw the plot + + self.plot_fft = self.sp_fft.plot([], 'bo-') # make plot for FFT + self.draw_fft() # draw the plot + + draw() + + def draw_time(self): + reals = self.iq.real + imags = self.iq.imag + self.plot_iq[0].set_data([self.time, reals]) + self.plot_iq[1].set_data([self.time, imags]) + self.sp_iq.set_xlim(self.time.min(), self.time.max()) + self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), + 1.5*max([reals.max(), imags.max()])]) + + def draw_fft(self): + self.plot_fft[0].set_data([self.freq, self.iq_fft]) + self.sp_fft.set_xlim(self.freq.min(), self.freq.max()) + self.sp_fft.set_ylim([self.iq_fft.min()-10, self.iq_fft.max()+10]) + + def update_plots(self): + self.draw_time() + self.draw_fft() + + self.xlim = self.sp_iq.get_xlim() + draw() + + def zoom(self, event): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): + self.xlim = newxlim + #xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0] - self.position)))) + #xmax = min(int(ceil(self.sample_rate*(self.xlim[1] - self.position))), len(self.iq)) + xmin = max(0, int(ceil(self.sample_rate*(self.xlim[0])))) + xmax = min(int(ceil(self.sample_rate*(self.xlim[1]))), len(self.iq)) + + iq = self.iq[xmin : xmax] + time = self.time[xmin : xmax] + + iq_fft = self.dofft(iq) + freq = self.calc_freq(time, self.sample_rate) + + self.plot_fft[0].set_data(freq, iq_fft) + self.sp_fft.axis([freq.min(), freq.max(), + iq_fft.min()-10, iq_fft.max()+10]) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + self.get_data() + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + self.get_data() + self.update_plots() + + @staticmethod + def setup_options(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-d", "--data-type", type="string", default="complex64", + help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") + parser.add_option("-B", "--block", type="int", default=1000, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + return parser + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + parser = plot_fft_base.setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_fft_base(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + diff --git a/gr-utils/src/python/plot_psd_base.py b/gr-utils/src/python/plot_psd_base.py new file mode 100755 index 000000000..78eed5f71 --- /dev/null +++ b/gr-utils/src/python/plot_psd_base.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python +# +# Copyright 2007,2008,2010,2011 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. +# + +try: + import scipy + from scipy import fftpack +except ImportError: + print "Please install SciPy to run this script (http://www.scipy.org/)" + raise SystemExit, 1 + +try: + from pylab import * +except ImportError: + print "Please install Matplotlib to run this script (http://matplotlib.sourceforge.net/)" + raise SystemExit, 1 + +from optparse import OptionParser +from scipy import log10 +from gnuradio.eng_option import eng_option + +class plot_psd_base: + def __init__(self, datatype, filename, options): + self.hfile = open(filename, "r") + self.block_length = options.block + self.start = options.start + self.sample_rate = options.sample_rate + self.psdfftsize = options.psd_size + self.specfftsize = options.spec_size + + self.dospec = options.enable_spec # if we want to plot the spectrogram + + self.datatype = getattr(scipy, datatype) #scipy.complex64 + self.sizeof_data = self.datatype().nbytes # number of bytes per sample in file + + self.axis_font_size = 16 + self.label_font_size = 18 + self.title_font_size = 20 + self.text_size = 22 + + # Setup PLOT + self.fig = figure(1, figsize=(16, 12), facecolor='w') + rcParams['xtick.labelsize'] = self.axis_font_size + rcParams['ytick.labelsize'] = self.axis_font_size + + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), + weight="heavy", size=self.text_size) + self.text_file_pos = figtext(0.10, 0.92, "File Position: ", + weight="heavy", size=self.text_size) + self.text_block = figtext(0.35, 0.92, ("Block Size: %d" % self.block_length), + weight="heavy", size=self.text_size) + self.text_sr = figtext(0.60, 0.915, ("Sample Rate: %.2f" % self.sample_rate), + weight="heavy", size=self.text_size) + self.make_plots() + + self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True) + self.button_left = Button(self.button_left_axes, "<") + self.button_left_callback = self.button_left.on_clicked(self.button_left_click) + + self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True) + self.button_right = Button(self.button_right_axes, ">") + self.button_right_callback = self.button_right.on_clicked(self.button_right_click) + + self.xlim = scipy.array(self.sp_iq.get_xlim()) + + self.manager = get_current_fig_manager() + connect('draw_event', self.zoom) + connect('key_press_event', self.click) + show() + + def get_data(self): + self.position = self.hfile.tell()/self.sizeof_data + self.text_file_pos.set_text("File Position: %d" % self.position) + try: + self.iq = scipy.fromfile(self.hfile, dtype=self.datatype, count=self.block_length) + except MemoryError: + print "End of File" + return False + else: + # retesting length here as newer version of scipy does not throw a MemoryError, just + # returns a zero-length array + if(len(self.iq) > 0): + tstep = 1.0 / self.sample_rate + #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) + self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) + + self.iq_psd, self.freq = self.dopsd(self.iq) + return True + else: + print "End of File" + return False + + def dopsd(self, iq): + ''' Need to do this here and plot later so we can do the fftshift ''' + overlap = self.psdfftsize/4 + winfunc = scipy.blackman + psd,freq = mlab.psd(iq, self.psdfftsize, self.sample_rate, + window = lambda d: d*winfunc(self.psdfftsize), + noverlap = overlap) + psd = 10.0*log10(abs(psd)) + return (psd, freq) + + def make_plots(self): + # if specified on the command-line, set file pointer + self.hfile.seek(self.sizeof_data*self.start, 1) + + iqdims = [[0.075, 0.2, 0.4, 0.6], [0.075, 0.55, 0.4, 0.3]] + psddims = [[0.575, 0.2, 0.4, 0.6], [0.575, 0.55, 0.4, 0.3]] + specdims = [0.2, 0.125, 0.6, 0.3] + + # Subplot for real and imaginary parts of signal + self.sp_iq = self.fig.add_subplot(2,2,1, position=iqdims[self.dospec]) + self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") + self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold") + + # Subplot for PSD plot + self.sp_psd = self.fig.add_subplot(2,2,2, position=psddims[self.dospec]) + self.sp_psd.set_title(("PSD"), fontsize=self.title_font_size, fontweight="bold") + self.sp_psd.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") + + r = self.get_data() + + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals + self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags + self.draw_time(self.time, self.iq) # draw the plot + + self.plot_psd = self.sp_psd.plot([], 'b') # make plot for PSD + self.draw_psd(self.freq, self.iq_psd) # draw the plot + + + if self.dospec: + # Subplot for spectrogram plot + self.sp_spec = self.fig.add_subplot(2,2,3, position=specdims) + self.sp_spec.set_title(("Spectrogram"), fontsize=self.title_font_size, fontweight="bold") + self.sp_spec.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold") + self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") + + self.draw_spec(self.time, self.iq) + + draw() + + def draw_time(self, t, iq): + reals = iq.real + imags = iq.imag + self.plot_iq[0].set_data([t, reals]) + self.plot_iq[1].set_data([t, imags]) + self.sp_iq.set_xlim(t.min(), t.max()) + self.sp_iq.set_ylim([1.5*min([reals.min(), imags.min()]), + 1.5*max([reals.max(), imags.max()])]) + + def draw_psd(self, f, p): + self.plot_psd[0].set_data([f, p]) + self.sp_psd.set_ylim([p.min()-10, p.max()+10]) + self.sp_psd.set_xlim([f.min(), f.max()]) + + def draw_spec(self, t, s): + overlap = self.specfftsize/4 + winfunc = scipy.blackman + self.sp_spec.clear() + self.sp_spec.specgram(s, self.specfftsize, self.sample_rate, + window = lambda d: d*winfunc(self.specfftsize), + noverlap = overlap, xextent=[t.min(), t.max()]) + + def update_plots(self): + self.draw_time(self.time, self.iq) + self.draw_psd(self.freq, self.iq_psd) + + if self.dospec: + self.draw_spec(self.time, self.iq) + + self.xlim = scipy.array(self.sp_iq.get_xlim()) # so zoom doesn't get called + + draw() + + def zoom(self, event): + newxlim = scipy.array(self.sp_iq.get_xlim()) + curxlim = scipy.array(self.xlim) + if(newxlim[0] != curxlim[0] or newxlim[1] != curxlim[1]): + #xmin = max(0, int(ceil(self.sample_rate*(newxlim[0] - self.position)))) + #xmax = min(int(ceil(self.sample_rate*(newxlim[1] - self.position))), len(self.iq)) + xmin = max(0, int(ceil(self.sample_rate*(newxlim[0])))) + xmax = min(int(ceil(self.sample_rate*(newxlim[1]))), len(self.iq)) + + iq = scipy.array(self.iq[xmin : xmax]) + time = scipy.array(self.time[xmin : xmax]) + + iq_psd, freq = self.dopsd(iq) + + self.draw_psd(freq, iq_psd) + self.xlim = scipy.array(self.sp_iq.get_xlim()) + + draw() + + def click(self, event): + forward_valid_keys = [" ", "down", "right"] + backward_valid_keys = ["up", "left"] + + if(find(event.key, forward_valid_keys)): + self.step_forward() + + elif(find(event.key, backward_valid_keys)): + self.step_backward() + + def button_left_click(self, event): + self.step_backward() + + def button_right_click(self, event): + self.step_forward() + + def step_forward(self): + r = self.get_data() + if(r): + self.update_plots() + + def step_backward(self): + # Step back in file position + if(self.hfile.tell() >= 2*self.sizeof_data*self.block_length ): + self.hfile.seek(-2*self.sizeof_data*self.block_length, 1) + else: + self.hfile.seek(-self.hfile.tell(),1) + r = self.get_data() + if(r): + self.update_plots() + + @staticmethod + def setup_options(): + usage="%prog: [options] input_filename" + description = "Takes a GNU Radio binary file (with specified data type using --data-type) and displays the I&Q data versus time as well as the power spectral density (PSD) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples. Finally, the size of the FFT to use for the PSD and spectrogram plots can be set independently with --psd-size and --spec-size, respectively. The spectrogram plot does not display by default and is turned on with -S or --enable-spec." + + parser = OptionParser(option_class=eng_option, conflict_handler="resolve", + usage=usage, description=description) + parser.add_option("-d", "--data-type", type="string", default="complex64", + help="Specify the data type (complex64, float32, (u)int32, (u)int16, (u)int8) [default=%default]") + parser.add_option("-B", "--block", type="int", default=8192, + help="Specify the block size [default=%default]") + parser.add_option("-s", "--start", type="int", default=0, + help="Specify where to start in the file [default=%default]") + parser.add_option("-R", "--sample-rate", type="eng_float", default=1.0, + help="Set the sampler rate of the data [default=%default]") + parser.add_option("", "--psd-size", type="int", default=1024, + help="Set the size of the PSD FFT [default=%default]") + parser.add_option("", "--spec-size", type="int", default=256, + help="Set the size of the spectrogram FFT [default=%default]") + parser.add_option("-S", "--enable-spec", action="store_true", default=False, + help="Turn on plotting the spectrogram [default=%default]") + + return parser + +def find(item_in, list_search): + try: + return list_search.index(item_in) != None + except ValueError: + return False + +def main(): + parser = plot_psd_base.setup_options() + (options, args) = parser.parse_args () + if len(args) != 1: + parser.print_help() + raise SystemExit, 1 + filename = args[0] + + dc = plot_psd_base(options.data_type, filename, options) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass + + + -- cgit From f919f9dcbb54a08e6e26d6c229ce92fb784fa1b2 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 13 Apr 2012 18:36:53 -0400 Subject: Removed whitespace and added dtools/bin/remove-whitespace as a tool to do this in the future. The sed script was provided by Moritz Fischer. --- gr-utils/src/python/gr_filter_design | 60 ++++++++++++++++++------------------ gr-utils/src/python/gr_plot_char | 14 ++++----- gr-utils/src/python/gr_plot_const | 38 +++++++++++------------ gr-utils/src/python/gr_plot_fft | 10 +++--- gr-utils/src/python/gr_plot_fft_c | 14 ++++----- gr-utils/src/python/gr_plot_fft_f | 14 ++++----- gr-utils/src/python/gr_plot_float | 14 ++++----- gr-utils/src/python/gr_plot_int | 14 ++++----- gr-utils/src/python/gr_plot_iq | 28 ++++++++--------- gr-utils/src/python/gr_plot_psd | 10 +++--- gr-utils/src/python/gr_plot_psd_c | 12 ++++---- gr-utils/src/python/gr_plot_psd_f | 12 ++++---- gr-utils/src/python/gr_plot_qt | 42 ++++++++++++------------- gr-utils/src/python/gr_plot_short | 14 ++++----- gr-utils/src/python/plot_data.py | 26 ++++++++-------- gr-utils/src/python/plot_fft_base.py | 30 +++++++++--------- gr-utils/src/python/plot_psd_base.py | 36 +++++++++++----------- 17 files changed, 194 insertions(+), 194 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_filter_design b/gr-utils/src/python/gr_filter_design index e8703db4f..cc21ea5e7 100755 --- a/gr-utils/src/python/gr_filter_design +++ b/gr-utils/src/python/gr_filter_design @@ -76,9 +76,9 @@ class gr_plot_filter(QtGui.QMainWindow): "High Pass", "Root Raised Cosine", "Gaussian") self.optFilters = ("Low Pass", "Band Pass", "Complex Band Pass", "Band Notch", "High Pass") - + self.set_windowed() - + # Initialize to LPF self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage) @@ -211,19 +211,19 @@ class gr_plot_filter(QtGui.QMainWindow): self.gui.filterTypeWidget.setCurrentWidget(self.gui.gausPage) self.design() - + def changed_filter_design_type(self, design): if(design == "Equiripple"): self.set_equiripple() else: self.set_windowed() - + self.design() def set_equiripple(self): # Stop sending the signal for this function self.gui.filterTypeComboBox.blockSignals(True) - + self.equiripple = True self.gui.lpfPassBandRippleLabel.setVisible(True) self.gui.lpfPassBandRippleEdit.setVisible(True) @@ -252,11 +252,11 @@ class gr_plot_filter(QtGui.QMainWindow): # Tell gui its ok to start sending this signal again self.gui.filterTypeComboBox.blockSignals(False) - + def set_windowed(self): # Stop sending the signal for this function self.gui.filterTypeComboBox.blockSignals(True) - + self.equiripple = False self.gui.lpfPassBandRippleLabel.setVisible(False) self.gui.lpfPassBandRippleEdit.setVisible(False) @@ -332,7 +332,7 @@ class gr_plot_filter(QtGui.QMainWindow): if(ret): tb = sb - pb - + taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten, wintype) params = {"fs": fs, "gain": gain, "wintype": wintype, @@ -341,7 +341,7 @@ class gr_plot_filter(QtGui.QMainWindow): return (taps, params, ret) else: return ([], [], ret) - + def design_win_bpf(self, fs, gain, wintype): ret = True pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() @@ -417,7 +417,7 @@ class gr_plot_filter(QtGui.QMainWindow): if(r): tb = pb - sb taps = gr.firdes.high_pass_2(gain, fs, pb, tb, - atten, wintype) + atten, wintype) params = {"fs": fs, "gain": gain, "wintype": wintype, "filttype": "hpf", "sbend": sb, "pbstart": pb, "atten": atten, "ntaps": len(taps)} @@ -490,7 +490,7 @@ class gr_plot_filter(QtGui.QMainWindow): return (taps, params, ret) else: return ([], [], ret) - + def design_opt_bpf(self, fs, gain): ret = True pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble() @@ -631,15 +631,15 @@ class gr_plot_filter(QtGui.QMainWindow): self.update_phase_curves() if(tab == 3): self.update_group_curves() - + def get_fft(self, fs, taps, Npts): Ts = 1.0/fs fftpts = fftpack.fft(taps, Npts) - self.freq = scipy.arange(0, fs, 1.0/(Npts*Ts)) + self.freq = scipy.arange(0, fs, 1.0/(Npts*Ts)) self.fftdB = 20.0*scipy.log10(abs(fftpts)) self.fftDeg = scipy.unwrap(scipy.angle(fftpts)) self.groupDelay = -scipy.diff(self.fftDeg) - + def update_time_curves(self): ntaps = len(self.taps) if(ntaps > 0): @@ -656,17 +656,17 @@ class gr_plot_filter(QtGui.QMainWindow): 0, ntaps) self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft, ymin, ymax) - + # Set the zoomer base to unzoom to the new axis self.timeZoomer.setZoomBase() - + self.gui.timePlot.replot() - + def update_freq_curves(self): npts = len(self.fftdB) if(npts > 0): self.freqcurve.setData(self.freq, self.fftdB) - + # Reset the x-axis to the new time scale ymax = 1.5 * max(self.fftdB[0:npts/2]) ymin = 1.1 * min(self.fftdB[0:npts/2]) @@ -676,10 +676,10 @@ class gr_plot_filter(QtGui.QMainWindow): xmin, xmax) self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft, ymin, ymax) - + # Set the zoomer base to unzoom to the new axis self.freqZoomer.setZoomBase() - + self.gui.freqPlot.replot() @@ -687,7 +687,7 @@ class gr_plot_filter(QtGui.QMainWindow): npts = len(self.fftDeg) if(npts > 0): self.phasecurve.setData(self.freq, self.fftDeg) - + # Reset the x-axis to the new time scale ymax = 1.5 * max(self.fftDeg[0:npts/2]) ymin = 1.1 * min(self.fftDeg[0:npts/2]) @@ -697,17 +697,17 @@ class gr_plot_filter(QtGui.QMainWindow): xmin, xmax) self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft, ymin, ymax) - + # Set the zoomer base to unzoom to the new axis self.phaseZoomer.setZoomBase() - + self.gui.phasePlot.replot() def update_group_curves(self): npts = len(self.groupDelay) if(npts > 0): self.groupcurve.setData(self.freq, self.groupDelay) - + # Reset the x-axis to the new time scale ymax = 1.5 * max(self.groupDelay[0:npts/2]) ymin = 1.1 * min(self.groupDelay[0:npts/2]) @@ -717,10 +717,10 @@ class gr_plot_filter(QtGui.QMainWindow): xmin, xmax) self.gui.groupPlot.setAxisScale(self.gui.groupPlot.yLeft, ymin, ymax) - + # Set the zoomer base to unzoom to the new axis self.groupZoomer.setZoomBase() - + self.gui.groupPlot.replot() def action_save_dialog(self): @@ -732,7 +732,7 @@ class gr_plot_filter(QtGui.QMainWindow): ("Could not save to file: %s" % filename), "&Ok") return - + csvhandle = csv.writer(handle, delimiter=",") for k in self.params.keys(): csvhandle.writerow([k, self.params[k]]) @@ -743,7 +743,7 @@ class gr_plot_filter(QtGui.QMainWindow): filename = QtGui.QFileDialog.getOpenFileName(self, "Open CSV Filter File", ".", "") if(len(filename) == 0): return - + try: handle = open(filename, "rb") except IOError: @@ -849,9 +849,9 @@ class gr_plot_filter(QtGui.QMainWindow): self.update_freq_curves() self.update_phase_curves() self.update_group_curves() - + self.gui.nTapsEdit.setText(Qt.QString("%1").arg(self.taps.size)) - + def setup_options(): usage="%prog: [options] (input_filename)" diff --git a/gr-utils/src/python/gr_plot_char b/gr-utils/src/python/gr_plot_char index 87a323c9c..a2b93a63c 100755 --- a/gr-utils/src/python/gr_plot_char +++ b/gr-utils/src/python/gr_plot_char @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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. -# +# try: import scipy @@ -40,7 +40,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) < 1: parser.print_help() @@ -55,4 +55,4 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_const b/gr-utils/src/python/gr_plot_const index 8873e5b7e..749ad035b 100755 --- a/gr-utils/src/python/gr_plot_const +++ b/gr-utils/src/python/gr_plot_const @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008,2011 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. -# +# try: import scipy @@ -53,11 +53,11 @@ class draw_constellation: self.fig = figure(1, figsize=(16, 9), facecolor='w') rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16) self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16) self.text_block = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length), - weight="heavy", size=16) + weight="heavy", size=16) self.text_sr = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate), weight="heavy", size=16) self.make_plots() @@ -90,7 +90,7 @@ class draw_constellation: if(len(iq) > 0): self.reals = scipy.array([r.real for r in iq]) self.imags = scipy.array([i.imag for i in iq]) - + self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) return True else: @@ -102,7 +102,7 @@ class draw_constellation: self.hfile.seek(self.sizeof_data*self.start, 1) r = self.get_data() - + # Subplot for real and imaginary parts of signal self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6]) self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") @@ -141,7 +141,7 @@ class draw_constellation: self.plot_const[0].set_data([self.reals, self.imags]) self.sp_const.axis([-2, 2, -2, 2]) draw() - + def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) @@ -163,7 +163,7 @@ class draw_constellation: if(find(event.key, forward_valid_keys)): self.step_forward() - + elif(find(event.key, backward_valid_keys)): self.step_backward() @@ -195,16 +195,16 @@ class draw_constellation: r = self.get_data() if(r): self.update_plots() - - + + def mouse_button_callback(self, event): x, y = event.xdata, event.ydata - + if x is not None and y is not None: if(event.inaxes == self.sp_iq): self.indx = searchsorted(self.time, [x]) self.set_trace(self.indx) - + def set_trace(self, indx): self.plot_iq[2].set_data(self.time[indx], self.reals[indx]) @@ -212,13 +212,13 @@ class draw_constellation: self.plot_const[1].set_data(self.reals[indx], self.imags[indx]) draw() - + def find(item_in, list_search): try: return list_search.index(item_in) != None except ValueError: return False - + def main(): usage="%prog: [options] input_filename" @@ -231,7 +231,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) != 1: parser.print_help() @@ -245,6 +245,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_fft b/gr-utils/src/python/gr_plot_fft index 6859ea471..434348164 100644 --- a/gr-utils/src/python/gr_plot_fft +++ b/gr-utils/src/python/gr_plot_fft @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2012 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # GNU Radio is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. -# +# # GNU Radio is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -# +# from gnuradio.plot_fft_base import plot_fft_base diff --git a/gr-utils/src/python/gr_plot_fft_c b/gr-utils/src/python/gr_plot_fft_c index e4ee9c5a9..43e808d95 100755 --- a/gr-utils/src/python/gr_plot_fft_c +++ b/gr-utils/src/python/gr_plot_fft_c @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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.plot_fft_base import plot_fft_base @@ -27,7 +27,7 @@ from gnuradio.plot_fft_base import plot_fft_base def main(): parser = plot_fft_base.setup_options() parser.remove_option("--data-type") - + (options, args) = parser.parse_args () if len(args) != 1: parser.print_help() @@ -41,6 +41,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_fft_f b/gr-utils/src/python/gr_plot_fft_f index 66c75a8ff..dee9b17de 100755 --- a/gr-utils/src/python/gr_plot_fft_f +++ b/gr-utils/src/python/gr_plot_fft_f @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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.plot_fft_base import plot_fft_base @@ -27,7 +27,7 @@ from gnuradio.plot_fft_base import plot_fft_base def main(): parser = plot_fft_base.setup_options() parser.remove_option("--data-type") - + (options, args) = parser.parse_args () if len(args) != 1: parser.print_help() @@ -41,6 +41,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_float b/gr-utils/src/python/gr_plot_float index e5c22a315..22806e48a 100755 --- a/gr-utils/src/python/gr_plot_float +++ b/gr-utils/src/python/gr_plot_float @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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. -# +# try: import scipy @@ -40,7 +40,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) < 1: parser.print_help() @@ -55,4 +55,4 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_int b/gr-utils/src/python/gr_plot_int index b44d4360a..355ddf018 100755 --- a/gr-utils/src/python/gr_plot_int +++ b/gr-utils/src/python/gr_plot_int @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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. -# +# try: import scipy @@ -40,7 +40,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) < 1: parser.print_help() @@ -55,4 +55,4 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_iq b/gr-utils/src/python/gr_plot_iq index 316e60a75..bf8077b6b 100755 --- a/gr-utils/src/python/gr_plot_iq +++ b/gr-utils/src/python/gr_plot_iq @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008,2011 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. -# +# try: import scipy @@ -53,7 +53,7 @@ class draw_iq: self.fig = figure(1, figsize=(16, 9), facecolor='w') rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), @@ -86,13 +86,13 @@ class draw_iq: self.reals = scipy.array([r.real for r in self.iq]) self.imags = scipy.array([i.imag for i in self.iq]) self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))]) - + def make_plots(self): # if specified on the command-line, set file pointer self.hfile.seek(self.sizeof_data*self.start, 1) self.get_data() - + # Subplot for real and imaginary parts of signal self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67]) self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") @@ -111,14 +111,14 @@ class draw_iq: 1.5*max([self.reals.max(), self.imags.max()])]) self.sp_iq.set_xlim(self.time.min(), self.time.max()) draw() - + def click(self, event): forward_valid_keys = [" ", "down", "right"] backward_valid_keys = ["up", "left"] if(find(event.key, forward_valid_keys)): self.step_forward() - + elif(find(event.key, backward_valid_keys)): self.step_backward() @@ -140,14 +140,14 @@ class draw_iq: self.hfile.seek(-self.hfile.tell(),1) self.get_data() self.update_plots() - + def find(item_in, list_search): try: return list_search.index(item_in) != None except ValueError: return False - + def main(): usage="%prog: [options] input_filename" description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples." @@ -159,7 +159,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) != 1: parser.print_help() @@ -173,6 +173,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_psd b/gr-utils/src/python/gr_plot_psd index 658e7b297..059ca6b64 100644 --- a/gr-utils/src/python/gr_plot_psd +++ b/gr-utils/src/python/gr_plot_psd @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2012 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # GNU Radio is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. -# +# # GNU Radio is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -# +# from gnuradio.plot_psd_base import plot_psd_base diff --git a/gr-utils/src/python/gr_plot_psd_c b/gr-utils/src/python/gr_plot_psd_c index 192f263ec..fff2bff0f 100755 --- a/gr-utils/src/python/gr_plot_psd_c +++ b/gr-utils/src/python/gr_plot_psd_c @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2008 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 optparse import OptionParser from gnuradio.plot_psd_base import plot_psd_base @@ -42,6 +42,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_psd_f b/gr-utils/src/python/gr_plot_psd_f index fab312645..ec6799479 100755 --- a/gr-utils/src/python/gr_plot_psd_f +++ b/gr-utils/src/python/gr_plot_psd_f @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2008 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 optparse import OptionParser from gnuradio.plot_psd_base import plot_psd_base @@ -42,6 +42,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/gr_plot_qt b/gr-utils/src/python/gr_plot_qt index 937d0014b..153359f0c 100755 --- a/gr-utils/src/python/gr_plot_qt +++ b/gr-utils/src/python/gr_plot_qt @@ -55,12 +55,12 @@ class SpectrogramData(Qwt.QwtRasterData): def rasterHint(self, rect): return Qt.QSize(self.sp.shape[0], self.sp.shape[1]) - + def copy(self): return self def range(self): - + return Qwt.QwtDoubleInterval(self.sp.min(), self.sp.max()) def value(self, x, y): @@ -77,7 +77,7 @@ class gr_plot_qt(QtGui.QMainWindow): QtGui.QWidget.__init__(self, parent) self.gui = Ui_MainWindow() self.gui.setupUi(self) - + self.filename = None self.block_length = options.block_length self.start = options.start @@ -127,8 +127,8 @@ class gr_plot_qt(QtGui.QMainWindow): self.connect(self.gui.colorComboBox, Qt.SIGNAL("activated (const QString&)"), self.colorComboBoxEdit) - - + + # Set up line style combo box self.line_styles = {"None" : Qwt.QwtSymbol.NoSymbol, "Circle" : Qwt.QwtSymbol.Ellipse, @@ -290,7 +290,7 @@ class gr_plot_qt(QtGui.QMainWindow): def reload_file(self): if(self.filename): self.initialize(self.filename) - + def initialize(self, filename): self.filename = filename self.hfile = open(filename, "r") @@ -308,7 +308,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.init_data_input() self.get_data(self.cur_start, self.cur_stop) self.get_psd() - self.get_specgram() + self.get_specgram() self.gui.plotHBar.setSliderPosition(0) self.gui.plotHBar.setMaximum(self.signal_size-self.block_length) @@ -322,7 +322,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.signal_size = self.hfile.tell()/self.sizeof_data #print "Sizeof File: ", self.signal_size self.hfile.seek(0, os.SEEK_SET) - + def get_data(self, start, end): if(end > start): self.hfile.seek(start*self.sizeof_data, os.SEEK_SET) @@ -365,7 +365,7 @@ class gr_plot_qt(QtGui.QMainWindow): noverlap=self.specfftsize/4.0, window=winpoints, scale_by_freq=False) - + self.iq_spec = 10.0*scipy.log10(abs(iq_spec)) self.spec_f = f self.spec_t = t @@ -379,7 +379,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.specfftsize = fftSize.toInt()[0] self.get_specgram() self.update_specgram_curves() - + def colorComboBoxEdit(self, colorSelection): colorstr = str(colorSelection.toAscii()) color_func = self.color_modes[colorstr] @@ -443,7 +443,7 @@ class gr_plot_qt(QtGui.QMainWindow): tend = self.cur_stop / self.sample_rate self.gui.fileTimeStartLineEdit.setText(Qt.QString("%1").arg(tstart)) self.gui.fileTimeStopLineEdit.setText(Qt.QString("%1").arg(tend)) - + self.get_data(self.cur_start, self.cur_stop) self.update_time_curves() @@ -456,7 +456,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.set_file_pos_box(self.cur_start, self.cur_stop) except AttributeError: pass - + def file_time_changed(self): tstart = self.gui.fileTimeStartLineEdit.text().toDouble() @@ -548,16 +548,16 @@ class gr_plot_qt(QtGui.QMainWindow): # Set the zoomer base to unzoom to the new axis self.timeZoomer.setZoomBase() - + self.gui.timePlot.replot() - + def update_psd_curves(self): self.psdcurve.setData(self.freq, self.iq_psd) self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom, min(self.freq), max(self.freq)) - + # Set the zoomer base to unzoom to the new axis self.freqZoomer.setZoomBase() @@ -579,10 +579,10 @@ class gr_plot_qt(QtGui.QMainWindow): self.gui.specPlot.setAxisScale(self.gui.specPlot.yLeft, min(self.spec_t), max(self.spec_t)) - self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight, + self.gui.specPlot.setAxisScale(self.gui.specPlot.yRight, self.iq_spec.min(), self.iq_spec.max()) - + # Set the zoomer base to unzoom to the new axis self.specZoomer.setZoomBase() @@ -604,7 +604,7 @@ class gr_plot_qt(QtGui.QMainWindow): self.rcurve.setSymbol(self.rsym) self.icurve.setSymbol(self.isym) self.gui.timePlot.replot() - + def color_black_on_white(self): blue = QtGui.qRgb(0x00, 0x00, 0xFF) red = QtGui.qRgb(0xFF, 0x00, 0x00) @@ -636,7 +636,7 @@ class gr_plot_qt(QtGui.QMainWindow): whiteBrush = Qt.QBrush(Qt.QColor("white")) whiteBrush = Qt.QBrush(Qt.QColor(white)) redBrush = Qt.QBrush(Qt.QColor(red)) - + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) @@ -658,7 +658,7 @@ class gr_plot_qt(QtGui.QMainWindow): whiteBrush = Qt.QBrush(Qt.QColor("white")) greenBrush = Qt.QBrush(Qt.QColor(green)) redBrush = Qt.QBrush(Qt.QColor(red)) - + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) @@ -679,7 +679,7 @@ class gr_plot_qt(QtGui.QMainWindow): whiteBrush = Qt.QBrush(Qt.QColor("white")) blueBrush = Qt.QBrush(Qt.QColor(blue)) redBrush = Qt.QBrush(Qt.QColor(red)) - + self.gui.timePlot.setCanvasBackground(QtGui.QColor("black")) self.gui.freqPlot.setCanvasBackground(QtGui.QColor("black")) self.timeZoomer.setTrackerPen(Qt.QPen(whiteBrush, self.pen_width)) diff --git a/gr-utils/src/python/gr_plot_short b/gr-utils/src/python/gr_plot_short index 3466e0b7d..702a2a94a 100755 --- a/gr-utils/src/python/gr_plot_short +++ b/gr-utils/src/python/gr_plot_short @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008 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. -# +# try: import scipy @@ -40,7 +40,7 @@ def main(): help="Specify where to start in the file [default=%default]") parser.add_option("-R", "--sample-rate", type="float", default=1.0, help="Set the sampler rate of the data [default=%default]") - + (options, args) = parser.parse_args () if len(args) < 1: parser.print_help() @@ -55,4 +55,4 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/plot_data.py b/gr-utils/src/python/plot_data.py index 15012e589..242ca2a4b 100644 --- a/gr-utils/src/python/plot_data.py +++ b/gr-utils/src/python/plot_data.py @@ -1,23 +1,23 @@ # # Copyright 2007,2008,2011 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. -# +# try: import scipy @@ -57,7 +57,7 @@ class plot_data: self.fig = figure(1, figsize=(16, 9), facecolor='w') rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - + self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) self.text_block = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length), weight="heavy", size=self.text_size) @@ -78,7 +78,7 @@ class plot_data: self.manager = get_current_fig_manager() connect('key_press_event', self.click) show() - + def get_data(self, hfile): self.text_file_pos.set_text("File Position: %d" % (hfile.tell()//self.sizeof_data)) try: @@ -88,7 +88,7 @@ class plot_data: else: self.f = scipy.array(f) self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.f))]) - + def make_plots(self): self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6]) self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold") @@ -104,7 +104,7 @@ class plot_data: hf.seek(self.sizeof_data*self.start, 1) self.get_data(hf) - + # Subplot for real and imaginary parts of signal self.plot_f += plot(self.time, self.f, 'o-') maxval = max(maxval, self.f.max()) @@ -126,16 +126,16 @@ class plot_data: minval = min(minval, self.f.min()) self.sp_f.set_ylim([1.5*minval, 1.5*maxval]) - + draw() - + def click(self, event): forward_valid_keys = [" ", "down", "right"] backward_valid_keys = ["up", "left"] if(find(event.key, forward_valid_keys)): self.step_forward() - + elif(find(event.key, backward_valid_keys)): self.step_backward() @@ -156,7 +156,7 @@ class plot_data: else: hf.seek(-hf.tell(),1) self.update_plots() - + def find(item_in, list_search): try: diff --git a/gr-utils/src/python/plot_fft_base.py b/gr-utils/src/python/plot_fft_base.py index 0b5df504b..4afdc3a36 100755 --- a/gr-utils/src/python/plot_fft_base.py +++ b/gr-utils/src/python/plot_fft_base.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008,2011 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. -# +# try: import scipy @@ -54,7 +54,7 @@ class plot_fft_base: self.fig = figure(1, figsize=(16, 12), facecolor='w') rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - + self.text_file = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size) self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size) self.text_block = figtext(0.35, 0.88, ("Block Size: %d" % self.block_length), @@ -77,7 +77,7 @@ class plot_fft_base: connect('draw_event', self.zoom) connect('key_press_event', self.click) show() - + def get_data(self): self.position = self.hfile.tell()/self.sizeof_data self.text_file_pos.set_text("File Position: %d" % (self.position)) @@ -87,7 +87,7 @@ class plot_fft_base: print "End of File" else: self.iq_fft = self.dofft(self.iq) - + tstep = 1.0 / self.sample_rate #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) @@ -107,7 +107,7 @@ class plot_fft_base: Fn = 0.5 * sample_rate freq = scipy.array([-Fn + i*Fs for i in xrange(N)]) return freq - + def make_plots(self): # if specified on the command-line, set file pointer self.hfile.seek(self.sizeof_data*self.start, 1) @@ -125,7 +125,7 @@ class plot_fft_base: self.sp_fft.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") self.get_data() - + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags self.draw_time() # draw the plot @@ -155,7 +155,7 @@ class plot_fft_base: self.xlim = self.sp_iq.get_xlim() draw() - + def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) @@ -168,10 +168,10 @@ class plot_fft_base: iq = self.iq[xmin : xmax] time = self.time[xmin : xmax] - + iq_fft = self.dofft(iq) freq = self.calc_freq(time, self.sample_rate) - + self.plot_fft[0].set_data(freq, iq_fft) self.sp_fft.axis([freq.min(), freq.max(), iq_fft.min()-10, iq_fft.max()+10]) @@ -184,7 +184,7 @@ class plot_fft_base: if(find(event.key, forward_valid_keys)): self.step_forward() - + elif(find(event.key, backward_valid_keys)): self.step_backward() @@ -244,6 +244,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + diff --git a/gr-utils/src/python/plot_psd_base.py b/gr-utils/src/python/plot_psd_base.py index 78eed5f71..fe3c9e12b 100755 --- a/gr-utils/src/python/plot_psd_base.py +++ b/gr-utils/src/python/plot_psd_base.py @@ -1,24 +1,24 @@ #!/usr/bin/env python # # Copyright 2007,2008,2010,2011 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. -# +# try: import scipy @@ -60,7 +60,7 @@ class plot_psd_base: self.fig = figure(1, figsize=(16, 12), facecolor='w') rcParams['xtick.labelsize'] = self.axis_font_size rcParams['ytick.labelsize'] = self.axis_font_size - + self.text_file = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=self.text_size) self.text_file_pos = figtext(0.10, 0.92, "File Position: ", @@ -85,7 +85,7 @@ class plot_psd_base: connect('draw_event', self.zoom) connect('key_press_event', self.click) show() - + def get_data(self): self.position = self.hfile.tell()/self.sizeof_data self.text_file_pos.set_text("File Position: %d" % self.position) @@ -101,13 +101,13 @@ class plot_psd_base: tstep = 1.0 / self.sample_rate #self.time = scipy.array([tstep*(self.position + i) for i in xrange(len(self.iq))]) self.time = scipy.array([tstep*(i) for i in xrange(len(self.iq))]) - + self.iq_psd, self.freq = self.dopsd(self.iq) return True else: print "End of File" return False - + def dopsd(self, iq): ''' Need to do this here and plot later so we can do the fftshift ''' overlap = self.psdfftsize/4 @@ -125,7 +125,7 @@ class plot_psd_base: iqdims = [[0.075, 0.2, 0.4, 0.6], [0.075, 0.55, 0.4, 0.3]] psddims = [[0.575, 0.2, 0.4, 0.6], [0.575, 0.55, 0.4, 0.3]] specdims = [0.2, 0.125, 0.6, 0.3] - + # Subplot for real and imaginary parts of signal self.sp_iq = self.fig.add_subplot(2,2,1, position=iqdims[self.dospec]) self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold") @@ -139,7 +139,7 @@ class plot_psd_base: self.sp_psd.set_ylabel("Power Spectrum (dBm)", fontsize=self.label_font_size, fontweight="bold") r = self.get_data() - + self.plot_iq = self.sp_iq.plot([], 'bo-') # make plot for reals self.plot_iq += self.sp_iq.plot([], 'ro-') # make plot for imags self.draw_time(self.time, self.iq) # draw the plot @@ -156,7 +156,7 @@ class plot_psd_base: self.sp_spec.set_ylabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold") self.draw_spec(self.time, self.iq) - + draw() def draw_time(self, t, iq): @@ -189,9 +189,9 @@ class plot_psd_base: self.draw_spec(self.time, self.iq) self.xlim = scipy.array(self.sp_iq.get_xlim()) # so zoom doesn't get called - + draw() - + def zoom(self, event): newxlim = scipy.array(self.sp_iq.get_xlim()) curxlim = scipy.array(self.xlim) @@ -205,7 +205,7 @@ class plot_psd_base: time = scipy.array(self.time[xmin : xmax]) iq_psd, freq = self.dopsd(iq) - + self.draw_psd(freq, iq_psd) self.xlim = scipy.array(self.sp_iq.get_xlim()) @@ -217,7 +217,7 @@ class plot_psd_base: if(find(event.key, forward_valid_keys)): self.step_forward() - + elif(find(event.key, backward_valid_keys)): self.step_backward() @@ -241,7 +241,7 @@ class plot_psd_base: r = self.get_data() if(r): self.update_plots() - + @staticmethod def setup_options(): usage="%prog: [options] input_filename" @@ -287,6 +287,6 @@ if __name__ == "__main__": main() except KeyboardInterrupt: pass - + -- cgit From c5d29f9029cd08393e8c91e7ff0d1aa966f10bdb Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 21 Nov 2012 17:27:09 -0500 Subject: core: adding Python files to easily parse header info of a file. Also a utility script that you pass a filename to and it prints out the meta data. --- gr-utils/src/python/CMakeLists.txt | 1 + gr-utils/src/python/gr_read_file_metadata | 59 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 gr-utils/src/python/gr_read_file_metadata (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/CMakeLists.txt b/gr-utils/src/python/CMakeLists.txt index 90caeb234..13fa06bbc 100644 --- a/gr-utils/src/python/CMakeLists.txt +++ b/gr-utils/src/python/CMakeLists.txt @@ -50,6 +50,7 @@ GR_PYTHON_INSTALL( gr_plot_short gr_plot_qt gr_filter_design + gr_read_file_metadata DESTINATION ${GR_RUNTIME_DIR} COMPONENT "utils" ) diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata new file mode 100644 index 000000000..657ad7c2b --- /dev/null +++ b/gr-utils/src/python/gr_read_file_metadata @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import sys +from optparse import OptionParser + +from gnuradio import gr +from gnuradio import parse_file_metadata + +def main(filename): + handle = open(filename, "rb") + + # just read out header bytes + header_str = handle.read(parse_file_metadata.HEADER_LENGTH) + + # Convert from string to PMT (should be a dictionary) + try: + header = gr.pmt_deserialize_str(header_str) + except RuntimeError: + sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n") + sys.exit(1) + #gr.pmt_print(header) + + info = parse_file_metadata.parse_header(header, True) + #print info + +if __name__ == "__main__": + usage="%prog: [options] filename" + description = "Read in a GNU Radio file with meta data, extracts the header and prints it." + + parser = OptionParser(conflict_handler="resolve", + usage=usage, description=description) + (options, args) = parser.parse_args () + + if(len(args) < 1): + sys.stderr.write("No filename given\n") + sys.exit(1) + + filename = args[0] + main(filename) -- cgit From 9dc8f8b18043e71b50b3a254cb52bf355e97e6fa Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 24 Nov 2012 19:09:02 -0500 Subject: core: Update file_meta_sink to inject headers into data stream. When a tag with updated metadata information is received, close out the previous header (by setting the segment size) and create a new header with the new data. Specifically for sample rate and time stamps. Will be useful for extra_dict when implemented. --- gr-utils/src/python/gr_read_file_metadata | 33 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata index 657ad7c2b..47109aead 100644 --- a/gr-utils/src/python/gr_read_file_metadata +++ b/gr-utils/src/python/gr_read_file_metadata @@ -29,19 +29,28 @@ from gnuradio import parse_file_metadata def main(filename): handle = open(filename, "rb") - # just read out header bytes - header_str = handle.read(parse_file_metadata.HEADER_LENGTH) - - # Convert from string to PMT (should be a dictionary) - try: - header = gr.pmt_deserialize_str(header_str) - except RuntimeError: - sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n") - sys.exit(1) - #gr.pmt_print(header) + nread = 0 + while(True): + # read out next header bytes + hdr_start = handle.tell() + header_str = handle.read(parse_file_metadata.HEADER_LENGTH) + if(len(header_str) == 0): + break + + # Convert from string to PMT (should be a dictionary) + try: + header = gr.pmt_deserialize_str(header_str) + except RuntimeError: + sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n") + sys.exit(1) + #gr.pmt_print(header) + + info = parse_file_metadata.parse_header(header, hdr_start, True) + print "\n\n" + + nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH - info = parse_file_metadata.parse_header(header, True) - #print info + handle.seek(nread, 0) if __name__ == "__main__": usage="%prog: [options] filename" -- cgit From 88a9e1f9332d54c1743d062adfaf48aa6d3040ff Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 27 Nov 2012 11:59:26 -0800 Subject: core: adding ability to handle extra data in headers. --- gr-utils/src/python/gr_read_file_metadata | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata index 47109aead..850c29ee7 100644 --- a/gr-utils/src/python/gr_read_file_metadata +++ b/gr-utils/src/python/gr_read_file_metadata @@ -29,6 +29,7 @@ from gnuradio import parse_file_metadata def main(filename): handle = open(filename, "rb") + nheaders = 0 nread = 0 while(True): # read out next header bytes @@ -45,12 +46,27 @@ def main(filename): sys.exit(1) #gr.pmt_print(header) + print "HEADER {0}".format(nheaders) info = parse_file_metadata.parse_header(header, hdr_start, True) - print "\n\n" - nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH + if(info["extra_len"] > 0): + extra_str = handle.read(info["extra_len"]) + if(len(extra_str) == 0): + break + + try: + extra = gr.pmt_deserialize_str(extra_str) + except RuntimeError: + sys.stderr.write("Could not deserialize extras: invalid or corrupt data file.\n") + sys.exit(1) + print "\nExtra Header:" + extra_info = parse_file_metadata.parse_extra_dict(extra, info, True) + + nheaders += 1 + nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH + info["extra_len"] + 1 handle.seek(nread, 0) + print "\n\n" if __name__ == "__main__": usage="%prog: [options] filename" -- cgit From cdf8cb7fd8f8e835a23b7f9e6b62014f86bcf24a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 28 Nov 2012 09:39:48 -0800 Subject: utils: adding GRCC - a GNU Radio Companion command-line compiler tool. --- gr-utils/src/python/CMakeLists.txt | 1 + gr-utils/src/python/grcc | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 gr-utils/src/python/grcc (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/CMakeLists.txt b/gr-utils/src/python/CMakeLists.txt index 90caeb234..e5d99d8b6 100644 --- a/gr-utils/src/python/CMakeLists.txt +++ b/gr-utils/src/python/CMakeLists.txt @@ -50,6 +50,7 @@ GR_PYTHON_INSTALL( gr_plot_short gr_plot_qt gr_filter_design + grcc DESTINATION ${GR_RUNTIME_DIR} COMPONENT "utils" ) diff --git a/gr-utils/src/python/grcc b/gr-utils/src/python/grcc new file mode 100755 index 000000000..3ad5505d1 --- /dev/null +++ b/gr-utils/src/python/grcc @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +try: + from grc.python.Platform import Platform +except ImportError: + from gnuradio.grc.python.Platform import Platform + +from optparse import OptionParser +import os, sys + +class grcc: + def __init__(self, grcfile, out_dir): + self.platform = Platform() + data = self.platform.parse_flow_graph(grcfile) + + self.fg = self.platform.get_new_flow_graph() + self.fg.import_data(data) + self.fg.validate() + + gen = self.platform.get_generator()(self.fg, out_dir) + gen.write() + +if __name__ == "__main__": + usage="%prog: [options] filename" + description = "Compiles a GRC file (.grc) into a GNU Radio Python program. The program is stored in ~/.grc_gnuradio by default, but this location can be changed with the -d option." + + parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-d", "--directory", type="string", default='{0}/.grc_gnuradio/'.format(os.environ["HOME"]), + help="Specify the directory to output the compile program [default=%default]") + (options, args) = parser.parse_args () + + if(len(args) != 1): + sys.stderr.write("Please specify a GRC file name to compile.\n") + sys.exit(1) + + g = grcc(args[0], options.directory+"/") -- cgit From fbef82839ef85bfd7837f8534af2a3a74018930a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 28 Nov 2012 14:06:57 -0800 Subject: utils: updating GRCC with a -e flag to execute the program after building. --- gr-utils/src/python/grcc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/grcc b/gr-utils/src/python/grcc index 3ad5505d1..7e5665dc0 100755 --- a/gr-utils/src/python/grcc +++ b/gr-utils/src/python/grcc @@ -30,6 +30,7 @@ import os, sys class grcc: def __init__(self, grcfile, out_dir): + self.out_dir = out_dir self.platform = Platform() data = self.platform.parse_flow_graph(grcfile) @@ -37,8 +38,12 @@ class grcc: self.fg.import_data(data) self.fg.validate() - gen = self.platform.get_generator()(self.fg, out_dir) - gen.write() + self.gen = self.platform.get_generator()(self.fg, out_dir) + self.gen.write() + + def exec_program(self): + progname = self.fg.get_option('id') + os.system("{0}/{1}.py".format(self.out_dir, progname)) if __name__ == "__main__": usage="%prog: [options] filename" @@ -47,6 +52,8 @@ if __name__ == "__main__": parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) parser.add_option("-d", "--directory", type="string", default='{0}/.grc_gnuradio/'.format(os.environ["HOME"]), help="Specify the directory to output the compile program [default=%default]") + parser.add_option("-e", "--execute", action="store_true", default=False, + help="Run the program after compiling [default=%default]") (options, args) = parser.parse_args () if(len(args) != 1): @@ -54,3 +61,6 @@ if __name__ == "__main__": sys.exit(1) g = grcc(args[0], options.directory+"/") + + if(options.execute): + g.exec_program() -- cgit From 611959d2f9af4595200186acf85a64f5bf318fac Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 4 Dec 2012 18:36:35 -0500 Subject: core: updated metadata structure to use relative header info. Now the start tag info in the header is relative to the begining of the header (so, basically, the size of the header + extras). --- gr-utils/src/python/gr_read_file_metadata | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata index 850c29ee7..ba530ca54 100644 --- a/gr-utils/src/python/gr_read_file_metadata +++ b/gr-utils/src/python/gr_read_file_metadata @@ -44,10 +44,9 @@ def main(filename): except RuntimeError: sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n") sys.exit(1) - #gr.pmt_print(header) print "HEADER {0}".format(nheaders) - info = parse_file_metadata.parse_header(header, hdr_start, True) + info = parse_file_metadata.parse_header(header, True) if(info["extra_len"] > 0): extra_str = handle.read(info["extra_len"]) @@ -64,7 +63,7 @@ def main(filename): extra_info = parse_file_metadata.parse_extra_dict(extra, info, True) nheaders += 1 - nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH + info["extra_len"] + 1 + nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH + info["extra_len"] handle.seek(nread, 0) print "\n\n" -- cgit From f1de74af9270235126b67e9507111df5752a3e5c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 12 Dec 2012 18:45:53 -0500 Subject: core: add new options to GRC for file_meta_sink. Also updates gr_read_file_metadata to add a -D option that properly parses a detached header. --- gr-utils/src/python/gr_read_file_metadata | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata index ba530ca54..efbf8d15d 100644 --- a/gr-utils/src/python/gr_read_file_metadata +++ b/gr-utils/src/python/gr_read_file_metadata @@ -26,7 +26,7 @@ from optparse import OptionParser from gnuradio import gr from gnuradio import parse_file_metadata -def main(filename): +def main(filename, detached=False): handle = open(filename, "rb") nheaders = 0 @@ -63,7 +63,9 @@ def main(filename): extra_info = parse_file_metadata.parse_extra_dict(extra, info, True) nheaders += 1 - nread += info['nbytes'] + parse_file_metadata.HEADER_LENGTH + info["extra_len"] + nread += parse_file_metadata.HEADER_LENGTH + info["extra_len"] + if(not detached): + nread += info['nbytes'] handle.seek(nread, 0) print "\n\n" @@ -73,6 +75,8 @@ if __name__ == "__main__": parser = OptionParser(conflict_handler="resolve", usage=usage, description=description) + parser.add_option("-D", "--detached", action="store_true", default=False, + help="Used if header is detached.") (options, args) = parser.parse_args () if(len(args) < 1): @@ -80,4 +84,4 @@ if __name__ == "__main__": sys.exit(1) filename = args[0] - main(filename) + main(filename, options.detached) -- cgit From 461ece56b36a44b2405282630157739c7f9a26ba Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 14 Dec 2012 16:10:30 -0500 Subject: blocks: moving file metadata sink/source to gr-blocks. --- gr-utils/src/python/gr_read_file_metadata | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_read_file_metadata b/gr-utils/src/python/gr_read_file_metadata index efbf8d15d..cf0cd5b11 100644 --- a/gr-utils/src/python/gr_read_file_metadata +++ b/gr-utils/src/python/gr_read_file_metadata @@ -23,8 +23,8 @@ import sys from optparse import OptionParser -from gnuradio import gr -from gnuradio import parse_file_metadata +from gruel import pmt +from gnuradio.blocks import parse_file_metadata def main(filename, detached=False): handle = open(filename, "rb") @@ -40,7 +40,7 @@ def main(filename, detached=False): # Convert from string to PMT (should be a dictionary) try: - header = gr.pmt_deserialize_str(header_str) + header = pmt.pmt_deserialize_str(header_str) except RuntimeError: sys.stderr.write("Could not deserialize header: invalid or corrupt data file.\n") sys.exit(1) @@ -54,7 +54,7 @@ def main(filename, detached=False): break try: - extra = gr.pmt_deserialize_str(extra_str) + extra = pmt.pmt_deserialize_str(extra_str) except RuntimeError: sys.stderr.write("Could not deserialize extras: invalid or corrupt data file.\n") sys.exit(1) -- cgit From a62f90d8cc96b9dea9289ad6e420d1c0b16f6c36 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 24 Jan 2013 19:33:03 +0100 Subject: utils: added modtool --- gr-utils/src/python/CMakeLists.txt | 4 +- .../src/python/create-gnuradio-out-of-tree-project | 69 -- gr-utils/src/python/gr_modtool | 61 ++ gr-utils/src/python/modtool/CMakeLists.txt | 40 + gr-utils/src/python/modtool/README.modtool | 8 + gr-utils/src/python/modtool/__init__.py | 34 + gr-utils/src/python/modtool/cmakefile_editor.py | 97 ++ gr-utils/src/python/modtool/code_generator.py | 32 + gr-utils/src/python/modtool/grc_xml_generator.py | 85 ++ gr-utils/src/python/modtool/modtool_add.py | 296 ++++++ gr-utils/src/python/modtool/modtool_base.py | 139 +++ gr-utils/src/python/modtool/modtool_disable.py | 144 +++ gr-utils/src/python/modtool/modtool_help.py | 66 ++ gr-utils/src/python/modtool/modtool_info.py | 137 +++ gr-utils/src/python/modtool/modtool_makexml.py | 151 +++ gr-utils/src/python/modtool/modtool_newmod.py | 88 ++ gr-utils/src/python/modtool/modtool_rm.py | 155 +++ gr-utils/src/python/modtool/newmod_tarfile.py | 1034 ++++++++++++++++++++ gr-utils/src/python/modtool/parser_cc_block.py | 205 ++++ gr-utils/src/python/modtool/templates.py | 698 +++++++++++++ gr-utils/src/python/modtool/util_functions.py | 127 +++ 21 files changed, 3600 insertions(+), 70 deletions(-) delete mode 100755 gr-utils/src/python/create-gnuradio-out-of-tree-project create mode 100755 gr-utils/src/python/gr_modtool create mode 100644 gr-utils/src/python/modtool/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/README.modtool create mode 100644 gr-utils/src/python/modtool/__init__.py create mode 100644 gr-utils/src/python/modtool/cmakefile_editor.py create mode 100644 gr-utils/src/python/modtool/code_generator.py create mode 100644 gr-utils/src/python/modtool/grc_xml_generator.py create mode 100644 gr-utils/src/python/modtool/modtool_add.py create mode 100644 gr-utils/src/python/modtool/modtool_base.py create mode 100644 gr-utils/src/python/modtool/modtool_disable.py create mode 100644 gr-utils/src/python/modtool/modtool_help.py create mode 100644 gr-utils/src/python/modtool/modtool_info.py create mode 100644 gr-utils/src/python/modtool/modtool_makexml.py create mode 100644 gr-utils/src/python/modtool/modtool_newmod.py create mode 100644 gr-utils/src/python/modtool/modtool_rm.py create mode 100644 gr-utils/src/python/modtool/newmod_tarfile.py create mode 100644 gr-utils/src/python/modtool/parser_cc_block.py create mode 100644 gr-utils/src/python/modtool/templates.py create mode 100644 gr-utils/src/python/modtool/util_functions.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/CMakeLists.txt b/gr-utils/src/python/CMakeLists.txt index d2af6b952..ef4e66d13 100644 --- a/gr-utils/src/python/CMakeLists.txt +++ b/gr-utils/src/python/CMakeLists.txt @@ -35,7 +35,7 @@ GR_PYTHON_INSTALL( GR_PYTHON_INSTALL( PROGRAMS - create-gnuradio-out-of-tree-project + gr_modtool gr_plot_char gr_plot_const gr_plot_fft @@ -55,3 +55,5 @@ GR_PYTHON_INSTALL( DESTINATION ${GR_RUNTIME_DIR} COMPONENT "utils" ) + +add_subdirectory(modtool) diff --git a/gr-utils/src/python/create-gnuradio-out-of-tree-project b/gr-utils/src/python/create-gnuradio-out-of-tree-project deleted file mode 100755 index d5e32c92b..000000000 --- a/gr-utils/src/python/create-gnuradio-out-of-tree-project +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python - -from optparse import OptionParser -import os -import re -import sys -import subprocess - -tarball_url="http://gnuradio.org/releases/gnuradio/gr-howto-write-a-block-3.3git-651-g642252d8.tar.gz" - -def open_tarball(tarball_name=None): - """Return a readable fileobject that references the tarball. - If tarball_name is None, download from the net - """ - if tarball_name: - return open(tarball_name, 'r') - p = subprocess.Popen(["wget", "-O", "-", tarball_url], - close_fds=True, stdout=subprocess.PIPE) - return p.stdout - -def extract_and_rename_files(tarball, module_name): - # Requires GNU tar. - tar_cmd = 'tar xz --strip-components=1 --transform="s/howto/%s/g"' % (module_name,) - p = subprocess.Popen(tar_cmd, shell=True, stdin=tarball, close_fds=True) - sts = os.waitpid(p.pid, 0) - return sts == 0 - -def main(): - usage = "%prog: [options] new_module_name" - description="Create a prototype 'out of tree' GNU Radio project" - parser = OptionParser(usage=usage, description=description) - parser.add_option("-T", "--tarball", type="string", default=None, - help="path to gr-howto-build-a-block gzipped tarball [default=]") - (options, args) = parser.parse_args() - if len(args) != 1: - parser.print_help() - raise SystemExit,2 - module_name = args[0] - if not re.match(r'[_a-z][_a-z0-9]*$', module_name): - sys.stderr.write("module_name '%s' may only contain [a-z0-9_]\n" % (module_name)) - raise SystemExit, 1 - - # Ensure there's no file or directory called - if os.path.exists(module_name): - sys.stderr.write("A file or directory named '%s' already exists\n" % (module_name,)) - raise SystemExit, 1 - - os.mkdir(module_name) - os.chdir(module_name) - - ok = extract_and_rename_files(open_tarball(options.tarball), module_name) - - # rename file contents - upper_module_name = module_name.upper() - sed_cmd = 'sed -i -e "s/howto-write-a-block/%s/g" -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, module_name, \ - upper_module_name) - os.system('find . -type f -print0 | xargs -0 ' + sed_cmd) - - sys.stdout.write(""" -Project '%s' is now ready to build. - - $ ./bootstrap - $ ./configure --prefix=/home/[user]/install - $ (make && make check && make install) 2>&1 | tee make.log - -""" % (module_name,)) - -if __name__ == '__main__': - main() diff --git a/gr-utils/src/python/gr_modtool b/gr-utils/src/python/gr_modtool new file mode 100755 index 000000000..bc41d56f5 --- /dev/null +++ b/gr-utils/src/python/gr_modtool @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# +""" A tool for editing GNU Radio out-of-tree modules. """ + +import sys +from gnuradio.modtool import * + +def get_class_dict(): + " Return a dictionary of the available commands in the form command->class " + classdict = {} + for g in globals().values(): + try: + if issubclass(g, ModTool): + classdict[g.name] = g + for a in g.aliases: + classdict[a] = g + except (TypeError, AttributeError): + pass + return classdict + + +### Main code ################################################################ +def main(): + """ Here we go. Parse command, choose class and run. """ + cmd_dict = get_class_dict() + command = get_command_from_argv(cmd_dict.keys()) + if command is None: + print 'Usage:' + templates.Templates['usage'] + exit(2) + modtool = cmd_dict[command]() + modtool.setup() + modtool.run() + +if __name__ == '__main__': + if not ((sys.version_info[0] > 2) or + (sys.version_info[0] == 2 and sys.version_info[1] >= 7)): + print "Using Python < 2.7 is not recommended for gr_modtool." + try: + main() + except KeyboardInterrupt: + pass + diff --git a/gr-utils/src/python/modtool/CMakeLists.txt b/gr-utils/src/python/modtool/CMakeLists.txt new file mode 100644 index 000000000..3425b50d0 --- /dev/null +++ b/gr-utils/src/python/modtool/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright 2011 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. + +GR_PYTHON_INSTALL(FILES + __init__.py + cmakefile_editor.py + code_generator.py + grc_xml_generator.py + modtool_add.py + modtool_base.py + modtool_disable.py + modtool_help.py + modtool_info.py + modtool_makexml.py + modtool_newmod.py + modtool_rm.py + newmod_tarfile.py + parser_cc_block.py + templates.py + util_functions.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/modtool + COMPONENT "utils" +) + diff --git a/gr-utils/src/python/modtool/README.modtool b/gr-utils/src/python/modtool/README.modtool new file mode 100644 index 000000000..93ce97292 --- /dev/null +++ b/gr-utils/src/python/modtool/README.modtool @@ -0,0 +1,8 @@ +gr_modtool: Swiss Army Knife for editing GNU Radio modules and -components. + +Adding a new subcommand +======================= + +* Add a new file called modtool_SUBCOMMAND +* Have a look at the other subcommands, it must inherit from ModTool +* Add that file to __init__.py and CMakeLists.txt diff --git a/gr-utils/src/python/modtool/__init__.py b/gr-utils/src/python/modtool/__init__.py new file mode 100644 index 000000000..a10747254 --- /dev/null +++ b/gr-utils/src/python/modtool/__init__.py @@ -0,0 +1,34 @@ +# +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from cmakefile_editor import CMakeFileEditor +from code_generator import GRMTemplate +from grc_xml_generator import GRCXMLGenerator +from modtool_add import ModToolAdd +from modtool_base import ModTool +from modtool_disable import ModToolDisable +from modtool_help import ModToolHelp +from modtool_info import ModToolInfo +from modtool_makexml import ModToolMakeXML +from modtool_newmod import ModToolNewModule +from modtool_rm import ModToolRemove +from parser_cc_block import ParserCCBlock +from util_functions import * diff --git a/gr-utils/src/python/modtool/cmakefile_editor.py b/gr-utils/src/python/modtool/cmakefile_editor.py new file mode 100644 index 000000000..fe50373bb --- /dev/null +++ b/gr-utils/src/python/modtool/cmakefile_editor.py @@ -0,0 +1,97 @@ +""" Edit CMakeLists.txt files """ + +import re + +### CMakeFile.txt editor class ############################################### +class CMakeFileEditor(object): + """A tool for editing CMakeLists.txt files. """ + def __init__(self, filename, separator=' ', indent=' '): + self.filename = filename + self.cfile = open(filename, 'r').read() + self.separator = separator + self.indent = indent + + def get_entry_value(self, entry, to_ignore=''): + """ Get the value of an entry. + to_ignore is the part of the entry you don't care about. """ + regexp = '%s\(%s([^()]+)\)' % (entry, to_ignore) + mobj = re.search(regexp, self.cfile, flags=re.MULTILINE) + if mobj is None: + return None + value = mobj.groups()[0].strip() + return value + + def append_value(self, entry, value, to_ignore=''): + """ Add a value to an entry. """ + regexp = re.compile('(%s\([^()]*?)\s*?(\s?%s)\)' % (entry, to_ignore), + re.MULTILINE) + substi = r'\1' + self.separator + value + r'\2)' + self.cfile = regexp.sub(substi, self.cfile, count=1) + + def remove_value(self, entry, value, to_ignore=''): + """Remove a value from an entry.""" + regexp = '^\s*(%s\(\s*%s[^()]*?\s*)%s\s*([^()]*\))' % (entry, to_ignore, value) + regexp = re.compile(regexp, re.MULTILINE) + self.cfile = re.sub(regexp, r'\1\2', self.cfile, count=1) + + def delete_entry(self, entry, value_pattern=''): + """Remove an entry from the current buffer.""" + regexp = '%s\s*\([^()]*%s[^()]*\)[^\n]*\n' % (entry, value_pattern) + regexp = re.compile(regexp, re.MULTILINE) + self.cfile = re.sub(regexp, '', self.cfile, count=1) + + def write(self): + """ Write the changes back to the file. """ + open(self.filename, 'w').write(self.cfile) + + def remove_double_newlines(self): + """Simply clear double newlines from the file buffer.""" + self.cfile = re.compile('\n\n\n+', re.MULTILINE).sub('\n\n', self.cfile) + + def find_filenames_match(self, regex): + """ Find the filenames that match a certain regex + on lines that aren't comments """ + filenames = [] + reg = re.compile(regex) + fname_re = re.compile('[a-zA-Z]\w+\.\w{1,5}$') + for line in self.cfile.splitlines(): + if len(line.strip()) == 0 or line.strip()[0] == '#': + continue + for word in re.split('[ /)(\t\n\r\f\v]', line): + if fname_re.match(word) and reg.search(word): + filenames.append(word) + return filenames + + def disable_file(self, fname): + """ Comment out a file """ + starts_line = False + for line in self.cfile.splitlines(): + if len(line.strip()) == 0 or line.strip()[0] == '#': + continue + if re.search(r'\b'+fname+r'\b', line): + if re.match(fname, line.lstrip()): + starts_line = True + break + comment_out_re = r'#\1' + '\n' + self.indent + if not starts_line: + comment_out_re = r'\n' + self.indent + comment_out_re + (self.cfile, nsubs) = re.subn(r'(\b'+fname+r'\b)\s*', comment_out_re, self.cfile) + if nsubs == 0: + print "Warning: A replacement failed when commenting out %s. Check the CMakeFile.txt manually." % fname + elif nsubs > 1: + print "Warning: Replaced %s %d times (instead of once). Check the CMakeFile.txt manually." % (fname, nsubs) + + def comment_out_lines(self, pattern, comment_str='#'): + """ Comments out all lines that match with pattern """ + for line in self.cfile.splitlines(): + if re.search(pattern, line): + self.cfile = self.cfile.replace(line, comment_str+line) + + def check_for_glob(self, globstr): + """ Returns true if a glob as in globstr is found in the cmake file """ + glob_re = r'GLOB\s[a-z_]+\s"%s"' % globstr.replace('*', '\*') + if re.search(glob_re, self.cfile, flags=re.MULTILINE|re.IGNORECASE) is not None: + return True + else: + return False + diff --git a/gr-utils/src/python/modtool/code_generator.py b/gr-utils/src/python/modtool/code_generator.py new file mode 100644 index 000000000..b727f611e --- /dev/null +++ b/gr-utils/src/python/modtool/code_generator.py @@ -0,0 +1,32 @@ +""" A code generator (needed by ModToolAdd) """ + +from templates import Templates +import Cheetah.Template +from util_functions import str_to_fancyc_comment +from util_functions import str_to_python_comment +from util_functions import strip_default_values +from util_functions import strip_arg_types + +### Code generator class ##################################################### +class GRMTemplate(Cheetah.Template.Template): + """ An extended template class """ + def __init__(self, src, searchList): + self.grtypelist = { + 'sync': 'gr_sync_block', + 'sink': 'gr_sync_block', + 'source': 'gr_sync_block', + 'decimator': 'gr_sync_decimator', + 'interpolator': 'gr_sync_interpolator', + 'general': 'gr_block', + 'hier': 'gr_hier_block2', + 'noblock': ''} + searchList['str_to_fancyc_comment'] = str_to_fancyc_comment + searchList['str_to_python_comment'] = str_to_python_comment + searchList['strip_default_values'] = strip_default_values + searchList['strip_arg_types'] = strip_arg_types + Cheetah.Template.Template.__init__(self, src, searchList=searchList) + self.grblocktype = self.grtypelist[searchList['blocktype']] + +def get_template(tpl_id, **kwargs): + """ Return the template given by tpl_id, parsed through Cheetah """ + return str(GRMTemplate(Templates[tpl_id], searchList=kwargs)) diff --git a/gr-utils/src/python/modtool/grc_xml_generator.py b/gr-utils/src/python/modtool/grc_xml_generator.py new file mode 100644 index 000000000..2fa61863f --- /dev/null +++ b/gr-utils/src/python/modtool/grc_xml_generator.py @@ -0,0 +1,85 @@ +import xml.etree.ElementTree as ET +from util_functions import is_number, xml_indent + +### GRC XML Generator ######################################################## +try: + import lxml.etree + LXML_IMPORTED = True +except ImportError: + LXML_IMPORTED = False + +class GRCXMLGenerator(object): + """ Create and write the XML bindings for a GRC block. """ + def __init__(self, modname=None, blockname=None, doc=None, params=None, iosig=None): + """docstring for __init__""" + params_list = ['$'+s['key'] for s in params if s['in_constructor']] + # Can't make a dict 'cause order matters + self._header = (('name', blockname.replace('_', ' ').capitalize()), + ('key', '%s_%s' % (modname, blockname)), + ('category', modname.upper()), + ('import', 'import %s' % modname), + ('make', '%s.%s(%s)' % (modname, blockname, ', '.join(params_list))) + ) + self.params = params + self.iosig = iosig + self.doc = doc + self.root = None + if LXML_IMPORTED: + self._prettyprint = self._lxml_prettyprint + else: + self._prettyprint = self._manual_prettyprint + + def _lxml_prettyprint(self): + """ XML pretty printer using lxml """ + return lxml.etree.tostring( + lxml.etree.fromstring(ET.tostring(self.root, encoding="UTF-8")), + pretty_print=True + ) + + def _manual_prettyprint(self): + """ XML pretty printer using xml_indent """ + xml_indent(self.root) + return ET.tostring(self.root, encoding="UTF-8") + + def make_xml(self): + """ Create the actual tag tree """ + root = ET.Element("block") + iosig = self.iosig + for tag, value in self._header: + this_tag = ET.SubElement(root, tag) + this_tag.text = value + for param in self.params: + param_tag = ET.SubElement(root, 'param') + ET.SubElement(param_tag, 'name').text = param['key'].capitalize() + ET.SubElement(param_tag, 'key').text = param['key'] + if len(param['default']): + ET.SubElement(param_tag, 'value').text = param['default'] + ET.SubElement(param_tag, 'type').text = param['type'] + for inout in sorted(iosig.keys()): + if iosig[inout]['max_ports'] == '0': + continue + for i in range(len(iosig[inout]['type'])): + s_tag = ET.SubElement(root, {'in': 'sink', 'out': 'source'}[inout]) + ET.SubElement(s_tag, 'name').text = inout + ET.SubElement(s_tag, 'type').text = iosig[inout]['type'][i] + if iosig[inout]['vlen'][i] != '1': + vlen = iosig[inout]['vlen'][i] + if is_number(vlen): + ET.SubElement(s_tag, 'vlen').text = vlen + else: + ET.SubElement(s_tag, 'vlen').text = '$'+vlen + if i == len(iosig[inout]['type'])-1: + if not is_number(iosig[inout]['max_ports']): + ET.SubElement(s_tag, 'nports').text = iosig[inout]['max_ports'] + elif len(iosig[inout]['type']) < int(iosig[inout]['max_ports']): + ET.SubElement(s_tag, 'nports').text = str(int(iosig[inout]['max_ports']) - + len(iosig[inout]['type'])+1) + if self.doc is not None: + ET.SubElement(root, 'doc').text = self.doc + self.root = root + + def save(self, filename): + """ Write the XML file """ + self.make_xml() + open(filename, 'w').write(self._prettyprint()) + diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py new file mode 100644 index 000000000..c664d7c1a --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -0,0 +1,296 @@ +""" Module to add new blocks """ + +import os +import sys +import re +from optparse import OptionGroup + +from util_functions import append_re_line_sequence, ask_yes_no +from cmakefile_editor import CMakeFileEditor +from modtool_base import ModTool +from templates import Templates +from code_generator import get_template +import Cheetah.Template + +### Add new block module ##################################################### +class ModToolAdd(ModTool): + """ Add block to the out-of-tree module. """ + name = 'add' + aliases = ('insert',) + _block_types = ('sink', 'source', 'sync', 'decimator', 'interpolator', + 'general', 'hier', 'noblock') + def __init__(self): + ModTool.__init__(self) + self._add_cc_qa = False + self._add_py_qa = False + + def setup_parser(self): + parser = ModTool.setup_parser(self) + parser.usage = '%prog add [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "Add module options") + ogroup.add_option("-t", "--block-type", type="choice", + choices=self._block_types, default=None, help="One of %s." % ', '.join(self._block_types)) + ogroup.add_option("--license-file", type="string", default=None, + help="File containing the license header for every source code file.") + ogroup.add_option("--argument-list", type="string", default=None, + help="The argument list for the constructor and make functions.") + ogroup.add_option("--add-python-qa", action="store_true", default=None, + help="If given, Python QA code is automatically added if possible.") + ogroup.add_option("--add-cpp-qa", action="store_true", default=None, + help="If given, C++ QA code is automatically added if possible.") + ogroup.add_option("--skip-cmakefiles", action="store_true", default=False, + help="If given, only source files are written, but CMakeLists.txt files are left unchanged.") + ogroup.add_option("-l", "--lang", type="choice", choices=('cpp', 'c++', 'python'), + default='cpp', help="Language (cpp or python)") + parser.add_option_group(ogroup) + return parser + + def setup(self): + ModTool.setup(self) + options = self.options + self._info['blocktype'] = options.block_type + if self._info['blocktype'] is None: + while self._info['blocktype'] not in self._block_types: + self._info['blocktype'] = raw_input("Enter code type: ") + if self._info['blocktype'] not in self._block_types: + print 'Must be one of ' + str(self._block_types) + self._info['lang'] = options.lang + if self._info['lang'] == 'c++': + self._info['lang'] = 'cpp' + print "Language: %s" % {'cpp': 'C++', 'python': 'Python'}[self._info['lang']] + + if ((self._skip_subdirs['lib'] and self._info['lang'] == 'cpp') + or (self._skip_subdirs['python'] and self._info['lang'] == 'python')): + print "Missing or skipping relevant subdir." + sys.exit(1) + + if self._info['blockname'] is None: + if len(self.args) >= 2: + self._info['blockname'] = self.args[1] + else: + self._info['blockname'] = raw_input("Enter name of block/code (without module name prefix): ") + if not re.match('[a-zA-Z0-9_]+', self._info['blockname']): + print 'Invalid block name.' + sys.exit(2) + print "Block/code identifier: " + self._info['blockname'] + self._info['fullblockname'] = self._info['modname'] + '_' + self._info['blockname'] + self._info['license'] = self.setup_choose_license() + + if options.argument_list is not None: + self._info['arglist'] = options.argument_list + else: + self._info['arglist'] = raw_input('Enter valid argument list, including default arguments: ') + + if not (self._info['blocktype'] in ('noblock') or self._skip_subdirs['python']): + self._add_py_qa = options.add_python_qa + if self._add_py_qa is None: + self._add_py_qa = ask_yes_no('Add Python QA code?', True) + if self._info['lang'] == 'cpp': + self._add_cc_qa = options.add_cpp_qa + if self._add_cc_qa is None: + self._add_cc_qa = ask_yes_no('Add C++ QA code?', not self._add_py_qa) + if self._info['version'] == 'autofoo' and not self.options.skip_cmakefiles: + print "Warning: Autotools modules are not supported. ", + print "Files will be created, but Makefiles will not be edited." + self.options.skip_cmakefiles = True + + + def setup_choose_license(self): + """ Select a license by the following rules, in this order: + 1) The contents of the file given by --license-file + 2) The contents of the file LICENSE or LICENCE in the modules + top directory + 3) The default license. """ + if self.options.license_file is not None \ + and os.path.isfile(self.options.license_file): + return open(self.options.license_file).read() + elif os.path.isfile('LICENSE'): + return open('LICENSE').read() + elif os.path.isfile('LICENCE'): + return open('LICENCE').read() + else: + return Templates['defaultlicense'] + + def _write_tpl(self, tpl, path, fname): + """ Shorthand for writing a substituted template to a file""" + print "Adding file '%s'..." % fname + open(os.path.join(path, fname), 'w').write(get_template(tpl, **self._info)) + + def run(self): + """ Go, go, go. """ + has_swig = ( + self._info['lang'] == 'cpp' + and not self._skip_subdirs['swig'] + ) + has_grc = False + if self._info['lang'] == 'cpp': + print "Traversing lib..." + self._run_lib() + has_grc = has_swig + else: # Python + print "Traversing python..." + self._run_python() + if self._info['blocktype'] != 'noblock': + has_grc = True + if has_swig: + print "Traversing swig..." + self._run_swig() + if self._add_py_qa: + print "Adding Python QA..." + self._run_python_qa() + if has_grc and not self._skip_subdirs['grc']: + print "Traversing grc..." + self._run_grc() + + def _run_lib(self): + """ Do everything that needs doing in the subdir 'lib' and 'include'. + - add .cc and .h files + - include them into CMakeLists.txt + - check if C++ QA code is req'd + - if yes, create qa_*.{cc,h} and add them to CMakeLists.txt + """ + def _add_qa(): + " Add C++ QA files for 3.7 API " + fname_qa_h = 'qa_%s.h' % self._info['blockname'] + fname_qa_cc = 'qa_%s.cc' % self._info['blockname'] + self._write_tpl('qa_cpp', 'lib', fname_qa_cc) + self._write_tpl('qa_h', 'lib', fname_qa_h) + if not self.options.skip_cmakefiles: + try: + append_re_line_sequence(self._file['cmlib'], + '\$\{CMAKE_CURRENT_SOURCE_DIR\}/qa_%s.cc.*\n' % self._info['modname'], + ' ${CMAKE_CURRENT_SOURCE_DIR}/qa_%s.cc' % self._info['blockname']) + append_re_line_sequence(self._file['qalib'], + '#include.*\n', + '#include "%s"' % fname_qa_h) + append_re_line_sequence(self._file['qalib'], + '(addTest.*suite.*\n|new CppUnit.*TestSuite.*\n)', + ' s->addTest(gr::%s::qa_%s::suite());' % (self._info['modname'], + self._info['blockname']) + ) + except IOError: + print "Can't add C++ QA files." + def _add_qa36(): + " Add C++ QA files for pre-3.7 API (not autotools) " + fname_qa_cc = 'qa_%s.cc' % self._info['fullblockname'] + self._write_tpl('qa_cpp36', 'lib', fname_qa_cc) + if not self.options.skip_cmakefiles: + open(self._file['cmlib'], 'a').write( + str( + Cheetah.Template.Template( + Templates['qa_cmakeentry36'], + searchList={'basename': os.path.splitext(fname_qa_cc)[0], + 'filename': fname_qa_cc, + 'modname': self._info['modname'] + } + ) + ) + ) + ed = CMakeFileEditor(self._file['cmlib']) + ed.remove_double_newlines() + ed.write() + fname_cc = None + fname_h = None + if self._info['version'] == '37': + fname_h = self._info['blockname'] + '.h' + fname_cc = self._info['blockname'] + '.cc' + if self._info['blocktype'] in ('source', 'sink', 'sync', 'decimator', + 'interpolator', 'general', 'hier'): + fname_cc = self._info['blockname'] + '_impl.cc' + self._write_tpl('block_impl_h', 'lib', self._info['blockname'] + '_impl.h') + self._write_tpl('block_impl_cpp', 'lib', fname_cc) + self._write_tpl('block_def_h', self._info['includedir'], fname_h) + else: # Pre-3.7 or autotools + fname_h = self._info['fullblockname'] + '.h' + fname_cc = self._info['fullblockname'] + '.cc' + self._write_tpl('block_h36', self._info['includedir'], fname_h) + self._write_tpl('block_cpp36', 'lib', fname_cc) + if not self.options.skip_cmakefiles: + ed = CMakeFileEditor(self._file['cmlib']) + ed.append_value('add_library', fname_cc) + ed.write() + ed = CMakeFileEditor(self._file['cminclude']) + ed.append_value('install', fname_h, 'DESTINATION[^()]+') + ed.write() + if self._add_cc_qa: + if self._info['version'] == '37': + _add_qa() + elif self._info['version'] == '36': + _add_qa36() + elif self._info['version'] == 'autofoo': + print "Warning: C++ QA files not supported for autotools." + + def _run_swig(self): + """ Do everything that needs doing in the subdir 'swig'. + - Edit main *.i file + """ + if self._get_mainswigfile() is None: + print 'Warning: No main swig file found.' + return + print "Editing %s..." % self._file['swig'] + mod_block_sep = '/' + if self._info['version'] == '36': + mod_block_sep = '_' + swig_block_magic_str = get_template('swig_block_magic', **self._info) + include_str = '#include "%s%s%s.h"' % ( + self._info['modname'], + mod_block_sep, + self._info['blockname']) + if re.search('#include', open(self._file['swig'], 'r').read()): + append_re_line_sequence(self._file['swig'], '^#include.*\n', include_str) + else: # I.e., if the swig file is empty + oldfile = open(self._file['swig'], 'r').read() + regexp = re.compile('^%\{\n', re.MULTILINE) + oldfile = regexp.sub('%%{\n%s\n' % include_str, oldfile, count=1) + open(self._file['swig'], 'w').write(oldfile) + open(self._file['swig'], 'a').write(swig_block_magic_str) + + def _run_python_qa(self): + """ Do everything that needs doing in the subdir 'python' to add + QA code. + - add .py files + - include in CMakeLists.txt + """ + fname_py_qa = 'qa_' + self._info['blockname'] + '.py' + self._write_tpl('qa_python', 'python', fname_py_qa) + os.chmod(os.path.join('python', fname_py_qa), 0755) + if self.options.skip_cmakefiles or CMakeFileEditor(self._file['cmpython']).check_for_glob('qa_*.py'): + return + print "Editing python/CMakeLists.txt..." + open(self._file['cmpython'], 'a').write( + 'GR_ADD_TEST(qa_%s ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/%s)\n' % \ + (self._info['blockname'], fname_py_qa)) + + def _run_python(self): + """ Do everything that needs doing in the subdir 'python' to add + a Python block. + - add .py file + - include in CMakeLists.txt + - include in __init__.py + """ + fname_py = self._info['blockname'] + '.py' + self._write_tpl('block_python', 'python', fname_py) + append_re_line_sequence(self._file['pyinit'], + '(^from.*import.*\n|# import any pure.*\n)', + 'from %s import *' % self._info['blockname']) + if self.options.skip_cmakefiles: + return + ed = CMakeFileEditor(self._file['cmpython']) + ed.append_value('GR_PYTHON_INSTALL', fname_py, 'DESTINATION[^()]+') + ed.write() + + def _run_grc(self): + """ Do everything that needs doing in the subdir 'grc' to add + a GRC bindings XML file. + - add .xml file + - include in CMakeLists.txt + """ + fname_grc = self._info['fullblockname'] + '.xml' + self._write_tpl('grc_xml', 'grc', fname_grc) + ed = CMakeFileEditor(self._file['cmgrc'], '\n ') + if self.options.skip_cmakefiles or ed.check_for_glob('*.xml'): + return + print "Editing grc/CMakeLists.txt..." + ed.append_value('install', fname_grc, 'DESTINATION[^()]+') + ed.write() + diff --git a/gr-utils/src/python/modtool/modtool_base.py b/gr-utils/src/python/modtool/modtool_base.py new file mode 100644 index 000000000..edb0f14ee --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_base.py @@ -0,0 +1,139 @@ +""" Base class for the modules """ + +import os +import re +import sys +from optparse import OptionParser, OptionGroup + +from util_functions import get_modname +from templates import Templates + +### ModTool base class ####################################################### +class ModTool(object): + """ Base class for all modtool command classes. """ + def __init__(self): + self._subdirs = ['lib', 'include', 'python', 'swig', 'grc'] # List subdirs where stuff happens + self._has_subdirs = {} + self._skip_subdirs = {} + self._info = {} + self._file = {} + for subdir in self._subdirs: + self._has_subdirs[subdir] = False + self._skip_subdirs[subdir] = False + self.parser = self.setup_parser() + self.args = None + self.options = None + self._dir = None + + def setup_parser(self): + """ Init the option parser. If derived classes need to add options, + override this and call the parent function. """ + parser = OptionParser(usage=Templates['usage'], add_help_option=False) + ogroup = OptionGroup(parser, "General options") + ogroup.add_option("-h", "--help", action="help", help="Displays this help message.") + ogroup.add_option("-d", "--directory", type="string", default=".", + help="Base directory of the module.") + ogroup.add_option("-n", "--module-name", type="string", default=None, + help="Name of the GNU Radio module. If possible, this gets detected from CMakeLists.txt.") + ogroup.add_option("-N", "--block-name", type="string", default=None, + help="Name of the block, minus the module name prefix.") + ogroup.add_option("--skip-lib", action="store_true", default=False, + help="Don't do anything in the lib/ subdirectory.") + ogroup.add_option("--skip-swig", action="store_true", default=False, + help="Don't do anything in the swig/ subdirectory.") + ogroup.add_option("--skip-python", action="store_true", default=False, + help="Don't do anything in the python/ subdirectory.") + ogroup.add_option("--skip-grc", action="store_true", default=False, + help="Don't do anything in the grc/ subdirectory.") + parser.add_option_group(ogroup) + return parser + + def setup(self): + """ Initialise all internal variables, such as the module name etc. """ + (options, self.args) = self.parser.parse_args() + self._dir = options.directory + if not self._check_directory(self._dir): + print "No GNU Radio module found in the given directory. Quitting." + sys.exit(1) + print "Operating in directory " + self._dir + if options.module_name is not None: + self._info['modname'] = options.module_name + else: + self._info['modname'] = get_modname() + if self._info['modname'] is None: + print "No GNU Radio module found in the given directory. Quitting." + sys.exit(1) + print "GNU Radio module name identified: " + self._info['modname'] + if self._info['version'] == '36' and os.path.isdir(os.path.join('include', self._info['modname'])): + self._info['version'] = '37' + if options.skip_lib or not self._has_subdirs['lib']: + self._skip_subdirs['lib'] = True + if options.skip_python or not self._has_subdirs['python']: + self._skip_subdirs['python'] = True + if options.skip_swig or self._get_mainswigfile() is None or not self._has_subdirs['swig']: + self._skip_subdirs['swig'] = True + if options.skip_grc or not self._has_subdirs['grc']: + self._skip_subdirs['grc'] = True + self._info['blockname'] = options.block_name + self.options = options + self._setup_files() + + def _setup_files(self): + """ Initialise the self._file[] dictionary """ + if not self._skip_subdirs['swig']: + self._file['swig'] = os.path.join('swig', self._get_mainswigfile()) + self._file['qalib'] = os.path.join('lib', 'qa_%s.cc' % self._info['modname']) + self._file['pyinit'] = os.path.join('python', '__init__.py') + self._file['cmlib'] = os.path.join('lib', 'CMakeLists.txt') + self._file['cmgrc'] = os.path.join('grc', 'CMakeLists.txt') + self._file['cmpython'] = os.path.join('python', 'CMakeLists.txt') + if self._info['version'] in ('37', 'component'): + self._info['includedir'] = os.path.join('include', self._info['modname']) + else: + self._info['includedir'] = 'include' + self._file['cminclude'] = os.path.join(self._info['includedir'], 'CMakeLists.txt') + self._file['cmswig'] = os.path.join('swig', 'CMakeLists.txt') + + def _check_directory(self, directory): + """ Guesses if dir is a valid GNU Radio module directory by looking for + CMakeLists.txt and at least one of the subdirs lib/, python/ and swig/. + Changes the directory, if valid. """ + has_makefile = False + try: + files = os.listdir(directory) + os.chdir(directory) + except OSError: + print "Can't read or chdir to directory %s." % directory + return False + for f in files: + if os.path.isfile(f) and f == 'CMakeLists.txt': + if re.search('find_package\(GnuradioCore\)', open(f).read()) is not None: + self._info['version'] = '36' # Might be 37, check that later + has_makefile = True + elif re.search('GR_REGISTER_COMPONENT', open(f).read()) is not None: + self._info['version'] = '36' # Might be 37, check that later + self._info['is_component'] = True + has_makefile = True + # TODO search for autofoo + elif os.path.isdir(f): + if (f in self._has_subdirs.keys()): + self._has_subdirs[f] = True + else: + self._skip_subdirs[f] = True + return bool(has_makefile and (self._has_subdirs.values())) + + def _get_mainswigfile(self): + """ Find out which name the main SWIG file has. In particular, is it + a MODNAME.i or a MODNAME_swig.i? Returns None if none is found. """ + modname = self._info['modname'] + swig_files = (modname + '.i', + modname + '_swig.i') + for fname in swig_files: + if os.path.isfile(os.path.join(self._dir, 'swig', fname)): + return fname + return None + + def run(self): + """ Override this. """ + pass + diff --git a/gr-utils/src/python/modtool/modtool_disable.py b/gr-utils/src/python/modtool/modtool_disable.py new file mode 100644 index 000000000..67f15ad53 --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_disable.py @@ -0,0 +1,144 @@ +""" Disable blocks module """ + +import os +import re +import sys +from optparse import OptionGroup + +from modtool_base import ModTool +from cmakefile_editor import CMakeFileEditor + +### Disable module ########################################################### +class ModToolDisable(ModTool): + """ Disable block (comments out CMake entries for files) """ + name = 'disable' + aliases = ('dis',) + def __init__(self): + ModTool.__init__(self) + + def setup_parser(self): + " Initialise the option parser for 'gr_modtool.py rm' " + parser = ModTool.setup_parser(self) + parser.usage = '%prog disable [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "Disable module options") + ogroup.add_option("-p", "--pattern", type="string", default=None, + help="Filter possible choices for blocks to be disabled.") + ogroup.add_option("-y", "--yes", action="store_true", default=False, + help="Answer all questions with 'yes'.") + parser.add_option_group(ogroup) + return parser + + def setup(self): + ModTool.setup(self) + options = self.options + if options.pattern is not None: + self._info['pattern'] = options.pattern + elif options.block_name is not None: + self._info['pattern'] = options.block_name + elif len(self.args) >= 2: + self._info['pattern'] = self.args[1] + else: + self._info['pattern'] = raw_input('Which blocks do you want to disable? (Regex): ') + if len(self._info['pattern']) == 0: + self._info['pattern'] = '.' + self._info['yes'] = options.yes + + def run(self): + """ Go, go, go! """ + def _handle_py_qa(cmake, fname): + """ Do stuff for py qa """ + cmake.comment_out_lines('GR_ADD_TEST.*'+fname) + return True + def _handle_py_mod(cmake, fname): + """ Do stuff for py extra files """ + try: + initfile = open(self._file['pyinit']).read() + except IOError: + print "Could not edit __init__.py, that might be a problem." + return False + pymodname = os.path.splitext(fname)[0] + initfile = re.sub(r'((from|import)\s+\b'+pymodname+r'\b)', r'#\1', initfile) + open(self._file['pyinit'], 'w').write(initfile) + return False + def _handle_cc_qa(cmake, fname): + """ Do stuff for cc qa """ + if self._info['version'] == '37': + cmake.comment_out_lines('\$\{CMAKE_CURRENT_SOURCE_DIR\}/'+fname) + fname_base = os.path.splitext(fname)[0] + ed = CMakeFileEditor(self._file['qalib']) # Abusing the CMakeFileEditor... + ed.comment_out_lines('#include\s+"%s.h"' % fname_base, comment_str='//') + ed.comment_out_lines('%s::suite\(\)' % fname_base, comment_str='//') + ed.write() + elif self._info['version'] == '36': + cmake.comment_out_lines('add_executable.*'+fname) + cmake.comment_out_lines('target_link_libraries.*'+os.path.splitext(fname)[0]) + cmake.comment_out_lines('GR_ADD_TEST.*'+os.path.splitext(fname)[0]) + return True + def _handle_h_swig(cmake, fname): + """ Comment out include files from the SWIG file, + as well as the block magic """ + swigfile = open(self._file['swig']).read() + (swigfile, nsubs) = re.subn('(.include\s+"(%s/)?%s")' % ( + self._info['modname'], fname), + r'//\1', swigfile) + if nsubs > 0: + print "Changing %s..." % self._file['swig'] + if nsubs > 1: # Need to find a single BLOCK_MAGIC + blockname = os.path.splitext(fname[len(self._info['modname'])+1:])[0] + if self._info['version'] == '37': + blockname = os.path.splitext(fname)[0] + (swigfile, nsubs) = re.subn('(GR_SWIG_BLOCK_MAGIC2?.+%s.+;)' % blockname, r'//\1', swigfile) + if nsubs > 1: + print "Hm, changed more then expected while editing %s." % self._file['swig'] + open(self._file['swig'], 'w').write(swigfile) + return False + def _handle_i_swig(cmake, fname): + """ Comment out include files from the SWIG file, + as well as the block magic """ + swigfile = open(self._file['swig']).read() + blockname = os.path.splitext(fname[len(self._info['modname'])+1:])[0] + if self._info['version'] == '37': + blockname = os.path.splitext(fname)[0] + swigfile = re.sub('(%include\s+"'+fname+'")', r'//\1', swigfile) + print "Changing %s..." % self._file['swig'] + swigfile = re.sub('(GR_SWIG_BLOCK_MAGIC2?.+'+blockname+'.+;)', r'//\1', swigfile) + open(self._file['swig'], 'w').write(swigfile) + return False + # List of special rules: 0: subdir, 1: filename re match, 2: function + special_treatments = ( + ('python', 'qa.+py$', _handle_py_qa), + ('python', '^(?!qa).+py$', _handle_py_mod), + ('lib', 'qa.+\.cc$', _handle_cc_qa), + ('include/%s' % self._info['modname'], '.+\.h$', _handle_h_swig), + ('include', '.+\.h$', _handle_h_swig), + ('swig', '.+\.i$', _handle_i_swig) + ) + for subdir in self._subdirs: + if self._skip_subdirs[subdir]: continue + if self._info['version'] == '37' and subdir == 'include': + subdir = 'include/%s' % self._info['modname'] + try: + cmake = CMakeFileEditor(os.path.join(subdir, 'CMakeLists.txt')) + except IOError: + continue + print "Traversing %s..." % subdir + filenames = cmake.find_filenames_match(self._info['pattern']) + yes = self._info['yes'] + for fname in filenames: + file_disabled = False + if not yes: + ans = raw_input("Really disable %s? [Y/n/a/q]: " % fname).lower().strip() + if ans == 'a': + yes = True + if ans == 'q': + sys.exit(0) + if ans == 'n': + continue + for special_treatment in special_treatments: + if special_treatment[0] == subdir and re.match(special_treatment[1], fname): + file_disabled = special_treatment[2](cmake, fname) + if not file_disabled: + cmake.disable_file(fname) + cmake.write() + print "Careful: 'gr_modtool disable' does not resolve dependencies." + diff --git a/gr-utils/src/python/modtool/modtool_help.py b/gr-utils/src/python/modtool/modtool_help.py new file mode 100644 index 000000000..a1dd3c466 --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_help.py @@ -0,0 +1,66 @@ +""" The help module """ + +from modtool_base import ModTool +from modtool_info import ModToolInfo +from modtool_add import ModToolAdd +from modtool_rm import ModToolRemove +from modtool_newmod import ModToolNewModule +from modtool_disable import ModToolDisable +from modtool_makexml import ModToolMakeXML +from util_functions import get_command_from_argv +from templates import Templates + +def get_class_dict(): + " Return a dictionary of the available commands in the form command->class " + classdict = {} + for g in globals().values(): + try: + if issubclass(g, ModTool): + classdict[g.name] = g + for a in g.aliases: + classdict[a] = g + except (TypeError, AttributeError): + pass + return classdict + + +### Help module ############################################################## +def print_class_descriptions(): + ''' Go through all ModTool* classes and print their name, + alias and description. ''' + desclist = [] + for gvar in globals().values(): + try: + if issubclass(gvar, ModTool) and not issubclass(gvar, ModToolHelp): + desclist.append((gvar.name, ','.join(gvar.aliases), gvar.__doc__)) + except (TypeError, AttributeError): + pass + print 'Name Aliases Description' + print '=====================================================================' + for description in desclist: + print '%-8s %-12s %s' % description + +class ModToolHelp(ModTool): + ''' Show some help. ''' + name = 'help' + aliases = ('h', '?') + def __init__(self): + ModTool.__init__(self) + + def setup(self): + pass + + def run(self): + cmd_dict = get_class_dict() + cmds = cmd_dict.keys() + cmds.remove(self.name) + for a in self.aliases: + cmds.remove(a) + help_requested_for = get_command_from_argv(cmds) + if help_requested_for is None: + print 'Usage:' + Templates['usage'] + print '\nList of possible commands:\n' + print_class_descriptions() + return + cmd_dict[help_requested_for]().setup_parser().print_help() + diff --git a/gr-utils/src/python/modtool/modtool_info.py b/gr-utils/src/python/modtool/modtool_info.py new file mode 100644 index 000000000..80fa27832 --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_info.py @@ -0,0 +1,137 @@ +""" Returns information about a module """ + +import os +from optparse import OptionGroup + +from modtool_base import ModTool +from util_functions import get_modname + +### Info module ############################################################## +class ModToolInfo(ModTool): + """ Return information about a given module """ + name = 'info' + aliases = ('getinfo', 'inf') + def __init__(self): + ModTool.__init__(self) + + def setup_parser(self): + " Initialise the option parser for 'gr_modtool.py info' " + parser = ModTool.setup_parser(self) + parser.usage = '%prog info [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "Info options") + ogroup.add_option("--python-readable", action="store_true", default=None, + help="Return the output in a format that's easier to read for Python scripts.") + ogroup.add_option("--suggested-dirs", default=None, type="string", + help="Suggest typical include dirs if nothing better can be detected.") + parser.add_option_group(ogroup) + return parser + + def setup(self): + # Won't call parent's setup(), because that's too chatty + (self.options, self.args) = self.parser.parse_args() + + def run(self): + """ Go, go, go! """ + mod_info = {} + mod_info['base_dir'] = self._get_base_dir(self.options.directory) + if mod_info['base_dir'] is None: + if self.options.python_readable: + print '{}' + else: + print "No module found." + exit(1) + os.chdir(mod_info['base_dir']) + mod_info['modname'] = get_modname() + if mod_info['modname'] is None: + if self.options.python_readable: + print '{}' + else: + print "No module found." + exit(1) + if self._info['version'] == '36' and os.path.isdir(os.path.join('include', mod_info['modname'])): + self._info['version'] = '37' + mod_info['version'] = self._info['version'] + if 'is_component' in self._info.keys(): + mod_info['is_component'] = True + mod_info['incdirs'] = [] + mod_incl_dir = os.path.join(mod_info['base_dir'], 'include') + if os.path.isdir(os.path.join(mod_incl_dir, mod_info['modname'])): + mod_info['incdirs'].append(os.path.join(mod_incl_dir, mod_info['modname'])) + else: + mod_info['incdirs'].append(mod_incl_dir) + build_dir = self._get_build_dir(mod_info) + if build_dir is not None: + mod_info['build_dir'] = build_dir + mod_info['incdirs'] += self._get_include_dirs(mod_info) + if self.options.python_readable: + print str(mod_info) + else: + self._pretty_print(mod_info) + + def _get_base_dir(self, start_dir): + """ Figure out the base dir (where the top-level cmake file is) """ + base_dir = os.path.abspath(start_dir) + if self._check_directory(base_dir): + return base_dir + else: + (up_dir, this_dir) = os.path.split(base_dir) + if os.path.split(up_dir)[1] == 'include': + up_dir = os.path.split(up_dir)[0] + if self._check_directory(up_dir): + return up_dir + return None + + def _get_build_dir(self, mod_info): + """ Figure out the build dir (i.e. where you run 'cmake'). This checks + for a file called CMakeCache.txt, which is created when running cmake. + If that hasn't happened, the build dir cannot be detected, unless it's + called 'build', which is then assumed to be the build dir. """ + base_build_dir = mod_info['base_dir'] + if 'is_component' in mod_info.keys(): + (base_build_dir, rest_dir) = os.path.split(base_build_dir) + has_build_dir = os.path.isdir(os.path.join(base_build_dir , 'build')) + if (has_build_dir and os.path.isfile(os.path.join(base_build_dir, 'CMakeCache.txt'))): + return os.path.join(base_build_dir, 'build') + else: + for (dirpath, dirnames, filenames) in os.walk(base_build_dir): + if 'CMakeCache.txt' in filenames: + return dirpath + if has_build_dir: + return os.path.join(base_build_dir, 'build') + return None + + def _get_include_dirs(self, mod_info): + """ Figure out include dirs for the make process. """ + inc_dirs = [] + path_or_internal = {True: 'INTERNAL', + False: 'PATH'}['is_component' in mod_info.keys()] + try: + cmakecache_fid = open(os.path.join(mod_info['build_dir'], 'CMakeCache.txt')) + for line in cmakecache_fid: + if line.find('GNURADIO_CORE_INCLUDE_DIRS:%s' % path_or_internal) != -1: + inc_dirs += line.replace('GNURADIO_CORE_INCLUDE_DIRS:%s=' % path_or_internal, '').strip().split(';') + if line.find('GRUEL_INCLUDE_DIRS:%s' % path_or_internal) != -1: + inc_dirs += line.replace('GRUEL_INCLUDE_DIRS:%s=' % path_or_internal, '').strip().split(';') + except IOError: + pass + if len(inc_dirs) == 0 and self.options.suggested_dirs is not None: + inc_dirs = [os.path.normpath(path) for path in self.options.suggested_dirs.split(':') if os.path.isdir(path)] + return inc_dirs + + def _pretty_print(self, mod_info): + """ Output the module info in human-readable format """ + index_names = {'base_dir': 'Base directory', + 'modname': 'Module name', + 'is_component': 'Is GR component', + 'build_dir': 'Build directory', + 'incdirs': 'Include directories'} + for key in mod_info.keys(): + if key == 'version': + print " API version: %s" % { + '36': 'pre-3.7', + '37': 'post-3.7', + 'autofoo': 'Autotools (pre-3.5)' + }[mod_info['version']] + else: + print '%19s: %s' % (index_names[key], mod_info[key]) + diff --git a/gr-utils/src/python/modtool/modtool_makexml.py b/gr-utils/src/python/modtool/modtool_makexml.py new file mode 100644 index 000000000..5a1a24f1b --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_makexml.py @@ -0,0 +1,151 @@ +""" Automatically create XML bindings for GRC from block code """ + +import sys +import os +import re +import glob +from optparse import OptionGroup + +from modtool_base import ModTool +from parser_cc_block import ParserCCBlock +from grc_xml_generator import GRCXMLGenerator +from cmakefile_editor import CMakeFileEditor + +### Remove module ########################################################### +class ModToolMakeXML(ModTool): + """ Make XML file for GRC block bindings """ + name = 'makexml' + aliases = ('mx',) + def __init__(self): + ModTool.__init__(self) + + def setup_parser(self): + " Initialise the option parser for 'gr_modtool.py makexml' " + parser = ModTool.setup_parser(self) + parser.usage = '%prog makexml [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "Make XML module options") + ogroup.add_option("-p", "--pattern", type="string", default=None, + help="Filter possible choices for blocks to be parsed.") + ogroup.add_option("-y", "--yes", action="store_true", default=False, + help="Answer all questions with 'yes'. This can overwrite existing files!") + parser.add_option_group(ogroup) + return parser + + def setup(self): + ModTool.setup(self) + options = self.options + if options.pattern is not None: + self._info['pattern'] = options.pattern + elif options.block_name is not None: + self._info['pattern'] = options.block_name + elif len(self.args) >= 2: + self._info['pattern'] = self.args[1] + else: + self._info['pattern'] = raw_input('Which blocks do you want to parse? (Regex): ') + if len(self._info['pattern']) == 0: + self._info['pattern'] = '.' + self._info['yes'] = options.yes + + def run(self): + """ Go, go, go! """ + print "Warning: This is an experimental feature. Don't expect any magic." + # 1) Go through lib/ + if not self._skip_subdirs['lib']: + if self._info['version'] == '37': + files = self._search_files('lib', '*_impl.cc') + else: + files = self._search_files('lib', '*.cc') + for f in files: + if os.path.basename(f)[0:2] == 'qa': + continue + (params, iosig, blockname) = self._parse_cc_h(f) + self._make_grc_xml_from_block_data(params, iosig, blockname) + # 2) Go through python/ + + + def _search_files(self, path, path_glob): + """ Search for files matching pattern in the given path. """ + files = glob.glob("%s/%s"% (path, path_glob)) + files_filt = [] + print "Searching for matching files in %s/:" % path + for f in files: + if re.search(self._info['pattern'], os.path.basename(f)) is not None: + files_filt.append(f) + if len(files_filt) == 0: + print "None found." + return files_filt + + def _make_grc_xml_from_block_data(self, params, iosig, blockname): + """ Take the return values from the parser and call the XML + generator. Also, check the makefile if the .xml file is in there. + If necessary, add. """ + fname_xml = '%s_%s.xml' % (self._info['modname'], blockname) + # Some adaptions for the GRC + for inout in ('in', 'out'): + if iosig[inout]['max_ports'] == '-1': + iosig[inout]['max_ports'] = '$num_%sputs' % inout + params.append({'key': 'num_%sputs' % inout, + 'type': 'int', + 'name': 'Num %sputs' % inout, + 'default': '2', + 'in_constructor': False}) + if os.path.isfile(os.path.join('grc', fname_xml)): + # TODO add an option to keep + print "Warning: Overwriting existing GRC file." + grc_generator = GRCXMLGenerator( + modname=self._info['modname'], + blockname=blockname, + params=params, + iosig=iosig + ) + grc_generator.save(os.path.join('grc', fname_xml)) + if not self._skip_subdirs['grc']: + ed = CMakeFileEditor(self._file['cmgrc']) + if re.search(fname_xml, ed.cfile) is None and not ed.check_for_glob('*.xml'): + print "Adding GRC bindings to grc/CMakeLists.txt..." + ed.append_value('install', fname_xml, 'DESTINATION[^()]+') + ed.write() + + def _parse_cc_h(self, fname_cc): + """ Go through a .cc and .h-file defining a block and return info """ + def _type_translate(p_type, default_v=None): + """ Translates a type from C++ to GRC """ + translate_dict = {'float': 'float', + 'double': 'real', + 'int': 'int', + 'gr_complex': 'complex', + 'char': 'byte', + 'unsigned char': 'byte', + 'std::string': 'string', + 'std::vector': 'int_vector', + 'std::vector': 'real_vector', + 'std::vector': 'complex_vector', + } + if p_type in ('int',) and default_v[:2].lower() == '0x': + return 'hex' + try: + return translate_dict[p_type] + except KeyError: + return 'raw' + def _get_blockdata(fname_cc): + """ Return the block name and the header file name from the .cc file name """ + blockname = os.path.splitext(os.path.basename(fname_cc.replace('_impl.', '.')))[0] + fname_h = (blockname + '.h').replace('_impl.', '.') + blockname = blockname.replace(self._info['modname']+'_', '', 1) + return (blockname, fname_h) + # Go, go, go + print "Making GRC bindings for %s..." % fname_cc + (blockname, fname_h) = _get_blockdata(fname_cc) + try: + parser = ParserCCBlock(fname_cc, + os.path.join(self._info['includedir'], fname_h), + blockname, + self._info['version'], + _type_translate + ) + except IOError: + print "Can't open some of the files necessary to parse %s." % fname_cc + sys.exit(1) + return (parser.read_params(), parser.read_io_signature(), blockname) + + diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py new file mode 100644 index 000000000..730b72e39 --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -0,0 +1,88 @@ +""" Create a whole new out-of-tree module """ + +import os +import re +import sys +import base64 +import tarfile +from optparse import OptionGroup + +from modtool_base import ModTool +from newmod_tarfile import NEWMOD_TARFILE + +### New out-of-tree-mod module ############################################### +class ModToolNewModule(ModTool): + """ Create a new out-of-tree module """ + name = 'newmod' + aliases = ('nm', 'create') + def __init__(self): + ModTool.__init__(self) + + def setup_parser(self): + " Initialise the option parser for 'gr_modtool.py newmod' " + parser = ModTool.setup_parser(self) + parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "New out-of-tree module options") + parser.add_option_group(ogroup) + return parser + + def setup(self): + (options, self.args) = self.parser.parse_args() + self._info['modname'] = options.module_name + if self._info['modname'] is None: + if len(self.args) >= 2: + self._info['modname'] = self.args[1] + else: + self._info['modname'] = raw_input('Name of the new module: ') + if not re.match('[a-zA-Z0-9_]+', self._info['modname']): + print 'Invalid module name.' + sys.exit(2) + self._dir = options.directory + if self._dir == '.': + self._dir = './gr-%s' % self._info['modname'] + print 'Module directory is "%s".' % self._dir + try: + os.stat(self._dir) + except OSError: + pass # This is what should happen + else: + print 'The given directory exists.' + sys.exit(2) + + def run(self): + """ + * Unpack the tar.bz2 to the new locations + * Remove the bz2 + * Open all files, rename howto and HOWTO to the module name + * Rename files and directories that contain the word howto + """ + print "Creating directory..." + try: + os.mkdir(self._dir) + os.chdir(self._dir) + except OSError: + print 'Could not create directory %s. Quitting.' % self._dir + sys.exit(2) + print "Copying howto example..." + open('tmp.tar.bz2', 'wb').write(base64.b64decode(NEWMOD_TARFILE)) + print "Unpacking..." + tar = tarfile.open('tmp.tar.bz2', mode='r:bz2') + tar.extractall() + tar.close() + os.unlink('tmp.tar.bz2') + print "Replacing occurences of 'howto' to '%s'..." % self._info['modname'], + for root, dirs, files in os.walk('.'): + for filename in files: + f = os.path.join(root, filename) + s = open(f, 'r').read() + s = s.replace('howto', self._info['modname']) + s = s.replace('HOWTO', self._info['modname'].upper()) + open(f, 'w').write(s) + if filename.find('howto') != -1: + os.rename(f, os.path.join(root, filename.replace('howto', self._info['modname']))) + if os.path.basename(root) == 'howto': + os.rename(root, os.path.join(os.path.dirname(root), self._info['modname'])) + print "Done." + print "Use 'gr_modtool add' to add a new block to this currently empty module." + + diff --git a/gr-utils/src/python/modtool/modtool_rm.py b/gr-utils/src/python/modtool/modtool_rm.py new file mode 100644 index 000000000..16bfeb34c --- /dev/null +++ b/gr-utils/src/python/modtool/modtool_rm.py @@ -0,0 +1,155 @@ +""" Remove blocks module """ + +import os +import re +import sys +import glob +from optparse import OptionGroup + +from util_functions import remove_pattern_from_file +from modtool_base import ModTool +from cmakefile_editor import CMakeFileEditor + +### Remove module ########################################################### +class ModToolRemove(ModTool): + """ Remove block (delete files and remove Makefile entries) """ + name = 'remove' + aliases = ('rm', 'del') + def __init__(self): + ModTool.__init__(self) + + def setup_parser(self): + " Initialise the option parser for 'gr_modtool.py rm' " + parser = ModTool.setup_parser(self) + parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' + ogroup = OptionGroup(parser, "Remove module options") + ogroup.add_option("-p", "--pattern", type="string", default=None, + help="Filter possible choices for blocks to be deleted.") + ogroup.add_option("-y", "--yes", action="store_true", default=False, + help="Answer all questions with 'yes'.") + parser.add_option_group(ogroup) + return parser + + def setup(self): + ModTool.setup(self) + options = self.options + if options.pattern is not None: + self._info['pattern'] = options.pattern + elif options.block_name is not None: + self._info['pattern'] = options.block_name + elif len(self.args) >= 2: + self._info['pattern'] = self.args[1] + else: + self._info['pattern'] = raw_input('Which blocks do you want to delete? (Regex): ') + if len(self._info['pattern']) == 0: + self._info['pattern'] = '.' + self._info['yes'] = options.yes + + def run(self): + """ Go, go, go! """ + def _remove_cc_test_case(filename=None, ed=None): + """ Special function that removes the occurrences of a qa*.cc file + from the CMakeLists.txt. """ + if filename[:2] != 'qa': + return + if self._info['version'] == '37': + (base, ext) = os.path.splitext(filename) + if ext == '.h': + remove_pattern_from_file(self._file['qalib'], + '^#include "%s"\s*$' % filename) + remove_pattern_from_file(self._file['qalib'], + '^\s*s->addTest\(gr::%s::%s::suite\(\)\);\s*$' % ( + self._info['modname'], base) + ) + elif ext == '.cc': + ed.remove_value('list', + '\$\{CMAKE_CURRENT_SOURCE_DIR\}/%s' % filename, + 'APPEND test_%s_sources' % self._info['modname']) + else: + filebase = os.path.splitext(filename)[0] + ed.delete_entry('add_executable', filebase) + ed.delete_entry('target_link_libraries', filebase) + ed.delete_entry('GR_ADD_TEST', filebase) + ed.remove_double_newlines() + + def _remove_py_test_case(filename=None, ed=None): + """ Special function that removes the occurrences of a qa*.{cc,h} file + from the CMakeLists.txt and the qa_$modname.cc. """ + if filename[:2] != 'qa': + return + filebase = os.path.splitext(filename)[0] + ed.delete_entry('GR_ADD_TEST', filebase) + ed.remove_double_newlines() + + def _make_swig_regex(filename): + filebase = os.path.splitext(filename)[0] + pyblockname = filebase.replace(self._info['modname'] + '_', '') + regexp = r'(^\s*GR_SWIG_BLOCK_MAGIC2?\(%s,\s*%s\);|^\s*.include\s*"(%s/)?%s"\s*)' % \ + (self._info['modname'], pyblockname, self._info['modname'], filename) + return regexp + # Go, go, go! + if not self._skip_subdirs['lib']: + self._run_subdir('lib', ('*.cc', '*.h'), ('add_library',), + cmakeedit_func=_remove_cc_test_case) + if not self._skip_subdirs['include']: + incl_files_deleted = self._run_subdir(self._info['includedir'], ('*.h',), ('install',)) + if not self._skip_subdirs['swig']: + swig_files_deleted = self._run_subdir('swig', ('*.i',), ('install',)) + for f in incl_files_deleted + swig_files_deleted: + # TODO do this on all *.i files + remove_pattern_from_file(self._file['swig'], _make_swig_regex(f)) + if not self._skip_subdirs['python']: + py_files_deleted = self._run_subdir('python', ('*.py',), ('GR_PYTHON_INSTALL',), + cmakeedit_func=_remove_py_test_case) + for f in py_files_deleted: + remove_pattern_from_file(self._file['pyinit'], '.*import\s+%s.*' % f[:-3]) + remove_pattern_from_file(self._file['pyinit'], '.*from\s+%s\s+import.*\n' % f[:-3]) + if not self._skip_subdirs['grc']: + self._run_subdir('grc', ('*.xml',), ('install',)) + + + def _run_subdir(self, path, globs, makefile_vars, cmakeedit_func=None): + """ Delete all files that match a certain pattern in path. + path - The directory in which this will take place + globs - A tuple of standard UNIX globs of files to delete (e.g. *.xml) + makefile_vars - A tuple with a list of CMakeLists.txt-variables which + may contain references to the globbed files + cmakeedit_func - If the CMakeLists.txt needs special editing, use this + """ + # 1. Create a filtered list + files = [] + for g in globs: + files = files + glob.glob("%s/%s"% (path, g)) + files_filt = [] + print "Searching for matching files in %s/:" % path + for f in files: + if re.search(self._info['pattern'], os.path.basename(f)) is not None: + files_filt.append(f) + if len(files_filt) == 0: + print "None found." + return [] + # 2. Delete files, Makefile entries and other occurences + files_deleted = [] + ed = CMakeFileEditor('%s/CMakeLists.txt' % path) + yes = self._info['yes'] + for f in files_filt: + b = os.path.basename(f) + if not yes: + ans = raw_input("Really delete %s? [Y/n/a/q]: " % f).lower().strip() + if ans == 'a': + yes = True + if ans == 'q': + sys.exit(0) + if ans == 'n': + continue + files_deleted.append(b) + print "Deleting %s." % f + os.unlink(f) + print "Deleting occurrences of %s from %s/CMakeLists.txt..." % (b, path) + for var in makefile_vars: + ed.remove_value(var, b) + if cmakeedit_func is not None: + cmakeedit_func(b, ed) + ed.write() + return files_deleted + diff --git a/gr-utils/src/python/modtool/newmod_tarfile.py b/gr-utils/src/python/modtool/newmod_tarfile.py new file mode 100644 index 000000000..06d7e8f90 --- /dev/null +++ b/gr-utils/src/python/modtool/newmod_tarfile.py @@ -0,0 +1,1034 @@ +### The entire new module zipfile as base64 encoded tar.bz2 ### +NEWMOD_TARFILE = """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""" diff --git a/gr-utils/src/python/modtool/parser_cc_block.py b/gr-utils/src/python/modtool/parser_cc_block.py new file mode 100644 index 000000000..447fe113d --- /dev/null +++ b/gr-utils/src/python/modtool/parser_cc_block.py @@ -0,0 +1,205 @@ +''' A parser for blocks written in C++ ''' +import re +import sys + +### Parser for CC blocks #################################################### +def dummy_translator(the_type, default_v=None): + """ Doesn't really translate. """ + return the_type + +class ParserCCBlock(object): + """ Class to read blocks written in C++ """ + def __init__(self, filename_cc, filename_h, blockname, version, type_trans=dummy_translator): + self.code_cc = open(filename_cc).read() + self.code_h = open(filename_h).read() + self.blockname = blockname + self.type_trans = type_trans + self.version = version + + def read_io_signature(self): + """ Scans a .cc file for an IO signature. """ + def _figure_out_iotype_and_vlen(iosigcall, typestr): + """ From a type identifier, returns the data type. + E.g., for sizeof(int), it will return 'int'. + Returns a list! """ + if 'gr_make_iosignaturev' in iosigcall: + print 'tbi' + raise ValueError + return {'type': [_typestr_to_iotype(x) for x in typestr.split(',')], + 'vlen': [_typestr_to_vlen(x) for x in typestr.split(',')] + } + def _typestr_to_iotype(typestr): + """ Convert a type string (e.g. sizeof(int) * vlen) to the type (e.g. 'int'). """ + type_match = re.search('sizeof\s*\(([^)]*)\)', typestr) + if type_match is None: + return self.type_trans('char') + return self.type_trans(type_match.group(1)) + def _typestr_to_vlen(typestr): + """ From a type identifier, returns the vector length of the block's + input/out. E.g., for 'sizeof(int) * 10', it returns 10. For + 'sizeof(int)', it returns '1'. For 'sizeof(int) * vlen', it returns + the string vlen. """ + # Catch fringe case where no sizeof() is given + if typestr.find('sizeof') == -1: + return typestr + if typestr.find('*') == -1: + return '1' + vlen_parts = typestr.split('*') + for fac in vlen_parts: + if fac.find('sizeof') != -1: + vlen_parts.remove(fac) + if len(vlen_parts) == 1: + return vlen_parts[0].strip() + elif len(vlen_parts) > 1: + return '*'.join(vlen_parts).strip() + iosig = {} + iosig_regex = '(?Pgr_make_io_signature[23v]?)\s*\(\s*(?P[^,]+),\s*(?P[^,]+),' + \ + '\s*(?P(\([^\)]*\)|[^)])+)\),\s*' + \ + '(?Pgr_make_io_signature[23v]?)\s*\(\s*(?P[^,]+),\s*(?P[^,]+),' + \ + '\s*(?P(\([^\)]*\)|[^)])+)\)' + iosig_match = re.compile(iosig_regex, re.MULTILINE).search(self.code_cc) + try: + iosig['in'] = _figure_out_iotype_and_vlen(iosig_match.group('incall'), + iosig_match.group('intype')) + iosig['in']['min_ports'] = iosig_match.group('inmin') + iosig['in']['max_ports'] = iosig_match.group('inmax') + except ValueError, Exception: + print "Error: Can't parse input signature." + try: + iosig['out'] = _figure_out_iotype_and_vlen(iosig_match.group('outcall'), + iosig_match.group('outtype')) + iosig['out']['min_ports'] = iosig_match.group('outmin') + iosig['out']['max_ports'] = iosig_match.group('outmax') + except ValueError, Exception: + print "Error: Can't parse output signature." + return iosig + + + def read_params(self): + """ Read the parameters required to initialize the block """ + def _scan_param_list(start_idx): + """ Go through a parameter list and return a tuple each: + (type, name, default_value). Python's re just doesn't cut + it for C++ code :( """ + i = start_idx + c = self.code_h + if c[i] != '(': + raise ValueError + i += 1 + + param_list = [] + read_state = 'type' + in_string = False + parens_count = 0 # Counts () + brackets_count = 0 # Counts <> + end_of_list = False + this_type = '' + this_name = '' + this_defv = '' + WHITESPACE = ' \t\n\r\f\v' + while not end_of_list: + # Keep track of (), stop when reaching final closing parens + if not in_string: + if c[i] == ')': + if parens_count == 0: + if read_state == 'type': + raise ValueError( + 'Found closing parentheses before finishing last argument (this is how far I got: %s)' + % str(param_list) + ) + param_list.append((this_type, this_name, this_defv)) + end_of_list = True + break + else: + parens_count -= 1 + elif c[i] == '(': + parens_count += 1 + # Parameter type (int, const std::string, std::vector, unsigned long ...) + if read_state == 'type': + if c[i] == '<': + brackets_count += 1 + if c[i] == '>': + brackets_count -= 1 + if c[i] == '&': + i += 1 + continue + if c[i] in WHITESPACE and brackets_count == 0: + while c[i] in WHITESPACE: + i += 1 + continue + if this_type == 'const' or this_type == '': # Ignore this + this_type = '' + elif this_type == 'unsigned': # Continue + this_type += ' ' + continue + else: + read_state = 'name' + continue + this_type += c[i] + i += 1 + continue + # Parameter name + if read_state == 'name': + if c[i] == '&' or c[i] in WHITESPACE: + i += 1 + elif c[i] == '=': + if parens_count != 0: + raise ValueError( + 'While parsing argument %d (%s): name finished but no closing parentheses.' + % (len(param_list)+1, this_type + ' ' + this_name) + ) + read_state = 'defv' + i += 1 + elif c[i] == ',': + if parens_count: + raise ValueError( + 'While parsing argument %d (%s): name finished but no closing parentheses.' + % (len(param_list)+1, this_type + ' ' + this_name) + ) + read_state = 'defv' + else: + this_name += c[i] + i += 1 + continue + # Default value + if read_state == 'defv': + if in_string: + if c[i] == '"' and c[i-1] != '\\': + in_string = False + else: + this_defv += c[i] + elif c[i] == ',': + if parens_count: + raise ValueError( + 'While parsing argument %d (%s): default value finished but no closing parentheses.' + % (len(param_list)+1, this_type + ' ' + this_name) + ) + read_state = 'type' + param_list.append((this_type, this_name, this_defv)) + this_type = '' + this_name = '' + this_defv = '' + else: + this_defv += c[i] + i += 1 + continue + return param_list + # Go, go, go! + if self.version == '37': + make_regex = 'static\s+sptr\s+make\s*' + else: + make_regex = '(?<=_API)\s+\w+_sptr\s+\w+_make_\w+\s*' + make_match = re.compile(make_regex, re.MULTILINE).search(self.code_h) + try: + params_list = _scan_param_list(make_match.end(0)) + except ValueError as ve: + print "Can't parse the argument list: ", ve.args[0] + sys.exit(0) + params = [] + for plist in params_list: + params.append({'type': self.type_trans(plist[0], plist[2]), + 'key': plist[1], + 'default': plist[2], + 'in_constructor': True}) + return params + diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py new file mode 100644 index 000000000..e3019bb70 --- /dev/null +++ b/gr-utils/src/python/modtool/templates.py @@ -0,0 +1,698 @@ +''' All the templates for skeleton files (needed by ModToolAdd) ''' + +from datetime import datetime + +### Templates ################################################################ +Templates = {} +Templates36 = {} + +# Default licence +Templates['defaultlicense'] = ''' +Copyright %d <+YOU OR YOUR COMPANY+>. + +This 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. + +This software 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 this software; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, +Boston, MA 02110-1301, USA. +''' % datetime.now().year + +# Header file of a sync/decimator/interpolator block +Templates['block_impl_h'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} +\#ifndef INCLUDED_${modname.upper()}_${blockname.upper()}_IMPL_H +\#define INCLUDED_${modname.upper()}_${blockname.upper()}_IMPL_H + +\#include <${modname}/${blockname}.h> + +namespace gr { + namespace ${modname} { + + class ${blockname}_impl : public ${blockname} + { + private: + // Nothing to declare in this block. + + public: + ${blockname}_impl(${strip_default_values($arglist)}); + ~${blockname}_impl(); + +#if $blocktype == 'general' + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + // Where all the action really happens + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +#else if $blocktype == 'hier' +#silent pass +#else + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +#end if + }; + + } // namespace ${modname} +} // namespace gr + +\#endif /* INCLUDED_${modname.upper()}_${blockname.upper()}_IMPL_H */ + +''' + +# C++ file of a GR block +Templates['block_impl_cpp'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} +\#ifdef HAVE_CONFIG_H +\#include "config.h" +\#endif + +\#include +#if $blocktype == 'noblock' +\#include <${modname}/${blockname}.h> +#else +\#include "${blockname}_impl.h" +#end if + +namespace gr { + namespace ${modname} { + +#if $blocktype == 'noblock' + $blockname::${blockname}(${strip_default_values($arglist)}) + { + } + + $blockname::~${blockname}() + { + } +#else + ${blockname}::sptr + ${blockname}::make(${strip_default_values($arglist)}) + { + return gnuradio::get_initial_sptr (new ${blockname}_impl(${strip_arg_types($arglist)})); + } + +#if $blocktype == 'decimator' +#set $decimation = ', <+decimation+>' +#else if $blocktype == 'interpolator' +#set $decimation = ', <+interpolation+>' +#else +#set $decimation = '' +#end if +#if $blocktype == 'source' +#set $inputsig = '0, 0, 0' +#else +#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof (<+float+>)' +#end if +#if $blocktype == 'sink' +#set $outputsig = '0, 0, 0' +#else +#set $outputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof (<+float+>)' +#end if + /* + * The private constructor + */ + ${blockname}_impl::${blockname}_impl(${strip_default_values($arglist)}) + : ${grblocktype}("${blockname}", + gr_make_io_signature($inputsig), + gr_make_io_signature($outputsig)$decimation) +#if $blocktype == 'hier' + { + connect(self(), 0, d_firstblock, 0); + // connect other blocks + connect(d_lastblock, 0, self(), 0); + } +#else + {} +#end if + + /* + * Our virtual destructor. + */ + ${blockname}_impl::~${blockname}_impl() + { + } + +#if $blocktype == 'general' + void + ${blockname}_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ + } + + int + ${blockname}_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + + // Do <+signal processing+> + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; + } +#else if $blocktype == 'hier' +#silent pass +#else + int + ${blockname}_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + + // Do <+signal processing+> + + // Tell runtime system how many output items we produced. + return noutput_items; + } +#end if +#end if + + } /* namespace ${modname} */ +} /* namespace gr */ + +''' + +# Block definition header file (for include/) +Templates['block_def_h'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} + +\#ifndef INCLUDED_${modname.upper()}_${blockname.upper()}_H +\#define INCLUDED_${modname.upper()}_${blockname.upper()}_H + +\#include <${modname}/api.h> +\#include <${grblocktype}.h> + +namespace gr { + namespace ${modname} { + +#if $blocktype == 'noblock' + /*! + * \\brief <+description+> + * + */ + class ${modname.upper()}_API $blockname + { + ${blockname}(${arglist}); + ~${blockname}(); + private: + }; +#else + /*! + * \\brief <+description of block+> + * \ingroup ${modname} + * + */ + class ${modname.upper()}_API ${blockname} : virtual public $grblocktype + { + public: + typedef boost::shared_ptr<${blockname}> sptr; + + /*! + * \\brief Return a shared_ptr to a new instance of ${modname}::${blockname}. + * + * To avoid accidental use of raw pointers, ${modname}::${blockname}'s + * constructor is in a private implementation + * class. ${modname}::${blockname}::make is the public interface for + * creating new instances. + */ + static sptr make($arglist); + }; +#end if + + } // namespace ${modname} +} // namespace gr + +\#endif /* INCLUDED_${modname.upper()}_${blockname.upper()}_H */ + +''' + +# Python block (from grextras!) +Templates['block_python'] = '''\#!/usr/bin/env python +${str_to_python_comment($license)} +# +#if $blocktype == 'noblock' +#stop +#end if + +#if $blocktype in ('sync', 'sink', 'source') +#set $parenttype = 'gr.sync_block' +#else +#set $parenttype = {'hier': 'gr.hier_block2', 'interpolator': 'gr.interp_block', 'decimator': 'gr.decim_block', 'general': 'gr.block'}[$blocktype] +#end if +#if $blocktype != 'hier' +import numpy +#if $blocktype == 'source' +#set $inputsig = 'None' +#else +#set $inputsig = '[<+numpy.float+>]' +#end if +#if $blocktype == 'sink' +#set $outputsig = 'None' +#else +#set $outputsig = '[<+numpy.float+>]' +#end if +#else +#if $blocktype == 'source' +#set $inputsig = '0, 0, 0' +#else +#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, gr.sizeof_<+float+>' +#end if +#if $blocktype == 'sink' +#set $outputsig = '0, 0, 0' +#else +#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, gr.sizeof_<+float+>' +#end if +#end if +#if $blocktype == 'interpolator' +#set $deciminterp = ', <+interpolation+>' +#else if $blocktype == 'decimator' +#set $deciminterp = ', <+decimation+>' +#set $deciminterp = '' +#else +#end if +from gnuradio import gr + +class ${blockname}(${parenttype}): + """ + docstring for block ${blockname} + """ + def __init__(self#if $arglist == '' then '' else ', '#$arglist): + gr.${parenttype}.__init__(self, +#if $blocktype == 'hier' + "$blockname", + gr.io_signature(${inputsig}), # Input signature + gr.io_signature(${outputsig})) # Output signature + + # Define blocks and connect them + self.connect() +#stop +#else + name="${blockname}", + in_sig=${inputsig}, + out_sig=${outputsig}${deciminterp}) +#end if + +#if $blocktype == 'general' + def forecast(self, noutput_items, ninput_items_required): + #setup size of input_items[i] for work call + for i in range(len(ninput_items_required)): + ninput_items_required[i] = noutput_items + + def general_work(self, input_items, output_items): + output_items[0][:] = input_items[0] + consume(0, len(input_items[0]) + \#self.consume_each(len(input_items[0])) + return len(output_items[0]) +#stop +#else + def work(self, input_items, output_items): +#end if + + def work(self, input_items, output_items): +#if $blocktype != 'source' + in0 = input_items[0] +#end if +#if $blocktype != 'sink' + out = output_items[0] +#end if + # <+signal processing here+> +#if $blocktype in ('sync', 'decimator', 'interpolator') + out[:] = in0 + return len(output_items[0]) +#else if $blocktype == 'sink' + return len(input_items[0]) +#else if $blocktype == 'source' + out[:] = whatever + return len(output_items[0]) +#end if + +''' + +# C++ file for QA +Templates['qa_cpp'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} + +\#include "qa_${blockname}.h" +\#include + +\#include <$modname/${blockname}.h> + +namespace gr { + namespace ${modname} { + + void + qa_${blockname}::t1() + { + // Put test here + } + + } /* namespace ${modname} */ +} /* namespace gr */ + +''' + +# Header file for QA +Templates['qa_h'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} + +\#ifndef _QA_${blockname.upper()}_H_ +\#define _QA_${blockname.upper()}_H_ + +\#include +\#include + +namespace gr { + namespace ${modname} { + + class qa_${blockname} : public CppUnit::TestCase + { + public: + CPPUNIT_TEST_SUITE(qa_${blockname}); + CPPUNIT_TEST(t1); + CPPUNIT_TEST_SUITE_END(); + + private: + void t1(); + }; + + } /* namespace ${modname} */ +} /* namespace gr */ + +\#endif /* _QA_${blockname.upper()}_H_ */ + +''' + +# Python QA code +Templates['qa_python'] = '''\#!/usr/bin/env python +${str_to_python_comment($license)} +# + +from gnuradio import gr, gr_unittest +#if $lang == 'cpp' +import ${modname}_swig as ${modname} +#else +from ${blockname} import ${blockname} +#end if + +class qa_$blockname (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + # set up fg + self.tb.run () + # check data + + +if __name__ == '__main__': + gr_unittest.run(qa_${blockname}, "qa_${blockname}.xml") +''' + +Templates['grc_xml'] = ''' + + $blockname + ${modname}_$blockname + $modname + import $modname + ${modname}.${blockname}(${strip_arg_types($arglist)}) + + + ... + ... + ... + + + + + in + + + + + + out + + + +''' + +# Usage +Templates['usage'] = ''' +gr_modtool.py [options] -- Run with the given options. +gr_modtool.py help -- Show a list of commands. +gr_modtool.py help -- Shows the help for a given command. ''' + +# SWIG string +Templates['swig_block_magic'] = """#if $version == '37' +#set $mod_block_sep = '/' +#set $block_magic_version = '2' +#else +#set $mod_block_sep = '_' +#set $block_magic_version = '' +#end if +%include "${modname}${mod_block_sep}${blockname}.h" +GR_SWIG_BLOCK_MAGIC${block_magic_version}($modname, $blockname); +""" + +## Old stuff +# C++ file of a GR block +Templates['block_cpp36'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} +\#ifdef HAVE_CONFIG_H +\#include "config.h" +\#endif + +#if $blocktype != 'noblock' +\#include +#end if +\#include "${modname}_${blockname}.h" + +#if $blocktype == 'noblock' +${modname}_${blockname}::${modname}_${blockname}(${strip_default_values($arglist)}) +{ +} + +${modname}_${blockname}::~${modname}_${blockname}() +{ +} +#else +${modname}_${blockname}_sptr +${modname}_make_${blockname} (${strip_default_values($arglist)}) +{ + return gnuradio::get_initial_sptr (new ${modname}_${blockname}(${strip_arg_types($arglist)})); +} + +#if $blocktype == 'decimator' +#set $decimation = ', <+decimation+>' +#else if $blocktype == 'interpolator' +#set $decimation = ', <+interpolation+>' +#else +#set $decimation = '' +#end if +#if $blocktype == 'sink' +#set $inputsig = '0, 0, 0' +#else +#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof (<+float+>)' +#end if +#if $blocktype == 'source' +#set $outputsig = '0, 0, 0' +#else +#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, sizeof (<+float+>)' +#end if + +/* + * The private constructor + */ +${modname}_${blockname}::${modname}_${blockname} (${strip_default_values($arglist)}) + : ${grblocktype} ("${blockname}", + gr_make_io_signature($inputsig), + gr_make_io_signature($outputsig)$decimation) +{ +#if $blocktype == 'hier' + connect(self(), 0, d_firstblock, 0); + // <+connect other blocks+> + connect(d_lastblock, 0, self(), 0); +#else + // Put in <+constructor stuff+> here +#end if +} + + +/* + * Our virtual destructor. + */ +${modname}_${blockname}::~${modname}_${blockname}() +{ + // Put in <+destructor stuff+> here +} +#end if + + +#if $blocktype == 'general' +void +${modname}_${blockname}::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */ +} + +int +${modname}_${blockname}::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + + // Do <+signal processing+> + // Tell runtime system how many input items we consumed on + // each input stream. + consume_each (noutput_items); + + // Tell runtime system how many output items we produced. + return noutput_items; +} +#else if $blocktype == 'hier' or $blocktype == 'noblock' +#pass +#else +int +${modname}_${blockname}::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + + // Do <+signal processing+> + + // Tell runtime system how many output items we produced. + return noutput_items; +} +#end if + +''' + +# Block definition header file (for include/) +Templates['block_h36'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} + +\#ifndef INCLUDED_${modname.upper()}_${blockname.upper()}_H +\#define INCLUDED_${modname.upper()}_${blockname.upper()}_H + +\#include <${modname}_api.h> +#if $blocktype == 'noblock' +class ${modname.upper()}_API $blockname +{ + ${blockname}(${arglist}); + ~${blockname}(); + private: +}; + +#else +\#include <${grblocktype}.h> + +class ${modname}_${blockname}; + +typedef boost::shared_ptr<${modname}_${blockname}> ${modname}_${blockname}_sptr; + +${modname.upper()}_API ${modname}_${blockname}_sptr ${modname}_make_${blockname} ($arglist); + +/*! + * \\brief <+description+> + * \ingroup ${modname} + * + */ +class ${modname.upper()}_API ${modname}_${blockname} : public $grblocktype +{ + private: + friend ${modname.upper()}_API ${modname}_${blockname}_sptr ${modname}_make_${blockname} (${strip_default_values($arglist)}); + + ${modname}_${blockname}(${strip_default_values($arglist)}); + + public: + ~${modname}_${blockname}(); + +#if $blocktype == 'general' + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + // Where all the action really happens + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +#else if $blocktype == 'hier' +#pass +#else + // Where all the action really happens + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +#end if +}; +#end if + +\#endif /* INCLUDED_${modname.upper()}_${blockname.upper()}_H */ + +''' + +# C++ file for QA +Templates['qa_cpp36'] = '''/* -*- c++ -*- */ +${str_to_fancyc_comment($license)} + +\#include + +BOOST_AUTO_TEST_CASE(qa_${modname}_${blockname}_t1){ + BOOST_CHECK_EQUAL(2 + 2, 4); + // TODO BOOST_* test macros here +} + +BOOST_AUTO_TEST_CASE(qa_${modname}_${blockname}_t2){ + BOOST_CHECK_EQUAL(2 + 2, 4); + // TODO BOOST_* test macros here +} + +''' + +# Header file for QA +Templates['qa_cmakeentry36'] = """ +add_executable($basename $filename) +target_link_libraries($basename gnuradio-$modname \${Boost_LIBRARIES}) +GR_ADD_TEST($basename $basename) +""" + diff --git a/gr-utils/src/python/modtool/util_functions.py b/gr-utils/src/python/modtool/util_functions.py new file mode 100644 index 000000000..029ae04bf --- /dev/null +++ b/gr-utils/src/python/modtool/util_functions.py @@ -0,0 +1,127 @@ +""" Utility functions for gr_modtool.py """ + +import re +import sys + +### Utility functions ######################################################## +def get_command_from_argv(possible_cmds): + """ Read the requested command from argv. This can't be done with optparse, + since the option parser isn't defined before the command is known, and + optparse throws an error.""" + command = None + for arg in sys.argv: + if arg[0] == "-": + continue + else: + command = arg + if command in possible_cmds: + return arg + return None + +def append_re_line_sequence(filename, linepattern, newline): + """Detects the re 'linepattern' in the file. After its last occurrence, + paste 'newline'. If the pattern does not exist, append the new line + to the file. Then, write. """ + oldfile = open(filename, 'r').read() + lines = re.findall(linepattern, oldfile, flags=re.MULTILINE) + if len(lines) == 0: + open(filename, 'a').write(newline) + return + last_line = lines[-1] + newfile = oldfile.replace(last_line, last_line + newline + '\n') + open(filename, 'w').write(newfile) + +def remove_pattern_from_file(filename, pattern): + """ Remove all occurrences of a given pattern from a file. """ + oldfile = open(filename, 'r').read() + pattern = re.compile(pattern, re.MULTILINE) + open(filename, 'w').write(pattern.sub('', oldfile)) + +def str_to_fancyc_comment(text): + """ Return a string as a C formatted comment. """ + l_lines = text.splitlines() + outstr = "/* " + l_lines[0] + "\n" + for line in l_lines[1:]: + outstr += " * " + line + "\n" + outstr += " */\n" + return outstr + +def str_to_python_comment(text): + """ Return a string as a Python formatted comment. """ + return re.compile('^', re.MULTILINE).sub('# ', text) + +def strip_default_values(string): + """ Strip default values from a C++ argument list. """ + return re.sub(' *=[^,)]*', '', string) + +def strip_arg_types(string): + """" Strip the argument types from a list of arguments + Example: "int arg1, double arg2" -> "arg1, arg2" """ + string = strip_default_values(string) + return ", ".join([part.strip().split(' ')[-1] for part in string.split(',')]) + +def get_modname(): + """ Grep the current module's name from gnuradio.project or CMakeLists.txt """ + modname_trans = {'howto-write-a-block': 'howto'} + try: + prfile = open('gnuradio.project', 'r').read() + regexp = r'projectname\s*=\s*([a-zA-Z0-9-_]+)$' + return re.search(regexp, prfile, flags=re.MULTILINE).group(1).strip() + except IOError: + pass + # OK, there's no gnuradio.project. So, we need to guess. + cmfile = open('CMakeLists.txt', 'r').read() + regexp = r'(project\s*\(\s*|GR_REGISTER_COMPONENT\(")gr-(?P[a-zA-Z1-9-_]+)(\s*(CXX)?|" ENABLE)' + try: + modname = re.search(regexp, cmfile, flags=re.MULTILINE).group('modname').strip() + if modname in modname_trans.keys(): + modname = modname_trans[modname] + return modname + except AttributeError: + return None + +def get_class_dict(): + " Return a dictionary of the available commands in the form command->class " + classdict = {} + for g in globals().values(): + try: + if issubclass(g, ModTool): + classdict[g.name] = g + for a in g.aliases: + classdict[a] = g + except (TypeError, AttributeError): + pass + return classdict + +def is_number(s): + " Return True if the string s contains a number. " + try: + float(s) + return True + except ValueError: + return False + +def xml_indent(elem, level=0): + """ Adds indents to XML for pretty printing """ + i = "\n" + level*" " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + xml_indent(elem, level+1) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + +def ask_yes_no(question, default): + """ Asks a binary question. Returns True for yes, False for no. + default is given as a boolean. """ + question += {True: ' [Y/n] ', False: ' [y/N] '}[default] + if raw_input(question).lower() != {True: 'n', False: 'y'}[default]: + return default + else: + return not default -- cgit From f24128ea9036f68e61ff9350ce86ec619f9ae286 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Fri, 25 Jan 2013 15:43:02 +0100 Subject: utils: modtool now installs an example dir instead of the bz2 --- gr-utils/src/python/modtool/CMakeLists.txt | 24 +- gr-utils/src/python/modtool/README.modtool | 11 + .../src/python/modtool/gr-newmod/CMakeLists.txt | 145 + .../python/modtool/gr-newmod/apps/CMakeLists.txt | 25 + .../cmake/Modules/CMakeParseArgumentsCopy.cmake | 138 + .../gr-newmod/cmake/Modules/FindCppUnit.cmake | 36 + .../gr-newmod/cmake/Modules/FindGnuradioCore.cmake | 26 + .../gr-newmod/cmake/Modules/FindGruel.cmake | 26 + .../gr-newmod/cmake/Modules/GrMiscUtils.cmake | 210 + .../gr-newmod/cmake/Modules/GrPlatform.cmake | 46 + .../modtool/gr-newmod/cmake/Modules/GrPython.cmake | 227 + .../modtool/gr-newmod/cmake/Modules/GrSwig.cmake | 229 + .../modtool/gr-newmod/cmake/Modules/GrTest.cmake | 133 + .../gr-newmod/cmake/cmake_uninstall.cmake.in | 32 + .../python/modtool/gr-newmod/docs/CMakeLists.txt | 35 + .../src/python/modtool/gr-newmod/docs/README.howto | 11 + .../modtool/gr-newmod/docs/doxygen/CMakeLists.txt | 52 + .../modtool/gr-newmod/docs/doxygen/Doxyfile.in | 1504 ++++ .../gr-newmod/docs/doxygen/Doxyfile.swig_doc.in | 1514 ++++ .../gr-newmod/docs/doxygen/doxyxml/__init__.py | 82 + .../modtool/gr-newmod/docs/doxygen/doxyxml/base.py | 219 + .../gr-newmod/docs/doxygen/doxyxml/doxyindex.py | 237 + .../docs/doxygen/doxyxml/generated/__init__.py | 7 + .../docs/doxygen/doxyxml/generated/compound.py | 503 ++ .../doxygen/doxyxml/generated/compoundsuper.py | 8342 ++++++++++++++++++++ .../docs/doxygen/doxyxml/generated/index.py | 77 + .../docs/doxygen/doxyxml/generated/indexsuper.py | 523 ++ .../modtool/gr-newmod/docs/doxygen/doxyxml/text.py | 56 + .../gr-newmod/docs/doxygen/other/group_defs.dox | 7 + .../gr-newmod/docs/doxygen/other/main_page.dox | 10 + .../modtool/gr-newmod/docs/doxygen/swig_doc.py | 255 + .../python/modtool/gr-newmod/grc/CMakeLists.txt | 22 + .../modtool/gr-newmod/include/howto/CMakeLists.txt | 26 + .../python/modtool/gr-newmod/include/howto/api.h | 33 + .../python/modtool/gr-newmod/lib/CMakeLists.txt | 63 + .../src/python/modtool/gr-newmod/lib/qa_howto.cc | 36 + .../src/python/modtool/gr-newmod/lib/qa_howto.h | 38 + .../src/python/modtool/gr-newmod/lib/test_howto.cc | 43 + .../python/modtool/gr-newmod/python/CMakeLists.txt | 43 + .../python/modtool/gr-newmod/python/__init__.py | 54 + .../python/modtool/gr-newmod/swig/CMakeLists.txt | 61 + .../src/python/modtool/gr-newmod/swig/howto_swig.i | 13 + gr-utils/src/python/modtool/modtool.conf.in | 6 + gr-utils/src/python/modtool/modtool_newmod.py | 28 +- gr-utils/src/python/modtool/newmod_tarfile.py | 1034 --- 45 files changed, 15186 insertions(+), 1056 deletions(-) create mode 100644 gr-utils/src/python/modtool/gr-newmod/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/apps/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/CMakeParseArgumentsCopy.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindCppUnit.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGnuradioCore.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGruel.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrMiscUtils.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPlatform.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPython.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrSwig.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrTest.cmake create mode 100644 gr-utils/src/python/modtool/gr-newmod/cmake/cmake_uninstall.cmake.in create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/README.howto create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.in create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.swig_doc.in create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/__init__.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/base.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/__init__.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compound.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compoundsuper.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/index.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/indexsuper.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/text.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/group_defs.dox create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/main_page.dox create mode 100644 gr-utils/src/python/modtool/gr-newmod/docs/doxygen/swig_doc.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/grc/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/include/howto/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/include/howto/api.h create mode 100644 gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.cc create mode 100644 gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.h create mode 100644 gr-utils/src/python/modtool/gr-newmod/lib/test_howto.cc create mode 100644 gr-utils/src/python/modtool/gr-newmod/python/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/python/__init__.py create mode 100644 gr-utils/src/python/modtool/gr-newmod/swig/CMakeLists.txt create mode 100644 gr-utils/src/python/modtool/gr-newmod/swig/howto_swig.i create mode 100644 gr-utils/src/python/modtool/modtool.conf.in delete mode 100644 gr-utils/src/python/modtool/newmod_tarfile.py (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/CMakeLists.txt b/gr-utils/src/python/modtool/CMakeLists.txt index 3425b50d0..7647c86f6 100644 --- a/gr-utils/src/python/modtool/CMakeLists.txt +++ b/gr-utils/src/python/modtool/CMakeLists.txt @@ -30,7 +30,6 @@ GR_PYTHON_INSTALL(FILES modtool_makexml.py modtool_newmod.py modtool_rm.py - newmod_tarfile.py parser_cc_block.py templates.py util_functions.py @@ -38,3 +37,26 @@ GR_PYTHON_INSTALL(FILES COMPONENT "utils" ) +set(GR_PKG_MODTOOL_DATA_DIR ${GR_PKG_DATA_DIR}/modtool) +install(DIRECTORY gr-newmod + DESTINATION ${GR_PKG_MODTOOL_DATA_DIR} + COMPONENT "utils" +) + + +######################################################################## +# Create and install the modtool conf file +######################################################################## +file(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/${GR_PKG_MODTOOL_DATA_DIR}/gr-newmod newmoddir) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/modtool.conf.in + ${CMAKE_CURRENT_BINARY_DIR}/modtool.conf +@ONLY) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/modtool.conf + DESTINATION ${GR_PREFSDIR} + COMPONENT "utils" +) + diff --git a/gr-utils/src/python/modtool/README.modtool b/gr-utils/src/python/modtool/README.modtool index 93ce97292..84c2e66c1 100644 --- a/gr-utils/src/python/modtool/README.modtool +++ b/gr-utils/src/python/modtool/README.modtool @@ -6,3 +6,14 @@ Adding a new subcommand * Add a new file called modtool_SUBCOMMAND * Have a look at the other subcommands, it must inherit from ModTool * Add that file to __init__.py and CMakeLists.txt + +The gr-newmod directory +======================= +This dir basically contains a copy of gr-howto-write-a-block from the gnuradio +sources, with some differences: +- All example blocks, apps, grc files (...) and references thereto in the + CMake files are removed +- In the top-level CMake file, the project is called 'gr-howto'. +- Any time anything relevant is changed in gr-howto-write-a-block, it should + be changed here, too. + diff --git a/gr-utils/src/python/modtool/gr-newmod/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/CMakeLists.txt new file mode 100644 index 000000000..deea791f8 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/CMakeLists.txt @@ -0,0 +1,145 @@ +# Copyright 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. + + +######################################################################## +# Project setup +######################################################################## +cmake_minimum_required(VERSION 2.6) +project(gr-howto CXX C) +enable_testing() + +#select the release build type by default to get optimization flags +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") + message(STATUS "Build type not specified: defaulting to release.") +endif(NOT CMAKE_BUILD_TYPE) +set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) + +######################################################################## +# Compiler specific setup +######################################################################## +if(CMAKE_COMPILER_IS_GNUCXX AND NOT WIN32) + #http://gcc.gnu.org/wiki/Visibility + add_definitions(-fvisibility=hidden) +endif() + +######################################################################## +# Find boost +######################################################################## +if(UNIX AND EXISTS "/usr/lib64") + list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix +endif(UNIX AND EXISTS "/usr/lib64") +set(Boost_ADDITIONAL_VERSIONS + "1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39" + "1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44" + "1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49" + "1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54" + "1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59" + "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" + "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" +) +find_package(Boost "1.35" COMPONENTS filesystem system) + +if(NOT Boost_FOUND) + message(FATAL_ERROR "Boost required to compile howto") +endif() + +######################################################################## +# Install directories +######################################################################## +include(GrPlatform) #define LIB_SUFFIX +set(GR_RUNTIME_DIR bin) +set(GR_LIBRARY_DIR lib${LIB_SUFFIX}) +set(GR_INCLUDE_DIR include/howto) +set(GR_DATA_DIR share) +set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) +set(GR_DOC_DIR ${GR_DATA_DIR}/doc) +set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) +set(GR_CONF_DIR etc) +set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) +set(GR_LIBEXEC_DIR libexec) +set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) +set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks) + +######################################################################## +# Find gnuradio build dependencies +######################################################################## +find_package(Gruel) +find_package(GnuradioCore) +find_package(CppUnit) + +if(NOT GRUEL_FOUND) + message(FATAL_ERROR "Gruel required to compile howto") +endif() + +if(NOT GNURADIO_CORE_FOUND) + message(FATAL_ERROR "GnuRadio Core required to compile howto") +endif() + +if(NOT CPPUNIT_FOUND) + message(FATAL_ERROR "CppUnit required to compile howto") +endif() + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${CMAKE_SOURCE_DIR}/include + ${Boost_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} + ${CPPUNIT_INCLUDE_DIRS} + ${GNURADIO_CORE_INCLUDE_DIRS} +) + +link_directories( + ${Boost_LIBRARY_DIRS} + ${GRUEL_LIBRARY_DIRS} + ${CPPUNIT_LIBRARY_DIRS} + ${GNURADIO_CORE_LIBRARY_DIRS} +) + +# Set component parameters +set(GR_HOWTO_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE) +set(GR_HOWTO_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/swig CACHE INTERNAL "" FORCE) + +######################################################################## +# Create uninstall target +######################################################################## +configure_file( + ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +@ONLY) + +add_custom_target(uninstall + ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(include/howto) +add_subdirectory(lib) +add_subdirectory(swig) +add_subdirectory(python) +add_subdirectory(grc) +add_subdirectory(apps) +add_subdirectory(docs) diff --git a/gr-utils/src/python/modtool/gr-newmod/apps/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/apps/CMakeLists.txt new file mode 100644 index 000000000..c837d77f6 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/apps/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2011 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. + +include(GrPython) + +GR_PYTHON_INSTALL( + PROGRAMS + DESTINATION bin +) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/CMakeParseArgumentsCopy.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/CMakeParseArgumentsCopy.cmake new file mode 100644 index 000000000..7ce4c49ae --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/CMakeParseArgumentsCopy.cmake @@ -0,0 +1,138 @@ +# CMAKE_PARSE_ARGUMENTS( args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for +# parsing the arguments given to that macro or function. +# It processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any value +# following, like e.g. the OPTIONAL keyword of the install() command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this macro +# which can be followed by more than one value, like e.g. the TARGETS or +# FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. +# These variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether +# your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments as the +# real install() command: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) +# ... +# +# Assume my_install() has been called like this: +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# After the cmake_parse_arguments() call the macro will have set the following +# variables: +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# You can the continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a one_value_keyword +# another recognized keyword follows, this is interpreted as the beginning of +# the new option. +# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach(option) + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else(insideValues) + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif(insideValues) + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach(currentArg) + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach(arg_name) + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindCppUnit.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindCppUnit.cmake new file mode 100644 index 000000000..9af308f84 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindCppUnit.cmake @@ -0,0 +1,36 @@ +# http://www.cmake.org/pipermail/cmake/2006-October/011446.html +# Modified to use pkg config and use standard var names + +# +# Find the CppUnit includes and library +# +# This module defines +# CPPUNIT_INCLUDE_DIR, where to find tiff.h, etc. +# CPPUNIT_LIBRARIES, the libraries to link against to use CppUnit. +# CPPUNIT_FOUND, If false, do not try to use CppUnit. + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_CPPUNIT "cppunit") + +FIND_PATH(CPPUNIT_INCLUDE_DIRS + NAMES cppunit/TestCase.h + HINTS ${PC_CPPUNIT_INCLUDE_DIR} + PATHS + /usr/local/include + /usr/include +) + +FIND_LIBRARY(CPPUNIT_LIBRARIES + NAMES cppunit + HINTS ${PC_CPPUNIT_LIBDIR} + PATHS + ${CPPUNIT_INCLUDE_DIRS}/../lib + /usr/local/lib + /usr/lib +) + +LIST(APPEND CPPUNIT_LIBRARIES ${CMAKE_DL_LIBS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS) +MARK_AS_ADVANCED(CPPUNIT_LIBRARIES CPPUNIT_INCLUDE_DIRS) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGnuradioCore.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGnuradioCore.cmake new file mode 100644 index 000000000..3773588a7 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGnuradioCore.cmake @@ -0,0 +1,26 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GNURADIO_CORE gnuradio-core) + +FIND_PATH( + GNURADIO_CORE_INCLUDE_DIRS + NAMES gr_random.h + HINTS $ENV{GNURADIO_CORE_DIR}/include/gnuradio + ${PC_GNURADIO_CORE_INCLUDEDIR} + PATHS /usr/local/include/gnuradio + /usr/include/gnuradio +) + +FIND_LIBRARY( + GNURADIO_CORE_LIBRARIES + NAMES gnuradio-core + HINTS $ENV{GNURADIO_CORE_DIR}/lib + ${PC_GNURADIO_CORE_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_CORE DEFAULT_MSG GNURADIO_CORE_LIBRARIES GNURADIO_CORE_INCLUDE_DIRS) +MARK_AS_ADVANCED(GNURADIO_CORE_LIBRARIES GNURADIO_CORE_INCLUDE_DIRS) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGruel.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGruel.cmake new file mode 100644 index 000000000..58dff7044 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/FindGruel.cmake @@ -0,0 +1,26 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_GRUEL gruel) + +FIND_PATH( + GRUEL_INCLUDE_DIRS + NAMES gruel/attributes.h + HINTS $ENV{GRUEL_DIR}/include + ${PC_GRUEL_INCLUDEDIR} + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + GRUEL_LIBRARIES + NAMES gruel + HINTS $ENV{GRUEL_DIR}/lib + ${PC_GRUEL_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GRUEL DEFAULT_MSG GRUEL_LIBRARIES GRUEL_INCLUDE_DIRS) +MARK_AS_ADVANCED(GRUEL_LIBRARIES GRUEL_INCLUDE_DIRS) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrMiscUtils.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrMiscUtils.cmake new file mode 100644 index 000000000..9331d5deb --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrMiscUtils.cmake @@ -0,0 +1,210 @@ +# Copyright 2010-2011 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. + +if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE) + return() +endif() +set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE) + +######################################################################## +# Set global variable macro. +# Used for subdirectories to export settings. +# Example: include and library paths. +######################################################################## +function(GR_SET_GLOBAL var) + set(${var} ${ARGN} CACHE INTERNAL "" FORCE) +endfunction(GR_SET_GLOBAL) + +######################################################################## +# Set the pre-processor definition if the condition is true. +# - def the pre-processor definition to set and condition name +######################################################################## +function(GR_ADD_COND_DEF def) + if(${def}) + add_definitions(-D${def}) + endif(${def}) +endfunction(GR_ADD_COND_DEF) + +######################################################################## +# Check for a header and conditionally set a compile define. +# - hdr the relative path to the header file +# - def the pre-processor definition to set +######################################################################## +function(GR_CHECK_HDR_N_DEF hdr def) + include(CheckIncludeFileCXX) + CHECK_INCLUDE_FILE_CXX(${hdr} ${def}) + GR_ADD_COND_DEF(${def}) +endfunction(GR_CHECK_HDR_N_DEF) + +######################################################################## +# Include subdirectory macro. +# Sets the CMake directory variables, +# includes the subdirectory CMakeLists.txt, +# resets the CMake directory variables. +# +# This macro includes subdirectories rather than adding them +# so that the subdirectory can affect variables in the level above. +# This provides a work-around for the lack of convenience libraries. +# This way a subdirectory can append to the list of library sources. +######################################################################## +macro(GR_INCLUDE_SUBDIRECTORY subdir) + #insert the current directories on the front of the list + list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR}) + list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR}) + + #set the current directories to the names of the subdirs + set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}) + set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir}) + + #include the subdirectory CMakeLists to run it + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt) + + #reset the value of the current directories + list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR) + list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR) + + #pop the subdir names of the front of the list + list(REMOVE_AT _cmake_source_dirs 0) + list(REMOVE_AT _cmake_binary_dirs 0) +endmacro(GR_INCLUDE_SUBDIRECTORY) + +######################################################################## +# Check if a compiler flag works and conditionally set a compile define. +# - flag the compiler flag to check for +# - have the variable to set with result +######################################################################## +macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(${flag} ${have}) + if(${have}) + add_definitions(${flag}) + endif(${have}) +endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE) + +######################################################################## +# Generates the .la libtool file +# This appears to generate libtool files that cannot be used by auto*. +# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest]) +# Notice: there is not COMPONENT option, these will not get distributed. +######################################################################## +function(GR_LIBTOOL) + if(NOT DEFINED GENERATE_LIBTOOL) + set(GENERATE_LIBTOOL OFF) #disabled by default + endif() + + if(GENERATE_LIBTOOL) + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN}) + + find_program(LIBTOOL libtool) + if(LIBTOOL) + include(CMakeMacroLibtoolFile) + CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION}) + endif(LIBTOOL) + endif(GENERATE_LIBTOOL) + +endfunction(GR_LIBTOOL) + +######################################################################## +# Do standard things to the library target +# - set target properties +# - make install rules +# Also handle gnuradio custom naming conventions w/ extras mode. +######################################################################## +function(GR_LIBRARY_FOO target) + #parse the arguments for component names + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN}) + + #set additional target properties + set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER}) + + #install the generated files like so... + install(TARGETS ${target} + LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file + ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT} # .lib file + RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file + ) + + #extras mode enabled automatically on linux + if(NOT DEFINED LIBRARY_EXTRAS) + set(LIBRARY_EXTRAS ${LINUX}) + endif() + + #special extras mode to enable alternative naming conventions + if(LIBRARY_EXTRAS) + + #create .la file before changing props + GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR}) + + #give the library a special name with ultra-zero soversion + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0") + set(target_name lib${target}-${LIBVER}.so.0.0.0) + + #custom command to generate symlinks + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + COMMAND ${CMAKE_COMMAND} -E touch ${target_name} #so the symlinks point to something valid so cmake 2.6 will install + ) + + #and install the extra symlinks + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so + ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0 + DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} + ) + + endif(LIBRARY_EXTRAS) +endfunction(GR_LIBRARY_FOO) + +######################################################################## +# Create a dummy custom command that depends on other targets. +# Usage: +# GR_GEN_TARGET_DEPS(unique_name target_deps ...) +# ADD_CUSTOM_COMMAND( ${target_deps}) +# +# Custom command cant depend on targets, but can depend on executables, +# and executables can depend on targets. So this is the process: +######################################################################## +function(GR_GEN_TARGET_DEPS name var) + file( + WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in + "int main(void){return 0;}\n" + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp + ) + add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp) + if(ARGN) + add_dependencies(${name} ${ARGN}) + endif(ARGN) + + if(CMAKE_CROSSCOMPILING) + set(${var} "DEPENDS;${name}" PARENT_SCOPE) #cant call command when cross + else() + set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE) + endif() +endfunction(GR_GEN_TARGET_DEPS) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPlatform.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPlatform.cmake new file mode 100644 index 000000000..a2e4f3b34 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPlatform.cmake @@ -0,0 +1,46 @@ +# Copyright 2011 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. + +if(DEFINED __INCLUDED_GR_PLATFORM_CMAKE) + return() +endif() +set(__INCLUDED_GR_PLATFORM_CMAKE TRUE) + +######################################################################## +# Setup additional defines for OS types +######################################################################## +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(LINUX TRUE) +endif() + +if(LINUX AND EXISTS "/etc/debian_version") + set(DEBIAN TRUE) +endif() + +if(LINUX AND EXISTS "/etc/redhat-release") + set(REDHAT TRUE) +endif() + +######################################################################## +# when the library suffix should be 64 (applies to redhat linux family) +######################################################################## +if(NOT DEFINED LIB_SUFFIX AND REDHAT AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$") + set(LIB_SUFFIX 64) +endif() +set(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix") diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPython.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPython.cmake new file mode 100644 index 000000000..efdddf371 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrPython.cmake @@ -0,0 +1,227 @@ +# Copyright 2010-2011 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. + +if(DEFINED __INCLUDED_GR_PYTHON_CMAKE) + return() +endif() +set(__INCLUDED_GR_PYTHON_CMAKE TRUE) + +######################################################################## +# Setup the python interpreter: +# This allows the user to specify a specific interpreter, +# or finds the interpreter via the built-in cmake module. +######################################################################## +#this allows the user to override PYTHON_EXECUTABLE +if(PYTHON_EXECUTABLE) + + set(PYTHONINTERP_FOUND TRUE) + +#otherwise if not set, try to automatically find it +else(PYTHON_EXECUTABLE) + + #use the built-in find script + find_package(PythonInterp) + + #and if that fails use the find program routine + if(NOT PYTHONINTERP_FOUND) + find_program(PYTHON_EXECUTABLE NAMES python python2.7 python2.6 python2.5) + if(PYTHON_EXECUTABLE) + set(PYTHONINTERP_FOUND TRUE) + endif(PYTHON_EXECUTABLE) + endif(NOT PYTHONINTERP_FOUND) + +endif(PYTHON_EXECUTABLE) + +#make the path to the executable appear in the cmake gui +set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter") + +#make sure we can use -B with python (introduced in 2.6) +if(PYTHON_EXECUTABLE) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -B -c "" + OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT + ) + if(PYTHON_HAS_DASH_B_RESULT EQUAL 0) + set(PYTHON_DASH_B "-B") + endif() +endif(PYTHON_EXECUTABLE) + +######################################################################## +# Check for the existence of a python module: +# - desc a string description of the check +# - mod the name of the module to import +# - cmd an additional command to run +# - have the result variable to set +######################################################################## +macro(GR_PYTHON_CHECK_MODULE desc mod cmd have) + message(STATUS "") + message(STATUS "Python checking for ${desc}") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c " +######################################### +try: import ${mod} +except: exit(-1) +try: assert ${cmd} +except: exit(-1) +#########################################" + RESULT_VARIABLE ${have} + ) + if(${have} EQUAL 0) + message(STATUS "Python checking for ${desc} - found") + set(${have} TRUE) + else(${have} EQUAL 0) + message(STATUS "Python checking for ${desc} - not found") + set(${have} FALSE) + endif(${have} EQUAL 0) +endmacro(GR_PYTHON_CHECK_MODULE) + +######################################################################## +# Sets the python installation directory GR_PYTHON_DIR +######################################################################## +execute_process(COMMAND ${PYTHON_EXECUTABLE} -c " +from distutils import sysconfig +print sysconfig.get_python_lib(plat_specific=True, prefix='') +" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE +) +file(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR) + +######################################################################## +# Create an always-built target with a unique name +# Usage: GR_UNIQUE_TARGET( ) +######################################################################## +function(GR_UNIQUE_TARGET desc) + file(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib +unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5] +print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))" + OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE) + add_custom_target(${_target} ALL DEPENDS ${ARGN}) +endfunction(GR_UNIQUE_TARGET) + +######################################################################## +# Install python sources (also builds and installs byte-compiled python) +######################################################################## +function(GR_PYTHON_INSTALL) + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN}) + + #################################################################### + if(GR_PYTHON_INSTALL_FILES) + #################################################################### + install(${ARGN}) #installs regular python files + + #create a list of all generated files + unset(pysrcfiles) + unset(pycfiles) + unset(pyofiles) + foreach(pyfile ${GR_PYTHON_INSTALL_FILES}) + get_filename_component(pyfile ${pyfile} ABSOLUTE) + list(APPEND pysrcfiles ${pyfile}) + + #determine if this file is in the source or binary directory + file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile}) + string(LENGTH "${source_rel_path}" source_rel_path_len) + file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile}) + string(LENGTH "${binary_rel_path}" binary_rel_path_len) + + #and set the generated path appropriately + if(${source_rel_path_len} GREATER ${binary_rel_path_len}) + set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path}) + else() + set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path}) + endif() + list(APPEND pycfiles ${pygenfile}c) + list(APPEND pyofiles ${pygenfile}o) + + #ensure generation path exists + get_filename_component(pygen_path ${pygenfile} PATH) + file(MAKE_DIRECTORY ${pygen_path}) + + endforeach(pyfile) + + #the command to generate the pyc files + add_custom_command( + DEPENDS ${pysrcfiles} OUTPUT ${pycfiles} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles} + ) + + #the command to generate the pyo files + add_custom_command( + DEPENDS ${pysrcfiles} OUTPUT ${pyofiles} + COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles} + ) + + #create install rule and add generated files to target list + set(python_install_gen_targets ${pycfiles} ${pyofiles}) + install(FILES ${python_install_gen_targets} + DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} + COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} + ) + + + #################################################################### + elseif(GR_PYTHON_INSTALL_PROGRAMS) + #################################################################### + file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native) + + foreach(pyfile ${GR_PYTHON_INSTALL_PROGRAMS}) + get_filename_component(pyfile_name ${pyfile} NAME) + get_filename_component(pyfile ${pyfile} ABSOLUTE) + string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe") + list(APPEND python_install_gen_targets ${pyexefile}) + + get_filename_component(pyexefile_path ${pyexefile} PATH) + file(MAKE_DIRECTORY ${pyexefile_path}) + + add_custom_command( + OUTPUT ${pyexefile} DEPENDS ${pyfile} + COMMAND ${PYTHON_EXECUTABLE} -c + \"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\" + COMMENT "Shebangin ${pyfile_name}" + ) + + #on windows, python files need an extension to execute + get_filename_component(pyfile_ext ${pyfile} EXT) + if(WIN32 AND NOT pyfile_ext) + set(pyfile_name "${pyfile_name}.py") + endif() + + install(PROGRAMS ${pyexefile} RENAME ${pyfile_name} + DESTINATION ${GR_PYTHON_INSTALL_DESTINATION} + COMPONENT ${GR_PYTHON_INSTALL_COMPONENT} + ) + endforeach(pyfile) + + endif() + + GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets}) + +endfunction(GR_PYTHON_INSTALL) + +######################################################################## +# Write the python helper script that generates byte code files +######################################################################## +file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py " +import sys, py_compile +files = sys.argv[1:] +srcs, gens = files[:len(files)/2], files[len(files)/2:] +for src, gen in zip(srcs, gens): + py_compile.compile(file=src, cfile=gen, doraise=True) +") diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrSwig.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrSwig.cmake new file mode 100644 index 000000000..6ba5ee3a5 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrSwig.cmake @@ -0,0 +1,229 @@ +# Copyright 2010-2011 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. + +if(DEFINED __INCLUDED_GR_SWIG_CMAKE) + return() +endif() +set(__INCLUDED_GR_SWIG_CMAKE TRUE) + +include(GrPython) + +######################################################################## +# Builds a swig documentation file to be generated into python docstrings +# Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....) +# +# Set the following variable to specify extra dependent targets: +# - GR_SWIG_DOCS_SOURCE_DEPS +# - GR_SWIG_DOCS_TARGET_DEPS +######################################################################## +function(GR_SWIG_MAKE_DOCS output_file) + find_package(Doxygen) + if(DOXYGEN_FOUND) + + #setup the input files variable list, quote formated + set(input_files) + unset(INPUT_PATHS) + foreach(input_path ${ARGN}) + if (IS_DIRECTORY ${input_path}) #when input path is a directory + file(GLOB input_path_h_files ${input_path}/*.h) + else() #otherwise its just a file, no glob + set(input_path_h_files ${input_path}) + endif() + list(APPEND input_files ${input_path_h_files}) + set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"") + endforeach(input_path) + + #determine the output directory + get_filename_component(name ${output_file} NAME_WE) + get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH) + set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs) + make_directory(${OUTPUT_DIRECTORY}) + + #generate the Doxyfile used by doxygen + configure_file( + ${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in + ${OUTPUT_DIRECTORY}/Doxyfile + @ONLY) + + #Create a dummy custom command that depends on other targets + include(GrMiscUtils) + GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS}) + + #call doxygen on the Doxyfile + input headers + add_custom_command( + OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml + DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps} + COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile + COMMENT "Generating doxygen xml for ${name} docs" + ) + + #call the swig_doc script on the xml files + add_custom_command( + OUTPUT ${output_file} + DEPENDS ${input_files} ${OUTPUT_DIRECTORY}/xml/index.xml + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py + ${OUTPUT_DIRECTORY}/xml + ${output_file} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen + ) + + else(DOXYGEN_FOUND) + file(WRITE ${output_file} "\n") #no doxygen -> empty file + endif(DOXYGEN_FOUND) +endfunction(GR_SWIG_MAKE_DOCS) + +######################################################################## +# Build a swig target for the common gnuradio use case. Usage: +# GR_SWIG_MAKE(target ifile ifile ifile...) +# +# Set the following variables before calling: +# - GR_SWIG_FLAGS +# - GR_SWIG_INCLUDE_DIRS +# - GR_SWIG_LIBRARIES +# - GR_SWIG_SOURCE_DEPS +# - GR_SWIG_TARGET_DEPS +# - GR_SWIG_DOC_FILE +# - GR_SWIG_DOC_DIRS +######################################################################## +macro(GR_SWIG_MAKE name) + set(ifiles ${ARGN}) + + #do swig doc generation if specified + if (GR_SWIG_DOC_FILE) + set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS}) + set(GR_SWIG_DOCS_TAREGT_DEPS ${GR_SWIG_TARGET_DEPS}) + GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS}) + list(APPEND GR_SWIG_SOURCE_DEPS ${GR_SWIG_DOC_FILE}) + endif() + + #append additional include directories + find_package(PythonLibs) + list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs) + list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS}) + list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) + list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) + + #determine include dependencies for swig file + execute_process( + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_BINARY_DIR}/get_swig_deps.py + "${ifiles}" "${GR_SWIG_INCLUDE_DIRS}" + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + #Create a dummy custom command that depends on other targets + include(GrMiscUtils) + GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS}) + set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag) + add_custom_command( + OUTPUT ${tag_file} + DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps} + COMMAND ${CMAKE_COMMAND} -E touch ${tag_file} + ) + + #append the specified include directories + include_directories(${GR_SWIG_INCLUDE_DIRS}) + list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file}) + + #setup the swig flags with flags and include directories + set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS}) + foreach(dir ${GR_SWIG_INCLUDE_DIRS}) + list(APPEND CMAKE_SWIG_FLAGS "-I${dir}") + endforeach(dir) + + #set the C++ property on the swig .i file so it builds + set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON) + + #setup the actual swig library target to be built + include(UseSWIG) + SWIG_ADD_MODULE(${name} python ${ifiles}) + SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES}) + +endmacro(GR_SWIG_MAKE) + +######################################################################## +# Install swig targets generated by GR_SWIG_MAKE. Usage: +# GR_SWIG_INSTALL( +# TARGETS target target target... +# [DESTINATION destination] +# [COMPONENT component] +# ) +######################################################################## +macro(GR_SWIG_INSTALL) + + include(CMakeParseArgumentsCopy) + CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN}) + + foreach(name ${GR_SWIG_INSTALL_TARGETS}) + install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME} + DESTINATION ${GR_SWIG_INSTALL_DESTINATION} + COMPONENT ${GR_SWIG_INSTALL_COMPONENT} + ) + + include(GrPython) + GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py + DESTINATION ${GR_SWIG_INSTALL_DESTINATION} + COMPONENT ${GR_SWIG_INSTALL_COMPONENT} + ) + + GR_LIBTOOL( + TARGET ${SWIG_MODULE_${name}_REAL_NAME} + DESTINATION ${GR_SWIG_INSTALL_DESTINATION} + ) + + endforeach(name) + +endmacro(GR_SWIG_INSTALL) + +######################################################################## +# Generate a python file that can determine swig dependencies. +# Used by the make macro above to determine extra dependencies. +# When you build C++, CMake figures out the header dependencies. +# This code essentially performs that logic for swig includes. +######################################################################## +file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py " + +import os, sys, re + +include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]') +include_dirs = sys.argv[2].split(';') + +def get_swig_incs(file_path): + file_contents = open(file_path, 'r').read() + return include_matcher.findall(file_contents, re.MULTILINE) + +def get_swig_deps(file_path, level): + deps = [file_path] + if level == 0: return deps + for inc_file in get_swig_incs(file_path): + for inc_dir in include_dirs: + inc_path = os.path.join(inc_dir, inc_file) + if not os.path.exists(inc_path): continue + deps.extend(get_swig_deps(inc_path, level-1)) + return deps + +if __name__ == '__main__': + ifiles = sys.argv[1].split(';') + deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], []) + #sys.stderr.write(';'.join(set(deps)) + '\\n\\n') + print(';'.join(set(deps))) +") diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrTest.cmake b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrTest.cmake new file mode 100644 index 000000000..6174c034e --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/Modules/GrTest.cmake @@ -0,0 +1,133 @@ +# Copyright 2010-2011 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. + +if(DEFINED __INCLUDED_GR_TEST_CMAKE) + return() +endif() +set(__INCLUDED_GR_TEST_CMAKE TRUE) + +######################################################################## +# Add a unit test and setup the environment for a unit test. +# Takes the same arguments as the ADD_TEST function. +# +# Before calling set the following variables: +# GR_TEST_TARGET_DEPS - built targets for the library path +# GR_TEST_LIBRARY_DIRS - directories for the library path +# GR_TEST_PYTHON_DIRS - directories for the python path +######################################################################## +function(GR_ADD_TEST test_name) + + if(WIN32) + #Ensure that the build exe also appears in the PATH. + list(APPEND GR_TEST_TARGET_DEPS ${ARGN}) + + #In the land of windows, all libraries must be in the PATH. + #Since the dependent libraries are not yet installed, + #we must manually set them in the PATH to run tests. + #The following appends the path of a target dependency. + foreach(target ${GR_TEST_TARGET_DEPS}) + get_target_property(location ${target} LOCATION) + if(location) + get_filename_component(path ${location} PATH) + string(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path}) + list(APPEND GR_TEST_LIBRARY_DIRS ${path}) + endif(location) + endforeach(target) + + #SWIG generates the python library files into a subdirectory. + #Therefore, we must append this subdirectory into PYTHONPATH. + #Only do this for the python directories matching the following: + foreach(pydir ${GR_TEST_PYTHON_DIRS}) + get_filename_component(name ${pydir} NAME) + if(name MATCHES "^(swig|lib|src)$") + list(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE}) + endif() + endforeach(pydir) + endif(WIN32) + + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir) + file(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list? + file(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list? + + set(environs "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}") + + #http://www.cmake.org/pipermail/cmake/2009-May/029464.html + #Replaced this add test + set environs code with the shell script generation. + #Its nicer to be able to manually run the shell script to diagnose problems. + #ADD_TEST(${ARGV}) + #SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}") + + if(UNIX) + set(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH") + #set both LD and DYLD paths to cover multiple UNIX OS library paths + list(APPEND libpath "$LD_LIBRARY_PATH" "$DYLD_LIBRARY_PATH") + list(APPEND pypath "$PYTHONPATH") + + #replace list separator with the path separator + string(REPLACE ";" ":" libpath "${libpath}") + string(REPLACE ";" ":" pypath "${pypath}") + list(APPEND environs "PATH=${binpath}" "LD_LIBRARY_PATH=${libpath}" "DYLD_LIBRARY_PATH=${libpath}" "PYTHONPATH=${pypath}") + + #generate a bat file that sets the environment and runs the test + find_program(SHELL sh) + set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh) + file(WRITE ${sh_file} "#!${SHELL}\n") + #each line sets an environment variable + foreach(environ ${environs}) + file(APPEND ${sh_file} "export ${environ}\n") + endforeach(environ) + #load the command to run with its arguments + foreach(arg ${ARGN}) + file(APPEND ${sh_file} "${arg} ") + endforeach(arg) + file(APPEND ${sh_file} "\n") + + #make the shell file executable + execute_process(COMMAND chmod +x ${sh_file}) + + add_test(${test_name} ${SHELL} ${sh_file}) + + endif(UNIX) + + if(WIN32) + list(APPEND libpath ${DLL_PATHS} "%PATH%") + list(APPEND pypath "%PYTHONPATH%") + + #replace list separator with the path separator (escaped) + string(REPLACE ";" "\\;" libpath "${libpath}") + string(REPLACE ";" "\\;" pypath "${pypath}") + list(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}") + + #generate a bat file that sets the environment and runs the test + set(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat) + file(WRITE ${bat_file} "@echo off\n") + #each line sets an environment variable + foreach(environ ${environs}) + file(APPEND ${bat_file} "SET ${environ}\n") + endforeach(environ) + #load the command to run with its arguments + foreach(arg ${ARGN}) + file(APPEND ${bat_file} "${arg} ") + endforeach(arg) + file(APPEND ${bat_file} "\n") + + add_test(${test_name} ${bat_file}) + endif(WIN32) + +endfunction(GR_ADD_TEST) diff --git a/gr-utils/src/python/modtool/gr-newmod/cmake/cmake_uninstall.cmake.in b/gr-utils/src/python/modtool/gr-newmod/cmake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..9ae1ae4bd --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,32 @@ +# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F + +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/docs/CMakeLists.txt new file mode 100644 index 000000000..f16fbf6db --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2011 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. + +######################################################################## +# Setup dependencies +######################################################################## +find_package(Doxygen) + +######################################################################## +# Begin conditional configuration +######################################################################## +if(ENABLE_DOXYGEN) + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(doxygen) + +endif(ENABLE_DOXYGEN) diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/README.howto b/gr-utils/src/python/modtool/gr-newmod/docs/README.howto new file mode 100644 index 000000000..a0a6c0f19 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/README.howto @@ -0,0 +1,11 @@ +This is the howto-write-a-block package meant as a guide to building +out-of-tree packages. To use the howto blocks, the Python namespaces +is in 'howto', which is imported as: + + import howto + +See the Doxygen documentation for details about the blocks available +in this package. A quick listing of the details can be found in Python +after importing by using: + + help(howto) diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/CMakeLists.txt new file mode 100644 index 000000000..1b4479929 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/CMakeLists.txt @@ -0,0 +1,52 @@ +# Copyright 2011 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. + +######################################################################## +# Create the doxygen configuration file +######################################################################## +file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) +file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) +file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir) +file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir) + +set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) +set(enable_html_docs YES) +set(enable_latex_docs NO) +set(enable_xml_docs YES) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile +@ONLY) + +set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) + +######################################################################## +# Make and install doxygen docs +######################################################################## +add_custom_command( + OUTPUT ${BUILT_DIRS} + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating documentation with doxygen" +) + +add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS}) + +install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.in b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.in new file mode 100644 index 000000000..cb6a913bb --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.in @@ -0,0 +1,1504 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "GNU Radio's HOWTO Package" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 4 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= NO + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text " + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @top_srcdir@ @top_builddir@ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h \ + *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = @abs_top_builddir@/docs/doxygen/html \ + @abs_top_builddir@/docs/doxygen/xml \ + @abs_top_builddir@/docs/doxygen/other/doxypy.py \ + @abs_top_builddir@/_CPack_Packages \ + @abs_top_srcdir@/cmake + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.deps/* \ + */.libs/* \ + */.svn/* \ + */CVS/* \ + */__init__.py \ + */qa_*.cc \ + */qa_*.h \ + */qa_*.py + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = ad9862 \ + numpy \ + *swig* \ + *Swig* \ + *my_top_block* \ + *my_graph* \ + *app_top_block* \ + *am_rx_graph* \ + *_queue_watcher_thread* \ + *parse* \ + *MyFrame* \ + *MyApp* \ + *PyObject* \ + *wfm_rx_block* \ + *_sptr* \ + *debug* \ + *wfm_rx_sca_block* \ + *tv_rx_block* \ + *wxapt_rx_block* \ + *example_signal* + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = *.py=@top_srcdir@/gnuradio-core/doc/other/doxypy.py + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = @enable_html_docs@ + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 180 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = @enable_latex_docs@ + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = @enable_xml_docs@ + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = @HAVE_DOT@ + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.swig_doc.in b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.swig_doc.in new file mode 100644 index 000000000..50b8aa81d --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/Doxyfile.swig_doc.in @@ -0,0 +1,1514 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @CPACK_PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @CPACK_PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @INPUT_PATHS@ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = NO + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = YES + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = YES + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/__init__.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/__init__.py new file mode 100644 index 000000000..5cd0b3c6c --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/__init__.py @@ -0,0 +1,82 @@ +# +# Copyright 2010 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. +# +""" +Python interface to contents of doxygen xml documentation. + +Example use: +See the contents of the example folder for the C++ and +doxygen-generated xml used in this example. + +>>> # Parse the doxygen docs. +>>> import os +>>> this_dir = os.path.dirname(globals()['__file__']) +>>> xml_path = this_dir + "/example/xml/" +>>> di = DoxyIndex(xml_path) + +Get a list of all top-level objects. + +>>> print([mem.name() for mem in di.members()]) +[u'Aadvark', u'aadvarky_enough', u'main'] + +Get all functions. + +>>> print([mem.name() for mem in di.in_category(DoxyFunction)]) +[u'aadvarky_enough', u'main'] + +Check if an object is present. + +>>> di.has_member(u'Aadvark') +True +>>> di.has_member(u'Fish') +False + +Get an item by name and check its properties. + +>>> aad = di.get_member(u'Aadvark') +>>> print(aad.brief_description) +Models the mammal Aadvark. +>>> print(aad.detailed_description) +Sadly the model is incomplete and cannot capture all aspects of an aadvark yet. + +This line is uninformative and is only to test line breaks in the comments. +>>> [mem.name() for mem in aad.members()] +[u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness'] +>>> aad.get_member(u'print').brief_description +u'Outputs the vital aadvark statistics.' + +""" + +from doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther + +def _test(): + import os + this_dir = os.path.dirname(globals()['__file__']) + xml_path = this_dir + "/example/xml/" + di = DoxyIndex(xml_path) + # Get the Aadvark class + aad = di.get_member('Aadvark') + aad.brief_description + import doctest + return doctest.testmod() + +if __name__ == "__main__": + _test() + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/base.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/base.py new file mode 100644 index 000000000..e8f026ab9 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/base.py @@ -0,0 +1,219 @@ +# +# Copyright 2010 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. +# +""" +A base class is created. + +Classes based upon this are used to make more user-friendly interfaces +to the doxygen xml docs than the generated classes provide. +""" + +import os +import pdb + +from xml.parsers.expat import ExpatError + +from generated import compound + + +class Base(object): + + class Duplicate(StandardError): + pass + + class NoSuchMember(StandardError): + pass + + class ParsingError(StandardError): + pass + + def __init__(self, parse_data, top=None): + self._parsed = False + self._error = False + self._parse_data = parse_data + self._members = [] + self._dict_members = {} + self._in_category = {} + self._data = {} + if top is not None: + self._xml_path = top._xml_path + # Set up holder of references + else: + top = self + self._refs = {} + self._xml_path = parse_data + self.top = top + + @classmethod + def from_refid(cls, refid, top=None): + """ Instantiate class from a refid rather than parsing object. """ + # First check to see if its already been instantiated. + if top is not None and refid in top._refs: + return top._refs[refid] + # Otherwise create a new instance and set refid. + inst = cls(None, top=top) + inst.refid = refid + inst.add_ref(inst) + return inst + + @classmethod + def from_parse_data(cls, parse_data, top=None): + refid = getattr(parse_data, 'refid', None) + if refid is not None and top is not None and refid in top._refs: + return top._refs[refid] + inst = cls(parse_data, top=top) + if refid is not None: + inst.refid = refid + inst.add_ref(inst) + return inst + + def add_ref(self, obj): + if hasattr(obj, 'refid'): + self.top._refs[obj.refid] = obj + + mem_classes = [] + + def get_cls(self, mem): + for cls in self.mem_classes: + if cls.can_parse(mem): + return cls + raise StandardError(("Did not find a class for object '%s'." \ + % (mem.get_name()))) + + def convert_mem(self, mem): + try: + cls = self.get_cls(mem) + converted = cls.from_parse_data(mem, self.top) + if converted is None: + raise StandardError('No class matched this object.') + self.add_ref(converted) + return converted + except StandardError, e: + print e + + @classmethod + def includes(cls, inst): + return isinstance(inst, cls) + + @classmethod + def can_parse(cls, obj): + return False + + def _parse(self): + self._parsed = True + + def _get_dict_members(self, cat=None): + """ + For given category a dictionary is returned mapping member names to + members of that category. For names that are duplicated the name is + mapped to None. + """ + self.confirm_no_error() + if cat not in self._dict_members: + new_dict = {} + for mem in self.in_category(cat): + if mem.name() not in new_dict: + new_dict[mem.name()] = mem + else: + new_dict[mem.name()] = self.Duplicate + self._dict_members[cat] = new_dict + return self._dict_members[cat] + + def in_category(self, cat): + self.confirm_no_error() + if cat is None: + return self._members + if cat not in self._in_category: + self._in_category[cat] = [mem for mem in self._members + if cat.includes(mem)] + return self._in_category[cat] + + def get_member(self, name, cat=None): + self.confirm_no_error() + # Check if it's in a namespace or class. + bits = name.split('::') + first = bits[0] + rest = '::'.join(bits[1:]) + member = self._get_dict_members(cat).get(first, self.NoSuchMember) + # Raise any errors that are returned. + if member in set([self.NoSuchMember, self.Duplicate]): + raise member() + if rest: + return member.get_member(rest, cat=cat) + return member + + def has_member(self, name, cat=None): + try: + mem = self.get_member(name, cat=cat) + return True + except self.NoSuchMember: + return False + + def data(self): + self.confirm_no_error() + return self._data + + def members(self): + self.confirm_no_error() + return self._members + + def process_memberdefs(self): + mdtss = [] + for sec in self._retrieved_data.compounddef.sectiondef: + mdtss += sec.memberdef + # At the moment we lose all information associated with sections. + # Sometimes a memberdef is in several sectiondef. + # We make sure we don't get duplicates here. + uniques = set([]) + for mem in mdtss: + converted = self.convert_mem(mem) + pair = (mem.name, mem.__class__) + if pair not in uniques: + uniques.add(pair) + self._members.append(converted) + + def retrieve_data(self): + filename = os.path.join(self._xml_path, self.refid + '.xml') + try: + self._retrieved_data = compound.parse(filename) + except ExpatError: + print('Error in xml in file %s' % filename) + self._error = True + self._retrieved_data = None + + def check_parsed(self): + if not self._parsed: + self._parse() + + def confirm_no_error(self): + self.check_parsed() + if self._error: + raise self.ParsingError() + + def error(self): + self.check_parsed() + return self._error + + def name(self): + # first see if we can do it without processing. + if self._parse_data is not None: + return self._parse_data.name + self.check_parsed() + return self._retrieved_data.compounddef.name diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py new file mode 100644 index 000000000..0132ab86f --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py @@ -0,0 +1,237 @@ +# +# Copyright 2010 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. +# +""" +Classes providing more user-friendly interfaces to the doxygen xml +docs than the generated classes provide. +""" + +import os + +from generated import index +from base import Base +from text import description + +class DoxyIndex(Base): + """ + Parses a doxygen xml directory. + """ + + __module__ = "gnuradio.utils.doxyxml" + + def _parse(self): + if self._parsed: + return + super(DoxyIndex, self)._parse() + self._root = index.parse(os.path.join(self._xml_path, 'index.xml')) + for mem in self._root.compound: + converted = self.convert_mem(mem) + # For files we want the contents to be accessible directly + # from the parent rather than having to go through the file + # object. + if self.get_cls(mem) == DoxyFile: + if mem.name.endswith('.h'): + self._members += converted.members() + self._members.append(converted) + else: + self._members.append(converted) + + +def generate_swig_doc_i(self): + """ + %feature("docstring") gr_make_align_on_samplenumbers_ss::align_state " + Wraps the C++: gr_align_on_samplenumbers_ss::align_state"; + """ + pass + + +class DoxyCompMem(Base): + + + kind = None + + def __init__(self, *args, **kwargs): + super(DoxyCompMem, self).__init__(*args, **kwargs) + + @classmethod + def can_parse(cls, obj): + return obj.kind == cls.kind + + def set_descriptions(self, parse_data): + bd = description(getattr(parse_data, 'briefdescription', None)) + dd = description(getattr(parse_data, 'detaileddescription', None)) + self._data['brief_description'] = bd + self._data['detailed_description'] = dd + +class DoxyCompound(DoxyCompMem): + pass + +class DoxyMember(DoxyCompMem): + pass + + +class DoxyFunction(DoxyMember): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'function' + + def _parse(self): + if self._parsed: + return + super(DoxyFunction, self)._parse() + self.set_descriptions(self._parse_data) + self._data['params'] = [] + prms = self._parse_data.param + for prm in prms: + self._data['params'].append(DoxyParam(prm)) + + brief_description = property(lambda self: self.data()['brief_description']) + detailed_description = property(lambda self: self.data()['detailed_description']) + params = property(lambda self: self.data()['params']) + +Base.mem_classes.append(DoxyFunction) + + +class DoxyParam(DoxyMember): + + __module__ = "gnuradio.utils.doxyxml" + + def _parse(self): + if self._parsed: + return + super(DoxyParam, self)._parse() + self.set_descriptions(self._parse_data) + self._data['declname'] = self._parse_data.declname + + brief_description = property(lambda self: self.data()['brief_description']) + detailed_description = property(lambda self: self.data()['detailed_description']) + declname = property(lambda self: self.data()['declname']) + +class DoxyClass(DoxyCompound): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'class' + + def _parse(self): + if self._parsed: + return + super(DoxyClass, self)._parse() + self.retrieve_data() + if self._error: + return + self.set_descriptions(self._retrieved_data.compounddef) + # Sectiondef.kind tells about whether private or public. + # We just ignore this for now. + self.process_memberdefs() + + brief_description = property(lambda self: self.data()['brief_description']) + detailed_description = property(lambda self: self.data()['detailed_description']) + +Base.mem_classes.append(DoxyClass) + + +class DoxyFile(DoxyCompound): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'file' + + def _parse(self): + if self._parsed: + return + super(DoxyFile, self)._parse() + self.retrieve_data() + self.set_descriptions(self._retrieved_data.compounddef) + if self._error: + return + self.process_memberdefs() + + brief_description = property(lambda self: self.data()['brief_description']) + detailed_description = property(lambda self: self.data()['detailed_description']) + +Base.mem_classes.append(DoxyFile) + + +class DoxyNamespace(DoxyCompound): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'namespace' + +Base.mem_classes.append(DoxyNamespace) + + +class DoxyGroup(DoxyCompound): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'group' + + def _parse(self): + if self._parsed: + return + super(DoxyGroup, self)._parse() + self.retrieve_data() + if self._error: + return + cdef = self._retrieved_data.compounddef + self._data['title'] = description(cdef.title) + # Process inner groups + grps = cdef.innergroup + for grp in grps: + converted = DoxyGroup.from_refid(grp.refid, top=self.top) + self._members.append(converted) + # Process inner classes + klasses = cdef.innerclass + for kls in klasses: + converted = DoxyClass.from_refid(kls.refid, top=self.top) + self._members.append(converted) + # Process normal members + self.process_memberdefs() + + title = property(lambda self: self.data()['title']) + + +Base.mem_classes.append(DoxyGroup) + + +class DoxyFriend(DoxyMember): + + __module__ = "gnuradio.utils.doxyxml" + + kind = 'friend' + +Base.mem_classes.append(DoxyFriend) + + +class DoxyOther(Base): + + __module__ = "gnuradio.utils.doxyxml" + + kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 'dir', 'page']) + + @classmethod + def can_parse(cls, obj): + return obj.kind in cls.kinds + +Base.mem_classes.append(DoxyOther) + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/__init__.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/__init__.py new file mode 100644 index 000000000..39823979f --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/__init__.py @@ -0,0 +1,7 @@ +""" +Contains generated files produced by generateDS.py. + +These do the real work of parsing the doxygen xml files but the +resultant classes are not very friendly to navigate so the rest of the +doxyxml module processes them further. +""" diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compound.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compound.py new file mode 100644 index 000000000..1522ac23f --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compound.py @@ -0,0 +1,503 @@ +#!/usr/bin/env python + +""" +Generated Mon Feb 9 19:08:05 2009 by generateDS.py. +""" + +from string import lower as str_lower +from xml.dom import minidom +from xml.dom import Node + +import sys + +import compoundsuper as supermod +from compoundsuper import MixedContainer + + +class DoxygenTypeSub(supermod.DoxygenType): + def __init__(self, version=None, compounddef=None): + supermod.DoxygenType.__init__(self, version, compounddef) + + def find(self, details): + + return self.compounddef.find(details) + +supermod.DoxygenType.subclass = DoxygenTypeSub +# end class DoxygenTypeSub + + +class compounddefTypeSub(supermod.compounddefType): + def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None): + supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers) + + def find(self, details): + + if self.id == details.refid: + return self + + for sectiondef in self.sectiondef: + result = sectiondef.find(details) + if result: + return result + + +supermod.compounddefType.subclass = compounddefTypeSub +# end class compounddefTypeSub + + +class listofallmembersTypeSub(supermod.listofallmembersType): + def __init__(self, member=None): + supermod.listofallmembersType.__init__(self, member) +supermod.listofallmembersType.subclass = listofallmembersTypeSub +# end class listofallmembersTypeSub + + +class memberRefTypeSub(supermod.memberRefType): + def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope='', name=''): + supermod.memberRefType.__init__(self, virt, prot, refid, ambiguityscope, scope, name) +supermod.memberRefType.subclass = memberRefTypeSub +# end class memberRefTypeSub + + +class compoundRefTypeSub(supermod.compoundRefType): + def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + supermod.compoundRefType.__init__(self, mixedclass_, content_) +supermod.compoundRefType.subclass = compoundRefTypeSub +# end class compoundRefTypeSub + + +class reimplementTypeSub(supermod.reimplementType): + def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None): + supermod.reimplementType.__init__(self, mixedclass_, content_) +supermod.reimplementType.subclass = reimplementTypeSub +# end class reimplementTypeSub + + +class incTypeSub(supermod.incType): + def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + supermod.incType.__init__(self, mixedclass_, content_) +supermod.incType.subclass = incTypeSub +# end class incTypeSub + + +class refTypeSub(supermod.refType): + def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + supermod.refType.__init__(self, mixedclass_, content_) +supermod.refType.subclass = refTypeSub +# end class refTypeSub + + + +class refTextTypeSub(supermod.refTextType): + def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): + supermod.refTextType.__init__(self, mixedclass_, content_) + +supermod.refTextType.subclass = refTextTypeSub +# end class refTextTypeSub + +class sectiondefTypeSub(supermod.sectiondefType): + + + def __init__(self, kind=None, header='', description=None, memberdef=None): + supermod.sectiondefType.__init__(self, kind, header, description, memberdef) + + def find(self, details): + + for memberdef in self.memberdef: + if memberdef.id == details.refid: + return memberdef + + return None + + +supermod.sectiondefType.subclass = sectiondefTypeSub +# end class sectiondefTypeSub + + +class memberdefTypeSub(supermod.memberdefType): + def __init__(self, initonly=None, kind=None, volatile=None, const=None, raise_=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition='', argsstring='', name='', read='', write='', bitfield='', reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None): + supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_, definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby) +supermod.memberdefType.subclass = memberdefTypeSub +# end class memberdefTypeSub + + +class descriptionTypeSub(supermod.descriptionType): + def __init__(self, title='', para=None, sect1=None, internal=None, mixedclass_=None, content_=None): + supermod.descriptionType.__init__(self, mixedclass_, content_) +supermod.descriptionType.subclass = descriptionTypeSub +# end class descriptionTypeSub + + +class enumvalueTypeSub(supermod.enumvalueType): + def __init__(self, prot=None, id=None, name='', initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None): + supermod.enumvalueType.__init__(self, mixedclass_, content_) +supermod.enumvalueType.subclass = enumvalueTypeSub +# end class enumvalueTypeSub + + +class templateparamlistTypeSub(supermod.templateparamlistType): + def __init__(self, param=None): + supermod.templateparamlistType.__init__(self, param) +supermod.templateparamlistType.subclass = templateparamlistTypeSub +# end class templateparamlistTypeSub + + +class paramTypeSub(supermod.paramType): + def __init__(self, type_=None, declname='', defname='', array='', defval=None, briefdescription=None): + supermod.paramType.__init__(self, type_, declname, defname, array, defval, briefdescription) +supermod.paramType.subclass = paramTypeSub +# end class paramTypeSub + + +class linkedTextTypeSub(supermod.linkedTextType): + def __init__(self, ref=None, mixedclass_=None, content_=None): + supermod.linkedTextType.__init__(self, mixedclass_, content_) +supermod.linkedTextType.subclass = linkedTextTypeSub +# end class linkedTextTypeSub + + +class graphTypeSub(supermod.graphType): + def __init__(self, node=None): + supermod.graphType.__init__(self, node) +supermod.graphType.subclass = graphTypeSub +# end class graphTypeSub + + +class nodeTypeSub(supermod.nodeType): + def __init__(self, id=None, label='', link=None, childnode=None): + supermod.nodeType.__init__(self, id, label, link, childnode) +supermod.nodeType.subclass = nodeTypeSub +# end class nodeTypeSub + + +class childnodeTypeSub(supermod.childnodeType): + def __init__(self, relation=None, refid=None, edgelabel=None): + supermod.childnodeType.__init__(self, relation, refid, edgelabel) +supermod.childnodeType.subclass = childnodeTypeSub +# end class childnodeTypeSub + + +class linkTypeSub(supermod.linkType): + def __init__(self, refid=None, external=None, valueOf_=''): + supermod.linkType.__init__(self, refid, external) +supermod.linkType.subclass = linkTypeSub +# end class linkTypeSub + + +class listingTypeSub(supermod.listingType): + def __init__(self, codeline=None): + supermod.listingType.__init__(self, codeline) +supermod.listingType.subclass = listingTypeSub +# end class listingTypeSub + + +class codelineTypeSub(supermod.codelineType): + def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None): + supermod.codelineType.__init__(self, external, lineno, refkind, refid, highlight) +supermod.codelineType.subclass = codelineTypeSub +# end class codelineTypeSub + + +class highlightTypeSub(supermod.highlightType): + def __init__(self, class_=None, sp=None, ref=None, mixedclass_=None, content_=None): + supermod.highlightType.__init__(self, mixedclass_, content_) +supermod.highlightType.subclass = highlightTypeSub +# end class highlightTypeSub + + +class referenceTypeSub(supermod.referenceType): + def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None): + supermod.referenceType.__init__(self, mixedclass_, content_) +supermod.referenceType.subclass = referenceTypeSub +# end class referenceTypeSub + + +class locationTypeSub(supermod.locationType): + def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''): + supermod.locationType.__init__(self, bodystart, line, bodyend, bodyfile, file) +supermod.locationType.subclass = locationTypeSub +# end class locationTypeSub + + +class docSect1TypeSub(supermod.docSect1Type): + def __init__(self, id=None, title='', para=None, sect2=None, internal=None, mixedclass_=None, content_=None): + supermod.docSect1Type.__init__(self, mixedclass_, content_) +supermod.docSect1Type.subclass = docSect1TypeSub +# end class docSect1TypeSub + + +class docSect2TypeSub(supermod.docSect2Type): + def __init__(self, id=None, title='', para=None, sect3=None, internal=None, mixedclass_=None, content_=None): + supermod.docSect2Type.__init__(self, mixedclass_, content_) +supermod.docSect2Type.subclass = docSect2TypeSub +# end class docSect2TypeSub + + +class docSect3TypeSub(supermod.docSect3Type): + def __init__(self, id=None, title='', para=None, sect4=None, internal=None, mixedclass_=None, content_=None): + supermod.docSect3Type.__init__(self, mixedclass_, content_) +supermod.docSect3Type.subclass = docSect3TypeSub +# end class docSect3TypeSub + + +class docSect4TypeSub(supermod.docSect4Type): + def __init__(self, id=None, title='', para=None, internal=None, mixedclass_=None, content_=None): + supermod.docSect4Type.__init__(self, mixedclass_, content_) +supermod.docSect4Type.subclass = docSect4TypeSub +# end class docSect4TypeSub + + +class docInternalTypeSub(supermod.docInternalType): + def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None): + supermod.docInternalType.__init__(self, mixedclass_, content_) +supermod.docInternalType.subclass = docInternalTypeSub +# end class docInternalTypeSub + + +class docInternalS1TypeSub(supermod.docInternalS1Type): + def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None): + supermod.docInternalS1Type.__init__(self, mixedclass_, content_) +supermod.docInternalS1Type.subclass = docInternalS1TypeSub +# end class docInternalS1TypeSub + + +class docInternalS2TypeSub(supermod.docInternalS2Type): + def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): + supermod.docInternalS2Type.__init__(self, mixedclass_, content_) +supermod.docInternalS2Type.subclass = docInternalS2TypeSub +# end class docInternalS2TypeSub + + +class docInternalS3TypeSub(supermod.docInternalS3Type): + def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): + supermod.docInternalS3Type.__init__(self, mixedclass_, content_) +supermod.docInternalS3Type.subclass = docInternalS3TypeSub +# end class docInternalS3TypeSub + + +class docInternalS4TypeSub(supermod.docInternalS4Type): + def __init__(self, para=None, mixedclass_=None, content_=None): + supermod.docInternalS4Type.__init__(self, mixedclass_, content_) +supermod.docInternalS4Type.subclass = docInternalS4TypeSub +# end class docInternalS4TypeSub + + +class docURLLinkSub(supermod.docURLLink): + def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docURLLink.__init__(self, mixedclass_, content_) +supermod.docURLLink.subclass = docURLLinkSub +# end class docURLLinkSub + + +class docAnchorTypeSub(supermod.docAnchorType): + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docAnchorType.__init__(self, mixedclass_, content_) +supermod.docAnchorType.subclass = docAnchorTypeSub +# end class docAnchorTypeSub + + +class docFormulaTypeSub(supermod.docFormulaType): + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docFormulaType.__init__(self, mixedclass_, content_) +supermod.docFormulaType.subclass = docFormulaTypeSub +# end class docFormulaTypeSub + + +class docIndexEntryTypeSub(supermod.docIndexEntryType): + def __init__(self, primaryie='', secondaryie=''): + supermod.docIndexEntryType.__init__(self, primaryie, secondaryie) +supermod.docIndexEntryType.subclass = docIndexEntryTypeSub +# end class docIndexEntryTypeSub + + +class docListTypeSub(supermod.docListType): + def __init__(self, listitem=None): + supermod.docListType.__init__(self, listitem) +supermod.docListType.subclass = docListTypeSub +# end class docListTypeSub + + +class docListItemTypeSub(supermod.docListItemType): + def __init__(self, para=None): + supermod.docListItemType.__init__(self, para) +supermod.docListItemType.subclass = docListItemTypeSub +# end class docListItemTypeSub + + +class docSimpleSectTypeSub(supermod.docSimpleSectType): + def __init__(self, kind=None, title=None, para=None): + supermod.docSimpleSectType.__init__(self, kind, title, para) +supermod.docSimpleSectType.subclass = docSimpleSectTypeSub +# end class docSimpleSectTypeSub + + +class docVarListEntryTypeSub(supermod.docVarListEntryType): + def __init__(self, term=None): + supermod.docVarListEntryType.__init__(self, term) +supermod.docVarListEntryType.subclass = docVarListEntryTypeSub +# end class docVarListEntryTypeSub + + +class docRefTextTypeSub(supermod.docRefTextType): + def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docRefTextType.__init__(self, mixedclass_, content_) +supermod.docRefTextType.subclass = docRefTextTypeSub +# end class docRefTextTypeSub + + +class docTableTypeSub(supermod.docTableType): + def __init__(self, rows=None, cols=None, row=None, caption=None): + supermod.docTableType.__init__(self, rows, cols, row, caption) +supermod.docTableType.subclass = docTableTypeSub +# end class docTableTypeSub + + +class docRowTypeSub(supermod.docRowType): + def __init__(self, entry=None): + supermod.docRowType.__init__(self, entry) +supermod.docRowType.subclass = docRowTypeSub +# end class docRowTypeSub + + +class docEntryTypeSub(supermod.docEntryType): + def __init__(self, thead=None, para=None): + supermod.docEntryType.__init__(self, thead, para) +supermod.docEntryType.subclass = docEntryTypeSub +# end class docEntryTypeSub + + +class docHeadingTypeSub(supermod.docHeadingType): + def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docHeadingType.__init__(self, mixedclass_, content_) +supermod.docHeadingType.subclass = docHeadingTypeSub +# end class docHeadingTypeSub + + +class docImageTypeSub(supermod.docImageType): + def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docImageType.__init__(self, mixedclass_, content_) +supermod.docImageType.subclass = docImageTypeSub +# end class docImageTypeSub + + +class docDotFileTypeSub(supermod.docDotFileType): + def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docDotFileType.__init__(self, mixedclass_, content_) +supermod.docDotFileType.subclass = docDotFileTypeSub +# end class docDotFileTypeSub + + +class docTocItemTypeSub(supermod.docTocItemType): + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + supermod.docTocItemType.__init__(self, mixedclass_, content_) +supermod.docTocItemType.subclass = docTocItemTypeSub +# end class docTocItemTypeSub + + +class docTocListTypeSub(supermod.docTocListType): + def __init__(self, tocitem=None): + supermod.docTocListType.__init__(self, tocitem) +supermod.docTocListType.subclass = docTocListTypeSub +# end class docTocListTypeSub + + +class docLanguageTypeSub(supermod.docLanguageType): + def __init__(self, langid=None, para=None): + supermod.docLanguageType.__init__(self, langid, para) +supermod.docLanguageType.subclass = docLanguageTypeSub +# end class docLanguageTypeSub + + +class docParamListTypeSub(supermod.docParamListType): + def __init__(self, kind=None, parameteritem=None): + supermod.docParamListType.__init__(self, kind, parameteritem) +supermod.docParamListType.subclass = docParamListTypeSub +# end class docParamListTypeSub + + +class docParamListItemSub(supermod.docParamListItem): + def __init__(self, parameternamelist=None, parameterdescription=None): + supermod.docParamListItem.__init__(self, parameternamelist, parameterdescription) +supermod.docParamListItem.subclass = docParamListItemSub +# end class docParamListItemSub + + +class docParamNameListSub(supermod.docParamNameList): + def __init__(self, parametername=None): + supermod.docParamNameList.__init__(self, parametername) +supermod.docParamNameList.subclass = docParamNameListSub +# end class docParamNameListSub + + +class docParamNameSub(supermod.docParamName): + def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None): + supermod.docParamName.__init__(self, mixedclass_, content_) +supermod.docParamName.subclass = docParamNameSub +# end class docParamNameSub + + +class docXRefSectTypeSub(supermod.docXRefSectType): + def __init__(self, id=None, xreftitle=None, xrefdescription=None): + supermod.docXRefSectType.__init__(self, id, xreftitle, xrefdescription) +supermod.docXRefSectType.subclass = docXRefSectTypeSub +# end class docXRefSectTypeSub + + +class docCopyTypeSub(supermod.docCopyType): + def __init__(self, link=None, para=None, sect1=None, internal=None): + supermod.docCopyType.__init__(self, link, para, sect1, internal) +supermod.docCopyType.subclass = docCopyTypeSub +# end class docCopyTypeSub + + +class docCharTypeSub(supermod.docCharType): + def __init__(self, char=None, valueOf_=''): + supermod.docCharType.__init__(self, char) +supermod.docCharType.subclass = docCharTypeSub +# end class docCharTypeSub + +class docParaTypeSub(supermod.docParaType): + def __init__(self, char=None, valueOf_=''): + supermod.docParaType.__init__(self, char) + + self.parameterlist = [] + self.simplesects = [] + self.content = [] + + def buildChildren(self, child_, nodeName_): + supermod.docParaType.buildChildren(self, child_, nodeName_) + + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == "ref": + obj_ = supermod.docRefTextType.factory() + obj_.build(child_) + self.content.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'parameterlist': + obj_ = supermod.docParamListType.factory() + obj_.build(child_) + self.parameterlist.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'simplesect': + obj_ = supermod.docSimpleSectType.factory() + obj_.build(child_) + self.simplesects.append(obj_) + + +supermod.docParaType.subclass = docParaTypeSub +# end class docParaTypeSub + + + +def parse(inFilename): + doc = minidom.parse(inFilename) + rootNode = doc.documentElement + rootObj = supermod.DoxygenType.factory() + rootObj.build(rootNode) + return rootObj + + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compoundsuper.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compoundsuper.py new file mode 100644 index 000000000..6255dda16 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/compoundsuper.py @@ -0,0 +1,8342 @@ +#!/usr/bin/env python + +# +# Generated Thu Jun 11 18:44:25 2009 by generateDS.py. +# + +import sys +import getopt +from string import lower as str_lower +from xml.dom import minidom +from xml.dom import Node + +# +# User methods +# +# Calls to the methods in these classes are generated by generateDS.py. +# You can replace these methods by re-implementing the following class +# in a module named generatedssuper.py. + +try: + from generatedssuper import GeneratedsSuper +except ImportError, exp: + + class GeneratedsSuper: + def format_string(self, input_data, input_name=''): + return input_data + def format_integer(self, input_data, input_name=''): + return '%d' % input_data + def format_float(self, input_data, input_name=''): + return '%f' % input_data + def format_double(self, input_data, input_name=''): + return '%e' % input_data + def format_boolean(self, input_data, input_name=''): + return '%s' % input_data + + +# +# If you have installed IPython you can uncomment and use the following. +# IPython is available from http://ipython.scipy.org/. +# + +## from IPython.Shell import IPShellEmbed +## args = '' +## ipshell = IPShellEmbed(args, +## banner = 'Dropping into IPython', +## exit_msg = 'Leaving Interpreter, back to program.') + +# Then use the following line where and when you want to drop into the +# IPython shell: +# ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') + +# +# Globals +# + +ExternalEncoding = 'ascii' + +# +# Support/utility functions. +# + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(' ') + +def quote_xml(inStr): + s1 = (isinstance(inStr, basestring) and inStr or + '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + return s1 + +def quote_attrib(inStr): + s1 = (isinstance(inStr, basestring) and inStr or + '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + if '"' in s1: + if "'" in s1: + s1 = '"%s"' % s1.replace('"', """) + else: + s1 = "'%s'" % s1 + else: + s1 = '"%s"' % s1 + return s1 + +def quote_python(inStr): + s1 = inStr + if s1.find("'") == -1: + if s1.find('\n') == -1: + return "'%s'" % s1 + else: + return "'''%s'''" % s1 + else: + if s1.find('"') != -1: + s1 = s1.replace('"', '\\"') + if s1.find('\n') == -1: + return '"%s"' % s1 + else: + return '"""%s"""' % s1 + + +class MixedContainer: + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name, namespace): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, namespace,name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write('<%s>%s' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write('<%s>%d' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write('<%s>%f' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write('<%s>%g' % (self.name, self.value, self.name)) + def exportLiteral(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ + (self.category, self.content_type, self.name, self.value)) + elif self.category == MixedContainer.CategorySimple: + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ + (self.category, self.content_type, self.name, self.value)) + else: # category == MixedContainer.CategoryComplex + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s",\n' % \ + (self.category, self.content_type, self.name,)) + self.value.exportLiteral(outfile, level + 1) + showIndent(outfile, level) + outfile.write(')\n') + + +class _MemberSpec(object): + def __init__(self, name='', data_type='', container=0): + self.name = name + self.data_type = data_type + self.container = container + def set_name(self, name): self.name = name + def get_name(self): return self.name + def set_data_type(self, data_type): self.data_type = data_type + def get_data_type(self): return self.data_type + def set_container(self, container): self.container = container + def get_container(self): return self.container + + +# +# Data representation classes. +# + +class DoxygenType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, version=None, compounddef=None): + self.version = version + self.compounddef = compounddef + def factory(*args_, **kwargs_): + if DoxygenType.subclass: + return DoxygenType.subclass(*args_, **kwargs_) + else: + return DoxygenType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_compounddef(self): return self.compounddef + def set_compounddef(self, compounddef): self.compounddef = compounddef + def get_version(self): return self.version + def set_version(self, version): self.version = version + def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='DoxygenType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'): + outfile.write(' version=%s' % (quote_attrib(self.version), )) + def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'): + if self.compounddef: + self.compounddef.export(outfile, level, namespace_, name_='compounddef') + def hasContent_(self): + if ( + self.compounddef is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='DoxygenType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.version is not None: + showIndent(outfile, level) + outfile.write('version = "%s",\n' % (self.version,)) + def exportLiteralChildren(self, outfile, level, name_): + if self.compounddef: + showIndent(outfile, level) + outfile.write('compounddef=model_.compounddefType(\n') + self.compounddef.exportLiteral(outfile, level, name_='compounddef') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('version'): + self.version = attrs.get('version').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'compounddef': + obj_ = compounddefType.factory() + obj_.build(child_) + self.set_compounddef(obj_) +# end class DoxygenType + + +class compounddefType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, prot=None, id=None, compoundname=None, title=None, basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None): + self.kind = kind + self.prot = prot + self.id = id + self.compoundname = compoundname + self.title = title + if basecompoundref is None: + self.basecompoundref = [] + else: + self.basecompoundref = basecompoundref + if derivedcompoundref is None: + self.derivedcompoundref = [] + else: + self.derivedcompoundref = derivedcompoundref + if includes is None: + self.includes = [] + else: + self.includes = includes + if includedby is None: + self.includedby = [] + else: + self.includedby = includedby + self.incdepgraph = incdepgraph + self.invincdepgraph = invincdepgraph + if innerdir is None: + self.innerdir = [] + else: + self.innerdir = innerdir + if innerfile is None: + self.innerfile = [] + else: + self.innerfile = innerfile + if innerclass is None: + self.innerclass = [] + else: + self.innerclass = innerclass + if innernamespace is None: + self.innernamespace = [] + else: + self.innernamespace = innernamespace + if innerpage is None: + self.innerpage = [] + else: + self.innerpage = innerpage + if innergroup is None: + self.innergroup = [] + else: + self.innergroup = innergroup + self.templateparamlist = templateparamlist + if sectiondef is None: + self.sectiondef = [] + else: + self.sectiondef = sectiondef + self.briefdescription = briefdescription + self.detaileddescription = detaileddescription + self.inheritancegraph = inheritancegraph + self.collaborationgraph = collaborationgraph + self.programlisting = programlisting + self.location = location + self.listofallmembers = listofallmembers + def factory(*args_, **kwargs_): + if compounddefType.subclass: + return compounddefType.subclass(*args_, **kwargs_) + else: + return compounddefType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_compoundname(self): return self.compoundname + def set_compoundname(self, compoundname): self.compoundname = compoundname + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_basecompoundref(self): return self.basecompoundref + def set_basecompoundref(self, basecompoundref): self.basecompoundref = basecompoundref + def add_basecompoundref(self, value): self.basecompoundref.append(value) + def insert_basecompoundref(self, index, value): self.basecompoundref[index] = value + def get_derivedcompoundref(self): return self.derivedcompoundref + def set_derivedcompoundref(self, derivedcompoundref): self.derivedcompoundref = derivedcompoundref + def add_derivedcompoundref(self, value): self.derivedcompoundref.append(value) + def insert_derivedcompoundref(self, index, value): self.derivedcompoundref[index] = value + def get_includes(self): return self.includes + def set_includes(self, includes): self.includes = includes + def add_includes(self, value): self.includes.append(value) + def insert_includes(self, index, value): self.includes[index] = value + def get_includedby(self): return self.includedby + def set_includedby(self, includedby): self.includedby = includedby + def add_includedby(self, value): self.includedby.append(value) + def insert_includedby(self, index, value): self.includedby[index] = value + def get_incdepgraph(self): return self.incdepgraph + def set_incdepgraph(self, incdepgraph): self.incdepgraph = incdepgraph + def get_invincdepgraph(self): return self.invincdepgraph + def set_invincdepgraph(self, invincdepgraph): self.invincdepgraph = invincdepgraph + def get_innerdir(self): return self.innerdir + def set_innerdir(self, innerdir): self.innerdir = innerdir + def add_innerdir(self, value): self.innerdir.append(value) + def insert_innerdir(self, index, value): self.innerdir[index] = value + def get_innerfile(self): return self.innerfile + def set_innerfile(self, innerfile): self.innerfile = innerfile + def add_innerfile(self, value): self.innerfile.append(value) + def insert_innerfile(self, index, value): self.innerfile[index] = value + def get_innerclass(self): return self.innerclass + def set_innerclass(self, innerclass): self.innerclass = innerclass + def add_innerclass(self, value): self.innerclass.append(value) + def insert_innerclass(self, index, value): self.innerclass[index] = value + def get_innernamespace(self): return self.innernamespace + def set_innernamespace(self, innernamespace): self.innernamespace = innernamespace + def add_innernamespace(self, value): self.innernamespace.append(value) + def insert_innernamespace(self, index, value): self.innernamespace[index] = value + def get_innerpage(self): return self.innerpage + def set_innerpage(self, innerpage): self.innerpage = innerpage + def add_innerpage(self, value): self.innerpage.append(value) + def insert_innerpage(self, index, value): self.innerpage[index] = value + def get_innergroup(self): return self.innergroup + def set_innergroup(self, innergroup): self.innergroup = innergroup + def add_innergroup(self, value): self.innergroup.append(value) + def insert_innergroup(self, index, value): self.innergroup[index] = value + def get_templateparamlist(self): return self.templateparamlist + def set_templateparamlist(self, templateparamlist): self.templateparamlist = templateparamlist + def get_sectiondef(self): return self.sectiondef + def set_sectiondef(self, sectiondef): self.sectiondef = sectiondef + def add_sectiondef(self, value): self.sectiondef.append(value) + def insert_sectiondef(self, index, value): self.sectiondef[index] = value + def get_briefdescription(self): return self.briefdescription + def set_briefdescription(self, briefdescription): self.briefdescription = briefdescription + def get_detaileddescription(self): return self.detaileddescription + def set_detaileddescription(self, detaileddescription): self.detaileddescription = detaileddescription + def get_inheritancegraph(self): return self.inheritancegraph + def set_inheritancegraph(self, inheritancegraph): self.inheritancegraph = inheritancegraph + def get_collaborationgraph(self): return self.collaborationgraph + def set_collaborationgraph(self, collaborationgraph): self.collaborationgraph = collaborationgraph + def get_programlisting(self): return self.programlisting + def set_programlisting(self, programlisting): self.programlisting = programlisting + def get_location(self): return self.location + def set_location(self, location): self.location = location + def get_listofallmembers(self): return self.listofallmembers + def set_listofallmembers(self, listofallmembers): self.listofallmembers = listofallmembers + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='compounddefType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='compounddefType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='compounddefType'): + if self.kind is not None: + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='compounddefType'): + if self.compoundname is not None: + showIndent(outfile, level) + outfile.write('<%scompoundname>%s\n' % (namespace_, self.format_string(quote_xml(self.compoundname).encode(ExternalEncoding), input_name='compoundname'), namespace_)) + if self.title is not None: + showIndent(outfile, level) + outfile.write('<%stitle>%s\n' % (namespace_, self.format_string(quote_xml(self.title).encode(ExternalEncoding), input_name='title'), namespace_)) + for basecompoundref_ in self.basecompoundref: + basecompoundref_.export(outfile, level, namespace_, name_='basecompoundref') + for derivedcompoundref_ in self.derivedcompoundref: + derivedcompoundref_.export(outfile, level, namespace_, name_='derivedcompoundref') + for includes_ in self.includes: + includes_.export(outfile, level, namespace_, name_='includes') + for includedby_ in self.includedby: + includedby_.export(outfile, level, namespace_, name_='includedby') + if self.incdepgraph: + self.incdepgraph.export(outfile, level, namespace_, name_='incdepgraph') + if self.invincdepgraph: + self.invincdepgraph.export(outfile, level, namespace_, name_='invincdepgraph') + for innerdir_ in self.innerdir: + innerdir_.export(outfile, level, namespace_, name_='innerdir') + for innerfile_ in self.innerfile: + innerfile_.export(outfile, level, namespace_, name_='innerfile') + for innerclass_ in self.innerclass: + innerclass_.export(outfile, level, namespace_, name_='innerclass') + for innernamespace_ in self.innernamespace: + innernamespace_.export(outfile, level, namespace_, name_='innernamespace') + for innerpage_ in self.innerpage: + innerpage_.export(outfile, level, namespace_, name_='innerpage') + for innergroup_ in self.innergroup: + innergroup_.export(outfile, level, namespace_, name_='innergroup') + if self.templateparamlist: + self.templateparamlist.export(outfile, level, namespace_, name_='templateparamlist') + for sectiondef_ in self.sectiondef: + sectiondef_.export(outfile, level, namespace_, name_='sectiondef') + if self.briefdescription: + self.briefdescription.export(outfile, level, namespace_, name_='briefdescription') + if self.detaileddescription: + self.detaileddescription.export(outfile, level, namespace_, name_='detaileddescription') + if self.inheritancegraph: + self.inheritancegraph.export(outfile, level, namespace_, name_='inheritancegraph') + if self.collaborationgraph: + self.collaborationgraph.export(outfile, level, namespace_, name_='collaborationgraph') + if self.programlisting: + self.programlisting.export(outfile, level, namespace_, name_='programlisting') + if self.location: + self.location.export(outfile, level, namespace_, name_='location') + if self.listofallmembers: + self.listofallmembers.export(outfile, level, namespace_, name_='listofallmembers') + def hasContent_(self): + if ( + self.compoundname is not None or + self.title is not None or + self.basecompoundref is not None or + self.derivedcompoundref is not None or + self.includes is not None or + self.includedby is not None or + self.incdepgraph is not None or + self.invincdepgraph is not None or + self.innerdir is not None or + self.innerfile is not None or + self.innerclass is not None or + self.innernamespace is not None or + self.innerpage is not None or + self.innergroup is not None or + self.templateparamlist is not None or + self.sectiondef is not None or + self.briefdescription is not None or + self.detaileddescription is not None or + self.inheritancegraph is not None or + self.collaborationgraph is not None or + self.programlisting is not None or + self.location is not None or + self.listofallmembers is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='compounddefType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('compoundname=%s,\n' % quote_python(self.compoundname).encode(ExternalEncoding)) + if self.title: + showIndent(outfile, level) + outfile.write('title=model_.xsd_string(\n') + self.title.exportLiteral(outfile, level, name_='title') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('basecompoundref=[\n') + level += 1 + for basecompoundref in self.basecompoundref: + showIndent(outfile, level) + outfile.write('model_.basecompoundref(\n') + basecompoundref.exportLiteral(outfile, level, name_='basecompoundref') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('derivedcompoundref=[\n') + level += 1 + for derivedcompoundref in self.derivedcompoundref: + showIndent(outfile, level) + outfile.write('model_.derivedcompoundref(\n') + derivedcompoundref.exportLiteral(outfile, level, name_='derivedcompoundref') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('includes=[\n') + level += 1 + for includes in self.includes: + showIndent(outfile, level) + outfile.write('model_.includes(\n') + includes.exportLiteral(outfile, level, name_='includes') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('includedby=[\n') + level += 1 + for includedby in self.includedby: + showIndent(outfile, level) + outfile.write('model_.includedby(\n') + includedby.exportLiteral(outfile, level, name_='includedby') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.incdepgraph: + showIndent(outfile, level) + outfile.write('incdepgraph=model_.graphType(\n') + self.incdepgraph.exportLiteral(outfile, level, name_='incdepgraph') + showIndent(outfile, level) + outfile.write('),\n') + if self.invincdepgraph: + showIndent(outfile, level) + outfile.write('invincdepgraph=model_.graphType(\n') + self.invincdepgraph.exportLiteral(outfile, level, name_='invincdepgraph') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('innerdir=[\n') + level += 1 + for innerdir in self.innerdir: + showIndent(outfile, level) + outfile.write('model_.innerdir(\n') + innerdir.exportLiteral(outfile, level, name_='innerdir') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('innerfile=[\n') + level += 1 + for innerfile in self.innerfile: + showIndent(outfile, level) + outfile.write('model_.innerfile(\n') + innerfile.exportLiteral(outfile, level, name_='innerfile') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('innerclass=[\n') + level += 1 + for innerclass in self.innerclass: + showIndent(outfile, level) + outfile.write('model_.innerclass(\n') + innerclass.exportLiteral(outfile, level, name_='innerclass') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('innernamespace=[\n') + level += 1 + for innernamespace in self.innernamespace: + showIndent(outfile, level) + outfile.write('model_.innernamespace(\n') + innernamespace.exportLiteral(outfile, level, name_='innernamespace') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('innerpage=[\n') + level += 1 + for innerpage in self.innerpage: + showIndent(outfile, level) + outfile.write('model_.innerpage(\n') + innerpage.exportLiteral(outfile, level, name_='innerpage') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('innergroup=[\n') + level += 1 + for innergroup in self.innergroup: + showIndent(outfile, level) + outfile.write('model_.innergroup(\n') + innergroup.exportLiteral(outfile, level, name_='innergroup') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.templateparamlist: + showIndent(outfile, level) + outfile.write('templateparamlist=model_.templateparamlistType(\n') + self.templateparamlist.exportLiteral(outfile, level, name_='templateparamlist') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('sectiondef=[\n') + level += 1 + for sectiondef in self.sectiondef: + showIndent(outfile, level) + outfile.write('model_.sectiondef(\n') + sectiondef.exportLiteral(outfile, level, name_='sectiondef') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.briefdescription: + showIndent(outfile, level) + outfile.write('briefdescription=model_.descriptionType(\n') + self.briefdescription.exportLiteral(outfile, level, name_='briefdescription') + showIndent(outfile, level) + outfile.write('),\n') + if self.detaileddescription: + showIndent(outfile, level) + outfile.write('detaileddescription=model_.descriptionType(\n') + self.detaileddescription.exportLiteral(outfile, level, name_='detaileddescription') + showIndent(outfile, level) + outfile.write('),\n') + if self.inheritancegraph: + showIndent(outfile, level) + outfile.write('inheritancegraph=model_.graphType(\n') + self.inheritancegraph.exportLiteral(outfile, level, name_='inheritancegraph') + showIndent(outfile, level) + outfile.write('),\n') + if self.collaborationgraph: + showIndent(outfile, level) + outfile.write('collaborationgraph=model_.graphType(\n') + self.collaborationgraph.exportLiteral(outfile, level, name_='collaborationgraph') + showIndent(outfile, level) + outfile.write('),\n') + if self.programlisting: + showIndent(outfile, level) + outfile.write('programlisting=model_.listingType(\n') + self.programlisting.exportLiteral(outfile, level, name_='programlisting') + showIndent(outfile, level) + outfile.write('),\n') + if self.location: + showIndent(outfile, level) + outfile.write('location=model_.locationType(\n') + self.location.exportLiteral(outfile, level, name_='location') + showIndent(outfile, level) + outfile.write('),\n') + if self.listofallmembers: + showIndent(outfile, level) + outfile.write('listofallmembers=model_.listofallmembersType(\n') + self.listofallmembers.exportLiteral(outfile, level, name_='listofallmembers') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'compoundname': + compoundname_ = '' + for text__content_ in child_.childNodes: + compoundname_ += text__content_.nodeValue + self.compoundname = compoundname_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + obj_ = docTitleType.factory() + obj_.build(child_) + self.set_title(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'basecompoundref': + obj_ = compoundRefType.factory() + obj_.build(child_) + self.basecompoundref.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'derivedcompoundref': + obj_ = compoundRefType.factory() + obj_.build(child_) + self.derivedcompoundref.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'includes': + obj_ = incType.factory() + obj_.build(child_) + self.includes.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'includedby': + obj_ = incType.factory() + obj_.build(child_) + self.includedby.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'incdepgraph': + obj_ = graphType.factory() + obj_.build(child_) + self.set_incdepgraph(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'invincdepgraph': + obj_ = graphType.factory() + obj_.build(child_) + self.set_invincdepgraph(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innerdir': + obj_ = refType.factory() + obj_.build(child_) + self.innerdir.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innerfile': + obj_ = refType.factory() + obj_.build(child_) + self.innerfile.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innerclass': + obj_ = refType.factory() + obj_.build(child_) + self.innerclass.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innernamespace': + obj_ = refType.factory() + obj_.build(child_) + self.innernamespace.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innerpage': + obj_ = refType.factory() + obj_.build(child_) + self.innerpage.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'innergroup': + obj_ = refType.factory() + obj_.build(child_) + self.innergroup.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'templateparamlist': + obj_ = templateparamlistType.factory() + obj_.build(child_) + self.set_templateparamlist(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sectiondef': + obj_ = sectiondefType.factory() + obj_.build(child_) + self.sectiondef.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'briefdescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_briefdescription(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detaileddescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_detaileddescription(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'inheritancegraph': + obj_ = graphType.factory() + obj_.build(child_) + self.set_inheritancegraph(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'collaborationgraph': + obj_ = graphType.factory() + obj_.build(child_) + self.set_collaborationgraph(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'programlisting': + obj_ = listingType.factory() + obj_.build(child_) + self.set_programlisting(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'location': + obj_ = locationType.factory() + obj_.build(child_) + self.set_location(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'listofallmembers': + obj_ = listofallmembersType.factory() + obj_.build(child_) + self.set_listofallmembers(obj_) +# end class compounddefType + + +class listofallmembersType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, member=None): + if member is None: + self.member = [] + else: + self.member = member + def factory(*args_, **kwargs_): + if listofallmembersType.subclass: + return listofallmembersType.subclass(*args_, **kwargs_) + else: + return listofallmembersType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_member(self): return self.member + def set_member(self, member): self.member = member + def add_member(self, value): self.member.append(value) + def insert_member(self, index, value): self.member[index] = value + def export(self, outfile, level, namespace_='', name_='listofallmembersType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='listofallmembersType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='listofallmembersType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='listofallmembersType'): + for member_ in self.member: + member_.export(outfile, level, namespace_, name_='member') + def hasContent_(self): + if ( + self.member is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='listofallmembersType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('member=[\n') + level += 1 + for member in self.member: + showIndent(outfile, level) + outfile.write('model_.member(\n') + member.exportLiteral(outfile, level, name_='member') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'member': + obj_ = memberRefType.factory() + obj_.build(child_) + self.member.append(obj_) +# end class listofallmembersType + + +class memberRefType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope=None, name=None): + self.virt = virt + self.prot = prot + self.refid = refid + self.ambiguityscope = ambiguityscope + self.scope = scope + self.name = name + def factory(*args_, **kwargs_): + if memberRefType.subclass: + return memberRefType.subclass(*args_, **kwargs_) + else: + return memberRefType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_scope(self): return self.scope + def set_scope(self, scope): self.scope = scope + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_virt(self): return self.virt + def set_virt(self, virt): self.virt = virt + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def get_ambiguityscope(self): return self.ambiguityscope + def set_ambiguityscope(self, ambiguityscope): self.ambiguityscope = ambiguityscope + def export(self, outfile, level, namespace_='', name_='memberRefType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='memberRefType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='memberRefType'): + if self.virt is not None: + outfile.write(' virt=%s' % (quote_attrib(self.virt), )) + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + if self.ambiguityscope is not None: + outfile.write(' ambiguityscope=%s' % (self.format_string(quote_attrib(self.ambiguityscope).encode(ExternalEncoding), input_name='ambiguityscope'), )) + def exportChildren(self, outfile, level, namespace_='', name_='memberRefType'): + if self.scope is not None: + showIndent(outfile, level) + outfile.write('<%sscope>%s\n' % (namespace_, self.format_string(quote_xml(self.scope).encode(ExternalEncoding), input_name='scope'), namespace_)) + if self.name is not None: + showIndent(outfile, level) + outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) + def hasContent_(self): + if ( + self.scope is not None or + self.name is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='memberRefType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.virt is not None: + showIndent(outfile, level) + outfile.write('virt = "%s",\n' % (self.virt,)) + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + if self.ambiguityscope is not None: + showIndent(outfile, level) + outfile.write('ambiguityscope = %s,\n' % (self.ambiguityscope,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('scope=%s,\n' % quote_python(self.scope).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('virt'): + self.virt = attrs.get('virt').value + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + if attrs.get('ambiguityscope'): + self.ambiguityscope = attrs.get('ambiguityscope').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'scope': + scope_ = '' + for text__content_ in child_.childNodes: + scope_ += text__content_.nodeValue + self.scope = scope_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'name': + name_ = '' + for text__content_ in child_.childNodes: + name_ += text__content_.nodeValue + self.name = name_ +# end class memberRefType + + +class scope(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if scope.subclass: + return scope.subclass(*args_, **kwargs_) + else: + return scope(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='scope', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='scope') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='scope'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='scope'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='scope'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class scope + + +class name(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if name.subclass: + return name.subclass(*args_, **kwargs_) + else: + return name(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='name', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='name') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='name'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='name'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='name'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class name + + +class compoundRefType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + self.virt = virt + self.prot = prot + self.refid = refid + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if compoundRefType.subclass: + return compoundRefType.subclass(*args_, **kwargs_) + else: + return compoundRefType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_virt(self): return self.virt + def set_virt(self, virt): self.virt = virt + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='compoundRefType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='compoundRefType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='compoundRefType'): + if self.virt is not None: + outfile.write(' virt=%s' % (quote_attrib(self.virt), )) + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='compoundRefType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='compoundRefType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.virt is not None: + showIndent(outfile, level) + outfile.write('virt = "%s",\n' % (self.virt,)) + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('virt'): + self.virt = attrs.get('virt').value + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class compoundRefType + + +class reimplementType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None): + self.refid = refid + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if reimplementType.subclass: + return reimplementType.subclass(*args_, **kwargs_) + else: + return reimplementType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='reimplementType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='reimplementType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='reimplementType'): + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='reimplementType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='reimplementType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class reimplementType + + +class incType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + self.local = local + self.refid = refid + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if incType.subclass: + return incType.subclass(*args_, **kwargs_) + else: + return incType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_local(self): return self.local + def set_local(self, local): self.local = local + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='incType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='incType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='incType'): + if self.local is not None: + outfile.write(' local=%s' % (quote_attrib(self.local), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='incType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='incType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.local is not None: + showIndent(outfile, level) + outfile.write('local = "%s",\n' % (self.local,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('local'): + self.local = attrs.get('local').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class incType + + +class refType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): + self.prot = prot + self.refid = refid + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if refType.subclass: + return refType.subclass(*args_, **kwargs_) + else: + return refType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='refType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='refType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='refType'): + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='refType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='refType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class refType + + +class refTextType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): + self.refid = refid + self.kindref = kindref + self.external = external + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if refTextType.subclass: + return refTextType.subclass(*args_, **kwargs_) + else: + return refTextType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def get_kindref(self): return self.kindref + def set_kindref(self, kindref): self.kindref = kindref + def get_external(self): return self.external + def set_external(self, external): self.external = external + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='refTextType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='refTextType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='refTextType'): + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + if self.kindref is not None: + outfile.write(' kindref=%s' % (quote_attrib(self.kindref), )) + if self.external is not None: + outfile.write(' external=%s' % (self.format_string(quote_attrib(self.external).encode(ExternalEncoding), input_name='external'), )) + def exportChildren(self, outfile, level, namespace_='', name_='refTextType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='refTextType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + if self.kindref is not None: + showIndent(outfile, level) + outfile.write('kindref = "%s",\n' % (self.kindref,)) + if self.external is not None: + showIndent(outfile, level) + outfile.write('external = %s,\n' % (self.external,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('refid'): + self.refid = attrs.get('refid').value + if attrs.get('kindref'): + self.kindref = attrs.get('kindref').value + if attrs.get('external'): + self.external = attrs.get('external').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class refTextType + + +class sectiondefType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, header=None, description=None, memberdef=None): + self.kind = kind + self.header = header + self.description = description + if memberdef is None: + self.memberdef = [] + else: + self.memberdef = memberdef + def factory(*args_, **kwargs_): + if sectiondefType.subclass: + return sectiondefType.subclass(*args_, **kwargs_) + else: + return sectiondefType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_header(self): return self.header + def set_header(self, header): self.header = header + def get_description(self): return self.description + def set_description(self, description): self.description = description + def get_memberdef(self): return self.memberdef + def set_memberdef(self, memberdef): self.memberdef = memberdef + def add_memberdef(self, value): self.memberdef.append(value) + def insert_memberdef(self, index, value): self.memberdef[index] = value + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def export(self, outfile, level, namespace_='', name_='sectiondefType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='sectiondefType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='sectiondefType'): + if self.kind is not None: + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + def exportChildren(self, outfile, level, namespace_='', name_='sectiondefType'): + if self.header is not None: + showIndent(outfile, level) + outfile.write('<%sheader>%s\n' % (namespace_, self.format_string(quote_xml(self.header).encode(ExternalEncoding), input_name='header'), namespace_)) + if self.description: + self.description.export(outfile, level, namespace_, name_='description') + for memberdef_ in self.memberdef: + memberdef_.export(outfile, level, namespace_, name_='memberdef') + def hasContent_(self): + if ( + self.header is not None or + self.description is not None or + self.memberdef is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='sectiondefType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('header=%s,\n' % quote_python(self.header).encode(ExternalEncoding)) + if self.description: + showIndent(outfile, level) + outfile.write('description=model_.descriptionType(\n') + self.description.exportLiteral(outfile, level, name_='description') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('memberdef=[\n') + level += 1 + for memberdef in self.memberdef: + showIndent(outfile, level) + outfile.write('model_.memberdef(\n') + memberdef.exportLiteral(outfile, level, name_='memberdef') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'header': + header_ = '' + for text__content_ in child_.childNodes: + header_ += text__content_.nodeValue + self.header = header_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'description': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_description(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'memberdef': + obj_ = memberdefType.factory() + obj_.build(child_) + self.memberdef.append(obj_) +# end class sectiondefType + + +class memberdefType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, initonly=None, kind=None, volatile=None, const=None, raisexx=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition=None, argsstring=None, name=None, read=None, write=None, bitfield=None, reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None): + self.initonly = initonly + self.kind = kind + self.volatile = volatile + self.const = const + self.raisexx = raisexx + self.virt = virt + self.readable = readable + self.prot = prot + self.explicit = explicit + self.new = new + self.final = final + self.writable = writable + self.add = add + self.static = static + self.remove = remove + self.sealed = sealed + self.mutable = mutable + self.gettable = gettable + self.inline = inline + self.settable = settable + self.id = id + self.templateparamlist = templateparamlist + self.type_ = type_ + self.definition = definition + self.argsstring = argsstring + self.name = name + self.read = read + self.write = write + self.bitfield = bitfield + if reimplements is None: + self.reimplements = [] + else: + self.reimplements = reimplements + if reimplementedby is None: + self.reimplementedby = [] + else: + self.reimplementedby = reimplementedby + if param is None: + self.param = [] + else: + self.param = param + if enumvalue is None: + self.enumvalue = [] + else: + self.enumvalue = enumvalue + self.initializer = initializer + self.exceptions = exceptions + self.briefdescription = briefdescription + self.detaileddescription = detaileddescription + self.inbodydescription = inbodydescription + self.location = location + if references is None: + self.references = [] + else: + self.references = references + if referencedby is None: + self.referencedby = [] + else: + self.referencedby = referencedby + def factory(*args_, **kwargs_): + if memberdefType.subclass: + return memberdefType.subclass(*args_, **kwargs_) + else: + return memberdefType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_templateparamlist(self): return self.templateparamlist + def set_templateparamlist(self, templateparamlist): self.templateparamlist = templateparamlist + def get_type(self): return self.type_ + def set_type(self, type_): self.type_ = type_ + def get_definition(self): return self.definition + def set_definition(self, definition): self.definition = definition + def get_argsstring(self): return self.argsstring + def set_argsstring(self, argsstring): self.argsstring = argsstring + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_read(self): return self.read + def set_read(self, read): self.read = read + def get_write(self): return self.write + def set_write(self, write): self.write = write + def get_bitfield(self): return self.bitfield + def set_bitfield(self, bitfield): self.bitfield = bitfield + def get_reimplements(self): return self.reimplements + def set_reimplements(self, reimplements): self.reimplements = reimplements + def add_reimplements(self, value): self.reimplements.append(value) + def insert_reimplements(self, index, value): self.reimplements[index] = value + def get_reimplementedby(self): return self.reimplementedby + def set_reimplementedby(self, reimplementedby): self.reimplementedby = reimplementedby + def add_reimplementedby(self, value): self.reimplementedby.append(value) + def insert_reimplementedby(self, index, value): self.reimplementedby[index] = value + def get_param(self): return self.param + def set_param(self, param): self.param = param + def add_param(self, value): self.param.append(value) + def insert_param(self, index, value): self.param[index] = value + def get_enumvalue(self): return self.enumvalue + def set_enumvalue(self, enumvalue): self.enumvalue = enumvalue + def add_enumvalue(self, value): self.enumvalue.append(value) + def insert_enumvalue(self, index, value): self.enumvalue[index] = value + def get_initializer(self): return self.initializer + def set_initializer(self, initializer): self.initializer = initializer + def get_exceptions(self): return self.exceptions + def set_exceptions(self, exceptions): self.exceptions = exceptions + def get_briefdescription(self): return self.briefdescription + def set_briefdescription(self, briefdescription): self.briefdescription = briefdescription + def get_detaileddescription(self): return self.detaileddescription + def set_detaileddescription(self, detaileddescription): self.detaileddescription = detaileddescription + def get_inbodydescription(self): return self.inbodydescription + def set_inbodydescription(self, inbodydescription): self.inbodydescription = inbodydescription + def get_location(self): return self.location + def set_location(self, location): self.location = location + def get_references(self): return self.references + def set_references(self, references): self.references = references + def add_references(self, value): self.references.append(value) + def insert_references(self, index, value): self.references[index] = value + def get_referencedby(self): return self.referencedby + def set_referencedby(self, referencedby): self.referencedby = referencedby + def add_referencedby(self, value): self.referencedby.append(value) + def insert_referencedby(self, index, value): self.referencedby[index] = value + def get_initonly(self): return self.initonly + def set_initonly(self, initonly): self.initonly = initonly + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def get_volatile(self): return self.volatile + def set_volatile(self, volatile): self.volatile = volatile + def get_const(self): return self.const + def set_const(self, const): self.const = const + def get_raise(self): return self.raisexx + def set_raise(self, raisexx): self.raisexx = raisexx + def get_virt(self): return self.virt + def set_virt(self, virt): self.virt = virt + def get_readable(self): return self.readable + def set_readable(self, readable): self.readable = readable + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_explicit(self): return self.explicit + def set_explicit(self, explicit): self.explicit = explicit + def get_new(self): return self.new + def set_new(self, new): self.new = new + def get_final(self): return self.final + def set_final(self, final): self.final = final + def get_writable(self): return self.writable + def set_writable(self, writable): self.writable = writable + def get_add(self): return self.add + def set_add(self, add): self.add = add + def get_static(self): return self.static + def set_static(self, static): self.static = static + def get_remove(self): return self.remove + def set_remove(self, remove): self.remove = remove + def get_sealed(self): return self.sealed + def set_sealed(self, sealed): self.sealed = sealed + def get_mutable(self): return self.mutable + def set_mutable(self, mutable): self.mutable = mutable + def get_gettable(self): return self.gettable + def set_gettable(self, gettable): self.gettable = gettable + def get_inline(self): return self.inline + def set_inline(self, inline): self.inline = inline + def get_settable(self): return self.settable + def set_settable(self, settable): self.settable = settable + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='memberdefType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='memberdefType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='memberdefType'): + if self.initonly is not None: + outfile.write(' initonly=%s' % (quote_attrib(self.initonly), )) + if self.kind is not None: + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + if self.volatile is not None: + outfile.write(' volatile=%s' % (quote_attrib(self.volatile), )) + if self.const is not None: + outfile.write(' const=%s' % (quote_attrib(self.const), )) + if self.raisexx is not None: + outfile.write(' raise=%s' % (quote_attrib(self.raisexx), )) + if self.virt is not None: + outfile.write(' virt=%s' % (quote_attrib(self.virt), )) + if self.readable is not None: + outfile.write(' readable=%s' % (quote_attrib(self.readable), )) + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.explicit is not None: + outfile.write(' explicit=%s' % (quote_attrib(self.explicit), )) + if self.new is not None: + outfile.write(' new=%s' % (quote_attrib(self.new), )) + if self.final is not None: + outfile.write(' final=%s' % (quote_attrib(self.final), )) + if self.writable is not None: + outfile.write(' writable=%s' % (quote_attrib(self.writable), )) + if self.add is not None: + outfile.write(' add=%s' % (quote_attrib(self.add), )) + if self.static is not None: + outfile.write(' static=%s' % (quote_attrib(self.static), )) + if self.remove is not None: + outfile.write(' remove=%s' % (quote_attrib(self.remove), )) + if self.sealed is not None: + outfile.write(' sealed=%s' % (quote_attrib(self.sealed), )) + if self.mutable is not None: + outfile.write(' mutable=%s' % (quote_attrib(self.mutable), )) + if self.gettable is not None: + outfile.write(' gettable=%s' % (quote_attrib(self.gettable), )) + if self.inline is not None: + outfile.write(' inline=%s' % (quote_attrib(self.inline), )) + if self.settable is not None: + outfile.write(' settable=%s' % (quote_attrib(self.settable), )) + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='memberdefType'): + if self.templateparamlist: + self.templateparamlist.export(outfile, level, namespace_, name_='templateparamlist') + if self.type_: + self.type_.export(outfile, level, namespace_, name_='type') + if self.definition is not None: + showIndent(outfile, level) + outfile.write('<%sdefinition>%s\n' % (namespace_, self.format_string(quote_xml(self.definition).encode(ExternalEncoding), input_name='definition'), namespace_)) + if self.argsstring is not None: + showIndent(outfile, level) + outfile.write('<%sargsstring>%s\n' % (namespace_, self.format_string(quote_xml(self.argsstring).encode(ExternalEncoding), input_name='argsstring'), namespace_)) + if self.name is not None: + showIndent(outfile, level) + outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) + if self.read is not None: + showIndent(outfile, level) + outfile.write('<%sread>%s\n' % (namespace_, self.format_string(quote_xml(self.read).encode(ExternalEncoding), input_name='read'), namespace_)) + if self.write is not None: + showIndent(outfile, level) + outfile.write('<%swrite>%s\n' % (namespace_, self.format_string(quote_xml(self.write).encode(ExternalEncoding), input_name='write'), namespace_)) + if self.bitfield is not None: + showIndent(outfile, level) + outfile.write('<%sbitfield>%s\n' % (namespace_, self.format_string(quote_xml(self.bitfield).encode(ExternalEncoding), input_name='bitfield'), namespace_)) + for reimplements_ in self.reimplements: + reimplements_.export(outfile, level, namespace_, name_='reimplements') + for reimplementedby_ in self.reimplementedby: + reimplementedby_.export(outfile, level, namespace_, name_='reimplementedby') + for param_ in self.param: + param_.export(outfile, level, namespace_, name_='param') + for enumvalue_ in self.enumvalue: + enumvalue_.export(outfile, level, namespace_, name_='enumvalue') + if self.initializer: + self.initializer.export(outfile, level, namespace_, name_='initializer') + if self.exceptions: + self.exceptions.export(outfile, level, namespace_, name_='exceptions') + if self.briefdescription: + self.briefdescription.export(outfile, level, namespace_, name_='briefdescription') + if self.detaileddescription: + self.detaileddescription.export(outfile, level, namespace_, name_='detaileddescription') + if self.inbodydescription: + self.inbodydescription.export(outfile, level, namespace_, name_='inbodydescription') + if self.location: + self.location.export(outfile, level, namespace_, name_='location', ) + for references_ in self.references: + references_.export(outfile, level, namespace_, name_='references') + for referencedby_ in self.referencedby: + referencedby_.export(outfile, level, namespace_, name_='referencedby') + def hasContent_(self): + if ( + self.templateparamlist is not None or + self.type_ is not None or + self.definition is not None or + self.argsstring is not None or + self.name is not None or + self.read is not None or + self.write is not None or + self.bitfield is not None or + self.reimplements is not None or + self.reimplementedby is not None or + self.param is not None or + self.enumvalue is not None or + self.initializer is not None or + self.exceptions is not None or + self.briefdescription is not None or + self.detaileddescription is not None or + self.inbodydescription is not None or + self.location is not None or + self.references is not None or + self.referencedby is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='memberdefType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.initonly is not None: + showIndent(outfile, level) + outfile.write('initonly = "%s",\n' % (self.initonly,)) + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + if self.volatile is not None: + showIndent(outfile, level) + outfile.write('volatile = "%s",\n' % (self.volatile,)) + if self.const is not None: + showIndent(outfile, level) + outfile.write('const = "%s",\n' % (self.const,)) + if self.raisexx is not None: + showIndent(outfile, level) + outfile.write('raisexx = "%s",\n' % (self.raisexx,)) + if self.virt is not None: + showIndent(outfile, level) + outfile.write('virt = "%s",\n' % (self.virt,)) + if self.readable is not None: + showIndent(outfile, level) + outfile.write('readable = "%s",\n' % (self.readable,)) + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.explicit is not None: + showIndent(outfile, level) + outfile.write('explicit = "%s",\n' % (self.explicit,)) + if self.new is not None: + showIndent(outfile, level) + outfile.write('new = "%s",\n' % (self.new,)) + if self.final is not None: + showIndent(outfile, level) + outfile.write('final = "%s",\n' % (self.final,)) + if self.writable is not None: + showIndent(outfile, level) + outfile.write('writable = "%s",\n' % (self.writable,)) + if self.add is not None: + showIndent(outfile, level) + outfile.write('add = "%s",\n' % (self.add,)) + if self.static is not None: + showIndent(outfile, level) + outfile.write('static = "%s",\n' % (self.static,)) + if self.remove is not None: + showIndent(outfile, level) + outfile.write('remove = "%s",\n' % (self.remove,)) + if self.sealed is not None: + showIndent(outfile, level) + outfile.write('sealed = "%s",\n' % (self.sealed,)) + if self.mutable is not None: + showIndent(outfile, level) + outfile.write('mutable = "%s",\n' % (self.mutable,)) + if self.gettable is not None: + showIndent(outfile, level) + outfile.write('gettable = "%s",\n' % (self.gettable,)) + if self.inline is not None: + showIndent(outfile, level) + outfile.write('inline = "%s",\n' % (self.inline,)) + if self.settable is not None: + showIndent(outfile, level) + outfile.write('settable = "%s",\n' % (self.settable,)) + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + if self.templateparamlist: + showIndent(outfile, level) + outfile.write('templateparamlist=model_.templateparamlistType(\n') + self.templateparamlist.exportLiteral(outfile, level, name_='templateparamlist') + showIndent(outfile, level) + outfile.write('),\n') + if self.type_: + showIndent(outfile, level) + outfile.write('type_=model_.linkedTextType(\n') + self.type_.exportLiteral(outfile, level, name_='type') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('definition=%s,\n' % quote_python(self.definition).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('argsstring=%s,\n' % quote_python(self.argsstring).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('read=%s,\n' % quote_python(self.read).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('write=%s,\n' % quote_python(self.write).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('bitfield=%s,\n' % quote_python(self.bitfield).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('reimplements=[\n') + level += 1 + for reimplements in self.reimplements: + showIndent(outfile, level) + outfile.write('model_.reimplements(\n') + reimplements.exportLiteral(outfile, level, name_='reimplements') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('reimplementedby=[\n') + level += 1 + for reimplementedby in self.reimplementedby: + showIndent(outfile, level) + outfile.write('model_.reimplementedby(\n') + reimplementedby.exportLiteral(outfile, level, name_='reimplementedby') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('param=[\n') + level += 1 + for param in self.param: + showIndent(outfile, level) + outfile.write('model_.param(\n') + param.exportLiteral(outfile, level, name_='param') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('enumvalue=[\n') + level += 1 + for enumvalue in self.enumvalue: + showIndent(outfile, level) + outfile.write('model_.enumvalue(\n') + enumvalue.exportLiteral(outfile, level, name_='enumvalue') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.initializer: + showIndent(outfile, level) + outfile.write('initializer=model_.linkedTextType(\n') + self.initializer.exportLiteral(outfile, level, name_='initializer') + showIndent(outfile, level) + outfile.write('),\n') + if self.exceptions: + showIndent(outfile, level) + outfile.write('exceptions=model_.linkedTextType(\n') + self.exceptions.exportLiteral(outfile, level, name_='exceptions') + showIndent(outfile, level) + outfile.write('),\n') + if self.briefdescription: + showIndent(outfile, level) + outfile.write('briefdescription=model_.descriptionType(\n') + self.briefdescription.exportLiteral(outfile, level, name_='briefdescription') + showIndent(outfile, level) + outfile.write('),\n') + if self.detaileddescription: + showIndent(outfile, level) + outfile.write('detaileddescription=model_.descriptionType(\n') + self.detaileddescription.exportLiteral(outfile, level, name_='detaileddescription') + showIndent(outfile, level) + outfile.write('),\n') + if self.inbodydescription: + showIndent(outfile, level) + outfile.write('inbodydescription=model_.descriptionType(\n') + self.inbodydescription.exportLiteral(outfile, level, name_='inbodydescription') + showIndent(outfile, level) + outfile.write('),\n') + if self.location: + showIndent(outfile, level) + outfile.write('location=model_.locationType(\n') + self.location.exportLiteral(outfile, level, name_='location') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('references=[\n') + level += 1 + for references in self.references: + showIndent(outfile, level) + outfile.write('model_.references(\n') + references.exportLiteral(outfile, level, name_='references') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('referencedby=[\n') + level += 1 + for referencedby in self.referencedby: + showIndent(outfile, level) + outfile.write('model_.referencedby(\n') + referencedby.exportLiteral(outfile, level, name_='referencedby') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('initonly'): + self.initonly = attrs.get('initonly').value + if attrs.get('kind'): + self.kind = attrs.get('kind').value + if attrs.get('volatile'): + self.volatile = attrs.get('volatile').value + if attrs.get('const'): + self.const = attrs.get('const').value + if attrs.get('raise'): + self.raisexx = attrs.get('raise').value + if attrs.get('virt'): + self.virt = attrs.get('virt').value + if attrs.get('readable'): + self.readable = attrs.get('readable').value + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('explicit'): + self.explicit = attrs.get('explicit').value + if attrs.get('new'): + self.new = attrs.get('new').value + if attrs.get('final'): + self.final = attrs.get('final').value + if attrs.get('writable'): + self.writable = attrs.get('writable').value + if attrs.get('add'): + self.add = attrs.get('add').value + if attrs.get('static'): + self.static = attrs.get('static').value + if attrs.get('remove'): + self.remove = attrs.get('remove').value + if attrs.get('sealed'): + self.sealed = attrs.get('sealed').value + if attrs.get('mutable'): + self.mutable = attrs.get('mutable').value + if attrs.get('gettable'): + self.gettable = attrs.get('gettable').value + if attrs.get('inline'): + self.inline = attrs.get('inline').value + if attrs.get('settable'): + self.settable = attrs.get('settable').value + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'templateparamlist': + obj_ = templateparamlistType.factory() + obj_.build(child_) + self.set_templateparamlist(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'type': + obj_ = linkedTextType.factory() + obj_.build(child_) + self.set_type(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'definition': + definition_ = '' + for text__content_ in child_.childNodes: + definition_ += text__content_.nodeValue + self.definition = definition_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'argsstring': + argsstring_ = '' + for text__content_ in child_.childNodes: + argsstring_ += text__content_.nodeValue + self.argsstring = argsstring_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'name': + name_ = '' + for text__content_ in child_.childNodes: + name_ += text__content_.nodeValue + self.name = name_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'read': + read_ = '' + for text__content_ in child_.childNodes: + read_ += text__content_.nodeValue + self.read = read_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'write': + write_ = '' + for text__content_ in child_.childNodes: + write_ += text__content_.nodeValue + self.write = write_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'bitfield': + bitfield_ = '' + for text__content_ in child_.childNodes: + bitfield_ += text__content_.nodeValue + self.bitfield = bitfield_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'reimplements': + obj_ = reimplementType.factory() + obj_.build(child_) + self.reimplements.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'reimplementedby': + obj_ = reimplementType.factory() + obj_.build(child_) + self.reimplementedby.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'param': + obj_ = paramType.factory() + obj_.build(child_) + self.param.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'enumvalue': + obj_ = enumvalueType.factory() + obj_.build(child_) + self.enumvalue.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'initializer': + obj_ = linkedTextType.factory() + obj_.build(child_) + self.set_initializer(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'exceptions': + obj_ = linkedTextType.factory() + obj_.build(child_) + self.set_exceptions(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'briefdescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_briefdescription(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detaileddescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_detaileddescription(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'inbodydescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_inbodydescription(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'location': + obj_ = locationType.factory() + obj_.build(child_) + self.set_location(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'references': + obj_ = referenceType.factory() + obj_.build(child_) + self.references.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'referencedby': + obj_ = referenceType.factory() + obj_.build(child_) + self.referencedby.append(obj_) +# end class memberdefType + + +class definition(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if definition.subclass: + return definition.subclass(*args_, **kwargs_) + else: + return definition(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='definition', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='definition') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='definition'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='definition'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='definition'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class definition + + +class argsstring(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if argsstring.subclass: + return argsstring.subclass(*args_, **kwargs_) + else: + return argsstring(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='argsstring', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='argsstring') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='argsstring'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='argsstring'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='argsstring'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class argsstring + + +class read(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if read.subclass: + return read.subclass(*args_, **kwargs_) + else: + return read(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='read', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='read') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='read'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='read'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='read'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class read + + +class write(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if write.subclass: + return write.subclass(*args_, **kwargs_) + else: + return write(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='write', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='write') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='write'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='write'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='write'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class write + + +class bitfield(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if bitfield.subclass: + return bitfield.subclass(*args_, **kwargs_) + else: + return bitfield(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='bitfield', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='bitfield') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='bitfield'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='bitfield'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='bitfield'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class bitfield + + +class descriptionType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, title=None, para=None, sect1=None, internal=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if descriptionType.subclass: + return descriptionType.subclass(*args_, **kwargs_) + else: + return descriptionType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect1(self): return self.sect1 + def set_sect1(self, sect1): self.sect1 = sect1 + def add_sect1(self, value): self.sect1.append(value) + def insert_sect1(self, index, value): self.sect1[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def export(self, outfile, level, namespace_='', name_='descriptionType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='descriptionType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='descriptionType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='descriptionType'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.title is not None or + self.para is not None or + self.sect1 is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='descriptionType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + childobj_ = docTitleType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'title', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect1': + childobj_ = docSect1Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect1', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + childobj_ = docInternalType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'internal', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class descriptionType + + +class enumvalueType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, prot=None, id=None, name=None, initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None): + self.prot = prot + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if enumvalueType.subclass: + return enumvalueType.subclass(*args_, **kwargs_) + else: + return enumvalueType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_initializer(self): return self.initializer + def set_initializer(self, initializer): self.initializer = initializer + def get_briefdescription(self): return self.briefdescription + def set_briefdescription(self, briefdescription): self.briefdescription = briefdescription + def get_detaileddescription(self): return self.detaileddescription + def set_detaileddescription(self, detaileddescription): self.detaileddescription = detaileddescription + def get_prot(self): return self.prot + def set_prot(self, prot): self.prot = prot + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='enumvalueType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='enumvalueType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='enumvalueType'): + if self.prot is not None: + outfile.write(' prot=%s' % (quote_attrib(self.prot), )) + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='enumvalueType'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.name is not None or + self.initializer is not None or + self.briefdescription is not None or + self.detaileddescription is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='enumvalueType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.prot is not None: + showIndent(outfile, level) + outfile.write('prot = "%s",\n' % (self.prot,)) + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('prot'): + self.prot = attrs.get('prot').value + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'name': + value_ = [] + for text_ in child_.childNodes: + value_.append(text_.nodeValue) + valuestr_ = ''.join(value_) + obj_ = self.mixedclass_(MixedContainer.CategorySimple, + MixedContainer.TypeString, 'name', valuestr_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'initializer': + childobj_ = linkedTextType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'initializer', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'briefdescription': + childobj_ = descriptionType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'briefdescription', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'detaileddescription': + childobj_ = descriptionType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'detaileddescription', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class enumvalueType + + +class templateparamlistType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, param=None): + if param is None: + self.param = [] + else: + self.param = param + def factory(*args_, **kwargs_): + if templateparamlistType.subclass: + return templateparamlistType.subclass(*args_, **kwargs_) + else: + return templateparamlistType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_param(self): return self.param + def set_param(self, param): self.param = param + def add_param(self, value): self.param.append(value) + def insert_param(self, index, value): self.param[index] = value + def export(self, outfile, level, namespace_='', name_='templateparamlistType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='templateparamlistType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='templateparamlistType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='templateparamlistType'): + for param_ in self.param: + param_.export(outfile, level, namespace_, name_='param') + def hasContent_(self): + if ( + self.param is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='templateparamlistType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('param=[\n') + level += 1 + for param in self.param: + showIndent(outfile, level) + outfile.write('model_.param(\n') + param.exportLiteral(outfile, level, name_='param') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'param': + obj_ = paramType.factory() + obj_.build(child_) + self.param.append(obj_) +# end class templateparamlistType + + +class paramType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, type_=None, declname=None, defname=None, array=None, defval=None, briefdescription=None): + self.type_ = type_ + self.declname = declname + self.defname = defname + self.array = array + self.defval = defval + self.briefdescription = briefdescription + def factory(*args_, **kwargs_): + if paramType.subclass: + return paramType.subclass(*args_, **kwargs_) + else: + return paramType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_type(self): return self.type_ + def set_type(self, type_): self.type_ = type_ + def get_declname(self): return self.declname + def set_declname(self, declname): self.declname = declname + def get_defname(self): return self.defname + def set_defname(self, defname): self.defname = defname + def get_array(self): return self.array + def set_array(self, array): self.array = array + def get_defval(self): return self.defval + def set_defval(self, defval): self.defval = defval + def get_briefdescription(self): return self.briefdescription + def set_briefdescription(self, briefdescription): self.briefdescription = briefdescription + def export(self, outfile, level, namespace_='', name_='paramType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='paramType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='paramType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='paramType'): + if self.type_: + self.type_.export(outfile, level, namespace_, name_='type') + if self.declname is not None: + showIndent(outfile, level) + outfile.write('<%sdeclname>%s\n' % (namespace_, self.format_string(quote_xml(self.declname).encode(ExternalEncoding), input_name='declname'), namespace_)) + if self.defname is not None: + showIndent(outfile, level) + outfile.write('<%sdefname>%s\n' % (namespace_, self.format_string(quote_xml(self.defname).encode(ExternalEncoding), input_name='defname'), namespace_)) + if self.array is not None: + showIndent(outfile, level) + outfile.write('<%sarray>%s\n' % (namespace_, self.format_string(quote_xml(self.array).encode(ExternalEncoding), input_name='array'), namespace_)) + if self.defval: + self.defval.export(outfile, level, namespace_, name_='defval') + if self.briefdescription: + self.briefdescription.export(outfile, level, namespace_, name_='briefdescription') + def hasContent_(self): + if ( + self.type_ is not None or + self.declname is not None or + self.defname is not None or + self.array is not None or + self.defval is not None or + self.briefdescription is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='paramType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + if self.type_: + showIndent(outfile, level) + outfile.write('type_=model_.linkedTextType(\n') + self.type_.exportLiteral(outfile, level, name_='type') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('declname=%s,\n' % quote_python(self.declname).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('defname=%s,\n' % quote_python(self.defname).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('array=%s,\n' % quote_python(self.array).encode(ExternalEncoding)) + if self.defval: + showIndent(outfile, level) + outfile.write('defval=model_.linkedTextType(\n') + self.defval.exportLiteral(outfile, level, name_='defval') + showIndent(outfile, level) + outfile.write('),\n') + if self.briefdescription: + showIndent(outfile, level) + outfile.write('briefdescription=model_.descriptionType(\n') + self.briefdescription.exportLiteral(outfile, level, name_='briefdescription') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'type': + obj_ = linkedTextType.factory() + obj_.build(child_) + self.set_type(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'declname': + declname_ = '' + for text__content_ in child_.childNodes: + declname_ += text__content_.nodeValue + self.declname = declname_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'defname': + defname_ = '' + for text__content_ in child_.childNodes: + defname_ += text__content_.nodeValue + self.defname = defname_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'array': + array_ = '' + for text__content_ in child_.childNodes: + array_ += text__content_.nodeValue + self.array = array_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'defval': + obj_ = linkedTextType.factory() + obj_.build(child_) + self.set_defval(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'briefdescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_briefdescription(obj_) +# end class paramType + + +class declname(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if declname.subclass: + return declname.subclass(*args_, **kwargs_) + else: + return declname(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='declname', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='declname') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='declname'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='declname'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='declname'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class declname + + +class defname(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if defname.subclass: + return defname.subclass(*args_, **kwargs_) + else: + return defname(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='defname', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='defname') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='defname'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='defname'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='defname'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class defname + + +class array(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if array.subclass: + return array.subclass(*args_, **kwargs_) + else: + return array(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='array', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='array') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='array'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='array'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='array'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class array + + +class linkedTextType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, ref=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if linkedTextType.subclass: + return linkedTextType.subclass(*args_, **kwargs_) + else: + return linkedTextType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_ref(self): return self.ref + def set_ref(self, ref): self.ref = ref + def add_ref(self, value): self.ref.append(value) + def insert_ref(self, index, value): self.ref[index] = value + def export(self, outfile, level, namespace_='', name_='linkedTextType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='linkedTextType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='linkedTextType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='linkedTextType'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.ref is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='linkedTextType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'ref': + childobj_ = docRefTextType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'ref', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class linkedTextType + + +class graphType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, node=None): + if node is None: + self.node = [] + else: + self.node = node + def factory(*args_, **kwargs_): + if graphType.subclass: + return graphType.subclass(*args_, **kwargs_) + else: + return graphType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_node(self): return self.node + def set_node(self, node): self.node = node + def add_node(self, value): self.node.append(value) + def insert_node(self, index, value): self.node[index] = value + def export(self, outfile, level, namespace_='', name_='graphType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='graphType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='graphType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='graphType'): + for node_ in self.node: + node_.export(outfile, level, namespace_, name_='node') + def hasContent_(self): + if ( + self.node is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='graphType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('node=[\n') + level += 1 + for node in self.node: + showIndent(outfile, level) + outfile.write('model_.node(\n') + node.exportLiteral(outfile, level, name_='node') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'node': + obj_ = nodeType.factory() + obj_.build(child_) + self.node.append(obj_) +# end class graphType + + +class nodeType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, label=None, link=None, childnode=None): + self.id = id + self.label = label + self.link = link + if childnode is None: + self.childnode = [] + else: + self.childnode = childnode + def factory(*args_, **kwargs_): + if nodeType.subclass: + return nodeType.subclass(*args_, **kwargs_) + else: + return nodeType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_label(self): return self.label + def set_label(self, label): self.label = label + def get_link(self): return self.link + def set_link(self, link): self.link = link + def get_childnode(self): return self.childnode + def set_childnode(self, childnode): self.childnode = childnode + def add_childnode(self, value): self.childnode.append(value) + def insert_childnode(self, index, value): self.childnode[index] = value + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='nodeType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='nodeType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='nodeType'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='nodeType'): + if self.label is not None: + showIndent(outfile, level) + outfile.write('<%slabel>%s\n' % (namespace_, self.format_string(quote_xml(self.label).encode(ExternalEncoding), input_name='label'), namespace_)) + if self.link: + self.link.export(outfile, level, namespace_, name_='link') + for childnode_ in self.childnode: + childnode_.export(outfile, level, namespace_, name_='childnode') + def hasContent_(self): + if ( + self.label is not None or + self.link is not None or + self.childnode is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='nodeType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('label=%s,\n' % quote_python(self.label).encode(ExternalEncoding)) + if self.link: + showIndent(outfile, level) + outfile.write('link=model_.linkType(\n') + self.link.exportLiteral(outfile, level, name_='link') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('childnode=[\n') + level += 1 + for childnode in self.childnode: + showIndent(outfile, level) + outfile.write('model_.childnode(\n') + childnode.exportLiteral(outfile, level, name_='childnode') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'label': + label_ = '' + for text__content_ in child_.childNodes: + label_ += text__content_.nodeValue + self.label = label_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'link': + obj_ = linkType.factory() + obj_.build(child_) + self.set_link(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'childnode': + obj_ = childnodeType.factory() + obj_.build(child_) + self.childnode.append(obj_) +# end class nodeType + + +class label(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if label.subclass: + return label.subclass(*args_, **kwargs_) + else: + return label(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='label', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='label') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='label'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='label'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='label'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class label + + +class childnodeType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, relation=None, refid=None, edgelabel=None): + self.relation = relation + self.refid = refid + if edgelabel is None: + self.edgelabel = [] + else: + self.edgelabel = edgelabel + def factory(*args_, **kwargs_): + if childnodeType.subclass: + return childnodeType.subclass(*args_, **kwargs_) + else: + return childnodeType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_edgelabel(self): return self.edgelabel + def set_edgelabel(self, edgelabel): self.edgelabel = edgelabel + def add_edgelabel(self, value): self.edgelabel.append(value) + def insert_edgelabel(self, index, value): self.edgelabel[index] = value + def get_relation(self): return self.relation + def set_relation(self, relation): self.relation = relation + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def export(self, outfile, level, namespace_='', name_='childnodeType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='childnodeType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='childnodeType'): + if self.relation is not None: + outfile.write(' relation=%s' % (quote_attrib(self.relation), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='childnodeType'): + for edgelabel_ in self.edgelabel: + showIndent(outfile, level) + outfile.write('<%sedgelabel>%s\n' % (namespace_, self.format_string(quote_xml(edgelabel_).encode(ExternalEncoding), input_name='edgelabel'), namespace_)) + def hasContent_(self): + if ( + self.edgelabel is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='childnodeType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.relation is not None: + showIndent(outfile, level) + outfile.write('relation = "%s",\n' % (self.relation,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('edgelabel=[\n') + level += 1 + for edgelabel in self.edgelabel: + showIndent(outfile, level) + outfile.write('%s,\n' % quote_python(edgelabel).encode(ExternalEncoding)) + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('relation'): + self.relation = attrs.get('relation').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'edgelabel': + edgelabel_ = '' + for text__content_ in child_.childNodes: + edgelabel_ += text__content_.nodeValue + self.edgelabel.append(edgelabel_) +# end class childnodeType + + +class edgelabel(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if edgelabel.subclass: + return edgelabel.subclass(*args_, **kwargs_) + else: + return edgelabel(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='edgelabel', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='edgelabel') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='edgelabel'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='edgelabel'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='edgelabel'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class edgelabel + + +class linkType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, refid=None, external=None, valueOf_=''): + self.refid = refid + self.external = external + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if linkType.subclass: + return linkType.subclass(*args_, **kwargs_) + else: + return linkType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def get_external(self): return self.external + def set_external(self, external): self.external = external + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='linkType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='linkType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='linkType'): + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + if self.external is not None: + outfile.write(' external=%s' % (self.format_string(quote_attrib(self.external).encode(ExternalEncoding), input_name='external'), )) + def exportChildren(self, outfile, level, namespace_='', name_='linkType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='linkType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + if self.external is not None: + showIndent(outfile, level) + outfile.write('external = %s,\n' % (self.external,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('refid'): + self.refid = attrs.get('refid').value + if attrs.get('external'): + self.external = attrs.get('external').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class linkType + + +class listingType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, codeline=None): + if codeline is None: + self.codeline = [] + else: + self.codeline = codeline + def factory(*args_, **kwargs_): + if listingType.subclass: + return listingType.subclass(*args_, **kwargs_) + else: + return listingType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_codeline(self): return self.codeline + def set_codeline(self, codeline): self.codeline = codeline + def add_codeline(self, value): self.codeline.append(value) + def insert_codeline(self, index, value): self.codeline[index] = value + def export(self, outfile, level, namespace_='', name_='listingType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='listingType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='listingType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='listingType'): + for codeline_ in self.codeline: + codeline_.export(outfile, level, namespace_, name_='codeline') + def hasContent_(self): + if ( + self.codeline is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='listingType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('codeline=[\n') + level += 1 + for codeline in self.codeline: + showIndent(outfile, level) + outfile.write('model_.codeline(\n') + codeline.exportLiteral(outfile, level, name_='codeline') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'codeline': + obj_ = codelineType.factory() + obj_.build(child_) + self.codeline.append(obj_) +# end class listingType + + +class codelineType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None): + self.external = external + self.lineno = lineno + self.refkind = refkind + self.refid = refid + if highlight is None: + self.highlight = [] + else: + self.highlight = highlight + def factory(*args_, **kwargs_): + if codelineType.subclass: + return codelineType.subclass(*args_, **kwargs_) + else: + return codelineType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_highlight(self): return self.highlight + def set_highlight(self, highlight): self.highlight = highlight + def add_highlight(self, value): self.highlight.append(value) + def insert_highlight(self, index, value): self.highlight[index] = value + def get_external(self): return self.external + def set_external(self, external): self.external = external + def get_lineno(self): return self.lineno + def set_lineno(self, lineno): self.lineno = lineno + def get_refkind(self): return self.refkind + def set_refkind(self, refkind): self.refkind = refkind + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def export(self, outfile, level, namespace_='', name_='codelineType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='codelineType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='codelineType'): + if self.external is not None: + outfile.write(' external=%s' % (quote_attrib(self.external), )) + if self.lineno is not None: + outfile.write(' lineno="%s"' % self.format_integer(self.lineno, input_name='lineno')) + if self.refkind is not None: + outfile.write(' refkind=%s' % (quote_attrib(self.refkind), )) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='codelineType'): + for highlight_ in self.highlight: + highlight_.export(outfile, level, namespace_, name_='highlight') + def hasContent_(self): + if ( + self.highlight is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='codelineType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.external is not None: + showIndent(outfile, level) + outfile.write('external = "%s",\n' % (self.external,)) + if self.lineno is not None: + showIndent(outfile, level) + outfile.write('lineno = %s,\n' % (self.lineno,)) + if self.refkind is not None: + showIndent(outfile, level) + outfile.write('refkind = "%s",\n' % (self.refkind,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('highlight=[\n') + level += 1 + for highlight in self.highlight: + showIndent(outfile, level) + outfile.write('model_.highlight(\n') + highlight.exportLiteral(outfile, level, name_='highlight') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('external'): + self.external = attrs.get('external').value + if attrs.get('lineno'): + try: + self.lineno = int(attrs.get('lineno').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (lineno): %s' % exp) + if attrs.get('refkind'): + self.refkind = attrs.get('refkind').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'highlight': + obj_ = highlightType.factory() + obj_.build(child_) + self.highlight.append(obj_) +# end class codelineType + + +class highlightType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, classxx=None, sp=None, ref=None, mixedclass_=None, content_=None): + self.classxx = classxx + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if highlightType.subclass: + return highlightType.subclass(*args_, **kwargs_) + else: + return highlightType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_sp(self): return self.sp + def set_sp(self, sp): self.sp = sp + def add_sp(self, value): self.sp.append(value) + def insert_sp(self, index, value): self.sp[index] = value + def get_ref(self): return self.ref + def set_ref(self, ref): self.ref = ref + def add_ref(self, value): self.ref.append(value) + def insert_ref(self, index, value): self.ref[index] = value + def get_class(self): return self.classxx + def set_class(self, classxx): self.classxx = classxx + def export(self, outfile, level, namespace_='', name_='highlightType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='highlightType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='highlightType'): + if self.classxx is not None: + outfile.write(' class=%s' % (quote_attrib(self.classxx), )) + def exportChildren(self, outfile, level, namespace_='', name_='highlightType'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.sp is not None or + self.ref is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='highlightType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.classxx is not None: + showIndent(outfile, level) + outfile.write('classxx = "%s",\n' % (self.classxx,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('class'): + self.classxx = attrs.get('class').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sp': + value_ = [] + for text_ in child_.childNodes: + value_.append(text_.nodeValue) + valuestr_ = ''.join(value_) + obj_ = self.mixedclass_(MixedContainer.CategorySimple, + MixedContainer.TypeString, 'sp', valuestr_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'ref': + childobj_ = docRefTextType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'ref', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class highlightType + + +class sp(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if sp.subclass: + return sp.subclass(*args_, **kwargs_) + else: + return sp(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='sp', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='sp') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='sp'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='sp'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='sp'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class sp + + +class referenceType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None): + self.endline = endline + self.startline = startline + self.refid = refid + self.compoundref = compoundref + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if referenceType.subclass: + return referenceType.subclass(*args_, **kwargs_) + else: + return referenceType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_endline(self): return self.endline + def set_endline(self, endline): self.endline = endline + def get_startline(self): return self.startline + def set_startline(self, startline): self.startline = startline + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def get_compoundref(self): return self.compoundref + def set_compoundref(self, compoundref): self.compoundref = compoundref + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='referenceType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='referenceType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='referenceType'): + if self.endline is not None: + outfile.write(' endline="%s"' % self.format_integer(self.endline, input_name='endline')) + if self.startline is not None: + outfile.write(' startline="%s"' % self.format_integer(self.startline, input_name='startline')) + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + if self.compoundref is not None: + outfile.write(' compoundref=%s' % (self.format_string(quote_attrib(self.compoundref).encode(ExternalEncoding), input_name='compoundref'), )) + def exportChildren(self, outfile, level, namespace_='', name_='referenceType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='referenceType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.endline is not None: + showIndent(outfile, level) + outfile.write('endline = %s,\n' % (self.endline,)) + if self.startline is not None: + showIndent(outfile, level) + outfile.write('startline = %s,\n' % (self.startline,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + if self.compoundref is not None: + showIndent(outfile, level) + outfile.write('compoundref = %s,\n' % (self.compoundref,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('endline'): + try: + self.endline = int(attrs.get('endline').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (endline): %s' % exp) + if attrs.get('startline'): + try: + self.startline = int(attrs.get('startline').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (startline): %s' % exp) + if attrs.get('refid'): + self.refid = attrs.get('refid').value + if attrs.get('compoundref'): + self.compoundref = attrs.get('compoundref').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class referenceType + + +class locationType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''): + self.bodystart = bodystart + self.line = line + self.bodyend = bodyend + self.bodyfile = bodyfile + self.file = file + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if locationType.subclass: + return locationType.subclass(*args_, **kwargs_) + else: + return locationType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_bodystart(self): return self.bodystart + def set_bodystart(self, bodystart): self.bodystart = bodystart + def get_line(self): return self.line + def set_line(self, line): self.line = line + def get_bodyend(self): return self.bodyend + def set_bodyend(self, bodyend): self.bodyend = bodyend + def get_bodyfile(self): return self.bodyfile + def set_bodyfile(self, bodyfile): self.bodyfile = bodyfile + def get_file(self): return self.file + def set_file(self, file): self.file = file + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='locationType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='locationType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='locationType'): + if self.bodystart is not None: + outfile.write(' bodystart="%s"' % self.format_integer(self.bodystart, input_name='bodystart')) + if self.line is not None: + outfile.write(' line="%s"' % self.format_integer(self.line, input_name='line')) + if self.bodyend is not None: + outfile.write(' bodyend="%s"' % self.format_integer(self.bodyend, input_name='bodyend')) + if self.bodyfile is not None: + outfile.write(' bodyfile=%s' % (self.format_string(quote_attrib(self.bodyfile).encode(ExternalEncoding), input_name='bodyfile'), )) + if self.file is not None: + outfile.write(' file=%s' % (self.format_string(quote_attrib(self.file).encode(ExternalEncoding), input_name='file'), )) + def exportChildren(self, outfile, level, namespace_='', name_='locationType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='locationType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.bodystart is not None: + showIndent(outfile, level) + outfile.write('bodystart = %s,\n' % (self.bodystart,)) + if self.line is not None: + showIndent(outfile, level) + outfile.write('line = %s,\n' % (self.line,)) + if self.bodyend is not None: + showIndent(outfile, level) + outfile.write('bodyend = %s,\n' % (self.bodyend,)) + if self.bodyfile is not None: + showIndent(outfile, level) + outfile.write('bodyfile = %s,\n' % (self.bodyfile,)) + if self.file is not None: + showIndent(outfile, level) + outfile.write('file = %s,\n' % (self.file,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('bodystart'): + try: + self.bodystart = int(attrs.get('bodystart').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (bodystart): %s' % exp) + if attrs.get('line'): + try: + self.line = int(attrs.get('line').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (line): %s' % exp) + if attrs.get('bodyend'): + try: + self.bodyend = int(attrs.get('bodyend').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (bodyend): %s' % exp) + if attrs.get('bodyfile'): + self.bodyfile = attrs.get('bodyfile').value + if attrs.get('file'): + self.file = attrs.get('file').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class locationType + + +class docSect1Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, title=None, para=None, sect2=None, internal=None, mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docSect1Type.subclass: + return docSect1Type.subclass(*args_, **kwargs_) + else: + return docSect1Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect2(self): return self.sect2 + def set_sect2(self, sect2): self.sect2 = sect2 + def add_sect2(self, value): self.sect2.append(value) + def insert_sect2(self, index, value): self.sect2[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='docSect1Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docSect1Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docSect1Type'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docSect1Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.title is not None or + self.para is not None or + self.sect2 is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docSect1Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + childobj_ = docTitleType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'title', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect2': + childobj_ = docSect2Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect2', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + childobj_ = docInternalS1Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'internal', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docSect1Type + + +class docSect2Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, title=None, para=None, sect3=None, internal=None, mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docSect2Type.subclass: + return docSect2Type.subclass(*args_, **kwargs_) + else: + return docSect2Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect3(self): return self.sect3 + def set_sect3(self, sect3): self.sect3 = sect3 + def add_sect3(self, value): self.sect3.append(value) + def insert_sect3(self, index, value): self.sect3[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='docSect2Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docSect2Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docSect2Type'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docSect2Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.title is not None or + self.para is not None or + self.sect3 is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docSect2Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + childobj_ = docTitleType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'title', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect3': + childobj_ = docSect3Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect3', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + childobj_ = docInternalS2Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'internal', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docSect2Type + + +class docSect3Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, title=None, para=None, sect4=None, internal=None, mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docSect3Type.subclass: + return docSect3Type.subclass(*args_, **kwargs_) + else: + return docSect3Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect4(self): return self.sect4 + def set_sect4(self, sect4): self.sect4 = sect4 + def add_sect4(self, value): self.sect4.append(value) + def insert_sect4(self, index, value): self.sect4[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='docSect3Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docSect3Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docSect3Type'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docSect3Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.title is not None or + self.para is not None or + self.sect4 is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docSect3Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + childobj_ = docTitleType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'title', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect4': + childobj_ = docSect4Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect4', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + childobj_ = docInternalS3Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'internal', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docSect3Type + + +class docSect4Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, title=None, para=None, internal=None, mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docSect4Type.subclass: + return docSect4Type.subclass(*args_, **kwargs_) + else: + return docSect4Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='docSect4Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docSect4Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docSect4Type'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docSect4Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.title is not None or + self.para is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docSect4Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + childobj_ = docTitleType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'title', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + childobj_ = docInternalS4Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'internal', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docSect4Type + + +class docInternalType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docInternalType.subclass: + return docInternalType.subclass(*args_, **kwargs_) + else: + return docInternalType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect1(self): return self.sect1 + def set_sect1(self, sect1): self.sect1 = sect1 + def add_sect1(self, value): self.sect1.append(value) + def insert_sect1(self, index, value): self.sect1[index] = value + def export(self, outfile, level, namespace_='', name_='docInternalType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docInternalType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docInternalType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docInternalType'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.para is not None or + self.sect1 is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docInternalType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect1': + childobj_ = docSect1Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect1', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docInternalType + + +class docInternalS1Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docInternalS1Type.subclass: + return docInternalS1Type.subclass(*args_, **kwargs_) + else: + return docInternalS1Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect2(self): return self.sect2 + def set_sect2(self, sect2): self.sect2 = sect2 + def add_sect2(self, value): self.sect2.append(value) + def insert_sect2(self, index, value): self.sect2[index] = value + def export(self, outfile, level, namespace_='', name_='docInternalS1Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docInternalS1Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docInternalS1Type'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docInternalS1Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.para is not None or + self.sect2 is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docInternalS1Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect2': + childobj_ = docSect2Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect2', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docInternalS1Type + + +class docInternalS2Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docInternalS2Type.subclass: + return docInternalS2Type.subclass(*args_, **kwargs_) + else: + return docInternalS2Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect3(self): return self.sect3 + def set_sect3(self, sect3): self.sect3 = sect3 + def add_sect3(self, value): self.sect3.append(value) + def insert_sect3(self, index, value): self.sect3[index] = value + def export(self, outfile, level, namespace_='', name_='docInternalS2Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docInternalS2Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docInternalS2Type'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docInternalS2Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.para is not None or + self.sect3 is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docInternalS2Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect3': + childobj_ = docSect3Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect3', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docInternalS2Type + + +class docInternalS3Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docInternalS3Type.subclass: + return docInternalS3Type.subclass(*args_, **kwargs_) + else: + return docInternalS3Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect3(self): return self.sect3 + def set_sect3(self, sect3): self.sect3 = sect3 + def add_sect3(self, value): self.sect3.append(value) + def insert_sect3(self, index, value): self.sect3[index] = value + def export(self, outfile, level, namespace_='', name_='docInternalS3Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docInternalS3Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docInternalS3Type'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docInternalS3Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.para is not None or + self.sect3 is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docInternalS3Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect3': + childobj_ = docSect4Type.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'sect3', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docInternalS3Type + + +class docInternalS4Type(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None, mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docInternalS4Type.subclass: + return docInternalS4Type.subclass(*args_, **kwargs_) + else: + return docInternalS4Type(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def export(self, outfile, level, namespace_='', name_='docInternalS4Type', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docInternalS4Type') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docInternalS4Type'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docInternalS4Type'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.para is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docInternalS4Type'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + childobj_ = docParaType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'para', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docInternalS4Type + + +class docTitleType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_='', mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docTitleType.subclass: + return docTitleType.subclass(*args_, **kwargs_) + else: + return docTitleType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docTitleType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docTitleType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docTitleType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docTitleType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docTitleType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docTitleType + + +class docParaType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_='', mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docParaType.subclass: + return docParaType.subclass(*args_, **kwargs_) + else: + return docParaType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docParaType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docParaType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docParaType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docParaType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docParaType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docParaType + + +class docMarkupType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_='', mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docMarkupType.subclass: + return docMarkupType.subclass(*args_, **kwargs_) + else: + return docMarkupType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docMarkupType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docMarkupType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docMarkupType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docMarkupType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docMarkupType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docMarkupType + + +class docURLLink(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None): + self.url = url + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docURLLink.subclass: + return docURLLink.subclass(*args_, **kwargs_) + else: + return docURLLink(*args_, **kwargs_) + factory = staticmethod(factory) + def get_url(self): return self.url + def set_url(self, url): self.url = url + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docURLLink', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docURLLink') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docURLLink'): + if self.url is not None: + outfile.write(' url=%s' % (self.format_string(quote_attrib(self.url).encode(ExternalEncoding), input_name='url'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docURLLink'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docURLLink'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.url is not None: + showIndent(outfile, level) + outfile.write('url = %s,\n' % (self.url,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('url'): + self.url = attrs.get('url').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docURLLink + + +class docAnchorType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docAnchorType.subclass: + return docAnchorType.subclass(*args_, **kwargs_) + else: + return docAnchorType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_id(self): return self.id + def set_id(self, id): self.id = id + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docAnchorType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docAnchorType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docAnchorType'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docAnchorType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docAnchorType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docAnchorType + + +class docFormulaType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docFormulaType.subclass: + return docFormulaType.subclass(*args_, **kwargs_) + else: + return docFormulaType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_id(self): return self.id + def set_id(self, id): self.id = id + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docFormulaType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docFormulaType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docFormulaType'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docFormulaType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docFormulaType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docFormulaType + + +class docIndexEntryType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, primaryie=None, secondaryie=None): + self.primaryie = primaryie + self.secondaryie = secondaryie + def factory(*args_, **kwargs_): + if docIndexEntryType.subclass: + return docIndexEntryType.subclass(*args_, **kwargs_) + else: + return docIndexEntryType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_primaryie(self): return self.primaryie + def set_primaryie(self, primaryie): self.primaryie = primaryie + def get_secondaryie(self): return self.secondaryie + def set_secondaryie(self, secondaryie): self.secondaryie = secondaryie + def export(self, outfile, level, namespace_='', name_='docIndexEntryType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docIndexEntryType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docIndexEntryType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docIndexEntryType'): + if self.primaryie is not None: + showIndent(outfile, level) + outfile.write('<%sprimaryie>%s\n' % (namespace_, self.format_string(quote_xml(self.primaryie).encode(ExternalEncoding), input_name='primaryie'), namespace_)) + if self.secondaryie is not None: + showIndent(outfile, level) + outfile.write('<%ssecondaryie>%s\n' % (namespace_, self.format_string(quote_xml(self.secondaryie).encode(ExternalEncoding), input_name='secondaryie'), namespace_)) + def hasContent_(self): + if ( + self.primaryie is not None or + self.secondaryie is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docIndexEntryType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('primaryie=%s,\n' % quote_python(self.primaryie).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('secondaryie=%s,\n' % quote_python(self.secondaryie).encode(ExternalEncoding)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'primaryie': + primaryie_ = '' + for text__content_ in child_.childNodes: + primaryie_ += text__content_.nodeValue + self.primaryie = primaryie_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'secondaryie': + secondaryie_ = '' + for text__content_ in child_.childNodes: + secondaryie_ += text__content_.nodeValue + self.secondaryie = secondaryie_ +# end class docIndexEntryType + + +class docListType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, listitem=None): + if listitem is None: + self.listitem = [] + else: + self.listitem = listitem + def factory(*args_, **kwargs_): + if docListType.subclass: + return docListType.subclass(*args_, **kwargs_) + else: + return docListType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_listitem(self): return self.listitem + def set_listitem(self, listitem): self.listitem = listitem + def add_listitem(self, value): self.listitem.append(value) + def insert_listitem(self, index, value): self.listitem[index] = value + def export(self, outfile, level, namespace_='', name_='docListType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docListType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docListType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docListType'): + for listitem_ in self.listitem: + listitem_.export(outfile, level, namespace_, name_='listitem') + def hasContent_(self): + if ( + self.listitem is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docListType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('listitem=[\n') + level += 1 + for listitem in self.listitem: + showIndent(outfile, level) + outfile.write('model_.listitem(\n') + listitem.exportLiteral(outfile, level, name_='listitem') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'listitem': + obj_ = docListItemType.factory() + obj_.build(child_) + self.listitem.append(obj_) +# end class docListType + + +class docListItemType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, para=None): + if para is None: + self.para = [] + else: + self.para = para + def factory(*args_, **kwargs_): + if docListItemType.subclass: + return docListItemType.subclass(*args_, **kwargs_) + else: + return docListItemType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def export(self, outfile, level, namespace_='', name_='docListItemType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docListItemType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docListItemType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docListItemType'): + for para_ in self.para: + para_.export(outfile, level, namespace_, name_='para') + def hasContent_(self): + if ( + self.para is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docListItemType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('para=[\n') + level += 1 + for para in self.para: + showIndent(outfile, level) + outfile.write('model_.para(\n') + para.exportLiteral(outfile, level, name_='para') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + obj_ = docParaType.factory() + obj_.build(child_) + self.para.append(obj_) +# end class docListItemType + + +class docSimpleSectType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, title=None, para=None): + self.kind = kind + self.title = title + if para is None: + self.para = [] + else: + self.para = para + def factory(*args_, **kwargs_): + if docSimpleSectType.subclass: + return docSimpleSectType.subclass(*args_, **kwargs_) + else: + return docSimpleSectType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_title(self): return self.title + def set_title(self, title): self.title = title + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def export(self, outfile, level, namespace_='', name_='docSimpleSectType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docSimpleSectType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docSimpleSectType'): + if self.kind is not None: + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + def exportChildren(self, outfile, level, namespace_='', name_='docSimpleSectType'): + if self.title: + self.title.export(outfile, level, namespace_, name_='title') + for para_ in self.para: + para_.export(outfile, level, namespace_, name_='para') + def hasContent_(self): + if ( + self.title is not None or + self.para is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docSimpleSectType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + def exportLiteralChildren(self, outfile, level, name_): + if self.title: + showIndent(outfile, level) + outfile.write('title=model_.docTitleType(\n') + self.title.exportLiteral(outfile, level, name_='title') + showIndent(outfile, level) + outfile.write('),\n') + showIndent(outfile, level) + outfile.write('para=[\n') + level += 1 + for para in self.para: + showIndent(outfile, level) + outfile.write('model_.para(\n') + para.exportLiteral(outfile, level, name_='para') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'title': + obj_ = docTitleType.factory() + obj_.build(child_) + self.set_title(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + obj_ = docParaType.factory() + obj_.build(child_) + self.para.append(obj_) +# end class docSimpleSectType + + +class docVarListEntryType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, term=None): + self.term = term + def factory(*args_, **kwargs_): + if docVarListEntryType.subclass: + return docVarListEntryType.subclass(*args_, **kwargs_) + else: + return docVarListEntryType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_term(self): return self.term + def set_term(self, term): self.term = term + def export(self, outfile, level, namespace_='', name_='docVarListEntryType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docVarListEntryType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docVarListEntryType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docVarListEntryType'): + if self.term: + self.term.export(outfile, level, namespace_, name_='term', ) + def hasContent_(self): + if ( + self.term is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docVarListEntryType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + if self.term: + showIndent(outfile, level) + outfile.write('term=model_.docTitleType(\n') + self.term.exportLiteral(outfile, level, name_='term') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'term': + obj_ = docTitleType.factory() + obj_.build(child_) + self.set_term(obj_) +# end class docVarListEntryType + + +class docVariableListType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if docVariableListType.subclass: + return docVariableListType.subclass(*args_, **kwargs_) + else: + return docVariableListType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docVariableListType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docVariableListType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docVariableListType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docVariableListType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docVariableListType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docVariableListType + + +class docRefTextType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): + self.refid = refid + self.kindref = kindref + self.external = external + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docRefTextType.subclass: + return docRefTextType.subclass(*args_, **kwargs_) + else: + return docRefTextType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def get_kindref(self): return self.kindref + def set_kindref(self, kindref): self.kindref = kindref + def get_external(self): return self.external + def set_external(self, external): self.external = external + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docRefTextType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docRefTextType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docRefTextType'): + if self.refid is not None: + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + if self.kindref is not None: + outfile.write(' kindref=%s' % (quote_attrib(self.kindref), )) + if self.external is not None: + outfile.write(' external=%s' % (self.format_string(quote_attrib(self.external).encode(ExternalEncoding), input_name='external'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docRefTextType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docRefTextType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + if self.kindref is not None: + showIndent(outfile, level) + outfile.write('kindref = "%s",\n' % (self.kindref,)) + if self.external is not None: + showIndent(outfile, level) + outfile.write('external = %s,\n' % (self.external,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('refid'): + self.refid = attrs.get('refid').value + if attrs.get('kindref'): + self.kindref = attrs.get('kindref').value + if attrs.get('external'): + self.external = attrs.get('external').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docRefTextType + + +class docTableType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, rows=None, cols=None, row=None, caption=None): + self.rows = rows + self.cols = cols + if row is None: + self.row = [] + else: + self.row = row + self.caption = caption + def factory(*args_, **kwargs_): + if docTableType.subclass: + return docTableType.subclass(*args_, **kwargs_) + else: + return docTableType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_row(self): return self.row + def set_row(self, row): self.row = row + def add_row(self, value): self.row.append(value) + def insert_row(self, index, value): self.row[index] = value + def get_caption(self): return self.caption + def set_caption(self, caption): self.caption = caption + def get_rows(self): return self.rows + def set_rows(self, rows): self.rows = rows + def get_cols(self): return self.cols + def set_cols(self, cols): self.cols = cols + def export(self, outfile, level, namespace_='', name_='docTableType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docTableType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docTableType'): + if self.rows is not None: + outfile.write(' rows="%s"' % self.format_integer(self.rows, input_name='rows')) + if self.cols is not None: + outfile.write(' cols="%s"' % self.format_integer(self.cols, input_name='cols')) + def exportChildren(self, outfile, level, namespace_='', name_='docTableType'): + for row_ in self.row: + row_.export(outfile, level, namespace_, name_='row') + if self.caption: + self.caption.export(outfile, level, namespace_, name_='caption') + def hasContent_(self): + if ( + self.row is not None or + self.caption is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docTableType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.rows is not None: + showIndent(outfile, level) + outfile.write('rows = %s,\n' % (self.rows,)) + if self.cols is not None: + showIndent(outfile, level) + outfile.write('cols = %s,\n' % (self.cols,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('row=[\n') + level += 1 + for row in self.row: + showIndent(outfile, level) + outfile.write('model_.row(\n') + row.exportLiteral(outfile, level, name_='row') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.caption: + showIndent(outfile, level) + outfile.write('caption=model_.docCaptionType(\n') + self.caption.exportLiteral(outfile, level, name_='caption') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('rows'): + try: + self.rows = int(attrs.get('rows').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (rows): %s' % exp) + if attrs.get('cols'): + try: + self.cols = int(attrs.get('cols').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (cols): %s' % exp) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'row': + obj_ = docRowType.factory() + obj_.build(child_) + self.row.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'caption': + obj_ = docCaptionType.factory() + obj_.build(child_) + self.set_caption(obj_) +# end class docTableType + + +class docRowType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, entry=None): + if entry is None: + self.entry = [] + else: + self.entry = entry + def factory(*args_, **kwargs_): + if docRowType.subclass: + return docRowType.subclass(*args_, **kwargs_) + else: + return docRowType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_entry(self): return self.entry + def set_entry(self, entry): self.entry = entry + def add_entry(self, value): self.entry.append(value) + def insert_entry(self, index, value): self.entry[index] = value + def export(self, outfile, level, namespace_='', name_='docRowType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docRowType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docRowType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docRowType'): + for entry_ in self.entry: + entry_.export(outfile, level, namespace_, name_='entry') + def hasContent_(self): + if ( + self.entry is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docRowType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('entry=[\n') + level += 1 + for entry in self.entry: + showIndent(outfile, level) + outfile.write('model_.entry(\n') + entry.exportLiteral(outfile, level, name_='entry') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'entry': + obj_ = docEntryType.factory() + obj_.build(child_) + self.entry.append(obj_) +# end class docRowType + + +class docEntryType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, thead=None, para=None): + self.thead = thead + if para is None: + self.para = [] + else: + self.para = para + def factory(*args_, **kwargs_): + if docEntryType.subclass: + return docEntryType.subclass(*args_, **kwargs_) + else: + return docEntryType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_thead(self): return self.thead + def set_thead(self, thead): self.thead = thead + def export(self, outfile, level, namespace_='', name_='docEntryType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docEntryType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docEntryType'): + if self.thead is not None: + outfile.write(' thead=%s' % (quote_attrib(self.thead), )) + def exportChildren(self, outfile, level, namespace_='', name_='docEntryType'): + for para_ in self.para: + para_.export(outfile, level, namespace_, name_='para') + def hasContent_(self): + if ( + self.para is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docEntryType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.thead is not None: + showIndent(outfile, level) + outfile.write('thead = "%s",\n' % (self.thead,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('para=[\n') + level += 1 + for para in self.para: + showIndent(outfile, level) + outfile.write('model_.para(\n') + para.exportLiteral(outfile, level, name_='para') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('thead'): + self.thead = attrs.get('thead').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + obj_ = docParaType.factory() + obj_.build(child_) + self.para.append(obj_) +# end class docEntryType + + +class docCaptionType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_='', mixedclass_=None, content_=None): + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docCaptionType.subclass: + return docCaptionType.subclass(*args_, **kwargs_) + else: + return docCaptionType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docCaptionType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docCaptionType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docCaptionType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docCaptionType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docCaptionType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docCaptionType + + +class docHeadingType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None): + self.level = level + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docHeadingType.subclass: + return docHeadingType.subclass(*args_, **kwargs_) + else: + return docHeadingType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_level(self): return self.level + def set_level(self, level): self.level = level + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docHeadingType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docHeadingType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docHeadingType'): + if self.level is not None: + outfile.write(' level="%s"' % self.format_integer(self.level, input_name='level')) + def exportChildren(self, outfile, level, namespace_='', name_='docHeadingType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docHeadingType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.level is not None: + showIndent(outfile, level) + outfile.write('level = %s,\n' % (self.level,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('level'): + try: + self.level = int(attrs.get('level').value) + except ValueError, exp: + raise ValueError('Bad integer attribute (level): %s' % exp) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docHeadingType + + +class docImageType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None): + self.width = width + self.type_ = type_ + self.name = name + self.height = height + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docImageType.subclass: + return docImageType.subclass(*args_, **kwargs_) + else: + return docImageType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_width(self): return self.width + def set_width(self, width): self.width = width + def get_type(self): return self.type_ + def set_type(self, type_): self.type_ = type_ + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_height(self): return self.height + def set_height(self, height): self.height = height + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docImageType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docImageType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docImageType'): + if self.width is not None: + outfile.write(' width=%s' % (self.format_string(quote_attrib(self.width).encode(ExternalEncoding), input_name='width'), )) + if self.type_ is not None: + outfile.write(' type=%s' % (quote_attrib(self.type_), )) + if self.name is not None: + outfile.write(' name=%s' % (self.format_string(quote_attrib(self.name).encode(ExternalEncoding), input_name='name'), )) + if self.height is not None: + outfile.write(' height=%s' % (self.format_string(quote_attrib(self.height).encode(ExternalEncoding), input_name='height'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docImageType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docImageType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.width is not None: + showIndent(outfile, level) + outfile.write('width = %s,\n' % (self.width,)) + if self.type_ is not None: + showIndent(outfile, level) + outfile.write('type_ = "%s",\n' % (self.type_,)) + if self.name is not None: + showIndent(outfile, level) + outfile.write('name = %s,\n' % (self.name,)) + if self.height is not None: + showIndent(outfile, level) + outfile.write('height = %s,\n' % (self.height,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('width'): + self.width = attrs.get('width').value + if attrs.get('type'): + self.type_ = attrs.get('type').value + if attrs.get('name'): + self.name = attrs.get('name').value + if attrs.get('height'): + self.height = attrs.get('height').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docImageType + + +class docDotFileType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None): + self.name = name + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docDotFileType.subclass: + return docDotFileType.subclass(*args_, **kwargs_) + else: + return docDotFileType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_name(self): return self.name + def set_name(self, name): self.name = name + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docDotFileType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docDotFileType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docDotFileType'): + if self.name is not None: + outfile.write(' name=%s' % (self.format_string(quote_attrib(self.name).encode(ExternalEncoding), input_name='name'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docDotFileType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docDotFileType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.name is not None: + showIndent(outfile, level) + outfile.write('name = %s,\n' % (self.name,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('name'): + self.name = attrs.get('name').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docDotFileType + + +class docTocItemType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): + self.id = id + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docTocItemType.subclass: + return docTocItemType.subclass(*args_, **kwargs_) + else: + return docTocItemType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_id(self): return self.id + def set_id(self, id): self.id = id + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docTocItemType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docTocItemType') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docTocItemType'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docTocItemType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docTocItemType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docTocItemType + + +class docTocListType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, tocitem=None): + if tocitem is None: + self.tocitem = [] + else: + self.tocitem = tocitem + def factory(*args_, **kwargs_): + if docTocListType.subclass: + return docTocListType.subclass(*args_, **kwargs_) + else: + return docTocListType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_tocitem(self): return self.tocitem + def set_tocitem(self, tocitem): self.tocitem = tocitem + def add_tocitem(self, value): self.tocitem.append(value) + def insert_tocitem(self, index, value): self.tocitem[index] = value + def export(self, outfile, level, namespace_='', name_='docTocListType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docTocListType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docTocListType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docTocListType'): + for tocitem_ in self.tocitem: + tocitem_.export(outfile, level, namespace_, name_='tocitem') + def hasContent_(self): + if ( + self.tocitem is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docTocListType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('tocitem=[\n') + level += 1 + for tocitem in self.tocitem: + showIndent(outfile, level) + outfile.write('model_.tocitem(\n') + tocitem.exportLiteral(outfile, level, name_='tocitem') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'tocitem': + obj_ = docTocItemType.factory() + obj_.build(child_) + self.tocitem.append(obj_) +# end class docTocListType + + +class docLanguageType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, langid=None, para=None): + self.langid = langid + if para is None: + self.para = [] + else: + self.para = para + def factory(*args_, **kwargs_): + if docLanguageType.subclass: + return docLanguageType.subclass(*args_, **kwargs_) + else: + return docLanguageType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_langid(self): return self.langid + def set_langid(self, langid): self.langid = langid + def export(self, outfile, level, namespace_='', name_='docLanguageType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docLanguageType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docLanguageType'): + if self.langid is not None: + outfile.write(' langid=%s' % (self.format_string(quote_attrib(self.langid).encode(ExternalEncoding), input_name='langid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docLanguageType'): + for para_ in self.para: + para_.export(outfile, level, namespace_, name_='para') + def hasContent_(self): + if ( + self.para is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docLanguageType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.langid is not None: + showIndent(outfile, level) + outfile.write('langid = %s,\n' % (self.langid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('para=[\n') + level += 1 + for para in self.para: + showIndent(outfile, level) + outfile.write('model_.para(\n') + para.exportLiteral(outfile, level, name_='para') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('langid'): + self.langid = attrs.get('langid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + obj_ = docParaType.factory() + obj_.build(child_) + self.para.append(obj_) +# end class docLanguageType + + +class docParamListType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, parameteritem=None): + self.kind = kind + if parameteritem is None: + self.parameteritem = [] + else: + self.parameteritem = parameteritem + def factory(*args_, **kwargs_): + if docParamListType.subclass: + return docParamListType.subclass(*args_, **kwargs_) + else: + return docParamListType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_parameteritem(self): return self.parameteritem + def set_parameteritem(self, parameteritem): self.parameteritem = parameteritem + def add_parameteritem(self, value): self.parameteritem.append(value) + def insert_parameteritem(self, index, value): self.parameteritem[index] = value + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def export(self, outfile, level, namespace_='', name_='docParamListType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docParamListType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docParamListType'): + if self.kind is not None: + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + def exportChildren(self, outfile, level, namespace_='', name_='docParamListType'): + for parameteritem_ in self.parameteritem: + parameteritem_.export(outfile, level, namespace_, name_='parameteritem') + def hasContent_(self): + if ( + self.parameteritem is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docParamListType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('parameteritem=[\n') + level += 1 + for parameteritem in self.parameteritem: + showIndent(outfile, level) + outfile.write('model_.parameteritem(\n') + parameteritem.exportLiteral(outfile, level, name_='parameteritem') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'parameteritem': + obj_ = docParamListItem.factory() + obj_.build(child_) + self.parameteritem.append(obj_) +# end class docParamListType + + +class docParamListItem(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, parameternamelist=None, parameterdescription=None): + if parameternamelist is None: + self.parameternamelist = [] + else: + self.parameternamelist = parameternamelist + self.parameterdescription = parameterdescription + def factory(*args_, **kwargs_): + if docParamListItem.subclass: + return docParamListItem.subclass(*args_, **kwargs_) + else: + return docParamListItem(*args_, **kwargs_) + factory = staticmethod(factory) + def get_parameternamelist(self): return self.parameternamelist + def set_parameternamelist(self, parameternamelist): self.parameternamelist = parameternamelist + def add_parameternamelist(self, value): self.parameternamelist.append(value) + def insert_parameternamelist(self, index, value): self.parameternamelist[index] = value + def get_parameterdescription(self): return self.parameterdescription + def set_parameterdescription(self, parameterdescription): self.parameterdescription = parameterdescription + def export(self, outfile, level, namespace_='', name_='docParamListItem', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docParamListItem') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docParamListItem'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docParamListItem'): + for parameternamelist_ in self.parameternamelist: + parameternamelist_.export(outfile, level, namespace_, name_='parameternamelist') + if self.parameterdescription: + self.parameterdescription.export(outfile, level, namespace_, name_='parameterdescription', ) + def hasContent_(self): + if ( + self.parameternamelist is not None or + self.parameterdescription is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docParamListItem'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('parameternamelist=[\n') + level += 1 + for parameternamelist in self.parameternamelist: + showIndent(outfile, level) + outfile.write('model_.parameternamelist(\n') + parameternamelist.exportLiteral(outfile, level, name_='parameternamelist') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.parameterdescription: + showIndent(outfile, level) + outfile.write('parameterdescription=model_.descriptionType(\n') + self.parameterdescription.exportLiteral(outfile, level, name_='parameterdescription') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'parameternamelist': + obj_ = docParamNameList.factory() + obj_.build(child_) + self.parameternamelist.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'parameterdescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_parameterdescription(obj_) +# end class docParamListItem + + +class docParamNameList(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, parametername=None): + if parametername is None: + self.parametername = [] + else: + self.parametername = parametername + def factory(*args_, **kwargs_): + if docParamNameList.subclass: + return docParamNameList.subclass(*args_, **kwargs_) + else: + return docParamNameList(*args_, **kwargs_) + factory = staticmethod(factory) + def get_parametername(self): return self.parametername + def set_parametername(self, parametername): self.parametername = parametername + def add_parametername(self, value): self.parametername.append(value) + def insert_parametername(self, index, value): self.parametername[index] = value + def export(self, outfile, level, namespace_='', name_='docParamNameList', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docParamNameList') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docParamNameList'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docParamNameList'): + for parametername_ in self.parametername: + parametername_.export(outfile, level, namespace_, name_='parametername') + def hasContent_(self): + if ( + self.parametername is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docParamNameList'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('parametername=[\n') + level += 1 + for parametername in self.parametername: + showIndent(outfile, level) + outfile.write('model_.parametername(\n') + parametername.exportLiteral(outfile, level, name_='parametername') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'parametername': + obj_ = docParamName.factory() + obj_.build(child_) + self.parametername.append(obj_) +# end class docParamNameList + + +class docParamName(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None): + self.direction = direction + if mixedclass_ is None: + self.mixedclass_ = MixedContainer + else: + self.mixedclass_ = mixedclass_ + if content_ is None: + self.content_ = [] + else: + self.content_ = content_ + def factory(*args_, **kwargs_): + if docParamName.subclass: + return docParamName.subclass(*args_, **kwargs_) + else: + return docParamName(*args_, **kwargs_) + factory = staticmethod(factory) + def get_ref(self): return self.ref + def set_ref(self, ref): self.ref = ref + def get_direction(self): return self.direction + def set_direction(self, direction): self.direction = direction + def export(self, outfile, level, namespace_='', name_='docParamName', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docParamName') + outfile.write('>') + self.exportChildren(outfile, level + 1, namespace_, name_) + outfile.write('\n' % (namespace_, name_)) + def exportAttributes(self, outfile, level, namespace_='', name_='docParamName'): + if self.direction is not None: + outfile.write(' direction=%s' % (quote_attrib(self.direction), )) + def exportChildren(self, outfile, level, namespace_='', name_='docParamName'): + for item_ in self.content_: + item_.export(outfile, level, item_.name, namespace_) + def hasContent_(self): + if ( + self.ref is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docParamName'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.direction is not None: + showIndent(outfile, level) + outfile.write('direction = "%s",\n' % (self.direction,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('content_ = [\n') + for item_ in self.content_: + item_.exportLiteral(outfile, level, name_) + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('direction'): + self.direction = attrs.get('direction').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'ref': + childobj_ = docRefTextType.factory() + childobj_.build(child_) + obj_ = self.mixedclass_(MixedContainer.CategoryComplex, + MixedContainer.TypeNone, 'ref', childobj_) + self.content_.append(obj_) + elif child_.nodeType == Node.TEXT_NODE: + obj_ = self.mixedclass_(MixedContainer.CategoryText, + MixedContainer.TypeNone, '', child_.nodeValue) + self.content_.append(obj_) +# end class docParamName + + +class docXRefSectType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, xreftitle=None, xrefdescription=None): + self.id = id + if xreftitle is None: + self.xreftitle = [] + else: + self.xreftitle = xreftitle + self.xrefdescription = xrefdescription + def factory(*args_, **kwargs_): + if docXRefSectType.subclass: + return docXRefSectType.subclass(*args_, **kwargs_) + else: + return docXRefSectType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_xreftitle(self): return self.xreftitle + def set_xreftitle(self, xreftitle): self.xreftitle = xreftitle + def add_xreftitle(self, value): self.xreftitle.append(value) + def insert_xreftitle(self, index, value): self.xreftitle[index] = value + def get_xrefdescription(self): return self.xrefdescription + def set_xrefdescription(self, xrefdescription): self.xrefdescription = xrefdescription + def get_id(self): return self.id + def set_id(self, id): self.id = id + def export(self, outfile, level, namespace_='', name_='docXRefSectType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docXRefSectType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docXRefSectType'): + if self.id is not None: + outfile.write(' id=%s' % (self.format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docXRefSectType'): + for xreftitle_ in self.xreftitle: + showIndent(outfile, level) + outfile.write('<%sxreftitle>%s\n' % (namespace_, self.format_string(quote_xml(xreftitle_).encode(ExternalEncoding), input_name='xreftitle'), namespace_)) + if self.xrefdescription: + self.xrefdescription.export(outfile, level, namespace_, name_='xrefdescription', ) + def hasContent_(self): + if ( + self.xreftitle is not None or + self.xrefdescription is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docXRefSectType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.id is not None: + showIndent(outfile, level) + outfile.write('id = %s,\n' % (self.id,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('xreftitle=[\n') + level += 1 + for xreftitle in self.xreftitle: + showIndent(outfile, level) + outfile.write('%s,\n' % quote_python(xreftitle).encode(ExternalEncoding)) + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.xrefdescription: + showIndent(outfile, level) + outfile.write('xrefdescription=model_.descriptionType(\n') + self.xrefdescription.exportLiteral(outfile, level, name_='xrefdescription') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('id'): + self.id = attrs.get('id').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'xreftitle': + xreftitle_ = '' + for text__content_ in child_.childNodes: + xreftitle_ += text__content_.nodeValue + self.xreftitle.append(xreftitle_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'xrefdescription': + obj_ = descriptionType.factory() + obj_.build(child_) + self.set_xrefdescription(obj_) +# end class docXRefSectType + + +class docCopyType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, link=None, para=None, sect1=None, internal=None): + self.link = link + if para is None: + self.para = [] + else: + self.para = para + if sect1 is None: + self.sect1 = [] + else: + self.sect1 = sect1 + self.internal = internal + def factory(*args_, **kwargs_): + if docCopyType.subclass: + return docCopyType.subclass(*args_, **kwargs_) + else: + return docCopyType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_para(self): return self.para + def set_para(self, para): self.para = para + def add_para(self, value): self.para.append(value) + def insert_para(self, index, value): self.para[index] = value + def get_sect1(self): return self.sect1 + def set_sect1(self, sect1): self.sect1 = sect1 + def add_sect1(self, value): self.sect1.append(value) + def insert_sect1(self, index, value): self.sect1[index] = value + def get_internal(self): return self.internal + def set_internal(self, internal): self.internal = internal + def get_link(self): return self.link + def set_link(self, link): self.link = link + def export(self, outfile, level, namespace_='', name_='docCopyType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docCopyType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docCopyType'): + if self.link is not None: + outfile.write(' link=%s' % (self.format_string(quote_attrib(self.link).encode(ExternalEncoding), input_name='link'), )) + def exportChildren(self, outfile, level, namespace_='', name_='docCopyType'): + for para_ in self.para: + para_.export(outfile, level, namespace_, name_='para') + for sect1_ in self.sect1: + sect1_.export(outfile, level, namespace_, name_='sect1') + if self.internal: + self.internal.export(outfile, level, namespace_, name_='internal') + def hasContent_(self): + if ( + self.para is not None or + self.sect1 is not None or + self.internal is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docCopyType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.link is not None: + showIndent(outfile, level) + outfile.write('link = %s,\n' % (self.link,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('para=[\n') + level += 1 + for para in self.para: + showIndent(outfile, level) + outfile.write('model_.para(\n') + para.exportLiteral(outfile, level, name_='para') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + showIndent(outfile, level) + outfile.write('sect1=[\n') + level += 1 + for sect1 in self.sect1: + showIndent(outfile, level) + outfile.write('model_.sect1(\n') + sect1.exportLiteral(outfile, level, name_='sect1') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + if self.internal: + showIndent(outfile, level) + outfile.write('internal=model_.docInternalType(\n') + self.internal.exportLiteral(outfile, level, name_='internal') + showIndent(outfile, level) + outfile.write('),\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('link'): + self.link = attrs.get('link').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'para': + obj_ = docParaType.factory() + obj_.build(child_) + self.para.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'sect1': + obj_ = docSect1Type.factory() + obj_.build(child_) + self.sect1.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'internal': + obj_ = docInternalType.factory() + obj_.build(child_) + self.set_internal(obj_) +# end class docCopyType + + +class docCharType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, char=None, valueOf_=''): + self.char = char + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if docCharType.subclass: + return docCharType.subclass(*args_, **kwargs_) + else: + return docCharType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_char(self): return self.char + def set_char(self, char): self.char = char + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docCharType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docCharType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docCharType'): + if self.char is not None: + outfile.write(' char=%s' % (quote_attrib(self.char), )) + def exportChildren(self, outfile, level, namespace_='', name_='docCharType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docCharType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.char is not None: + showIndent(outfile, level) + outfile.write('char = "%s",\n' % (self.char,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('char'): + self.char = attrs.get('char').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docCharType + + +class docEmptyType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, valueOf_=''): + self.valueOf_ = valueOf_ + def factory(*args_, **kwargs_): + if docEmptyType.subclass: + return docEmptyType.subclass(*args_, **kwargs_) + else: + return docEmptyType(*args_, **kwargs_) + factory = staticmethod(factory) + def getValueOf_(self): return self.valueOf_ + def setValueOf_(self, valueOf_): self.valueOf_ = valueOf_ + def export(self, outfile, level, namespace_='', name_='docEmptyType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='docEmptyType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='docEmptyType'): + pass + def exportChildren(self, outfile, level, namespace_='', name_='docEmptyType'): + if self.valueOf_.find('![CDATA')>-1: + value=quote_xml('%s' % self.valueOf_) + value=value.replace('![CDATA','') + outfile.write(value) + else: + outfile.write(quote_xml('%s' % self.valueOf_)) + def hasContent_(self): + if ( + self.valueOf_ is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='docEmptyType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + pass + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('valueOf_ = "%s",\n' % (self.valueOf_,)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + self.valueOf_ = '' + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + pass + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.TEXT_NODE: + self.valueOf_ += child_.nodeValue + elif child_.nodeType == Node.CDATA_SECTION_NODE: + self.valueOf_ += '![CDATA['+child_.nodeValue+']]' +# end class docEmptyType + + +USAGE_TEXT = """ +Usage: python .py [ -s ] +Options: + -s Use the SAX parser, not the minidom parser. +""" + +def usage(): + print USAGE_TEXT + sys.exit(1) + + +def parse(inFileName): + doc = minidom.parse(inFileName) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('\n') + rootObj.export(sys.stdout, 0, name_="doxygen", + namespacedef_='') + return rootObj + + +def parseString(inString): + doc = minidom.parseString(inString) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('\n') + rootObj.export(sys.stdout, 0, name_="doxygen", + namespacedef_='') + return rootObj + + +def parseLiteral(inFileName): + doc = minidom.parse(inFileName) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('from compound import *\n\n') + sys.stdout.write('rootObj = doxygen(\n') + rootObj.exportLiteral(sys.stdout, 0, name_="doxygen") + sys.stdout.write(')\n') + return rootObj + + +def main(): + args = sys.argv[1:] + if len(args) == 1: + parse(args[0]) + else: + usage() + + +if __name__ == '__main__': + main() + #import pdb + #pdb.run('main()') + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/index.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/index.py new file mode 100644 index 000000000..7a70e14a1 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/index.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +""" +Generated Mon Feb 9 19:08:05 2009 by generateDS.py. +""" + +from xml.dom import minidom + +import os +import sys +import compound + +import indexsuper as supermod + +class DoxygenTypeSub(supermod.DoxygenType): + def __init__(self, version=None, compound=None): + supermod.DoxygenType.__init__(self, version, compound) + + def find_compounds_and_members(self, details): + """ + Returns a list of all compounds and their members which match details + """ + + results = [] + for compound in self.compound: + members = compound.find_members(details) + if members: + results.append([compound, members]) + else: + if details.match(compound): + results.append([compound, []]) + + return results + +supermod.DoxygenType.subclass = DoxygenTypeSub +# end class DoxygenTypeSub + + +class CompoundTypeSub(supermod.CompoundType): + def __init__(self, kind=None, refid=None, name='', member=None): + supermod.CompoundType.__init__(self, kind, refid, name, member) + + def find_members(self, details): + """ + Returns a list of all members which match details + """ + + results = [] + + for member in self.member: + if details.match(member): + results.append(member) + + return results + +supermod.CompoundType.subclass = CompoundTypeSub +# end class CompoundTypeSub + + +class MemberTypeSub(supermod.MemberType): + + def __init__(self, kind=None, refid=None, name=''): + supermod.MemberType.__init__(self, kind, refid, name) + +supermod.MemberType.subclass = MemberTypeSub +# end class MemberTypeSub + + +def parse(inFilename): + + doc = minidom.parse(inFilename) + rootNode = doc.documentElement + rootObj = supermod.DoxygenType.factory() + rootObj.build(rootNode) + + return rootObj + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/indexsuper.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/indexsuper.py new file mode 100644 index 000000000..a99153019 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/generated/indexsuper.py @@ -0,0 +1,523 @@ +#!/usr/bin/env python + +# +# Generated Thu Jun 11 18:43:54 2009 by generateDS.py. +# + +import sys +import getopt +from string import lower as str_lower +from xml.dom import minidom +from xml.dom import Node + +# +# User methods +# +# Calls to the methods in these classes are generated by generateDS.py. +# You can replace these methods by re-implementing the following class +# in a module named generatedssuper.py. + +try: + from generatedssuper import GeneratedsSuper +except ImportError, exp: + + class GeneratedsSuper: + def format_string(self, input_data, input_name=''): + return input_data + def format_integer(self, input_data, input_name=''): + return '%d' % input_data + def format_float(self, input_data, input_name=''): + return '%f' % input_data + def format_double(self, input_data, input_name=''): + return '%e' % input_data + def format_boolean(self, input_data, input_name=''): + return '%s' % input_data + + +# +# If you have installed IPython you can uncomment and use the following. +# IPython is available from http://ipython.scipy.org/. +# + +## from IPython.Shell import IPShellEmbed +## args = '' +## ipshell = IPShellEmbed(args, +## banner = 'Dropping into IPython', +## exit_msg = 'Leaving Interpreter, back to program.') + +# Then use the following line where and when you want to drop into the +# IPython shell: +# ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') + +# +# Globals +# + +ExternalEncoding = 'ascii' + +# +# Support/utility functions. +# + +def showIndent(outfile, level): + for idx in range(level): + outfile.write(' ') + +def quote_xml(inStr): + s1 = (isinstance(inStr, basestring) and inStr or + '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + return s1 + +def quote_attrib(inStr): + s1 = (isinstance(inStr, basestring) and inStr or + '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + if '"' in s1: + if "'" in s1: + s1 = '"%s"' % s1.replace('"', """) + else: + s1 = "'%s'" % s1 + else: + s1 = '"%s"' % s1 + return s1 + +def quote_python(inStr): + s1 = inStr + if s1.find("'") == -1: + if s1.find('\n') == -1: + return "'%s'" % s1 + else: + return "'''%s'''" % s1 + else: + if s1.find('"') != -1: + s1 = s1.replace('"', '\\"') + if s1.find('\n') == -1: + return '"%s"' % s1 + else: + return '"""%s"""' % s1 + + +class MixedContainer: + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name, namespace): + if self.category == MixedContainer.CategoryText: + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export(outfile, level, namespace,name) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write('<%s>%s' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write('<%s>%d' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write('<%s>%f' % (self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write('<%s>%g' % (self.name, self.value, self.name)) + def exportLiteral(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ + (self.category, self.content_type, self.name, self.value)) + elif self.category == MixedContainer.CategorySimple: + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ + (self.category, self.content_type, self.name, self.value)) + else: # category == MixedContainer.CategoryComplex + showIndent(outfile, level) + outfile.write('MixedContainer(%d, %d, "%s",\n' % \ + (self.category, self.content_type, self.name,)) + self.value.exportLiteral(outfile, level + 1) + showIndent(outfile, level) + outfile.write(')\n') + + +class _MemberSpec(object): + def __init__(self, name='', data_type='', container=0): + self.name = name + self.data_type = data_type + self.container = container + def set_name(self, name): self.name = name + def get_name(self): return self.name + def set_data_type(self, data_type): self.data_type = data_type + def get_data_type(self): return self.data_type + def set_container(self, container): self.container = container + def get_container(self): return self.container + + +# +# Data representation classes. +# + +class DoxygenType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, version=None, compound=None): + self.version = version + if compound is None: + self.compound = [] + else: + self.compound = compound + def factory(*args_, **kwargs_): + if DoxygenType.subclass: + return DoxygenType.subclass(*args_, **kwargs_) + else: + return DoxygenType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_compound(self): return self.compound + def set_compound(self, compound): self.compound = compound + def add_compound(self, value): self.compound.append(value) + def insert_compound(self, index, value): self.compound[index] = value + def get_version(self): return self.version + def set_version(self, version): self.version = version + def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='DoxygenType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'): + outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), )) + def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'): + for compound_ in self.compound: + compound_.export(outfile, level, namespace_, name_='compound') + def hasContent_(self): + if ( + self.compound is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='DoxygenType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.version is not None: + showIndent(outfile, level) + outfile.write('version = %s,\n' % (self.version,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('compound=[\n') + level += 1 + for compound in self.compound: + showIndent(outfile, level) + outfile.write('model_.compound(\n') + compound.exportLiteral(outfile, level, name_='compound') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('version'): + self.version = attrs.get('version').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'compound': + obj_ = CompoundType.factory() + obj_.build(child_) + self.compound.append(obj_) +# end class DoxygenType + + +class CompoundType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, refid=None, name=None, member=None): + self.kind = kind + self.refid = refid + self.name = name + if member is None: + self.member = [] + else: + self.member = member + def factory(*args_, **kwargs_): + if CompoundType.subclass: + return CompoundType.subclass(*args_, **kwargs_) + else: + return CompoundType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_member(self): return self.member + def set_member(self, member): self.member = member + def add_member(self, value): self.member.append(value) + def insert_member(self, index, value): self.member[index] = value + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='CompoundType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'): + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'): + if self.name is not None: + showIndent(outfile, level) + outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) + for member_ in self.member: + member_.export(outfile, level, namespace_, name_='member') + def hasContent_(self): + if ( + self.name is not None or + self.member is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='CompoundType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) + showIndent(outfile, level) + outfile.write('member=[\n') + level += 1 + for member in self.member: + showIndent(outfile, level) + outfile.write('model_.member(\n') + member.exportLiteral(outfile, level, name_='member') + showIndent(outfile, level) + outfile.write('),\n') + level -= 1 + showIndent(outfile, level) + outfile.write('],\n') + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'name': + name_ = '' + for text__content_ in child_.childNodes: + name_ += text__content_.nodeValue + self.name = name_ + elif child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'member': + obj_ = MemberType.factory() + obj_.build(child_) + self.member.append(obj_) +# end class CompoundType + + +class MemberType(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, kind=None, refid=None, name=None): + self.kind = kind + self.refid = refid + self.name = name + def factory(*args_, **kwargs_): + if MemberType.subclass: + return MemberType.subclass(*args_, **kwargs_) + else: + return MemberType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_kind(self): return self.kind + def set_kind(self, kind): self.kind = kind + def get_refid(self): return self.refid + def set_refid(self, refid): self.refid = refid + def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''): + showIndent(outfile, level) + outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) + self.exportAttributes(outfile, level, namespace_, name_='MemberType') + if self.hasContent_(): + outfile.write('>\n') + self.exportChildren(outfile, level + 1, namespace_, name_) + showIndent(outfile, level) + outfile.write('\n' % (namespace_, name_)) + else: + outfile.write(' />\n') + def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'): + outfile.write(' kind=%s' % (quote_attrib(self.kind), )) + outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) + def exportChildren(self, outfile, level, namespace_='', name_='MemberType'): + if self.name is not None: + showIndent(outfile, level) + outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) + def hasContent_(self): + if ( + self.name is not None + ): + return True + else: + return False + def exportLiteral(self, outfile, level, name_='MemberType'): + level += 1 + self.exportLiteralAttributes(outfile, level, name_) + if self.hasContent_(): + self.exportLiteralChildren(outfile, level, name_) + def exportLiteralAttributes(self, outfile, level, name_): + if self.kind is not None: + showIndent(outfile, level) + outfile.write('kind = "%s",\n' % (self.kind,)) + if self.refid is not None: + showIndent(outfile, level) + outfile.write('refid = %s,\n' % (self.refid,)) + def exportLiteralChildren(self, outfile, level, name_): + showIndent(outfile, level) + outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) + def build(self, node_): + attrs = node_.attributes + self.buildAttributes(attrs) + for child_ in node_.childNodes: + nodeName_ = child_.nodeName.split(':')[-1] + self.buildChildren(child_, nodeName_) + def buildAttributes(self, attrs): + if attrs.get('kind'): + self.kind = attrs.get('kind').value + if attrs.get('refid'): + self.refid = attrs.get('refid').value + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and \ + nodeName_ == 'name': + name_ = '' + for text__content_ in child_.childNodes: + name_ += text__content_.nodeValue + self.name = name_ +# end class MemberType + + +USAGE_TEXT = """ +Usage: python .py [ -s ] +Options: + -s Use the SAX parser, not the minidom parser. +""" + +def usage(): + print USAGE_TEXT + sys.exit(1) + + +def parse(inFileName): + doc = minidom.parse(inFileName) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('\n') + rootObj.export(sys.stdout, 0, name_="doxygenindex", + namespacedef_='') + return rootObj + + +def parseString(inString): + doc = minidom.parseString(inString) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('\n') + rootObj.export(sys.stdout, 0, name_="doxygenindex", + namespacedef_='') + return rootObj + + +def parseLiteral(inFileName): + doc = minidom.parse(inFileName) + rootNode = doc.documentElement + rootObj = DoxygenType.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + sys.stdout.write('from index import *\n\n') + sys.stdout.write('rootObj = doxygenindex(\n') + rootObj.exportLiteral(sys.stdout, 0, name_="doxygenindex") + sys.stdout.write(')\n') + return rootObj + + +def main(): + args = sys.argv[1:] + if len(args) == 1: + parse(args[0]) + else: + usage() + + + + +if __name__ == '__main__': + main() + #import pdb + #pdb.run('main()') + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/text.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/text.py new file mode 100644 index 000000000..629edd180 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/doxyxml/text.py @@ -0,0 +1,56 @@ +# +# Copyright 2010 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. +# +""" +Utilities for extracting text from generated classes. +""" + +def is_string(txt): + if isinstance(txt, str): + return True + try: + if isinstance(txt, unicode): + return True + except NameError: + pass + return False + +def description(obj): + if obj is None: + return None + return description_bit(obj).strip() + +def description_bit(obj): + if hasattr(obj, 'content'): + contents = [description_bit(item) for item in obj.content] + result = ''.join(contents) + elif hasattr(obj, 'content_'): + contents = [description_bit(item) for item in obj.content_] + result = ''.join(contents) + elif hasattr(obj, 'value'): + result = description_bit(obj.value) + elif is_string(obj): + return obj + else: + raise StandardError('Expecting a string or something with content, content_ or value attribute') + # If this bit is a paragraph then add one some line breaks. + if hasattr(obj, 'name') and obj.name == 'para': + result += "\n\n" + return result diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/group_defs.dox b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/group_defs.dox new file mode 100644 index 000000000..708f8c6d9 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/group_defs.dox @@ -0,0 +1,7 @@ +/*! + * \defgroup block GNU Radio HOWTO C++ Signal Processing Blocks + * \brief All C++ blocks that can be used from the HOWTO GNU Radio + * module are listed here or in the subcategories below. + * + */ + diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/main_page.dox b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/main_page.dox new file mode 100644 index 000000000..635704491 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/other/main_page.dox @@ -0,0 +1,10 @@ +/*! \mainpage + +Welcome to the GNU Radio HOWTO Block + +This is the intro page for the Doxygen manual generated for the HOWTO +block (docs/doxygen/other/main_page.dox). Edit it to add more detailed +documentation about the new GNU Radio modules contained in this +project. + +*/ diff --git a/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/swig_doc.py b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/swig_doc.py new file mode 100644 index 000000000..4e1ce2e47 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/docs/doxygen/swig_doc.py @@ -0,0 +1,255 @@ +# +# Copyright 2010,2011 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. +# +""" +Creates the swig_doc.i SWIG interface file. +Execute using: python swig_doc.py xml_path outputfilename + +The file instructs SWIG to transfer the doxygen comments into the +python docstrings. + +""" + +import sys + +try: + from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base +except ImportError: + from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base + + +def py_name(name): + bits = name.split('_') + return '_'.join(bits[1:]) + +def make_name(name): + bits = name.split('_') + return bits[0] + '_make_' + '_'.join(bits[1:]) + + +class Block(object): + """ + Checks if doxyxml produced objects correspond to a gnuradio block. + """ + + @classmethod + def includes(cls, item): + if not isinstance(item, DoxyClass): + return False + # Check for a parsing error. + if item.error(): + return False + return item.has_member(make_name(item.name()), DoxyFriend) + + +def utoascii(text): + """ + Convert unicode text into ascii and escape quotes. + """ + if text is None: + return '' + out = text.encode('ascii', 'replace') + out = out.replace('"', '\\"') + return out + + +def combine_descriptions(obj): + """ + Combines the brief and detailed descriptions of an object together. + """ + description = [] + bd = obj.brief_description.strip() + dd = obj.detailed_description.strip() + if bd: + description.append(bd) + if dd: + description.append(dd) + return utoascii('\n\n'.join(description)).strip() + + +entry_templ = '%feature("docstring") {name} "{docstring}"' +def make_entry(obj, name=None, templ="{description}", description=None): + """ + Create a docstring entry for a swig interface file. + + obj - a doxyxml object from which documentation will be extracted. + name - the name of the C object (defaults to obj.name()) + templ - an optional template for the docstring containing only one + variable named 'description'. + description - if this optional variable is set then it's value is + used as the description instead of extracting it from obj. + """ + if name is None: + name=obj.name() + if "operator " in name: + return '' + if description is None: + description = combine_descriptions(obj) + docstring = templ.format(description=description) + if not docstring: + return '' + return entry_templ.format( + name=name, + docstring=docstring, + ) + + +def make_func_entry(func, name=None, description=None, params=None): + """ + Create a function docstring entry for a swig interface file. + + func - a doxyxml object from which documentation will be extracted. + name - the name of the C object (defaults to func.name()) + description - if this optional variable is set then it's value is + used as the description instead of extracting it from func. + params - a parameter list that overrides using func.params. + """ + if params is None: + params = func.params + params = [prm.declname for prm in params] + if params: + sig = "Params: (%s)" % ", ".join(params) + else: + sig = "Params: (NONE)" + templ = "{description}\n\n" + sig + return make_entry(func, name=name, templ=utoascii(templ), + description=description) + + +def make_class_entry(klass, description=None): + """ + Create a class docstring for a swig interface file. + """ + output = [] + output.append(make_entry(klass, description=description)) + for func in klass.in_category(DoxyFunction): + name = klass.name() + '::' + func.name() + output.append(make_func_entry(func, name=name)) + return "\n\n".join(output) + + +def make_block_entry(di, block): + """ + Create class and function docstrings of a gnuradio block for a + swig interface file. + """ + descriptions = [] + # Get the documentation associated with the class. + class_desc = combine_descriptions(block) + if class_desc: + descriptions.append(class_desc) + # Get the documentation associated with the make function + make_func = di.get_member(make_name(block.name()), DoxyFunction) + make_func_desc = combine_descriptions(make_func) + if make_func_desc: + descriptions.append(make_func_desc) + # Get the documentation associated with the file + try: + block_file = di.get_member(block.name() + ".h", DoxyFile) + file_desc = combine_descriptions(block_file) + if file_desc: + descriptions.append(file_desc) + except base.Base.NoSuchMember: + # Don't worry if we can't find a matching file. + pass + # And join them all together to make a super duper description. + super_description = "\n\n".join(descriptions) + # Associate the combined description with the class and + # the make function. + output = [] + output.append(make_class_entry(block, description=super_description)) + creator = block.get_member(block.name(), DoxyFunction) + output.append(make_func_entry(make_func, description=super_description, + params=creator.params)) + return "\n\n".join(output) + + +def make_swig_interface_file(di, swigdocfilename, custom_output=None): + + output = [""" +/* + * This file was automatically generated using swig_doc.py. + * + * Any changes to it will be lost next time it is regenerated. + */ +"""] + + if custom_output is not None: + output.append(custom_output) + + # Create docstrings for the blocks. + blocks = di.in_category(Block) + make_funcs = set([]) + for block in blocks: + try: + make_func = di.get_member(make_name(block.name()), DoxyFunction) + make_funcs.add(make_func.name()) + output.append(make_block_entry(di, block)) + except block.ParsingError: + print('Parsing error for block %s' % block.name()) + + # Create docstrings for functions + # Don't include the make functions since they have already been dealt with. + funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs] + for f in funcs: + try: + output.append(make_func_entry(f)) + except f.ParsingError: + print('Parsing error for function %s' % f.name()) + + # Create docstrings for classes + block_names = [block.name() for block in blocks] + klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names] + for k in klasses: + try: + output.append(make_class_entry(k)) + except k.ParsingError: + print('Parsing error for class %s' % k.name()) + + # Docstrings are not created for anything that is not a function or a class. + # If this excludes anything important please add it here. + + output = "\n\n".join(output) + + swig_doc = file(swigdocfilename, 'w') + swig_doc.write(output) + swig_doc.close() + +if __name__ == "__main__": + # Parse command line options and set up doxyxml. + err_msg = "Execute using: python swig_doc.py xml_path outputfilename" + if len(sys.argv) != 3: + raise StandardError(err_msg) + xml_path = sys.argv[1] + swigdocfilename = sys.argv[2] + di = DoxyIndex(xml_path) + + # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined! + # This is presumably a bug in SWIG. + #msg_q = di.get_member(u'gr_msg_queue', DoxyClass) + #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction) + #delete_head = msg_q.get_member(u'delete_head', DoxyFunction) + output = [] + #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail')) + #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head')) + custom_output = "\n\n".join(output) + + # Generate the docstrings interface file. + make_swig_interface_file(di, swigdocfilename, custom_output=custom_output) diff --git a/gr-utils/src/python/modtool/gr-newmod/grc/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/grc/CMakeLists.txt new file mode 100644 index 000000000..d776de752 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/grc/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2011 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. + +install(FILES + DESTINATION share/gnuradio/grc/blocks +) diff --git a/gr-utils/src/python/modtool/gr-newmod/include/howto/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/include/howto/CMakeLists.txt new file mode 100644 index 000000000..1cfb5a6ea --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/include/howto/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright 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. + +######################################################################## +# Install public header files +######################################################################## +install(FILES + api.h + DESTINATION include/howto +) diff --git a/gr-utils/src/python/modtool/gr-newmod/include/howto/api.h b/gr-utils/src/python/modtool/gr-newmod/include/howto/api.h new file mode 100644 index 000000000..5263a1cf7 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/include/howto/api.h @@ -0,0 +1,33 @@ +/* + * Copyright 2011 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. + */ + +#ifndef INCLUDED_HOWTO_API_H +#define INCLUDED_HOWTO_API_H + +#include + +#ifdef gnuradio_howto_EXPORTS +# define HOWTO_API __GR_ATTR_EXPORT +#else +# define HOWTO_API __GR_ATTR_IMPORT +#endif + +#endif /* INCLUDED_HOWTO_API_H */ diff --git a/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt new file mode 100644 index 000000000..f975d86e8 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright 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. + +######################################################################## +# Setup library +######################################################################## +include(GrPlatform) #define LIB_SUFFIX + +include_directories(${Boost_INCLUDE_DIR}) +link_directories(${Boost_LIBRARY_DIRS}) + +add_library(gnuradio-howto SHARED ) +target_link_libraries(gnuradio-howto ${Boost_LIBRARIES} ${GRUEL_LIBRARIES} ${GNURADIO_CORE_LIBRARIES}) +set_target_properties(gnuradio-howto PROPERTIES DEFINE_SYMBOL "gnuradio_howto_EXPORTS") + +######################################################################## +# Install built library files +######################################################################## +install(TARGETS gnuradio-howto + LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file + ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file + RUNTIME DESTINATION bin # .dll file +) + +######################################################################## +# Build and register unit test +######################################################################## +include(GrTest) + +include_directories(${CPPUNIT_INCLUDE_DIRS}) + +list(APPEND test_howto_sources + ${CMAKE_CURRENT_SOURCE_DIR}/test_howto.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_howto.cc +) + +add_executable(test-howto ${test_howto_sources}) + +target_link_libraries( + test-howto + ${GNURADIO_CORE_LIBRARIES} + ${Boost_LIBRARIES} + ${CPPUNIT_LIBRARIES} + gnuradio-howto +) + +GR_ADD_TEST(test_howto test-howto) diff --git a/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.cc b/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.cc new file mode 100644 index 000000000..f86aed4aa --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.cc @@ -0,0 +1,36 @@ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * This class gathers together all the test cases for the gr-filter + * directory into a single test suite. As you create new test cases, + * add them here. + */ + +#include "qa_howto.h" + +CppUnit::TestSuite * +qa_howto::suite() +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite("howto"); + + return s; +} diff --git a/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.h b/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.h new file mode 100644 index 000000000..8eff956b6 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/lib/qa_howto.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _QA_HOWTO_H_ +#define _QA_HOWTO_H_ + +#include +#include + +//! collect all the tests for the gr-filter directory + +class __GR_ATTR_EXPORT qa_howto +{ + public: + //! return suite of tests for all of gr-filter directory + static CppUnit::TestSuite *suite(); +}; + +#endif /* _QA_HOWTO_H_ */ diff --git a/gr-utils/src/python/modtool/gr-newmod/lib/test_howto.cc b/gr-utils/src/python/modtool/gr-newmod/lib/test_howto.cc new file mode 100644 index 000000000..bf344265d --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/lib/test_howto.cc @@ -0,0 +1,43 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include "qa_howto.h" +#include + +int +main (int argc, char **argv) +{ + CppUnit::TextTestRunner runner; + std::ofstream xmlfile(get_unittest_path("howto.xml").c_str()); + CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); + + runner.addTest(qa_howto::suite()); + runner.setOutputter(xmlout); + + bool was_successful = runner.run("", false); + + return was_successful ? 0 : 1; +} diff --git a/gr-utils/src/python/modtool/gr-newmod/python/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/python/CMakeLists.txt new file mode 100644 index 000000000..9901854c8 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/python/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright 2011 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. + +######################################################################## +# Include python install macros +######################################################################## +include(GrPython) +if(NOT PYTHONINTERP_FOUND) + return() +endif() + +######################################################################## +# Install python sources +######################################################################## +GR_PYTHON_INSTALL( + FILES + __init__.py + DESTINATION ${GR_PYTHON_DIR}/howto +) + +######################################################################## +# Handle the unit tests +######################################################################## +include(GrTest) + +set(GR_TEST_TARGET_DEPS gnuradio-howto) +set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) diff --git a/gr-utils/src/python/modtool/gr-newmod/python/__init__.py b/gr-utils/src/python/modtool/gr-newmod/python/__init__.py new file mode 100644 index 000000000..575cbfc22 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/python/__init__.py @@ -0,0 +1,54 @@ +# +# Copyright 2008,2009 Free Software Foundation, Inc. +# +# This application 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. +# +# This application 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# The presence of this file turns this directory into a Python package + +''' +This is the GNU Radio HOWTO module. Place your Python package +description here (python/__init__.py). +''' + +# ---------------------------------------------------------------- +# Temporary workaround for ticket:181 (swig+python problem) +import sys +_RTLD_GLOBAL = 0 +try: + from dl import RTLD_GLOBAL as _RTLD_GLOBAL +except ImportError: + try: + from DLFCN import RTLD_GLOBAL as _RTLD_GLOBAL + except ImportError: + pass + +if _RTLD_GLOBAL != 0: + _dlopenflags = sys.getdlopenflags() + sys.setdlopenflags(_dlopenflags|_RTLD_GLOBAL) +# ---------------------------------------------------------------- + + +# import swig generated symbols into the howto namespace +from howto_swig import * + +# import any pure python here +# + +# ---------------------------------------------------------------- +# Tail of workaround +if _RTLD_GLOBAL != 0: + sys.setdlopenflags(_dlopenflags) # Restore original flags +# ---------------------------------------------------------------- diff --git a/gr-utils/src/python/modtool/gr-newmod/swig/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/swig/CMakeLists.txt new file mode 100644 index 000000000..1e3e59e2c --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/swig/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright 2011 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. + +######################################################################## +# Include swig generation macros +######################################################################## +find_package(SWIG) +find_package(PythonLibs) +if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND) + return() +endif() +include(GrSwig) +include(GrPython) + +######################################################################## +# Setup swig generation +######################################################################## +foreach(incdir ${GNURADIO_CORE_INCLUDE_DIRS}) + list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/swig) +endforeach(incdir) + +foreach(incdir ${GRUEL_INCLUDE_DIRS}) + list(APPEND GR_SWIG_INCLUDE_DIRS ${incdir}/gruel/swig) +endforeach(incdir) + +set(GR_SWIG_LIBRARIES gnuradio-howto) +set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/howto_swig_doc.i) +set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) + +GR_SWIG_MAKE(howto_swig howto_swig.i) + +######################################################################## +# Install the build swig module +######################################################################## +GR_SWIG_INSTALL(TARGETS howto_swig DESTINATION ${GR_PYTHON_DIR}/howto) + +######################################################################## +# Install swig .i files for development +######################################################################## +install( + FILES + howto_swig.i + ${CMAKE_CURRENT_BINARY_DIR}/howto_swig_doc.i + DESTINATION ${GR_INCLUDE_DIR}/howto/swig +) diff --git a/gr-utils/src/python/modtool/gr-newmod/swig/howto_swig.i b/gr-utils/src/python/modtool/gr-newmod/swig/howto_swig.i new file mode 100644 index 000000000..4627d48d3 --- /dev/null +++ b/gr-utils/src/python/modtool/gr-newmod/swig/howto_swig.i @@ -0,0 +1,13 @@ +/* -*- c++ -*- */ + +#define HOWTO_API + +%include "gnuradio.i" // the common stuff + +//load generated python docstrings +%include "howto_swig_doc.i" + +%{ +%} + + diff --git a/gr-utils/src/python/modtool/modtool.conf.in b/gr-utils/src/python/modtool/modtool.conf.in new file mode 100644 index 000000000..8b3df1b9c --- /dev/null +++ b/gr-utils/src/python/modtool/modtool.conf.in @@ -0,0 +1,6 @@ +# This file contains system wide configuration data for GNU Radio. +# You may override any setting on a per-user basis by editing +# ~/.gnuradio/config.conf + +[modtool] +newmod_path = @newmoddir@ diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 730b72e39..9b2dc6e30 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -1,14 +1,10 @@ """ Create a whole new out-of-tree module """ +import shutil import os import re -import sys -import base64 -import tarfile from optparse import OptionGroup - from modtool_base import ModTool -from newmod_tarfile import NEWMOD_TARFILE ### New out-of-tree-mod module ############################################### class ModToolNewModule(ModTool): @@ -36,7 +32,7 @@ class ModToolNewModule(ModTool): self._info['modname'] = raw_input('Name of the new module: ') if not re.match('[a-zA-Z0-9_]+', self._info['modname']): print 'Invalid module name.' - sys.exit(2) + exit(2) self._dir = options.directory if self._dir == '.': self._dir = './gr-%s' % self._info['modname'] @@ -47,30 +43,21 @@ class ModToolNewModule(ModTool): pass # This is what should happen else: print 'The given directory exists.' - sys.exit(2) + exit(2) def run(self): """ - * Unpack the tar.bz2 to the new locations - * Remove the bz2 + * Copy the example dir recursively * Open all files, rename howto and HOWTO to the module name * Rename files and directories that contain the word howto """ - print "Creating directory..." + print "Creating out-of-tree module in %s..." % self._dir try: - os.mkdir(self._dir) + shutil.copytree('/home/braun/.usrlocal/share/gnuradio/modtool/gr-newmod', self._dir) os.chdir(self._dir) except OSError: print 'Could not create directory %s. Quitting.' % self._dir - sys.exit(2) - print "Copying howto example..." - open('tmp.tar.bz2', 'wb').write(base64.b64decode(NEWMOD_TARFILE)) - print "Unpacking..." - tar = tarfile.open('tmp.tar.bz2', mode='r:bz2') - tar.extractall() - tar.close() - os.unlink('tmp.tar.bz2') - print "Replacing occurences of 'howto' to '%s'..." % self._info['modname'], + exit(2) for root, dirs, files in os.walk('.'): for filename in files: f = os.path.join(root, filename) @@ -85,4 +72,3 @@ class ModToolNewModule(ModTool): print "Done." print "Use 'gr_modtool add' to add a new block to this currently empty module." - diff --git a/gr-utils/src/python/modtool/newmod_tarfile.py b/gr-utils/src/python/modtool/newmod_tarfile.py deleted file mode 100644 index 06d7e8f90..000000000 --- a/gr-utils/src/python/modtool/newmod_tarfile.py +++ /dev/null @@ -1,1034 +0,0 @@ -### The entire new module zipfile as base64 encoded tar.bz2 ### -NEWMOD_TARFILE = """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""" -- cgit From c4971ab2cb4bdbb9abc5d5320bd16b45cf263cf8 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Fri, 25 Jan 2013 17:52:46 +0100 Subject: utils: modtool minor updates --- gr-utils/src/python/modtool/cmakefile_editor.py | 2 +- gr-utils/src/python/modtool/modtool_add.py | 2 +- gr-utils/src/python/modtool/modtool_newmod.py | 2 +- gr-utils/src/python/modtool/templates.py | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/cmakefile_editor.py b/gr-utils/src/python/modtool/cmakefile_editor.py index fe50373bb..b18275707 100644 --- a/gr-utils/src/python/modtool/cmakefile_editor.py +++ b/gr-utils/src/python/modtool/cmakefile_editor.py @@ -5,7 +5,7 @@ import re ### CMakeFile.txt editor class ############################################### class CMakeFileEditor(object): """A tool for editing CMakeLists.txt files. """ - def __init__(self, filename, separator=' ', indent=' '): + def __init__(self, filename, separator='\n ', indent=' '): self.filename = filename self.cfile = open(filename, 'r').read() self.separator = separator diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py index c664d7c1a..581f3b0aa 100644 --- a/gr-utils/src/python/modtool/modtool_add.py +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -272,7 +272,7 @@ class ModToolAdd(ModTool): self._write_tpl('block_python', 'python', fname_py) append_re_line_sequence(self._file['pyinit'], '(^from.*import.*\n|# import any pure.*\n)', - 'from %s import *' % self._info['blockname']) + 'from %s import %s' % (self._info['blockname'], self._info['blockname'])) if self.options.skip_cmakefiles: return ed = CMakeFileEditor(self._file['cmpython']) diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 9b2dc6e30..0c69cb69e 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -51,7 +51,7 @@ class ModToolNewModule(ModTool): * Open all files, rename howto and HOWTO to the module name * Rename files and directories that contain the word howto """ - print "Creating out-of-tree module in %s..." % self._dir + print "Creating out-of-tree module in %s..." % self._dir, try: shutil.copytree('/home/braun/.usrlocal/share/gnuradio/modtool/gr-newmod', self._dir) os.chdir(self._dir) diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index e3019bb70..f41049c5a 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -287,8 +287,8 @@ import numpy #set $deciminterp = ', <+interpolation+>' #else if $blocktype == 'decimator' #set $deciminterp = ', <+decimation+>' -#set $deciminterp = '' #else +#set $deciminterp = '' #end if from gnuradio import gr @@ -297,7 +297,7 @@ class ${blockname}(${parenttype}): docstring for block ${blockname} """ def __init__(self#if $arglist == '' then '' else ', '#$arglist): - gr.${parenttype}.__init__(self, + ${parenttype}.__init__(self, #if $blocktype == 'hier' "$blockname", gr.io_signature(${inputsig}), # Input signature @@ -324,8 +324,6 @@ class ${blockname}(${parenttype}): \#self.consume_each(len(input_items[0])) return len(output_items[0]) #stop -#else - def work(self, input_items, output_items): #end if def work(self, input_items, output_items): -- cgit From 9ef0f125355a4541c691f18d05ad7ca7b6f7125e Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Sun, 27 Jan 2013 16:57:04 +0100 Subject: modtool: added copyleft headers --- gr-utils/src/python/modtool/__init__.py | 2 +- gr-utils/src/python/modtool/cmakefile_editor.py | 21 ++++++++++- gr-utils/src/python/modtool/code_generator.py | 21 ++++++++++- gr-utils/src/python/modtool/grc_xml_generator.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_add.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_base.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_disable.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_help.py | 44 ++++++++++++------------ gr-utils/src/python/modtool/modtool_info.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_makexml.py | 21 ++++++++++- gr-utils/src/python/modtool/modtool_newmod.py | 23 +++++++++++-- gr-utils/src/python/modtool/modtool_rm.py | 21 ++++++++++- gr-utils/src/python/modtool/parser_cc_block.py | 21 ++++++++++- gr-utils/src/python/modtool/templates.py | 22 ++++++++++-- gr-utils/src/python/modtool/util_functions.py | 21 ++++++++++- 15 files changed, 284 insertions(+), 38 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/__init__.py b/gr-utils/src/python/modtool/__init__.py index a10747254..7935e4b48 100644 --- a/gr-utils/src/python/modtool/__init__.py +++ b/gr-utils/src/python/modtool/__init__.py @@ -1,5 +1,5 @@ # -# Copyright 2012 Free Software Foundation, Inc. +# Copyright 2013 Free Software Foundation, Inc. # # This file is part of GNU Radio # diff --git a/gr-utils/src/python/modtool/cmakefile_editor.py b/gr-utils/src/python/modtool/cmakefile_editor.py index b18275707..ed5b71425 100644 --- a/gr-utils/src/python/modtool/cmakefile_editor.py +++ b/gr-utils/src/python/modtool/cmakefile_editor.py @@ -1,8 +1,27 @@ +# +# Copyright 2013 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. +# """ Edit CMakeLists.txt files """ import re -### CMakeFile.txt editor class ############################################### class CMakeFileEditor(object): """A tool for editing CMakeLists.txt files. """ def __init__(self, filename, separator='\n ', indent=' '): diff --git a/gr-utils/src/python/modtool/code_generator.py b/gr-utils/src/python/modtool/code_generator.py index b727f611e..525b3d1e9 100644 --- a/gr-utils/src/python/modtool/code_generator.py +++ b/gr-utils/src/python/modtool/code_generator.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ A code generator (needed by ModToolAdd) """ from templates import Templates @@ -7,7 +27,6 @@ from util_functions import str_to_python_comment from util_functions import strip_default_values from util_functions import strip_arg_types -### Code generator class ##################################################### class GRMTemplate(Cheetah.Template.Template): """ An extended template class """ def __init__(self, src, searchList): diff --git a/gr-utils/src/python/modtool/grc_xml_generator.py b/gr-utils/src/python/modtool/grc_xml_generator.py index 2fa61863f..7ccd44319 100644 --- a/gr-utils/src/python/modtool/grc_xml_generator.py +++ b/gr-utils/src/python/modtool/grc_xml_generator.py @@ -1,7 +1,26 @@ +# +# Copyright 2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# import xml.etree.ElementTree as ET from util_functions import is_number, xml_indent -### GRC XML Generator ######################################################## try: import lxml.etree LXML_IMPORTED = True diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py index 581f3b0aa..a6c84bea8 100644 --- a/gr-utils/src/python/modtool/modtool_add.py +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Module to add new blocks """ import os @@ -12,7 +32,6 @@ from templates import Templates from code_generator import get_template import Cheetah.Template -### Add new block module ##################################################### class ModToolAdd(ModTool): """ Add block to the out-of-tree module. """ name = 'add' diff --git a/gr-utils/src/python/modtool/modtool_base.py b/gr-utils/src/python/modtool/modtool_base.py index edb0f14ee..d824910e9 100644 --- a/gr-utils/src/python/modtool/modtool_base.py +++ b/gr-utils/src/python/modtool/modtool_base.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Base class for the modules """ import os @@ -8,7 +28,6 @@ from optparse import OptionParser, OptionGroup from util_functions import get_modname from templates import Templates -### ModTool base class ####################################################### class ModTool(object): """ Base class for all modtool command classes. """ def __init__(self): diff --git a/gr-utils/src/python/modtool/modtool_disable.py b/gr-utils/src/python/modtool/modtool_disable.py index 67f15ad53..b0fb13245 100644 --- a/gr-utils/src/python/modtool/modtool_disable.py +++ b/gr-utils/src/python/modtool/modtool_disable.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Disable blocks module """ import os @@ -8,7 +28,6 @@ from optparse import OptionGroup from modtool_base import ModTool from cmakefile_editor import CMakeFileEditor -### Disable module ########################################################### class ModToolDisable(ModTool): """ Disable block (comments out CMake entries for files) """ name = 'disable' diff --git a/gr-utils/src/python/modtool/modtool_help.py b/gr-utils/src/python/modtool/modtool_help.py index a1dd3c466..79474a963 100644 --- a/gr-utils/src/python/modtool/modtool_help.py +++ b/gr-utils/src/python/modtool/modtool_help.py @@ -1,30 +1,30 @@ +# +# Copyright 2013 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. +# """ The help module """ -from modtool_base import ModTool -from modtool_info import ModToolInfo -from modtool_add import ModToolAdd -from modtool_rm import ModToolRemove -from modtool_newmod import ModToolNewModule -from modtool_disable import ModToolDisable -from modtool_makexml import ModToolMakeXML -from util_functions import get_command_from_argv +from gnuradio.modtool import * +from util_functions import get_command_from_argv, get_class_dict from templates import Templates -def get_class_dict(): - " Return a dictionary of the available commands in the form command->class " - classdict = {} - for g in globals().values(): - try: - if issubclass(g, ModTool): - classdict[g.name] = g - for a in g.aliases: - classdict[a] = g - except (TypeError, AttributeError): - pass - return classdict - -### Help module ############################################################## def print_class_descriptions(): ''' Go through all ModTool* classes and print their name, alias and description. ''' diff --git a/gr-utils/src/python/modtool/modtool_info.py b/gr-utils/src/python/modtool/modtool_info.py index 80fa27832..e774db911 100644 --- a/gr-utils/src/python/modtool/modtool_info.py +++ b/gr-utils/src/python/modtool/modtool_info.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Returns information about a module """ import os @@ -6,7 +26,6 @@ from optparse import OptionGroup from modtool_base import ModTool from util_functions import get_modname -### Info module ############################################################## class ModToolInfo(ModTool): """ Return information about a given module """ name = 'info' diff --git a/gr-utils/src/python/modtool/modtool_makexml.py b/gr-utils/src/python/modtool/modtool_makexml.py index 5a1a24f1b..acf3e459c 100644 --- a/gr-utils/src/python/modtool/modtool_makexml.py +++ b/gr-utils/src/python/modtool/modtool_makexml.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Automatically create XML bindings for GRC from block code """ import sys @@ -11,7 +31,6 @@ from parser_cc_block import ParserCCBlock from grc_xml_generator import GRCXMLGenerator from cmakefile_editor import CMakeFileEditor -### Remove module ########################################################### class ModToolMakeXML(ModTool): """ Make XML file for GRC block bindings """ name = 'makexml' diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 0c69cb69e..7a5f635dd 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Create a whole new out-of-tree module """ import shutil @@ -6,7 +26,6 @@ import re from optparse import OptionGroup from modtool_base import ModTool -### New out-of-tree-mod module ############################################### class ModToolNewModule(ModTool): """ Create a new out-of-tree module """ name = 'newmod' @@ -36,7 +55,6 @@ class ModToolNewModule(ModTool): self._dir = options.directory if self._dir == '.': self._dir = './gr-%s' % self._info['modname'] - print 'Module directory is "%s".' % self._dir try: os.stat(self._dir) except OSError: @@ -56,6 +74,7 @@ class ModToolNewModule(ModTool): shutil.copytree('/home/braun/.usrlocal/share/gnuradio/modtool/gr-newmod', self._dir) os.chdir(self._dir) except OSError: + print 'FAILED' print 'Could not create directory %s. Quitting.' % self._dir exit(2) for root, dirs, files in os.walk('.'): diff --git a/gr-utils/src/python/modtool/modtool_rm.py b/gr-utils/src/python/modtool/modtool_rm.py index 16bfeb34c..bdbd802f3 100644 --- a/gr-utils/src/python/modtool/modtool_rm.py +++ b/gr-utils/src/python/modtool/modtool_rm.py @@ -1,3 +1,23 @@ +# +# Copyright 2013 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. +# """ Remove blocks module """ import os @@ -10,7 +30,6 @@ from util_functions import remove_pattern_from_file from modtool_base import ModTool from cmakefile_editor import CMakeFileEditor -### Remove module ########################################################### class ModToolRemove(ModTool): """ Remove block (delete files and remove Makefile entries) """ name = 'remove' diff --git a/gr-utils/src/python/modtool/parser_cc_block.py b/gr-utils/src/python/modtool/parser_cc_block.py index 447fe113d..d11353cc7 100644 --- a/gr-utils/src/python/modtool/parser_cc_block.py +++ b/gr-utils/src/python/modtool/parser_cc_block.py @@ -1,8 +1,27 @@ +# +# Copyright 2013 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. +# ''' A parser for blocks written in C++ ''' import re import sys -### Parser for CC blocks #################################################### def dummy_translator(the_type, default_v=None): """ Doesn't really translate. """ return the_type diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index f41049c5a..91d8370b9 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -1,10 +1,28 @@ +# +# Copyright 2013 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. +# ''' All the templates for skeleton files (needed by ModToolAdd) ''' from datetime import datetime -### Templates ################################################################ Templates = {} -Templates36 = {} # Default licence Templates['defaultlicense'] = ''' diff --git a/gr-utils/src/python/modtool/util_functions.py b/gr-utils/src/python/modtool/util_functions.py index 029ae04bf..33d8ad333 100644 --- a/gr-utils/src/python/modtool/util_functions.py +++ b/gr-utils/src/python/modtool/util_functions.py @@ -1,9 +1,28 @@ +# +# Copyright 2013 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. +# """ Utility functions for gr_modtool.py """ import re import sys -### Utility functions ######################################################## def get_command_from_argv(possible_cmds): """ Read the requested command from argv. This can't be done with optparse, since the option parser isn't defined before the command is known, and -- cgit From 1b71378943f40707d84a145ffa244f92acd4d643 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 28 Jan 2013 11:46:18 +0100 Subject: modtool: dir template update (added list for sources) --- gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt b/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt index f975d86e8..a9df565cf 100644 --- a/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt +++ b/gr-utils/src/python/modtool/gr-newmod/lib/CMakeLists.txt @@ -25,7 +25,10 @@ include(GrPlatform) #define LIB_SUFFIX include_directories(${Boost_INCLUDE_DIR}) link_directories(${Boost_LIBRARY_DIRS}) -add_library(gnuradio-howto SHARED ) +list(APPEND howto_sources +) + +add_library(gnuradio-howto SHARED ${howto_sources}) target_link_libraries(gnuradio-howto ${Boost_LIBRARIES} ${GRUEL_LIBRARIES} ${GNURADIO_CORE_LIBRARIES}) set_target_properties(gnuradio-howto PROPERTIES DEFINE_SYMBOL "gnuradio_howto_EXPORTS") @@ -46,8 +49,8 @@ include(GrTest) include_directories(${CPPUNIT_INCLUDE_DIRS}) list(APPEND test_howto_sources - ${CMAKE_CURRENT_SOURCE_DIR}/test_howto.cc - ${CMAKE_CURRENT_SOURCE_DIR}/qa_howto.cc + ${CMAKE_CURRENT_SOURCE_DIR}/test_howto.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_howto.cc ) add_executable(test-howto ${test_howto_sources}) -- cgit From 179b6fc774e9053d95bc1ff98427cd618d99501f Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 28 Jan 2013 11:46:58 +0100 Subject: modtool: more flexibility w/ adding and removing entries --- gr-utils/src/python/modtool/cmakefile_editor.py | 41 ++++++++++++------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/cmakefile_editor.py b/gr-utils/src/python/modtool/cmakefile_editor.py index ed5b71425..92121dda3 100644 --- a/gr-utils/src/python/modtool/cmakefile_editor.py +++ b/gr-utils/src/python/modtool/cmakefile_editor.py @@ -30,34 +30,27 @@ class CMakeFileEditor(object): self.separator = separator self.indent = indent - def get_entry_value(self, entry, to_ignore=''): - """ Get the value of an entry. - to_ignore is the part of the entry you don't care about. """ - regexp = '%s\(%s([^()]+)\)' % (entry, to_ignore) - mobj = re.search(regexp, self.cfile, flags=re.MULTILINE) - if mobj is None: - return None - value = mobj.groups()[0].strip() - return value - - def append_value(self, entry, value, to_ignore=''): + def append_value(self, entry, value, to_ignore_start='', to_ignore_end=''): """ Add a value to an entry. """ - regexp = re.compile('(%s\([^()]*?)\s*?(\s?%s)\)' % (entry, to_ignore), + regexp = re.compile('(%s\(%s[^()]*?)\s*?(\s?%s)\)' % (entry, to_ignore_start, to_ignore_end), re.MULTILINE) substi = r'\1' + self.separator + value + r'\2)' - self.cfile = regexp.sub(substi, self.cfile, count=1) + (self.cfile, nsubs) = regexp.subn(substi, self.cfile, count=1) + return nsubs - def remove_value(self, entry, value, to_ignore=''): + def remove_value(self, entry, value, to_ignore_start='', to_ignore_end=''): """Remove a value from an entry.""" - regexp = '^\s*(%s\(\s*%s[^()]*?\s*)%s\s*([^()]*\))' % (entry, to_ignore, value) + regexp = '^\s*(%s\(\s*%s[^()]*?\s*)%s\s*([^()]*%s\s*\))' % (entry, to_ignore_start, value, to_ignore_end) regexp = re.compile(regexp, re.MULTILINE) - self.cfile = re.sub(regexp, r'\1\2', self.cfile, count=1) + (self.cfile, nsubs) = re.subn(regexp, r'\1\2', self.cfile, count=1) + return nsubs def delete_entry(self, entry, value_pattern=''): """Remove an entry from the current buffer.""" regexp = '%s\s*\([^()]*%s[^()]*\)[^\n]*\n' % (entry, value_pattern) regexp = re.compile(regexp, re.MULTILINE) - self.cfile = re.sub(regexp, '', self.cfile, count=1) + (self.cfile, nsubs) = re.sub(regexp, '', self.cfile, count=1) + return nsubs def write(self): """ Write the changes back to the file. """ @@ -82,7 +75,14 @@ class CMakeFileEditor(object): return filenames def disable_file(self, fname): - """ Comment out a file """ + """ Comment out a file. + Example: + add_library( + file1.cc + ) + + Here, file1.cc becomes #file1.cc with disable_file('file1.cc'). + """ starts_line = False for line in self.cfile.splitlines(): if len(line.strip()) == 0 or line.strip()[0] == '#': @@ -109,8 +109,5 @@ class CMakeFileEditor(object): def check_for_glob(self, globstr): """ Returns true if a glob as in globstr is found in the cmake file """ glob_re = r'GLOB\s[a-z_]+\s"%s"' % globstr.replace('*', '\*') - if re.search(glob_re, self.cfile, flags=re.MULTILINE|re.IGNORECASE) is not None: - return True - else: - return False + return re.search(glob_re, self.cfile, flags=re.MULTILINE|re.IGNORECASE) is not None -- cgit From 03f101f509818a22d9488b4e5d08b9f0cd2b3b26 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 28 Jan 2013 11:48:10 +0100 Subject: modtool: newmod uses gr.prefs or --srcdir --- gr-utils/src/python/modtool/modtool_newmod.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 7a5f635dd..5e14493c3 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -24,6 +24,7 @@ import shutil import os import re from optparse import OptionGroup +from gnuradio import gr from modtool_base import ModTool class ModToolNewModule(ModTool): @@ -38,6 +39,8 @@ class ModToolNewModule(ModTool): parser = ModTool.setup_parser(self) parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' ogroup = OptionGroup(parser, "New out-of-tree module options") + ogroup.add_option("--srcdir", type="string", + help="Source directory for the module template.") parser.add_option_group(ogroup) return parser @@ -62,6 +65,12 @@ class ModToolNewModule(ModTool): else: print 'The given directory exists.' exit(2) + if options.srcdir is None: + options.srcdir = '/usr/local/share/gnuradio/modtool/gr-newmod', + self._srcdir = gr.prefs().get_string('modtool', 'newmod_path', options.srcdir) + if not os.path.isdir(self._srcdir): + print 'Error: Could not find gr-newmod source dir.' + exit(2) def run(self): """ @@ -71,10 +80,10 @@ class ModToolNewModule(ModTool): """ print "Creating out-of-tree module in %s..." % self._dir, try: - shutil.copytree('/home/braun/.usrlocal/share/gnuradio/modtool/gr-newmod', self._dir) + shutil.copytree(self._srcdir, self._dir) os.chdir(self._dir) except OSError: - print 'FAILED' + print 'Failed.' print 'Could not create directory %s. Quitting.' % self._dir exit(2) for root, dirs, files in os.walk('.'): -- cgit From ede34060de27184eb6f6df6b5fd03ae8a643bf91 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 28 Jan 2013 11:48:17 +0100 Subject: modtool: bugfixes --- gr-utils/src/python/modtool/modtool_add.py | 20 ++++++++------------ gr-utils/src/python/modtool/modtool_makexml.py | 2 +- gr-utils/src/python/modtool/modtool_rm.py | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py index a6c84bea8..32cfe0440 100644 --- a/gr-utils/src/python/modtool/modtool_add.py +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -81,7 +81,7 @@ class ModToolAdd(ModTool): if ((self._skip_subdirs['lib'] and self._info['lang'] == 'cpp') or (self._skip_subdirs['python'] and self._info['lang'] == 'python')): print "Missing or skipping relevant subdir." - sys.exit(1) + exit(1) if self._info['blockname'] is None: if len(self.args) >= 2: @@ -90,7 +90,7 @@ class ModToolAdd(ModTool): self._info['blockname'] = raw_input("Enter name of block/code (without module name prefix): ") if not re.match('[a-zA-Z0-9_]+', self._info['blockname']): print 'Invalid block name.' - sys.exit(2) + exit(2) print "Block/code identifier: " + self._info['blockname'] self._info['fullblockname'] = self._info['modname'] + '_' + self._info['blockname'] self._info['license'] = self.setup_choose_license() @@ -143,22 +143,17 @@ class ModToolAdd(ModTool): ) has_grc = False if self._info['lang'] == 'cpp': - print "Traversing lib..." self._run_lib() has_grc = has_swig else: # Python - print "Traversing python..." self._run_python() if self._info['blocktype'] != 'noblock': has_grc = True if has_swig: - print "Traversing swig..." self._run_swig() if self._add_py_qa: - print "Adding Python QA..." self._run_python_qa() if has_grc and not self._skip_subdirs['grc']: - print "Traversing grc..." self._run_grc() def _run_lib(self): @@ -178,7 +173,7 @@ class ModToolAdd(ModTool): try: append_re_line_sequence(self._file['cmlib'], '\$\{CMAKE_CURRENT_SOURCE_DIR\}/qa_%s.cc.*\n' % self._info['modname'], - ' ${CMAKE_CURRENT_SOURCE_DIR}/qa_%s.cc' % self._info['blockname']) + ' ${CMAKE_CURRENT_SOURCE_DIR}/qa_%s.cc' % self._info['blockname']) append_re_line_sequence(self._file['qalib'], '#include.*\n', '#include "%s"' % fname_qa_h) @@ -226,10 +221,11 @@ class ModToolAdd(ModTool): self._write_tpl('block_cpp36', 'lib', fname_cc) if not self.options.skip_cmakefiles: ed = CMakeFileEditor(self._file['cmlib']) - ed.append_value('add_library', fname_cc) + if not ed.append_value('list', fname_cc, to_ignore_start='APPEND %s_sources' % self._info['modname']): + ed.append_value('add_library', fname_cc) ed.write() ed = CMakeFileEditor(self._file['cminclude']) - ed.append_value('install', fname_h, 'DESTINATION[^()]+') + ed.append_value('install', fname_h, to_ignore_end='DESTINATION[^()]+') ed.write() if self._add_cc_qa: if self._info['version'] == '37': @@ -295,7 +291,7 @@ class ModToolAdd(ModTool): if self.options.skip_cmakefiles: return ed = CMakeFileEditor(self._file['cmpython']) - ed.append_value('GR_PYTHON_INSTALL', fname_py, 'DESTINATION[^()]+') + ed.append_value('GR_PYTHON_INSTALL', fname_py, to_ignore_end='DESTINATION[^()]+') ed.write() def _run_grc(self): @@ -310,6 +306,6 @@ class ModToolAdd(ModTool): if self.options.skip_cmakefiles or ed.check_for_glob('*.xml'): return print "Editing grc/CMakeLists.txt..." - ed.append_value('install', fname_grc, 'DESTINATION[^()]+') + ed.append_value('install', fname_grc, to_ignore_end='DESTINATION[^()]+') ed.write() diff --git a/gr-utils/src/python/modtool/modtool_makexml.py b/gr-utils/src/python/modtool/modtool_makexml.py index acf3e459c..104a0fdbd 100644 --- a/gr-utils/src/python/modtool/modtool_makexml.py +++ b/gr-utils/src/python/modtool/modtool_makexml.py @@ -122,7 +122,7 @@ class ModToolMakeXML(ModTool): ed = CMakeFileEditor(self._file['cmgrc']) if re.search(fname_xml, ed.cfile) is None and not ed.check_for_glob('*.xml'): print "Adding GRC bindings to grc/CMakeLists.txt..." - ed.append_value('install', fname_xml, 'DESTINATION[^()]+') + ed.append_value('install', fname_xml, to_ignore_end='DESTINATION[^()]+') ed.write() def _parse_cc_h(self, fname_cc): diff --git a/gr-utils/src/python/modtool/modtool_rm.py b/gr-utils/src/python/modtool/modtool_rm.py index bdbd802f3..02ce8ef3f 100644 --- a/gr-utils/src/python/modtool/modtool_rm.py +++ b/gr-utils/src/python/modtool/modtool_rm.py @@ -83,7 +83,7 @@ class ModToolRemove(ModTool): elif ext == '.cc': ed.remove_value('list', '\$\{CMAKE_CURRENT_SOURCE_DIR\}/%s' % filename, - 'APPEND test_%s_sources' % self._info['modname']) + to_ignore_start='APPEND test_%s_sources' % self._info['modname']) else: filebase = os.path.splitext(filename)[0] ed.delete_entry('add_executable', filebase) -- cgit From 2d695b3c4c86b5c206f95dcc1d71f97d808d98b8 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 28 Jan 2013 15:26:05 +0100 Subject: modtool: cleanup, bugfixes --- gr-utils/src/python/gr_modtool | 20 +----------------- gr-utils/src/python/modtool/__init__.py | 5 +++-- gr-utils/src/python/modtool/cmakefile_editor.py | 2 +- gr-utils/src/python/modtool/modtool_add.py | 1 - gr-utils/src/python/modtool/modtool_base.py | 28 ++++++++++++++++++++----- gr-utils/src/python/modtool/modtool_disable.py | 19 ++--------------- gr-utils/src/python/modtool/modtool_help.py | 4 ++-- gr-utils/src/python/modtool/modtool_info.py | 2 +- gr-utils/src/python/modtool/modtool_makexml.py | 26 +++++++---------------- gr-utils/src/python/modtool/modtool_newmod.py | 2 +- gr-utils/src/python/modtool/modtool_rm.py | 19 ++--------------- gr-utils/src/python/modtool/parser_cc_block.py | 5 +++-- gr-utils/src/python/modtool/templates.py | 6 +++--- gr-utils/src/python/modtool/util_functions.py | 19 ++++------------- 14 files changed, 53 insertions(+), 105 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/gr_modtool b/gr-utils/src/python/gr_modtool index bc41d56f5..8c5c710af 100755 --- a/gr-utils/src/python/gr_modtool +++ b/gr-utils/src/python/gr_modtool @@ -24,24 +24,9 @@ import sys from gnuradio.modtool import * -def get_class_dict(): - " Return a dictionary of the available commands in the form command->class " - classdict = {} - for g in globals().values(): - try: - if issubclass(g, ModTool): - classdict[g.name] = g - for a in g.aliases: - classdict[a] = g - except (TypeError, AttributeError): - pass - return classdict - - -### Main code ################################################################ def main(): """ Here we go. Parse command, choose class and run. """ - cmd_dict = get_class_dict() + cmd_dict = get_class_dict(globals().values()) command = get_command_from_argv(cmd_dict.keys()) if command is None: print 'Usage:' + templates.Templates['usage'] @@ -51,9 +36,6 @@ def main(): modtool.run() if __name__ == '__main__': - if not ((sys.version_info[0] > 2) or - (sys.version_info[0] == 2 and sys.version_info[1] >= 7)): - print "Using Python < 2.7 is not recommended for gr_modtool." try: main() except KeyboardInterrupt: diff --git a/gr-utils/src/python/modtool/__init__.py b/gr-utils/src/python/modtool/__init__.py index 7935e4b48..a242722ab 100644 --- a/gr-utils/src/python/modtool/__init__.py +++ b/gr-utils/src/python/modtool/__init__.py @@ -22,13 +22,14 @@ from cmakefile_editor import CMakeFileEditor from code_generator import GRMTemplate from grc_xml_generator import GRCXMLGenerator +from modtool_base import ModTool, get_class_dict from modtool_add import ModToolAdd -from modtool_base import ModTool from modtool_disable import ModToolDisable -from modtool_help import ModToolHelp from modtool_info import ModToolInfo from modtool_makexml import ModToolMakeXML from modtool_newmod import ModToolNewModule from modtool_rm import ModToolRemove +# Leave this at the end +from modtool_help import ModToolHelp from parser_cc_block import ParserCCBlock from util_functions import * diff --git a/gr-utils/src/python/modtool/cmakefile_editor.py b/gr-utils/src/python/modtool/cmakefile_editor.py index 92121dda3..3d90b8d16 100644 --- a/gr-utils/src/python/modtool/cmakefile_editor.py +++ b/gr-utils/src/python/modtool/cmakefile_editor.py @@ -49,7 +49,7 @@ class CMakeFileEditor(object): """Remove an entry from the current buffer.""" regexp = '%s\s*\([^()]*%s[^()]*\)[^\n]*\n' % (entry, value_pattern) regexp = re.compile(regexp, re.MULTILINE) - (self.cfile, nsubs) = re.sub(regexp, '', self.cfile, count=1) + (self.cfile, nsubs) = re.subn(regexp, '', self.cfile, count=1) return nsubs def write(self): diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py index 32cfe0440..7ca375b6f 100644 --- a/gr-utils/src/python/modtool/modtool_add.py +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -45,7 +45,6 @@ class ModToolAdd(ModTool): def setup_parser(self): parser = ModTool.setup_parser(self) - parser.usage = '%prog add [options]. \n Call %prog without any options to run it interactively.' ogroup = OptionGroup(parser, "Add module options") ogroup.add_option("-t", "--block-type", type="choice", choices=self._block_types, default=None, help="One of %s." % ', '.join(self._block_types)) diff --git a/gr-utils/src/python/modtool/modtool_base.py b/gr-utils/src/python/modtool/modtool_base.py index d824910e9..3f8f2bc3c 100644 --- a/gr-utils/src/python/modtool/modtool_base.py +++ b/gr-utils/src/python/modtool/modtool_base.py @@ -28,6 +28,7 @@ from optparse import OptionParser, OptionGroup from util_functions import get_modname from templates import Templates + class ModTool(object): """ Base class for all modtool command classes. """ def __init__(self): @@ -47,15 +48,17 @@ class ModTool(object): def setup_parser(self): """ Init the option parser. If derived classes need to add options, override this and call the parent function. """ - parser = OptionParser(usage=Templates['usage'], add_help_option=False) + parser = OptionParser(add_help_option=False) + parser.usage = '%prog ' + self.name + ' [options] \n' + \ + ' Call "%prog ' + self.name + '" without any options to run it interactively.' ogroup = OptionGroup(parser, "General options") ogroup.add_option("-h", "--help", action="help", help="Displays this help message.") ogroup.add_option("-d", "--directory", type="string", default=".", - help="Base directory of the module.") + help="Base directory of the module. Defaults to the cwd.") ogroup.add_option("-n", "--module-name", type="string", default=None, - help="Name of the GNU Radio module. If possible, this gets detected from CMakeLists.txt.") + help="Use this to override the current module's name (is normally autodetected).") ogroup.add_option("-N", "--block-name", type="string", default=None, - help="Name of the block, minus the module name prefix.") + help="Name of the block, where applicable.") ogroup.add_option("--skip-lib", action="store_true", default=False, help="Don't do anything in the lib/ subdirectory.") ogroup.add_option("--skip-swig", action="store_true", default=False, @@ -64,6 +67,8 @@ class ModTool(object): help="Don't do anything in the python/ subdirectory.") ogroup.add_option("--skip-grc", action="store_true", default=False, help="Don't do anything in the grc/ subdirectory.") + ogroup.add_option("-y", "--yes", action="store_true", default=False, + help="Answer all questions with 'yes'. This can overwrite and delete your files, so be careful.") parser.add_option_group(ogroup) return parser @@ -74,7 +79,6 @@ class ModTool(object): if not self._check_directory(self._dir): print "No GNU Radio module found in the given directory. Quitting." sys.exit(1) - print "Operating in directory " + self._dir if options.module_name is not None: self._info['modname'] = options.module_name else: @@ -96,6 +100,7 @@ class ModTool(object): self._info['blockname'] = options.block_name self.options = options self._setup_files() + self._info['yes'] = options.yes def _setup_files(self): """ Initialise the self._file[] dictionary """ @@ -156,3 +161,16 @@ class ModTool(object): """ Override this. """ pass +def get_class_dict(the_globals): + " Return a dictionary of the available commands in the form command->class " + classdict = {} + for g in the_globals: + try: + if issubclass(g, ModTool): + classdict[g.name] = g + for a in g.aliases: + classdict[a] = g + except (TypeError, AttributeError): + pass + return classdict + diff --git a/gr-utils/src/python/modtool/modtool_disable.py b/gr-utils/src/python/modtool/modtool_disable.py index b0fb13245..36725e557 100644 --- a/gr-utils/src/python/modtool/modtool_disable.py +++ b/gr-utils/src/python/modtool/modtool_disable.py @@ -35,24 +35,10 @@ class ModToolDisable(ModTool): def __init__(self): ModTool.__init__(self) - def setup_parser(self): - " Initialise the option parser for 'gr_modtool.py rm' " - parser = ModTool.setup_parser(self) - parser.usage = '%prog disable [options]. \n Call %prog without any options to run it interactively.' - ogroup = OptionGroup(parser, "Disable module options") - ogroup.add_option("-p", "--pattern", type="string", default=None, - help="Filter possible choices for blocks to be disabled.") - ogroup.add_option("-y", "--yes", action="store_true", default=False, - help="Answer all questions with 'yes'.") - parser.add_option_group(ogroup) - return parser - def setup(self): ModTool.setup(self) options = self.options - if options.pattern is not None: - self._info['pattern'] = options.pattern - elif options.block_name is not None: + if options.block_name is not None: self._info['pattern'] = options.block_name elif len(self.args) >= 2: self._info['pattern'] = self.args[1] @@ -60,7 +46,6 @@ class ModToolDisable(ModTool): self._info['pattern'] = raw_input('Which blocks do you want to disable? (Regex): ') if len(self._info['pattern']) == 0: self._info['pattern'] = '.' - self._info['yes'] = options.yes def run(self): """ Go, go, go! """ @@ -123,7 +108,7 @@ class ModToolDisable(ModTool): swigfile = re.sub('(GR_SWIG_BLOCK_MAGIC2?.+'+blockname+'.+;)', r'//\1', swigfile) open(self._file['swig'], 'w').write(swigfile) return False - # List of special rules: 0: subdir, 1: filename re match, 2: function + # List of special rules: 0: subdir, 1: filename re match, 2: callback special_treatments = ( ('python', 'qa.+py$', _handle_py_qa), ('python', '^(?!qa).+py$', _handle_py_mod), diff --git a/gr-utils/src/python/modtool/modtool_help.py b/gr-utils/src/python/modtool/modtool_help.py index 79474a963..76d9fd28b 100644 --- a/gr-utils/src/python/modtool/modtool_help.py +++ b/gr-utils/src/python/modtool/modtool_help.py @@ -21,7 +21,7 @@ """ The help module """ from gnuradio.modtool import * -from util_functions import get_command_from_argv, get_class_dict +from util_functions import get_command_from_argv from templates import Templates @@ -51,7 +51,7 @@ class ModToolHelp(ModTool): pass def run(self): - cmd_dict = get_class_dict() + cmd_dict = get_class_dict(globals().values()) cmds = cmd_dict.keys() cmds.remove(self.name) for a in self.aliases: diff --git a/gr-utils/src/python/modtool/modtool_info.py b/gr-utils/src/python/modtool/modtool_info.py index e774db911..680bd41b9 100644 --- a/gr-utils/src/python/modtool/modtool_info.py +++ b/gr-utils/src/python/modtool/modtool_info.py @@ -34,7 +34,7 @@ class ModToolInfo(ModTool): ModTool.__init__(self) def setup_parser(self): - " Initialise the option parser for 'gr_modtool.py info' " + " Initialise the option parser for 'gr_modtool info' " parser = ModTool.setup_parser(self) parser.usage = '%prog info [options]. \n Call %prog without any options to run it interactively.' ogroup = OptionGroup(parser, "Info options") diff --git a/gr-utils/src/python/modtool/modtool_makexml.py b/gr-utils/src/python/modtool/modtool_makexml.py index 104a0fdbd..777cc09e1 100644 --- a/gr-utils/src/python/modtool/modtool_makexml.py +++ b/gr-utils/src/python/modtool/modtool_makexml.py @@ -30,6 +30,7 @@ from modtool_base import ModTool from parser_cc_block import ParserCCBlock from grc_xml_generator import GRCXMLGenerator from cmakefile_editor import CMakeFileEditor +from util_functions import ask_yes_no class ModToolMakeXML(ModTool): """ Make XML file for GRC block bindings """ @@ -38,24 +39,10 @@ class ModToolMakeXML(ModTool): def __init__(self): ModTool.__init__(self) - def setup_parser(self): - " Initialise the option parser for 'gr_modtool.py makexml' " - parser = ModTool.setup_parser(self) - parser.usage = '%prog makexml [options]. \n Call %prog without any options to run it interactively.' - ogroup = OptionGroup(parser, "Make XML module options") - ogroup.add_option("-p", "--pattern", type="string", default=None, - help="Filter possible choices for blocks to be parsed.") - ogroup.add_option("-y", "--yes", action="store_true", default=False, - help="Answer all questions with 'yes'. This can overwrite existing files!") - parser.add_option_group(ogroup) - return parser - def setup(self): ModTool.setup(self) options = self.options - if options.pattern is not None: - self._info['pattern'] = options.pattern - elif options.block_name is not None: + if options.block_name is not None: self._info['pattern'] = options.block_name elif len(self.args) >= 2: self._info['pattern'] = self.args[1] @@ -63,7 +50,6 @@ class ModToolMakeXML(ModTool): self._info['pattern'] = raw_input('Which blocks do you want to parse? (Regex): ') if len(self._info['pattern']) == 0: self._info['pattern'] = '.' - self._info['yes'] = options.yes def run(self): """ Go, go, go! """ @@ -109,8 +95,11 @@ class ModToolMakeXML(ModTool): 'default': '2', 'in_constructor': False}) if os.path.isfile(os.path.join('grc', fname_xml)): - # TODO add an option to keep - print "Warning: Overwriting existing GRC file." + if not self._info['yes']: + if not ask_yes_no('Overwrite existing GRC file?', False): + return + else: + print "Warning: Overwriting existing GRC file." grc_generator = GRCXMLGenerator( modname=self._info['modname'], blockname=blockname, @@ -167,4 +156,3 @@ class ModToolMakeXML(ModTool): sys.exit(1) return (parser.read_params(), parser.read_io_signature(), blockname) - diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 5e14493c3..102d83d8d 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -35,7 +35,7 @@ class ModToolNewModule(ModTool): ModTool.__init__(self) def setup_parser(self): - " Initialise the option parser for 'gr_modtool.py newmod' " + " Initialise the option parser for 'gr_modtool newmod' " parser = ModTool.setup_parser(self) parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' ogroup = OptionGroup(parser, "New out-of-tree module options") diff --git a/gr-utils/src/python/modtool/modtool_rm.py b/gr-utils/src/python/modtool/modtool_rm.py index 02ce8ef3f..32dfee480 100644 --- a/gr-utils/src/python/modtool/modtool_rm.py +++ b/gr-utils/src/python/modtool/modtool_rm.py @@ -37,24 +37,10 @@ class ModToolRemove(ModTool): def __init__(self): ModTool.__init__(self) - def setup_parser(self): - " Initialise the option parser for 'gr_modtool.py rm' " - parser = ModTool.setup_parser(self) - parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' - ogroup = OptionGroup(parser, "Remove module options") - ogroup.add_option("-p", "--pattern", type="string", default=None, - help="Filter possible choices for blocks to be deleted.") - ogroup.add_option("-y", "--yes", action="store_true", default=False, - help="Answer all questions with 'yes'.") - parser.add_option_group(ogroup) - return parser - def setup(self): ModTool.setup(self) options = self.options - if options.pattern is not None: - self._info['pattern'] = options.pattern - elif options.block_name is not None: + if options.block_name is not None: self._info['pattern'] = options.block_name elif len(self.args) >= 2: self._info['pattern'] = self.args[1] @@ -62,7 +48,6 @@ class ModToolRemove(ModTool): self._info['pattern'] = raw_input('Which blocks do you want to delete? (Regex): ') if len(self._info['pattern']) == 0: self._info['pattern'] = '.' - self._info['yes'] = options.yes def run(self): """ Go, go, go! """ @@ -108,7 +93,7 @@ class ModToolRemove(ModTool): return regexp # Go, go, go! if not self._skip_subdirs['lib']: - self._run_subdir('lib', ('*.cc', '*.h'), ('add_library',), + self._run_subdir('lib', ('*.cc', '*.h'), ('add_library', 'list'), cmakeedit_func=_remove_cc_test_case) if not self._skip_subdirs['include']: incl_files_deleted = self._run_subdir(self._info['includedir'], ('*.h',), ('install',)) diff --git a/gr-utils/src/python/modtool/parser_cc_block.py b/gr-utils/src/python/modtool/parser_cc_block.py index d11353cc7..0d1d75f29 100644 --- a/gr-utils/src/python/modtool/parser_cc_block.py +++ b/gr-utils/src/python/modtool/parser_cc_block.py @@ -121,12 +121,13 @@ class ParserCCBlock(object): if not in_string: if c[i] == ')': if parens_count == 0: - if read_state == 'type': + if read_state == 'type' and len(this_type): raise ValueError( 'Found closing parentheses before finishing last argument (this is how far I got: %s)' % str(param_list) ) - param_list.append((this_type, this_name, this_defv)) + if len(this_type): + param_list.append((this_type, this_name, this_defv)) end_of_list = True break else: diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 91d8370b9..877735711 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -490,9 +490,9 @@ Templates['grc_xml'] = ''' # Usage Templates['usage'] = ''' -gr_modtool.py [options] -- Run with the given options. -gr_modtool.py help -- Show a list of commands. -gr_modtool.py help -- Shows the help for a given command. ''' +gr_modtool [options] -- Run with the given options. +gr_modtool help -- Show a list of commands. +gr_modtool help -- Shows the help for a given command. ''' # SWIG string Templates['swig_block_magic'] = """#if $version == '37' diff --git a/gr-utils/src/python/modtool/util_functions.py b/gr-utils/src/python/modtool/util_functions.py index 33d8ad333..4ca294ac3 100644 --- a/gr-utils/src/python/modtool/util_functions.py +++ b/gr-utils/src/python/modtool/util_functions.py @@ -18,11 +18,13 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # -""" Utility functions for gr_modtool.py """ +""" Utility functions for gr_modtool """ import re import sys +# None of these must depend on other modtool stuff! + def get_command_from_argv(possible_cmds): """ Read the requested command from argv. This can't be done with optparse, since the option parser isn't defined before the command is known, and @@ -38,7 +40,7 @@ def get_command_from_argv(possible_cmds): return None def append_re_line_sequence(filename, linepattern, newline): - """Detects the re 'linepattern' in the file. After its last occurrence, + """ Detects the re 'linepattern' in the file. After its last occurrence, paste 'newline'. If the pattern does not exist, append the new line to the file. Then, write. """ oldfile = open(filename, 'r').read() @@ -99,19 +101,6 @@ def get_modname(): except AttributeError: return None -def get_class_dict(): - " Return a dictionary of the available commands in the form command->class " - classdict = {} - for g in globals().values(): - try: - if issubclass(g, ModTool): - classdict[g.name] = g - for a in g.aliases: - classdict[a] = g - except (TypeError, AttributeError): - pass - return classdict - def is_number(s): " Return True if the string s contains a number. " try: -- cgit From 2ba9f1a544be17f40d60ba365bb084a342d41e0a Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Mon, 4 Feb 2013 15:34:41 +0100 Subject: modtool: bugfix, BLOCK_MAGIC should appear before %include --- gr-utils/src/python/modtool/modtool_add.py | 2 +- gr-utils/src/python/modtool/templates.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/modtool_add.py b/gr-utils/src/python/modtool/modtool_add.py index 7ca375b6f..e1d61cf0f 100644 --- a/gr-utils/src/python/modtool/modtool_add.py +++ b/gr-utils/src/python/modtool/modtool_add.py @@ -246,6 +246,7 @@ class ModToolAdd(ModTool): if self._info['version'] == '36': mod_block_sep = '_' swig_block_magic_str = get_template('swig_block_magic', **self._info) + open(self._file['swig'], 'a').write(swig_block_magic_str) include_str = '#include "%s%s%s.h"' % ( self._info['modname'], mod_block_sep, @@ -257,7 +258,6 @@ class ModToolAdd(ModTool): regexp = re.compile('^%\{\n', re.MULTILINE) oldfile = regexp.sub('%%{\n%s\n' % include_str, oldfile, count=1) open(self._file['swig'], 'w').write(oldfile) - open(self._file['swig'], 'a').write(swig_block_magic_str) def _run_python_qa(self): """ Do everything that needs doing in the subdir 'python' to add diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 877735711..f405bcabb 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -502,8 +502,8 @@ Templates['swig_block_magic'] = """#if $version == '37' #set $mod_block_sep = '_' #set $block_magic_version = '' #end if -%include "${modname}${mod_block_sep}${blockname}.h" GR_SWIG_BLOCK_MAGIC${block_magic_version}($modname, $blockname); +%include "${modname}${mod_block_sep}${blockname}.h" """ ## Old stuff -- cgit From d83d461c68a53e6ac6652ef53384698d13cdb8ed Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Wed, 6 Feb 2013 09:50:49 +0100 Subject: modtool: fixed block_magic and %include order --- gr-utils/src/python/modtool/templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index f405bcabb..877735711 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -502,8 +502,8 @@ Templates['swig_block_magic'] = """#if $version == '37' #set $mod_block_sep = '_' #set $block_magic_version = '' #end if -GR_SWIG_BLOCK_MAGIC${block_magic_version}($modname, $blockname); %include "${modname}${mod_block_sep}${blockname}.h" +GR_SWIG_BLOCK_MAGIC${block_magic_version}($modname, $blockname); """ ## Old stuff -- cgit From 788df86eb06bf5e39707ff0974bcbb0743e3d3a2 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 14 Feb 2013 17:56:36 +0100 Subject: modtool: fixed order for both 3.6 and 3.7 API versions --- gr-utils/src/python/modtool/templates.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 877735711..bfdba19c0 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -495,15 +495,13 @@ gr_modtool help -- Show a list of commands. gr_modtool help -- Shows the help for a given command. ''' # SWIG string -Templates['swig_block_magic'] = """#if $version == '37' -#set $mod_block_sep = '/' -#set $block_magic_version = '2' +Templates['swig_block_magic'] = """#if $version == '36' +GR_SWIG_BLOCK_MAGIC($modname, $blockname); +%include "${modname}_${blockname}.h" #else -#set $mod_block_sep = '_' -#set $block_magic_version = '' -#end if -%include "${modname}${mod_block_sep}${blockname}.h" -GR_SWIG_BLOCK_MAGIC${block_magic_version}($modname, $blockname); +%include "${modname}/${blockname}.h" +GR_SWIG_BLOCK_MAGIC2($modname, $blockname); +#end """ ## Old stuff -- cgit From d7766c2c8d12bbfaf29b83cfea5ff95475b45d86 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Tue, 26 Feb 2013 13:44:03 +0100 Subject: modtool: another fix in the SWIG generating code --- gr-utils/src/python/modtool/templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index bfdba19c0..706017cc2 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -501,7 +501,7 @@ GR_SWIG_BLOCK_MAGIC($modname, $blockname); #else %include "${modname}/${blockname}.h" GR_SWIG_BLOCK_MAGIC2($modname, $blockname); -#end +#end if """ ## Old stuff -- cgit From 54a4df9513ea681a8b376c4df3f4f846f92201c1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 5 Mar 2013 16:06:53 -0500 Subject: prefs: pass strings by reference. Also cleans up a comma in gr_modtool that made a string into a tuple (and C++ angry). --- gr-utils/src/python/modtool/modtool_newmod.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 102d83d8d..0613d5fbe 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -66,7 +66,7 @@ class ModToolNewModule(ModTool): print 'The given directory exists.' exit(2) if options.srcdir is None: - options.srcdir = '/usr/local/share/gnuradio/modtool/gr-newmod', + options.srcdir = '/usr/local/share/gnuradio/modtool/gr-newmod' self._srcdir = gr.prefs().get_string('modtool', 'newmod_path', options.srcdir) if not os.path.isdir(self._srcdir): print 'Error: Could not find gr-newmod source dir.' -- cgit From d7462afd9ab4ffccb0826ee463fdb17507002801 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Tue, 12 Mar 2013 09:39:48 +0100 Subject: modtool: Python general blocks used grextras syntax --- gr-utils/src/python/modtool/templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 706017cc2..9a916d68e 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -275,7 +275,7 @@ ${str_to_python_comment($license)} #if $blocktype in ('sync', 'sink', 'source') #set $parenttype = 'gr.sync_block' #else -#set $parenttype = {'hier': 'gr.hier_block2', 'interpolator': 'gr.interp_block', 'decimator': 'gr.decim_block', 'general': 'gr.block'}[$blocktype] +#set $parenttype = {'hier': 'gr.hier_block2', 'interpolator': 'gr.interp_block', 'decimator': 'gr.decim_block', 'general': 'gr.basic_block'}[$blocktype] #end if #if $blocktype != 'hier' import numpy -- cgit From 3693ee3259fa8bf2d9ad393842a80cd1fc330863 Mon Sep 17 00:00:00 2001 From: Mike Jameson Date: Tue, 12 Mar 2013 17:37:44 +0000 Subject: modtool: fixed general python block template --- gr-utils/src/python/modtool/templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 9a916d68e..87eb9f470 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -338,7 +338,7 @@ class ${blockname}(${parenttype}): def general_work(self, input_items, output_items): output_items[0][:] = input_items[0] - consume(0, len(input_items[0]) + consume(0, len(input_items[0])) \#self.consume_each(len(input_items[0])) return len(output_items[0]) #stop -- cgit From 91714eaa1fd33f4f801a9a8dedbd6832c01b1204 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 27 Mar 2013 15:33:35 -0400 Subject: utils: fixed wording in modtool for 'float' sink/source type. --- gr-utils/src/python/modtool/templates.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 87eb9f470..58617336e 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -473,7 +473,7 @@ Templates['grc_xml'] = ''' * optional (set to 1 for optional inputs) --> in - + out - + ''' -- cgit From 0a77df0393de27416d772b5ca7c2807ba4600bed Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Wed, 3 Apr 2013 09:11:26 +0200 Subject: modtool: fixes case when modulname ends in 0 --- gr-utils/src/python/modtool/util_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/util_functions.py b/gr-utils/src/python/modtool/util_functions.py index 4ca294ac3..c40dbd73b 100644 --- a/gr-utils/src/python/modtool/util_functions.py +++ b/gr-utils/src/python/modtool/util_functions.py @@ -92,7 +92,7 @@ def get_modname(): pass # OK, there's no gnuradio.project. So, we need to guess. cmfile = open('CMakeLists.txt', 'r').read() - regexp = r'(project\s*\(\s*|GR_REGISTER_COMPONENT\(")gr-(?P[a-zA-Z1-9-_]+)(\s*(CXX)?|" ENABLE)' + regexp = r'(project\s*\(\s*|GR_REGISTER_COMPONENT\(")gr-(?P[a-zA-Z0-9-_]+)(\s*(CXX)?|" ENABLE)' try: modname = re.search(regexp, cmfile, flags=re.MULTILINE).group('modname').strip() if modname in modname_trans.keys(): -- cgit From 6681c27c4bf6bb648684e4d716983a556ad860e8 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sun, 12 May 2013 11:25:35 +1000 Subject: utils: fix modtool template output signature --- gr-utils/src/python/modtool/templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 58617336e..d7cfffd06 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -136,7 +136,7 @@ namespace gr { #if $blocktype == 'sink' #set $outputsig = '0, 0, 0' #else -#set $outputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof (<+float+>)' +#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, sizeof (<+float+>)' #end if /* * The private constructor -- cgit From 4850598303359963de1b84791f0d66b8f9c9ad9c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 14 May 2013 18:36:25 +0100 Subject: modtool: fixed some setup for noblock gen. --- gr-utils/src/python/modtool/templates.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index d7cfffd06..878baaadf 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -230,9 +230,10 @@ namespace gr { */ class ${modname.upper()}_API $blockname { + public: ${blockname}(${arglist}); ~${blockname}(); - private: + private: }; #else /*! @@ -496,12 +497,16 @@ gr_modtool help -- Shows the help for a given command. ''' # SWIG string Templates['swig_block_magic'] = """#if $version == '36' +#if $blocktype != 'noblock' GR_SWIG_BLOCK_MAGIC($modname, $blockname); +#end if %include "${modname}_${blockname}.h" #else %include "${modname}/${blockname}.h" +#if $blocktype != 'noblock' GR_SWIG_BLOCK_MAGIC2($modname, $blockname); #end if +#end if """ ## Old stuff -- cgit From a0d37142a7b5144061af65c7bec2a4854a54a51c Mon Sep 17 00:00:00 2001 From: Tim Monahan-Mitchell Date: Sun, 19 May 2013 10:51:42 -0700 Subject: modtool: fix typo in help string --- gr-utils/src/python/modtool/modtool_newmod.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/modtool_newmod.py b/gr-utils/src/python/modtool/modtool_newmod.py index 0613d5fbe..e3b0e8e79 100644 --- a/gr-utils/src/python/modtool/modtool_newmod.py +++ b/gr-utils/src/python/modtool/modtool_newmod.py @@ -37,7 +37,7 @@ class ModToolNewModule(ModTool): def setup_parser(self): " Initialise the option parser for 'gr_modtool newmod' " parser = ModTool.setup_parser(self) - parser.usage = '%prog rm [options]. \n Call %prog without any options to run it interactively.' + parser.usage = '%prog nm [options]. \n Call %prog without any options to run it interactively.' ogroup = OptionGroup(parser, "New out-of-tree module options") ogroup.add_option("--srcdir", type="string", help="Source directory for the module template.") -- cgit From 2ebafea749da3101f4fb43d77444cedbc719ee08 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 24 May 2013 17:20:46 -0400 Subject: modtool: Fixes for intial templates of a block. 1. adds '$' to args in the GRC xml tag. 2. sets <+ITYPE+> and <+OTYPE+> for all I/O data types in io_signature and in work functions to be more clear what needs modification. Conflicts: gr-utils/src/python/modtool/templates.py --- gr-utils/src/python/modtool/code_generator.py | 2 ++ gr-utils/src/python/modtool/templates.py | 33 ++++++++++++++------------- gr-utils/src/python/modtool/util_functions.py | 6 +++++ 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'gr-utils/src/python') diff --git a/gr-utils/src/python/modtool/code_generator.py b/gr-utils/src/python/modtool/code_generator.py index 525b3d1e9..f6bfcd984 100644 --- a/gr-utils/src/python/modtool/code_generator.py +++ b/gr-utils/src/python/modtool/code_generator.py @@ -26,6 +26,7 @@ from util_functions import str_to_fancyc_comment from util_functions import str_to_python_comment from util_functions import strip_default_values from util_functions import strip_arg_types +from util_functions import strip_arg_types_grc class GRMTemplate(Cheetah.Template.Template): """ An extended template class """ @@ -43,6 +44,7 @@ class GRMTemplate(Cheetah.Template.Template): searchList['str_to_python_comment'] = str_to_python_comment searchList['strip_default_values'] = strip_default_values searchList['strip_arg_types'] = strip_arg_types + searchList['strip_arg_types_grc'] = strip_arg_types_grc Cheetah.Template.Template.__init__(self, src, searchList=searchList) self.grblocktype = self.grtypelist[searchList['blocktype']] diff --git a/gr-utils/src/python/modtool/templates.py b/gr-utils/src/python/modtool/templates.py index 878baaadf..362912c06 100644 --- a/gr-utils/src/python/modtool/templates.py +++ b/gr-utils/src/python/modtool/templates.py @@ -118,7 +118,8 @@ namespace gr { ${blockname}::sptr ${blockname}::make(${strip_default_values($arglist)}) { - return gnuradio::get_initial_sptr (new ${blockname}_impl(${strip_arg_types($arglist)})); + return gnuradio::get_initial_sptr + (new ${blockname}_impl(${strip_arg_types($arglist)})); } #if $blocktype == 'decimator' @@ -131,12 +132,12 @@ namespace gr { #if $blocktype == 'source' #set $inputsig = '0, 0, 0' #else -#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof (<+float+>)' +#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>)' #end if #if $blocktype == 'sink' #set $outputsig = '0, 0, 0' #else -#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, sizeof (<+float+>)' +#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>)' #end if /* * The private constructor @@ -175,8 +176,8 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - const float *in = (const float *) input_items[0]; - float *out = (float *) output_items[0]; + const <+ITYPE*> *in = (const <+ITYPE*> *) input_items[0]; + <+OTYPE*> *out = (<+OTYPE*> *) output_items[0]; // Do <+signal processing+> // Tell runtime system how many input items we consumed on @@ -194,8 +195,8 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - const float *in = (const float *) input_items[0]; - float *out = (float *) output_items[0]; + const <+ITYPE+> *in = (const <+ITYPE+> *) input_items[0]; + <+OTYPE+> *out = (<+OTYPE+> *) output_items[0]; // Do <+signal processing+> @@ -294,12 +295,12 @@ import numpy #if $blocktype == 'source' #set $inputsig = '0, 0, 0' #else -#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, gr.sizeof_<+float+>' +#set $inputsig = '<+MIN_IN+>, <+MAX_IN+>, gr.sizeof_<+ITYPE+>' #end if #if $blocktype == 'sink' #set $outputsig = '0, 0, 0' #else -#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, gr.sizeof_<+float+>' +#set $outputsig = '<+MIN_OUT+>, <+MAX_OUT+>, gr.sizeof_<+OTYPE+>' #end if #end if #if $blocktype == 'interpolator' @@ -455,7 +456,7 @@ Templates['grc_xml'] = ''' ${modname}_$blockname $modname import $modname - ${modname}.${blockname}(${strip_arg_types($arglist)}) + ${modname}.${blockname}(${strip_arg_types_grc($arglist)})