commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r8813 - gnuradio/branches/features/experimental-gui


From: jcorgan
Subject: [Commit-gnuradio] r8813 - gnuradio/branches/features/experimental-gui
Date: Sun, 6 Jul 2008 15:42:50 -0600 (MDT)

Author: jcorgan
Date: 2008-07-06 15:42:27 -0600 (Sun, 06 Jul 2008)
New Revision: 8813

Added:
   gnuradio/branches/features/experimental-gui/README
   gnuradio/branches/features/experimental-gui/fft_controller.py
   gnuradio/branches/features/experimental-gui/fft_top_block.py
   gnuradio/branches/features/experimental-gui/prop_val.py
   gnuradio/branches/features/experimental-gui/simple_usrp.py
   gnuradio/branches/features/experimental-gui/usrp_fft.py
Modified:
   gnuradio/branches/features/experimental-gui/
Log:
Experimental property/value interface code with USRP FFT code
as a partial implementation.  See README for details.



Property changes on: gnuradio/branches/features/experimental-gui
___________________________________________________________________
Name: svn:ignore
   + *.pyc


Added: gnuradio/branches/features/experimental-gui/README
===================================================================
--- gnuradio/branches/features/experimental-gui/README                          
(rev 0)
+++ gnuradio/branches/features/experimental-gui/README  2008-07-06 21:42:27 UTC 
(rev 8813)
@@ -0,0 +1,37 @@
+Experimental code demonstrating the property value abstraction and layering
+of topblock/controller/GUI code.
+
+* fft_top_block.py: 
+
+Pure GNU Radio flowgraph implementing FFT stream.  Doesn't know anything
+about GUIs or application operation.
+
+* fft_controller.py: 
+
+Application controller implementing property/value interface. Manipulates
+the top block in response to property changes/queries.
+
+* fft_gui.py: (Not yet written)
+
+Implements user interface.  Doesn't know anything about GNU Radio, but
+simply queries, sets, or listens to properties on the controller.
+
+* usrp_fft.py: 
+
+Top-level script.  Implements command line parameters, instantiates
+top block, controller and GUI (not yet written).
+
+* prop_val.py:
+
+Implements the property/value interface.
+
+* simple_usrp.py:
+
+Utility class for simplifying USRP operation.  May eventually make it into 
+blks2.
+
+STATUS:
+
+Currently, the top block and controller are written, but the GUI is not.  There
+is temporary code in usrp_fft.py to print a line to the screen every time the
+FFT frame is updated.

Added: gnuradio/branches/features/experimental-gui/fft_controller.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_controller.py               
                (rev 0)
+++ gnuradio/branches/features/experimental-gui/fft_controller.py       
2008-07-06 21:42:27 UTC (rev 8813)
@@ -0,0 +1,85 @@
+#
+# 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.
+#
+
+"""!
+GNU Radio controller for FFT streamer.  Implements property/value abstraction
+above fft_top_block.
+"""
+
+from prop_val import prop_val_interface
+import threading
+
+class fft_controller(prop_val_interface, threading.Thread):
+    def __init__(self, tb):
+       prop_val_interface.__init__(self)
+       threading.Thread.__init__(self)
+       self._tb = tb
+       
+       # External control interface.  These properties, when set by an external
+       # caller, result in the correct top block methods being invoked.
+       # These could be expanded to member functions to implement more advanced
+       # application logic, but here lambdas do the trick.
+
+       self.add_listener('decim',     lambda x: self._tb.set_decim(x))
+       self.add_listener('gain',      lambda x: self._tb.set_gain(x))
+       self.add_listener('freq',      lambda x: self._tb.set_freq(x))
+       self.add_listener('avg_alpha', lambda x: self._tb.set_avg_alpha(x))
+       self.add_listener('average',   lambda x: self._tb.set_average(x))
+
+       # TODO: set providers for various properties an external caller might
+       # like to know about here.  Can be member functions or lambdas, and
+       # would make calls on the top block to retrieve info.
+       #
+       # self.set_provider('foo', lambda: return 'bar')
+       # self.set_provider('decim', lambda: return self._tb.decim())
+       
+       # The controller is a thread
+       self.setDaemon(1)
+       self._keep_running = True
+
+    def on_init(self):
+       """
+       This method gets called by the external GUI or other code to start its
+       operation.
+       """
+       self._tb.start()
+       self.start()
+       
+    def run(self):
+       """
+       The background thread of the controller simply reads FFT frames from 
the 
+       top block message queue and sets the 'fft' property to their string 
representation.
+       External code can add one or more listeners to this property to receive
+       notification when an FFT frame comes in.
+       """
+       while self._keep_running:
+           msg = self._tb.queue().delete_head()
+           self['fft'] = msg.to_string()
+           
+    def on_exit(self):
+       """
+       This method gets called to shutdown the controller.  It lets the 
background
+       thread exit (not strictly necessary as Python will do so after the 
setDaemon(1)
+       call), then calls stop() and wait() on the top block.
+       """
+       self._keep_running = False 
+       self._tb.stop()
+       self._tb.wait()

Added: gnuradio/branches/features/experimental-gui/fft_top_block.py
===================================================================
--- gnuradio/branches/features/experimental-gui/fft_top_block.py                
                (rev 0)
+++ gnuradio/branches/features/experimental-gui/fft_top_block.py        
2008-07-06 21:42:27 UTC (rev 8813)
@@ -0,0 +1,108 @@
+#
+# 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, blks2
+import simple_usrp
+
+class fft_top_block(gr.top_block):
+    """!
+    GNU Radio top block to create a stream of FFT frames at a particular
+    frame rate from a USRP. The frames are enqueued in a gr.msg_queue for
+    external retrieval.
+
+    Provides functions to dynamically set USRP decimation rate, daughterboard
+    gain, receive center frequency, and averaging. 
+    """
+    def __init__(self, 
+                fft_size=512,
+                frame_rate=30,
+                ref_scale=50,
+                which=0,
+                decim=16,
+                width_8=False,
+                no_hb=False,
+                subdev_spec=None,
+                gain=None,
+                freq=None,
+                antenna=None,
+                avg_alpha=0.1,
+                average=False):
+       """!
+        Create an fft_top_block.
+
+        @param fft_size             Number of FFT bins (default is 512)
+        @param frame_rate           Number of frames/sec to create (default is 
30)
+        @param ref_scale            Sets 0 dB input amplitude
+        @param which               USRP # on USB bus (default is 0)
+        @param decim               Receive sample rate decimation (default is 
16)
+        @param width_8             Use 8-bit instead of 16-bit samples 
(default is False)
+        @param no_hb               Don't use half-band filter (default is 
False)
+        @param subdev_spec          Daughterboard selection (default is first 
found)
+        @param gain                Daughterboard RX gain (default is mid-range)
+        @param freq                Daughterboard RX frequency (default is 
mid-range)
+        @param antenna             Daughterboard RX antenna (default is 
board-default)
+        @param avg_alpha            FFT averaging (over time) constant 
[0.0-1.0] (default is 0.1)
+        @param average              Whether to implement FFT averaging [True, 
False] (default is False)
+        """
+        
+       gr.top_block.__init__(self, "fft_top_block")
+       
+       self._u = simple_usrp.source_c(which=which,
+                                      decim=decim,
+                                      width_8=width_8,
+                                      no_hb=no_hb,
+                                      subdev_spec=subdev_spec,
+                                      gain=gain,
+                                      freq=freq,
+                                      antenna=antenna)
+       
+       self._fft = blks2.logpwrfft_c(sample_rate=self._u.sample_rate(),
+                                     fft_size=fft_size,
+                                      frame_rate=frame_rate,
+                                      ref_scale=ref_scale,
+                                      avg_alpha=avg_alpha,
+                                      average=average)
+
+       self._msgq = gr.msg_queue(2)
+       self._sink = gr.message_sink(gr.sizeof_float*fft_size, self._msgq, True)
+       
+       self.connect(self._u, self._fft, self._sink)
+
+    # "Setters", which are called externally to affect flowgraph operation
+    def set_gain(self, gain):
+       return self._u.set_gain(gain)
+       
+    def set_freq(self, freq):
+       return self._u.set_freq(freq)
+       
+    def set_decim(self, decim):
+       self._u.set_decim(decim)
+       self._fft.set_sample_rate(self._u.sample_rate())
+
+    def set_avg_alpha(self, avg_alpha):
+       return self._fft.set_avg_alpha(avg_alpha)
+       
+    def set_average(self, average):
+       return self._fft.set_average(average)
+
+    # Getters, which are called externally to get information about the 
flowgraph
+    def queue(self):
+       return self._msgq

Added: gnuradio/branches/features/experimental-gui/prop_val.py
===================================================================
--- gnuradio/branches/features/experimental-gui/prop_val.py                     
        (rev 0)
+++ gnuradio/branches/features/experimental-gui/prop_val.py     2008-07-06 
21:42:27 UTC (rev 8813)
@@ -0,0 +1,124 @@
+#!/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.
+#
+
+"""!
+Abstract GNU Radio property/value dictionary with functional getters
+and setters.
+
+This is a proof of concept implementation, will likely change significantly.
+"""
+
+class property(object):
+    """
+    A property has a value that can be set or queried externally.
+    """    
+
+    def __init__(self):
+       self._provider = (None, None)
+       self._listeners = [ ]
+       self._cache = None
+       
+    def set_provider(self, handler, obj=None):
+       """
+       A property provider gets invoked whenever the property's value is
+       queried.  
+       
+       If the handler is an object method, 'obj' must be a reference
+       to the object.  Otherwise, the handler is treated as a bare function.
+       """
+       self._provider = (handler, obj)
+       
+    def add_listener(self, handler, obj=None):
+       """
+       A property listener gets invoked whenever the property's value is
+       set.  A property may have multiple listeners.
+       
+       If the handler is an object method, 'obj' must be a reference
+       to the object.  Otherwise, the handler is treated as a bare function.
+       """
+       self._listeners.append((handler, obj))
+
+    def set(self, value):
+       """
+       In response to being set, the property will call a series of listeners
+       with the new value.  If there is no provider for the property, the
+       value will be cached.
+       """
+       (handler, obj) = self._provider
+       if handler is None:
+           self._cache = value
+       if len(self._listeners) > 0:
+           for (handler, obj) in self._listeners:
+               if obj is not None:
+                   handler(obj, value)
+               else:
+                   handler(value)
+           
+    def get(self):
+       """
+       In response to being queried, if there is a provider set for the 
property,
+       it is invoked to retrieve the value.  Otherwise, the cached value is
+       returned.
+       """
+       (handler, obj) = self._provider
+       if handler is not None:
+           if obj is not None:
+               return handler(obj)
+           else:
+               return handler()
+       else:
+           return self._cache
+           
+class prop_val_interface(object):
+    """
+    The prop_val_interface mimics an automatic dictionary. Properties are set 
+    or queried using Python dictionary syntax, and non-existent keys are
+    automatically generated.
+    """ 
+    def __init__(self):
+       self._props = { }
+               
+    def _get_prop(self, key):
+       try:
+           p = self._props[key]
+       except KeyError:
+           p = property()
+           self._props[key] = p
+       return p
+       
+    def __getitem__(self, key):
+       return self._get_prop(key).get()
+
+    def __setitem__(self, key, value):
+       self._get_prop(key).set(value)
+           
+    def add_listener(self, key, handler, obj=None):
+       """
+       Invokes add_listener(...) on the selected property.
+       """
+       self._get_prop(key).add_listener(handler, obj)
+
+    def set_provider(self, key, handler, obj=None):
+       """ 
+       Invokes set_provider(...) on the selected property.
+       """
+       self._get_prop(key).set_provider(handler, obj)

Added: gnuradio/branches/features/experimental-gui/simple_usrp.py
===================================================================
--- gnuradio/branches/features/experimental-gui/simple_usrp.py                  
        (rev 0)
+++ gnuradio/branches/features/experimental-gui/simple_usrp.py  2008-07-06 
21:42:27 UTC (rev 8813)
@@ -0,0 +1,120 @@
+#
+# 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.
+#
+
+"""!
+High-level interfaces to USRP, simplifying common operations.
+
+This is proof-of-concept code and will likely change in incompatible ways.
+"""
+
+from gnuradio import gr, usrp
+
+class source_c(gr.hier_block2):
+    def __init__(self, 
+                which=0, 
+                decim=16, 
+                width_8=False,
+                no_hb=False,
+                subdev_spec=None,
+                gain=None,
+                freq=None,
+                antenna=None):
+       """!
+       Create a simple_usrp object supplying complex samples.
+
+       @param which            USRP # on USB bus (default is 0)
+       @param decim            Receive sample rate decimation (default is 16)
+       @param width_8          Use 8-bit instead of 16-bit samples (default is 
False)
+       @param no_hb            Don't use half-band filter (default is False)
+       @param subdev_spec      Daughterboard selection (default is first found)
+       @param gain             Daughterboard RX gain (default is mid-range)
+       @param freq             Daughterboard RX frequency (default is 
mid-range)
+       @param antenna          Daughterboard RX antenna (default is 
board-default)
+       """
+
+       gr.hier_block2.__init__(self, "simple_usrp.source_c",
+                               gr.io_signature(0, 0, 0),                    # 
Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex)) # 
Output signature
+
+       self._setup_usrp(which, decim, width_8, no_hb)
+       self._setup_db(subdev_spec, gain, freq, antenna)
+       self.connect(self._u, self)
+
+    def _setup_usrp(self, which, decim, width_8, no_hb):
+       if no_hb or decim < 8:
+           self._fpga_filename = 'std_4rx_0tx.rbf'
+       else:
+           self._fpga_filename = 'std_2rxhb_2tx.rbf'
+
+       self._u = usrp.source_c(which=which,
+                               fpga_filename=self._fpga_filename)
+
+       self.set_decim(decim)
+       if width_8:
+           format = self._u.make_format(8, 8)
+           self._u.set_format(format)
+
+    def _setup_db(self, subdev_spec, gain, freq, antenna):
+       if subdev_spec is None:
+           subdev_spec = usrp.pick_rx_subdevice(self._u)
+       self._u.set_mux(usrp.determine_rx_mux_value(self._u, subdev_spec))
+       self._subdev = usrp.selected_subdev(self._u, subdev_spec)
+       self.set_gain(gain)
+       self.set_freq(freq)
+       if antenna is not None:
+           self.subdev.select_rx_antenna(antenna)
+
+    def set_decim(self, decim):
+       """!
+       Set USRP RX decimation.
+
+       @param decim RX decimation rate
+       """
+       self._decim = decim
+       self._u.set_decim_rate(decim)
+
+    def set_gain(self, gain):
+       """!
+       Set USRP daughterboard gain.
+
+       @param gain RX daughterboard gain, (None=mid-range)
+       """
+       if gain is None:
+           g = self._subdev.gain_range()
+           gain = float(g[0]+g[1])/2.0
+       self._subdev.set_gain(gain)
+
+    def set_freq(self, freq):
+       """!
+       Set USRP/Daughterboard RX center frequency.
+
+       @param freq RX center frequency, (None=mid-range)
+       """
+       if freq is None:
+           f = self._subdev.freq_range()
+           freq = float(f[0]+f[1])/2.0
+       return self._u.tune(0, self._subdev, freq)
+
+    def sample_rate(self):
+       """!
+       Get USRP RX sample rate in samples/sec.
+       """
+       return self._u.adc_rate()/self._decim

Added: gnuradio/branches/features/experimental-gui/usrp_fft.py
===================================================================
--- gnuradio/branches/features/experimental-gui/usrp_fft.py                     
        (rev 0)
+++ gnuradio/branches/features/experimental-gui/usrp_fft.py     2008-07-06 
21:42:27 UTC (rev 8813)
@@ -0,0 +1,120 @@
+#!/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.eng_option import eng_option
+import sys
+
+# Import the top_block
+from fft_top_block import fft_top_block
+
+# Import the controller object
+from fft_controller import fft_controller
+
+# Import the GUI object
+# from fft_gui import fft_gui
+
+def get_options():
+    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("-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("", "--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()
+        sys.exit(1)
+    return (options, args)
+
+
+if __name__ == "__main__":
+    (options, args) = get_options()
+
+    # Applications have a 3-step initialization
+    
+    # Step 1: Create the GNU Radio top block.  This top block knows
+    # nothing of the GUI, and is manipulated by a GUI independent
+    # controller.
+    tb = fft_top_block(fft_size=512,
+                       frame_rate=10,
+                      ref_scale=50,
+                      which=options.which,
+                      decim=options.decim,
+                      width_8=options.width_8,
+                      no_hb=options.no_hb,
+                      subdev_spec=options.rx_subdev_spec,
+                      gain=options.gain,
+                      freq=options.freq,
+                      antenna=options.antenna,
+                      avg_alpha=options.avg_alpha,
+                      average=False)
+
+    # Step 2: Create the application controller and pass it 
+    # the top block it manipulates.  The controller implements
+    # a property/value interface to allow setting, getting, and
+    # listening properties that affect the application operation.
+    controller = fft_controller(tb)
+
+    # Step 3: Create the GUI and pass it the controller
+    # to manipulate.  The GUI code doesn't know anything about GNU
+    # Radio proper; it simply gets, sets, or listens to properties
+    # on the controller.  The 'GUI' can actually be a CLI batch
+    # program, an interactive shell, or anything that knows what to
+    # do with the controller properties.
+    #
+    # gui = fft_gui(controller)
+    # gui.run()
+
+    # END
+
+
+    # Temporary until GUI is written
+    #
+    # This simply adds a listener that prints a line whenever the FFT 
+    # property is updated, and invokes the controller init and exit
+    # methods.    
+    controller.add_listener('fft', lambda x: sys.stdout.write('FFT updated: 
'+`len(x)/4`+' bins\n'))
+    controller.on_init()
+    try:
+       raw_input("Press ENTER to stop...\n")
+    except KeyboardInterrupt:
+       pass
+    controller.on_exit()
+    # end temporary code


Property changes on: gnuradio/branches/features/experimental-gui/usrp_fft.py
___________________________________________________________________
Name: svn:executable
   + *





reply via email to

[Prev in Thread] Current Thread [Next in Thread]