[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r6483 - in grc/tags: . grc_0.69 grc_0.69/examples grc_
From: |
jblum |
Subject: |
[Commit-gnuradio] r6483 - in grc/tags: . grc_0.69 grc_0.69/examples grc_0.69/notes grc_0.69/src grc_0.69/src/Graphics grc_0.69/src/SignalBlockDefs |
Date: |
Wed, 19 Sep 2007 19:49:24 -0600 (MDT) |
Author: jblum
Date: 2007-09-19 19:49:24 -0600 (Wed, 19 Sep 2007)
New Revision: 6483
Added:
grc/tags/grc_0.69/
grc/tags/grc_0.69/examples/
grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml
grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt
grc/tags/grc_0.69/notes/release_notes.txt
grc/tags/grc_0.69/notes/todo.txt
grc/tags/grc_0.69/readme.txt
grc/tags/grc_0.69/src/ActionHandler.py
grc/tags/grc_0.69/src/Constants.py
grc/tags/grc_0.69/src/ExecFlowGraph.py
grc/tags/grc_0.69/src/Graphics/Dialogs.py
grc/tags/grc_0.69/src/Graphics/FlowGraph.py
grc/tags/grc_0.69/src/Graphics/MainWindow.py
grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py
grc/tags/grc_0.69/src/Preferences.py
grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py
grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py
grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py
grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py
grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py
grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py
grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py
Removed:
grc/tags/grc_0.69/examples/
grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml
grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt
grc/tags/grc_0.69/notes/notes.txt
grc/tags/grc_0.69/readme.txt
grc/tags/grc_0.69/src/ActionHandler.py
grc/tags/grc_0.69/src/Constants.py
grc/tags/grc_0.69/src/ExecFlowGraph.py
grc/tags/grc_0.69/src/Graphics/Dialogs.py
grc/tags/grc_0.69/src/Graphics/FlowGraph.py
grc/tags/grc_0.69/src/Graphics/MainWindow.py
grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py
grc/tags/grc_0.69/src/Preferences.py
grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py
grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py
grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py
grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py
grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py
grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py
grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py
Log:
tag grc 0.69
Copied: grc/tags/grc_0.69 (from rev 6211, grc/trunk)
Copied: grc/tags/grc_0.69/examples (from rev 6374, grc/trunk/examples)
Deleted: grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml
Copied: grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml (from rev 6449,
grc/trunk/examples/packet_mod_demod.grc.xml)
===================================================================
--- grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml
(rev 0)
+++ grc/tags/grc_0.69/examples/packet_mod_demod.grc.xml 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,215 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<flow_graph>
+ <timestamp>1189898583.51</timestamp>
+ <hostname>tiggle</hostname>
+ <version>0.69 beta</version>
+ <valid>True</valid>
+ <window_width>1600</window_width>
+ <window_height>1200</window_height>
+ <vars>
+ <var>
+ <key>samp_rate</key>
+ <value>100e3</value>
+ <min/>
+ <max/>
+ <step/>
+ </var>
+ <var>
+ <key>freq</key>
+ <value>500</value>
+ <min>0</min>
+ <max>1000</max>
+ <step>10.0</step>
+ </var>
+ <var>
+ <key>amp</key>
+ <value>1</value>
+ <min>0</min>
+ <max>2</max>
+ <step>0.02</step>
+ </var>
+ <var>
+ <key>off</key>
+ <value>0</value>
+ <min>-1</min>
+ <max>1</max>
+ <step>0.02</step>
+ </var>
+ </vars>
+ <signal_blocks>
+ <signal_block>
+ <tag>Note</tag>
+ <id>Note0</id>
+ <x_coordinate>408</x_coordinate>
+ <y_coordinate>270</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>A demonstration of the packet framework.</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Packet Demodulator</tag>
+ <id>Packet Demodulator0</id>
+ <x_coordinate>535</x_coordinate>
+ <y_coordinate>427</y_coordinate>
+ <rotation>180</rotation>
+ <params>
+ <param>1</param>
+ <param/>
+ <param>-1</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Scope Sink</tag>
+ <id>Scope Sink0</id>
+ <x_coordinate>219</x_coordinate>
+ <y_coordinate>402</y_coordinate>
+ <rotation>180</rotation>
+ <params>
+ <param>1</param>
+ <param>Output</param>
+ <param>$samp_rate</param>
+ <param>1</param>
+ <param>0</param>
+ <param>0.001</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Signal Source</tag>
+ <id>Signal Source0</id>
+ <x_coordinate>26</x_coordinate>
+ <y_coordinate>354</y_coordinate>
+ <rotation>90</rotation>
+ <params>
+ <param>1</param>
+ <param>$samp_rate</param>
+ <param>1</param>
+ <param>$freq</param>
+ <param>$amp</param>
+ <param>$off</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Scope Sink</tag>
+ <id>Scope Sink1</id>
+ <x_coordinate>125</x_coordinate>
+ <y_coordinate>178</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>1</param>
+ <param>Input</param>
+ <param>$samp_rate</param>
+ <param>1</param>
+ <param>0</param>
+ <param>0.001</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>GMSK Modulator</tag>
+ <id>GMSK Modulator0</id>
+ <x_coordinate>399</x_coordinate>
+ <y_coordinate>36</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>2</param>
+ <param>0.35</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>About</tag>
+ <id>About0</id>
+ <x_coordinate>480</x_coordinate>
+ <y_coordinate>176</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>Packet Mod/Demod</param>
+ <param>Josh Blum</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>GMSK Demodulator</tag>
+ <id>GMSK Demodulator0</id>
+ <x_coordinate>871</x_coordinate>
+ <y_coordinate>189</y_coordinate>
+ <rotation>270</rotation>
+ <params>
+ <param>2</param>
+ <param>0.05</param>
+ <param>0.5</param>
+ <param>0.005</param>
+ <param>0</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Throttle</tag>
+ <id>Throttle0</id>
+ <x_coordinate>703</x_coordinate>
+ <y_coordinate>36</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>0</param>
+ <param>$samp_rate*25</param>
+ <param>1</param>
+ </params>
+ </signal_block>
+ <signal_block>
+ <tag>Packet Modulator</tag>
+ <id>Packet Modulator0</id>
+ <x_coordinate>129</x_coordinate>
+ <y_coordinate>19</y_coordinate>
+ <rotation>0</rotation>
+ <params>
+ <param>1</param>
+ <param>2</param>
+ <param>1</param>
+ <param>512</param>
+ <param/>
+ <param>0</param>
+ </params>
+ </signal_block>
+ </signal_blocks>
+ <connections>
+ <connection>
+ <input_signal_block_id>Scope Sink1</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>Signal Source0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>Scope Sink0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>Packet Demodulator0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>Packet Modulator0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>Signal Source0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>GMSK Modulator0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>Packet Modulator0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>Packet Demodulator0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>GMSK Demodulator0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>Throttle0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>GMSK Modulator0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ <connection>
+ <input_signal_block_id>GMSK Demodulator0</input_signal_block_id>
+ <input_socket_index>0</input_socket_index>
+ <output_signal_block_id>Throttle0</output_signal_block_id>
+ <output_socket_index>0</output_socket_index>
+ </connection>
+ </connections>
+</flow_graph>
Deleted: grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt
Copied: grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt (from rev 6478,
grc/trunk/notes/creating_a_signal_block_def.txt)
===================================================================
--- grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt
(rev 0)
+++ grc/tags/grc_0.69/notes/creating_a_signal_block_def.txt 2007-09-20
01:49:24 UTC (rev 6483)
@@ -0,0 +1,213 @@
+###################################################################
+# How to create a signal block definition - Josh Blum
+###################################################################
+# Signal blocks in GRC are defined in python code. Each block gets its
own method:
+def MySignalBlockDef(sb):
+ # import any packages here and equate the actual gr constructor
+ #
+ # This is good practice:
+ # If a package or a block is not implemented in your version of
GNU Radio,
+ # an ImportError or AttributeError will be caught,
+ # and GRC can ignore this block.
+ from gnuradio import blks
+ fcn = blks.some_hier_block
+ # add input and output sockets
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Float())
+ # add signal block parameters
+ sb.add_param('Sample Rate', Float(default_samp_rate))
+ sb.add_param('Decimation', Int(default_decim))
+ # set a documentation string (optional)
+ sb.set_docs('''This is my block.''')
+ # create a method to build the actual GNU Radio block.
+ # The first parameter of this method must be the flow graph.
+ # The proceeding parmeters coorespond to the parameters above.
+ def make(fg, samp_rate, decim):
+ # create the signal block using fcn, and call every
parameter's parse method
+ block = fcn(samp_rate.parse(), decim.parse())
+ # add callbacks: callbacks are special methods of the
signal block
+ # that let us change parameters after the block is
created.
+ # If one of the parameters was based on a variable and
had a callback method,
+ # one could dynamically change the block's parameter(s)
by changing the variable.
+ # The first argument is the method, the second is the
unparsed data type:
+ fg.add_callback(block.set_samp_rate, samp_rate)
+ return block # return the block
+ # end the definition by returning a tuple: graphical block, the
make method
+ return sb, make
+# This is a very basic framework. You can do anything with your signal
block definition!
+# Just make sure all methods return the right things and that the number
of parameters matches up.
+
+###################################################################
+# Add your block to the tree:
+###################################################################
+ Edit SignalBlockDefs/SignalBlockTree.py.
+ Find your desired category and add the tuple to the tree:
+ ("My Signal Block's Name", MySignalBlockDef),
+
+###################################################################
+# Basic and Vector Data Types
+###################################################################
+
+Complex
+Float
+Int
+Short
+Byte
+
+ComplexVector
+FloatVector
+IntVector
+ShortVector
+ByteVector
+
+'''
+All of these data types share the same contructor, like so:
+Float(default_value, min, max)
+The default_value can be anything, it will be stored in the data type as a
string.
+Preferably, the default value will be a numeric python object,
+or a string representing a vector or a expression.
+For the basic data types, the min and max parameters determine what values are
considered valid.
+For the vector data types, the min and max parameters determine what vector
lengths are considered valid.
+The min and the max must be floats or ints.
+Also, do not use min and max for Complex, as this does not make sence and will
always be invalid.
+'''
+
+
+###################################################################
+# Enum and Bool Data Types
+###################################################################
+
+'''
+The Enum data types takes a finite list of choices.
+The data type stores the index of the choice.
+Parsing an Enum data type will return the choice at the stored index.
+'''
+
+example_enum = Enum([
+ ('Name of choice0', data0),
+ ('Name of choice1', data1),
+ ('Name of choice2', data2),
+ ], default_index)
+
+'''
+The Bool data type is a special type of Enum,
+with a choice for True and a choice for false.
+'''
+
+example_bool = Bool(true='Choose Yes', false='Choose No', default=True)
+
+
+###################################################################
+# Variable Data Type
+###################################################################
+
+'''
+The variable data type can represent any of the basic or vector data types.
+By using this data type, one can change the data type of a socket or a
parameter.
+A variable data type takes an Enum as its parameter.
+This Enum must parse to one of the basic or vector data types.
+'''
+
+example_enum_of_data_types = Enum([
+ ('Float Out', Float()),
+ ('Complex Out', Complex()),
+ ])
+sb.add_param('Choose Output Type', example_enum_of_data_types) #allow the user
to choose the data type
+sb.add_output_socket('out', Variable(example_enum_of_data_types))#the output
socket is now variable
+
+'''
+Now to do something more complicated:
+Suppose we want to use an Enum to control more than one variable,
+but the variables need to be different types.
+The Enum can hold a tuple or a list for each choice.
+The Variable's index parameter specifies the index of this tuple.
+Essentially, the tuple can be filled with anything; however,
+the indecies that the Variable references must be basic or vector data types.
+'''
+
+example_enum_of_data_types = Enum([
+ ('Float -> Complex', (gr.block_fc, Float(), Complex())),
+ ('Short -> Float', (gr.block_sf, Short(), Float())),
+ ])
+sb.add_param('Choose IO Types', example_enum_of_data_types) #allow the user
to choose the data type
+sb.add_input_socket('out', Variable(example_enum_of_data_types, index=1))#the
input socket uses 1st index
+sb.add_output_socket('out', Variable(example_enum_of_data_types, index=2))#the
output socket uses 2nd index
+
+'''
+In the case above, the 0th index of the tuple holds a specific gr block.
+Again, specifying the actual gr block is good practice:
+If a package or a block is not implemented in your version of GNU Radio,
+an ImportError or AttributeError will be caught,
+and GRC can ignore this block.
+The gr block can be retrieved in the make method by calling type.parse()[0],
+(since parse will return the tuple, and [0] gets the 0th element).
+'''
+
+###################################################################
+# Misc Data Types
+###################################################################
+
+String
+FileOpen
+FileSave
+
+'''
+A String data type can take on any value and will always be valid.
+The String data type is good for specifying names and titles.
+
+The FileOpen data type stores a file path as a string.
+It will only be valid if its string represents a file path to an existing file.
+
+The FileSave data type stores a file path as a string.
+It will only be valid if its string represents a file path with existing
directories.
+'''
+
+###################################################################
+# Special socket options
+###################################################################
+
+'''
+The methods add_input_socket and add_output_socket have two additional
parameters: optional and vlen.
+The "optional" parameter is a boolean value which is "False" by default.
+If the value is "True", the socket will pass validation even if it is left
unconnected.
+
+The "vlen" parameter is an Int data type which is None by default.
+If the value is an Int, the socket's data type will be vectorized when the Int
is greater than 1.
+(Vectorized means that a Complex data type will become ComplexVector and so
on...)
+'''
+
+#Usage
+sb.add_input_socket(cname, data_type, optional=False, vlen=None)
+
+###################################################################
+# Special param options
+###################################################################
+
+'''
+The method add param has four additional parameters: show_label, type, I/O
controllers
+
+The "show_label" parameter is a boolean value which is "True" by default.
+If the value is "False", this block's parameter will not be drawn into the
block's label.
+It saves space on the flow graph by not drawing redundant parameters.
+A parameter is redundant when its effect is seen on the block.
+Ex: A Enum controlling the output data type changes the color of the output
socket.
+
+The "type" parameter is a boolean value which is "False" by default.
+If the value is "True", Up and Down hotkeys will increment and decrement the
value.
+Warning: The "type" parameter should only be used with the Enum data type.
+Useful for changing a block's data type with hotkeys.
+
+The "I/O_socket_controller" parameter is a boolean value which is "False" by
default.
+If the value is "True", this block's parameter will control the number of
input or output sockets (respectivly).
+Warning: The "I/O_socket_controller" parameter should only be used with the
Integer data types (Int, Short, Byte).
+Useful for block with a dynamic number of inputs, like Add and Interleave.
+'''
+
+#Usage
+add_param(cname, data_type, show_label=True, type=False,
output_sockets_controller=False, input_sockets_controller=False)
+
+###################################################################
+# Final Notes
+###################################################################
+
+Please look through the src/SignalBlockDefs/*.py to see how all these
components work together...
Deleted: grc/tags/grc_0.69/notes/notes.txt
Copied: grc/tags/grc_0.69/notes/release_notes.txt (from rev 6478,
grc/trunk/notes/release_notes.txt)
===================================================================
--- grc/tags/grc_0.69/notes/release_notes.txt (rev 0)
+++ grc/tags/grc_0.69/notes/release_notes.txt 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,19 @@
+This release: GRC 0.69, September 19th 2007
+
+Last release: GRC 0.65, March 20th 2007
+
+Compatibility:
+ gnuradio trunk r6477 and subsequent revisions within a reasonable
time-period
+ gnuradio 3.1 branch
+
+Fixes and New Features:
+ -rx on usrp side b works
+ -usrp flex rf options
+ -usrp dual source and sink
+ -selector/deselector block
+ -packet modulator and demodulator
+ -misc block fixes and additions
+ -tabbed windows
+ -execute a flow graph without graphics
+ -new math expressions, with filter functions
+
Copied: grc/tags/grc_0.69/notes/todo.txt (from rev 6482,
grc/trunk/notes/todo.txt)
===================================================================
--- grc/tags/grc_0.69/notes/todo.txt (rev 0)
+++ grc/tags/grc_0.69/notes/todo.txt 2007-09-20 01:49:24 UTC (rev 6483)
@@ -0,0 +1,51 @@
+############ Blocks to Add: ####################
+-ofdm (blks2)
+-cpm (blks2)
+-filterbank (blks2)
+-usrp quad souce, set z == 1 to ignore Q inputs
+-multi-channel scope
+
+############ Known Problems: ####################
+-packet threads block on close
+-core abort with bad params to filter functions
+-blocks need to fix themselves when they go out of bounds, like in a resize
+-socket controllers should be intelligent on shrinkage
+-usrp transmit dies in lock/unlock
+-audio dies lock/unlock
+-channel model needs hier2
+
+############ Features to Add: ####################
+-startup tips
+-math expr from file
+-save working directory after close
+-create sub-flow graphs to be used in larger flow graphs
+-include dtd in saved flow graphs
+-fm demod example with expansion of wfm_recv block
+
+############ wxPython Features: ####################
+-dump wx running graph to png?
+-scroll box for graphs
+-dropdowns in wx graphics, for variable settings
+ self.scaling_chooser = wx.Choice(self, -1, choices=['Linear
Hz', 'Logarithmic Hz', 'LogHz'])
+ self.scaling_chooser.SetSelection(0) #default is linear hz
+ self.Bind(wx.EVT_CHOICE, self.scale, self.scaling_chooser)
+ selection = event.GetSelection()
+
+############ User Prefs: ####################
+--save scrollbar positions (hidden pref)
+
+############ Uninteresting Features: ####################
+-add the concept of a current working directory
+-auto param to usrp diagnose dialog
+-use popen3 once it works in cygwin
+-arrow like images for socket, to replace in/out strings
+-min/max in DataTypes can be other data types
+-press enter to close params
+
+############ Get GTK Stock IDs: ####################
+gtk.stock_list_ids()
+
+############ connect packet mod to demod: ####################
+gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+gr.unpack_k_bits_bb(self.bits_per_symbol())
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/readme.txt
Copied: grc/tags/grc_0.69/readme.txt (from rev 6478, grc/trunk/readme.txt)
===================================================================
--- grc/tags/grc_0.69/readme.txt (rev 0)
+++ grc/tags/grc_0.69/readme.txt 2007-09-20 01:49:24 UTC (rev 6483)
@@ -0,0 +1,14 @@
+Hello!
+
+Thank you for downloading GNU Radio Companion.
+This program is free software.
+A GPL license is distributed with this program.
+This license covers all the source code/python files.
+You will also find a "creative common license" for the grc icon.
+
+Intructions for GRC are available at:
+http://gnuradio.org/trac/wiki/GNURadioCompanion
+
+If you have questions, problems, suggestions, or want to contribute,
+please email me at jblum at jhu dot edu
+
Deleted: grc/tags/grc_0.69/src/ActionHandler.py
Copied: grc/tags/grc_0.69/src/ActionHandler.py (from rev 6460,
grc/trunk/src/ActionHandler.py)
===================================================================
--- grc/tags/grc_0.69/src/ActionHandler.py (rev 0)
+++ grc/tags/grc_0.69/src/ActionHandler.py 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,383 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden ActionHandler
+#ActionHandler builds the interface and handles most of the user inputs.
address@hidden Josh Blum
+
+import os, sys
+from Constants import *
+from Actions import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+import Graphics
+import Preferences
+from threading import Thread
+import Messages
+import ParseXML
+import random
+
+class ActionHandler:
+ """
+ The action handler will setup all the major window components,
+ and handle button presses and flow graph operations from the GUI.
+ """
+
+ def __init__(self, file_paths):
+ """!
+ ActionHandler constructor.
+ Create the main window, setup the message handler, import the
preferences,
+ and connect all of the action handlers. Finally, enter the gtk
main loop and block.
+ @param file_paths a list of flow graph file passed from command
line
+ """
+ if PY_GTK_ICON:
gtk.window_set_default_icon_from_file(PY_GTK_ICON)
+ for action in ACTIONS_LIST: action.connect('activate',
self._handle_actions)
+ ### create the main window and setup the Messages ###
+ self.main_window = Graphics.MainWindow(self.handle_states)
+ Preferences.load(self.main_window)
+ self.get_flow_graph = self.main_window.get_flow_graph
+ self.get_page = self.main_window.get_page
+ Messages.register_messenger(self.main_window.add_report_line)
+ Messages.register_messenger(sys.stdout.write)
+ Messages.send_init()
+ self.main_window.connect('delete_event', self._quit)
+ self.main_window.connect('key_press_event',
self._handle_key_press)
+ #flow graph settings
+ self.init_file_paths = file_paths
+ self.handle_states(APPLICATION_INITIALIZE)
+ # enter the mainloop
+ gtk.gdk.threads_init()
+ gtk.gdk.threads_enter()
+ gtk.main()
+ gtk.gdk.threads_leave()
+
+ def _handle_key_press(self, widget, event):
+ """
+ Handle key presses from the keyboard.
+ Translate key combos into actions.
+ Key combinations that do not include special keys, such as ctrl
or Fcn*,
+ Also, require that the flow graph has mouse focus when choosing
to handle keys.
+ @return true if the flow graph is in active use
+ """
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ #print 'Key "%s" (%d) was pressed' % (keyname, event.keyval)
+ #if event.state & gtk.gdk.CONTROL_MASK: print "Control was
being held down"
+ #if event.state & gtk.gdk.MOD1_MASK: print "Alt was being held
down"
+ #if event.state & gtk.gdk.SHIFT_MASK: print "Shift was being
held down"
+ #################### save/open/new/undo/redo
###############################
+ if event.state & gtk.gdk.CONTROL_MASK and keyname == 's':
+ self.handle_states(FLOW_GRAPH_SAVE)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'z':
+ self.handle_states(FLOW_GRAPH_UNDO)
+ elif event.state & gtk.gdk.CONTROL_MASK and (keyname in ('y',
'Z')):
+ self.handle_states(FLOW_GRAPH_REDO)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'o':
+ self.handle_states(FLOW_GRAPH_OPEN)
+ elif event.state & gtk.gdk.CONTROL_MASK and keyname == 'n':
+ self.handle_states(FLOW_GRAPH_NEW)
+ #################### Delete ###############################
+ elif self.get_flow_graph().get_focus_flag() and keyname ==
'Delete': #mouse focus
+ self.handle_states(ELEMENT_DELETE)
+ #################### Rotate ###############################
+ elif self.get_flow_graph().get_focus_flag() and keyname ==
'Right': #mouse focus
+ self.handle_states(SIGNAL_BLOCK_ROTATE_RIGHT)
+ elif self.get_flow_graph().get_focus_flag() and keyname ==
'Left': #mouse focus
+ self.handle_states(SIGNAL_BLOCK_ROTATE_LEFT)
+ #################### Data Type
###############################
+ elif self.get_flow_graph().get_focus_flag() and keyname ==
'Down': #mouse focus
+ self.handle_states(SIGNAL_BLOCK_INC_TYPE)
+ elif self.get_flow_graph().get_focus_flag() and keyname ==
'Up': #mouse focus
+ self.handle_states(SIGNAL_BLOCK_DEC_TYPE)
+ #################### Socket Controllers
###############################
+ elif self.get_flow_graph().get_focus_flag() and keyname in
('equal','plus', 'KP_Add'): #mouse focus
+ self.handle_states(SOCKET_CONTROLLER_INC)
+ elif self.get_flow_graph().get_focus_flag() and keyname in
('minus', 'KP_Subtract'): #mouse focus
+ self.handle_states(SOCKET_CONTROLLER_DEC)
+ #################### Exec/Stop/Print
###############################
+ elif keyname == 'F5':
+ self.handle_states(FLOW_GRAPH_EXEC)
+ elif keyname == 'F7':
+ self.handle_states(FLOW_GRAPH_STOP)
+ elif keyname == 'Print':
+ self.handle_states(FLOW_GRAPH_SCREEN_CAPTURE)
+ #propagate this if the fg is not in focus or nothing is selected
+ return self.get_flow_graph().get_focus_flag() and
self.get_flow_graph().is_selected()
+
+ def _quit(self, window, event):
+ """!
+ Handle the delete event from the main window.
+ Generated by pressing X to close, alt+f4, or right click+close.
+ This method in turns calls the state handler to quit.
+ @return true
+ """
+ self.handle_states(APPLICATION_QUIT)
+ return True
+
+ def _handle_actions(self, event):
+ """
+ Handle all of the activate signals from the gtk actions.
+ The action signals derive from clicking on a toolbar or menu
bar button.
+ Forward the action to the state handler.
+ """
+ self.handle_states(event.get_name())
+
+ def handle_states(self, state=''):
+ """!
+ Handle the state changes in the GUI.
+ Handle all of the state changes that arise from the action
handler or other Graphics and
+ inputs in the application. The state passed to the
handle_states method is a string descriping
+ the change. A series of if/elif statements handle the state by
greying out action buttons, causing
+ changes in the flow graph, saving/opening files... The
handle_states method is passed to the
+ contructors of many of the classes used in this application
enabling them to report any state change.
+ @param state a string describing the state change
+ """
+
##############################################################################################
+ # Initalize/Quit
+
##############################################################################################
+ if state == APPLICATION_INITIALIZE:
+ for action in ACTIONS_LIST: action.set_sensitive(False)
#set all actions disabled
+ # enable a select few actions
+ Graphics.enable_usrp_diagnostics() #try to enable
usrp diagnostics
+ for action in (
+ APPLICATION_QUIT, FLOW_GRAPH_NEW,
FLOW_GRAPH_OPEN, FLOW_GRAPH_SAVE_AS, FLOW_GRAPH_CLOSE,
+ ABOUT_WINDOW_DISPLAY,
DATA_TYPES_WINDOW_DISPLAY, HOTKEYS_WINDOW_DISPLAY, MATH_EXPR_WINDOW_DISPLAY,
+ FLOW_GRAPH_WINDOW_RESIZE, PREFS_WINDOW_DISPLAY,
FLOW_GRAPH_SCREEN_CAPTURE,
+ ): get_action_from_name(action).set_sensitive(True)
+ if not self.init_file_paths and
Preferences.restore_files(): self.init_file_paths = Preferences.files_open()
+ if not self.init_file_paths: self.init_file_paths = ['']
+ for file_path in self.init_file_paths:
self.main_window.new_page(file_path) #load pages from file paths
+ if not self.get_page(): self.main_window.new_page()
#ensure that at least a blank page exists
+ elif state == APPLICATION_QUIT:
+ if self.main_window.close_pages():
+ Preferences.save(self.main_window)
+ gtk.main_quit()
+ exit(0)
+
##############################################################################################
+ # Selections
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_SELECT or state == SOCKET_SELECT:
+ for action in (ELEMENT_DELETE,
SIGNAL_BLOCK_PARAM_MODIFY, SIGNAL_BLOCK_ROTATE_RIGHT,
SIGNAL_BLOCK_ROTATE_LEFT):
+ get_action_from_name(action).set_sensitive(True)
+ elif state == CONNECTION_SELECT:
+ get_action_from_name(ELEMENT_DELETE).set_sensitive(True)
+ for action in (SIGNAL_BLOCK_PARAM_MODIFY,
SIGNAL_BLOCK_ROTATE_RIGHT, SIGNAL_BLOCK_ROTATE_LEFT):
+
get_action_from_name(action).set_sensitive(False)
+ elif state == NOTHING_SELECT:
+ for action in (ELEMENT_DELETE,
SIGNAL_BLOCK_PARAM_MODIFY, SIGNAL_BLOCK_ROTATE_RIGHT,
SIGNAL_BLOCK_ROTATE_LEFT):
+
get_action_from_name(action).set_sensitive(False)
+ self.get_flow_graph().unselect()
+
##############################################################################################
+ # Move/Rotate/Delete/Create
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_MOVE:
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == SIGNAL_BLOCK_ROTATE_LEFT:
+ if self.get_flow_graph().rotate_selected(DIR_LEFT):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == SIGNAL_BLOCK_ROTATE_RIGHT:
+ if self.get_flow_graph().rotate_selected(DIR_RIGHT):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == ELEMENT_DELETE:
+ if self.get_flow_graph().delete_selected():
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.handle_states(NOTHING_SELECT)
+ self.get_page().set_saved(False)
+ elif state == CONNECTION_CREATE or state ==
SIGNAL_BLOCK_CREATE:
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.handle_states(NOTHING_SELECT)
+ self.get_page().set_saved(False)
+ elif state == SIGNAL_BLOCK_INC_TYPE:
+ if
self.get_flow_graph().type_controller_modify_selected(1):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == SIGNAL_BLOCK_DEC_TYPE:
+ if
self.get_flow_graph().type_controller_modify_selected(-1):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == SOCKET_CONTROLLER_INC:
+ if
self.get_flow_graph().socket_controller_modify_selected(1):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == SOCKET_CONTROLLER_DEC:
+ if
self.get_flow_graph().socket_controller_modify_selected(-1):
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+
##############################################################################################
+ # Window stuff
+
##############################################################################################
+ elif state == USRP_DIAGNOSTICS_DISPLAY:
+ Graphics.USRPDiagnosticsDialog()
+ elif state == PREFS_WINDOW_DISPLAY:
+ Graphics.PreferencesDialog()
+ self.get_flow_graph().update()
+ elif state == ABOUT_WINDOW_DISPLAY:
+ Graphics.AboutDialog()
+ elif state == DATA_TYPES_WINDOW_DISPLAY:
+ Graphics.DataTypesDialog()
+ elif state == HOTKEYS_WINDOW_DISPLAY:
+ Graphics.HotKeysDialog()
+ elif state == MATH_EXPR_WINDOW_DISPLAY:
+ Graphics.MathExprDialog()
+ elif state == FLOW_GRAPH_WINDOW_RESIZE:
+ dimensions =
Graphics.FlowGraphWindowSizeDialog(self.get_flow_graph().get_size_request()).run()
+ if dimensions:
+
self.get_flow_graph().set_size_request(*dimensions)
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+
##############################################################################################
+ # Variable and Param Modifications
+
##############################################################################################
+ elif state == SIGNAL_BLOCK_PARAM_MODIFY:
+ if self.get_flow_graph().param_modify_selected():
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ elif state == VARIABLE_MODIFY:
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+ self.get_flow_graph().update()
+ elif state == VARIABLE_REORDER:
+
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().to_nested_data())
+ self.get_page().set_saved(False)
+
##############################################################################################
+ # Undo/Redo
+
##############################################################################################
+ elif state == FLOW_GRAPH_UNDO:
+ nested_data =
self.get_page().get_state_cache().get_prev_state()
+ if nested_data != None:
+ self.handle_states(NOTHING_SELECT)
+
self.get_flow_graph().from_nested_data(nested_data)
+ self.get_page().set_saved(False)
+ elif state == FLOW_GRAPH_REDO:
+ nested_data =
self.get_page().get_state_cache().get_next_state()
+ if nested_data != None:
+ self.handle_states(NOTHING_SELECT)
+
self.get_flow_graph().from_nested_data(nested_data)
+ self.get_page().set_saved(False)
+
##############################################################################################
+ # New/Open/Save/Close
+
##############################################################################################
+ elif state == FLOW_GRAPH_NEW:
+ self.main_window.new_page()
+ elif state == FLOW_GRAPH_OPEN:
+ file_path =
Graphics.OpenFlowGraphFileDialog(self.get_flow_graph() and
self.get_page().get_file_path() or '').run()
+ if file_path != None:
self.main_window.new_page(file_path)
+ elif state == FLOW_GRAPH_CLOSE:
+ self.main_window.close_page()
+ elif state == FLOW_GRAPH_SAVE:
+ if not self.get_page().get_file_path():
self.handle_states(FLOW_GRAPH_SAVE_AS)
+ else:
+ try:
+
ParseXML.to_file(ParseXML.to_xml(self.get_flow_graph().to_nested_data()),
self.get_page().get_file_path())
+ self.get_page().set_saved(True)
+ except IOError:
+
Messages.send_fail_save(self.get_page().get_file_path())
+ self.get_page().set_saved(False)
+ elif state == FLOW_GRAPH_SAVE_AS:
+ file_path =
Graphics.SaveFlowGraphFileDialog(self.get_page().get_file_path()).run()
+ if file_path != None:
+ self.get_page().set_file_path(file_path)
+ self.handle_states(FLOW_GRAPH_SAVE)
+ elif state == FLOW_GRAPH_SCREEN_CAPTURE:
+ file_path =
Graphics.SaveImageFileDialog(self.get_page().get_file_path()).run()
+ if file_path != None:
+ pixmap = self.get_flow_graph().pixmap
+ width, height = pixmap.get_size()
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
0, 8, width, height)
+ pixbuf.get_from_drawable(pixmap,
pixmap.get_colormap(), 0, 0, 0, 0, width, height)
+ pixbuf.save(file_path,
IMAGE_FILE_EXTENSION[1:])
+
##############################################################################################
+ # Run/Stop
+
##############################################################################################
+ elif state == FLOW_GRAPH_EXEC:
+ if not self.get_page().get_pid_file():
+ if not self.get_page().get_saved() or not
self.get_page().get_file_path():
+ self.handle_states(FLOW_GRAPH_SAVE)
#only save if file path missing or not saved
+ if self.get_page().get_saved() and
self.get_page().get_file_path():
+ ExecFlowGraphThread(self) #only
exec if file path and saved
+ elif state == FLOW_GRAPH_STOP:
+ MUTEX.lock()
+ if self.get_page().get_pid_file():
+ try:
os.kill(int(open(self.get_page().get_pid_file(), 'r').read()), 9)
+ except: print "could not kill pid file:
%s"%self.get_page().get_pid_file()
+ MUTEX.unlock()
+ elif state == '': #pass and run the global actions
+ pass
+ else: print '!!! State "%s" not handled !!!'%state
+
##############################################################################################
+ # Global Actions for all States
+
##############################################################################################
+ #set the exec button if the flow graph is valid and is not
already running
+ MUTEX.lock()
+
get_action_from_name(FLOW_GRAPH_EXEC).set_sensitive(self.get_flow_graph().is_valid()
and not self.get_page().get_pid_file())
+
get_action_from_name(FLOW_GRAPH_STOP).set_sensitive(self.get_page().get_pid_file()
!= '')
+ MUTEX.unlock()
+ #saved status
+ get_action_from_name(FLOW_GRAPH_SAVE).set_sensitive(not
self.get_page().get_saved())
+ self.main_window.update()
+
+class ExecFlowGraphThread(Thread):
+ """Execute the flow graph as a new process and wait on it to finish."""
+ def __init__ (self, action_handler):
+ """!
+ ExecFlowGraphThread constructor.
+ @param action_handler an instance of an ActionHandler
+ """
+ Thread.__init__(self)
+ self.handle_states = action_handler.handle_states
+ self.flow_graph = action_handler.get_flow_graph()
+ #store page and dont use main window calls in run
+ self.page = action_handler.get_page()
+ #random id so multiple flow graphs can run w/o files
intersecting
+ rand_id = random.randint(10000, 99999)
+ #set files
+ self.file_path = self.page.get_file_path()
+ self.report_file = '/tmp/grc-%d-%d.report'%(os.getpid(),
rand_id)
+ self.pid_file = '/tmp/grc-%d-%d.pid'%(os.getpid(), rand_id)
+ self.page.set_pid_file(self.pid_file)
+ get_action_from_name(FLOW_GRAPH_EXEC).set_sensitive(False)
+ get_action_from_name(FLOW_GRAPH_STOP).set_sensitive(True)
+ Messages.send_start_exec(self.page.get_file_path())
+ self.start()
+
+ def run(self):
+ """Execute the flow graph."""
+ cmd = '%s "%s" --pid_file="%s" 2> "%s"'%(
+ DEFAULT_FLOW_GRAPH_EXEC,
+ self.file_path,
+ self.pid_file,
+ self.report_file,
+ )
+ os.system(cmd)
+ try:
+ report = open(self.report_file, 'r')
+ # read all the lines of the report file into a
list #
+ Messages.send_end_exec(report.readlines())
+ report.close()
+ os.remove(self.report_file)
+ except IOError: print "could not read report file:
%s"%self.report_file
+ try: os.remove(self.pid_file)
+ except: print "could not remove pid file: %s"%self.pid_file
+ MUTEX.lock()
+ self.page.set_pid_file('')
+ MUTEX.unlock()
+ self.handle_states()
+
Deleted: grc/tags/grc_0.69/src/Constants.py
Copied: grc/tags/grc_0.69/src/Constants.py (from rev 6478,
grc/trunk/src/Constants.py)
===================================================================
--- grc/tags/grc_0.69/src/Constants.py (rev 0)
+++ grc/tags/grc_0.69/src/Constants.py 2007-09-20 01:49:24 UTC (rev 6483)
@@ -0,0 +1,209 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Constants
+#Global constants
address@hidden Josh Blum
+
+import sys, os
+import mutex
+
+##mutex used when running a flow graph.
+MUTEX = mutex.mutex()
+def lock(mutex):
+ while not mutex.testandset(): pass #try to lock repeatedly until
lock is aquired
+MUTEX.lock = lambda: lock(MUTEX)
+
+######################################################################################################
+## Global Titles @{
+######################################################################################################
+
+##The current version of this code
+VERSION = '0.69'
+
+##The name to appear in the main window for a flow graph that has not been
saved to file.
+NEW_FLOGRAPH_TITLE = 'untitled'
+
+##The prefix title on the main window.
+MAIN_WINDOW_PREFIX = "GRC"
address@hidden
+
+######################################################################################################
+## Signal block connector lengths
+######################################################################################################
+
+##The length that a connection must extend from the socket until the length
depends on the index of the socket.
+CONNECTOR_EXTENSION_INITIAL_LENGTH = 11
+
+##The length that a connection must extend from the initial length times the
index of the socket, after this length, the connection may have a bend.
+CONNECTOR_EXTENSION_LENGTH = 11
+
+######################################################################################################
+## Signal block rotations
+######################################################################################################
+
+##List of possible angles (in degrees) that a signal block and its parameters
can be rotated to.
+POSSIBLE_ROTATIONS = (0, 90, 180, 270)
+
+##direction of rotation left.
+DIR_LEFT = 'left'
+
+##direction of rotation right.
+DIR_RIGHT = 'right'
+
+######################################################################################################
+## Dimension constraints for the various windows (in pixels)
+######################################################################################################
+
+##main window constraints @{
+DEFAULT_MAIN_WINDOW_WIDTH = 750
+
+DEFAULT_MAIN_WINDOW_HEIGHT = 550
address@hidden
+
+##flow graph window constraints @{
+MIN_WINDOW_WIDTH = 600
+MAX_WINDOW_WIDTH = 2400
+
+MIN_WINDOW_HEIGHT = 400
+MAX_WINDOW_HEIGHT = 1800
address@hidden
+
+##dialog constraints @{
+MIN_DIALOG_WIDTH = 400
+MIN_DIALOG_HEIGHT = 500
address@hidden
+
+##misc window constraints @{
+REPORTS_WINDOW_HEIGHT = 80
+
+SIGNAL_BLOCK_SELECTION_WINDOW_WIDTH = 250
+SIGNAL_BLOCK_SELECTION_WINDOW_HEIGHT = 250
+
+VARIABLE_MODIFICATION_WINDOW_WIDTH = 250
+VARIABLE_MODIFICATION_WINDOW_HEIGHT = 150
address@hidden
+
+######################################################################################################
+## Constraints for the sliders in the runnable flow graph @{
+######################################################################################################
+
+##The number of tics for a slider.
+DEFAULT_SLIDER_STEPS = 100
+
+##The max width that a row of sliders can use.
+MAX_SLIDERS_WIDTH = 600
+
+##Slider width in pixels
+DEFAULT_SLIDER_WIDTH = 200
+##Slider width in pixels
+MAX_SLIDER_WIDTH = 300
+##Slider width in pixels
+MIN_SLIDER_WIDTH = 100
+
+##The height in pixels.
+SLIDER_HEIGHT = 20
address@hidden
+
+######################################################################################################
+## Constraints on displayable labels and sockets @{
+######################################################################################################
+
+LABEL_SEPARATION = 4
+LABEL_PADDING_WIDTH=20
+LABEL_PADDING_HEIGHT=10
+
+SOCKET_SEPARATION = 20
+SOCKET_HEIGHT = 17
+SOCKET_WIDTH = 27
+SOCKET_BORDER_SEPARATION = 10
+
+PARAM_FONT = 'Sans 8'
+SIGNAL_BLOCK_FONT = 'Sans 9 Bold'
+SOCKET_FONT = 'Sans 8'
address@hidden
+
+######################################################################################################
+## Dragging, scrolling, and redrawing constants for the flow graph window in
pixels @{
+######################################################################################################
+
+##How close can the mouse get to the window border before mouse events are
ignored.
+BORDER_PROXIMITY_SENSITIVITY = 10
+
+##How close the mouse can get to the edge of the visible window before
scrolling is invoked.
+SCROLL_PROXIMITY_SENSITIVITY = 30
+
+##When the window has to be scrolled, move it this distance in the required
direction.
+SCROLL_DISTANCE = 15
+
+##The redrawing sensitivity, how many motion detection events must occur
before a redraw?
+MOTION_DETECT_REDRAWING_SENSITIVITY = 3
+
+##How close the mouse click can be to a connection and register a connection
select.
+CONNECTION_SELECT_SENSITIVITY = 5
address@hidden
+
+######################################################################################################
+# A state is recorded for each change to the flow graph, the size
dictates how many states we can record
+######################################################################################################
+
+##The size of the state saving cache in the flow graph (for undo/redo
functionality)
+STATE_CACHE_SIZE = 42
+
+######################################################################################################
+## Constansts dealing with File Paths @{
+######################################################################################################
+
+##Location of the python src directory.
+SRC_DIR = os.path.abspath(os.path.dirname(__file__))
+
+##Location of external data files.
+DATA_DIR = os.path.abspath(SRC_DIR+'/../data/')
+
+##The setting for a blank flow graph.
+INITIAL_FLOW_GRAPH_FILE =
os.path.abspath(DATA_DIR+'/initial_flow_graph.grc.xml')
+
+##The default file extension for flow graphs.
+FLOW_GRAPH_FILE_EXTENSION = '.grc.xml'
+
+##The default file extension for saving flow graph snap shots.
+IMAGE_FILE_EXTENSION = '.png'
+
+##The default path for the open/save dialogs.
+DEFAULT_FILE_PATH = os.path.expanduser('~')+'/'
+
+##The default icon for the gtk windows.
+PY_GTK_ICON = os.path.abspath(DATA_DIR+'/grc-icon-256.png')
+
+##The default icon for the wx windows.
+WX_APP_ICON = os.path.abspath(DATA_DIR+'/grc-icon-32.png')
+#>>> platform dependency! wx under cygwin has issues with icon paths #
+if sys.platform == 'cygwin': WX_APP_ICON = None
+
+##The default binary to execute python files.
+PYEXEC = 'python'
+#>>> platform dependency! MacOS requires pythonw to run wx apps #
+if sys.platform == 'darwin': PYEXEC = 'pythonw'
+
+##The default command to run a flow graph file.
+DEFAULT_FLOW_GRAPH_EXEC = '%s %s/ExecFlowGraphGUI.py'%(PYEXEC, SRC_DIR)
+
+##The default user preferences file.
+PREFERENCES_FILE_PATH = os.path.abspath(DEFAULT_FILE_PATH + '/.grc.xml')
address@hidden
+
Deleted: grc/tags/grc_0.69/src/ExecFlowGraph.py
Copied: grc/tags/grc_0.69/src/ExecFlowGraph.py (from rev 6347,
grc/trunk/src/ExecFlowGraph.py)
===================================================================
--- grc/tags/grc_0.69/src/ExecFlowGraph.py (rev 0)
+++ grc/tags/grc_0.69/src/ExecFlowGraph.py 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,196 @@
+#! /usr/bin/env python
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden ExecFlowGraph
+#Use an xml input file to build and run a gnu radio flow graph without
graphics.
address@hidden Josh Blum
+
+import ParseXML
+import Variables
+from Elements import SignalBlock
+from gnuradio import gr
+import os
+from Constants import FLOW_GRAPH_FILE_EXTENSION,MUTEX
+from optparse import OptionParser
+
+##############################################################################################
+# Flow Graph Builder
+##############################################################################################
+class FlowGraphBuilder(gr.top_block):
+ """ Parse the input file to build the gnuradio flow graph.
+ Register the variables, handle signal block callbacks. """
+
+ def __init__(self, file_path):
+ gr.top_block.__init__(self, file_path)
+ #internal data structures
+ self.callbacks = list()
+ self.callbacks_locked = list()
+ self.callbacks_cond = list()
+ self.var_keys = list()
+ self.started = False
+ #build the flow graph
+
self._parse_nested_data(ParseXML.from_xml(ParseXML.from_file(file_path)))
+
+ def _start(self):
+ """Start the flow graph."""
+ self.start()
+ self.started = True
+
+ def _stop(self):
+ """Stop the flow graph."""
+ self.stop()
+ self.started = False
+
+ def add_window(self, *args):
+ """Empty method for adding a window in the GUI flow graph."""
+ pass
+
+ def get_panel(self):
+ """Empty method for getting the wx panel in the GUI flow
graph."""
+ print """
+Graphical Sinks are not supported in ExecFlowGraph.py:
+ use ExecFlowGraphGUI.py [-d] or remove the Graphical Sink.
+Exiting!"""
+ exit(-1)
+
+ def add_callback(self, function, *data_type_params):
+ """
+ Register a callback function with its associated data.
+ @param function the callback function
+ @param data_type_params a list of data types
+ """
+ self.callbacks.append((function, data_type_params))
+
+ def add_callback_locked(self, function, *data_type_params):
+ """
+ Register a "locked" callback function with its associated data.
+ These callbacks will be called inside of a lock/unlock sequence.
+ @param function the callback function
+ @param data_type_params a list of data types
+ """
+ self.callbacks_locked.append((function, data_type_params))
+
+ def add_callback_cond(self, function, *data_type_params):
+ """
+ Register a "conditional" callback function with its associated
data.
+ These callbacks will be called inside of a lock/unlock sequence
+ only if at least one locked callback has been registered.
+ @param function the callback function
+ @param data_type_params a list of data types
+ """
+ self.callbacks_cond.append((function, data_type_params))
+
+ def _parse_callback(self, function, *data_type_params):
+ """
+ Parse a single callback. Call function on the data types.
+ @param function the callback function
+ @param data_type_params a list of data types
+ """
+ #print "***\nBegin A callback\n%s\n\n***"%function
+ try: function(*map(lambda param: param.parse(),
data_type_params))
+ except Exception, e: print "***\n\nerror parsing a callback ->
ignoring\n%s...\n\n***"%e
+ #print "***\nEnd A callback\n***"
+
+ def parse_callbacks(self):
+ """For each call back, parse all of the data and
+ call the registered callback function on that data."""
+ #MUTEX.lock()
+ #print "***\n\nCallback Time BEGIN\n\n***"
+ if self.started:
+ if self.callbacks: #parse regular callbacks
+ for function, data_type_params in
self.callbacks:
+ self._parse_callback(function,
*data_type_params)
+ if self.callbacks_locked: #parse locked callbacks
and conditional callbacks
+ self.lock()
+ for function, data_type_params in
self.callbacks_locked + self.callbacks_cond:
+ self._parse_callback(function,
*data_type_params)
+ self.unlock()
+ #print "***\n\nCallback Time END\n\n***"
+ #MUTEX.unlock()
+
+ def _parse_nested_data(self, nested_data):
+ """!
+ Parse nested data from a flow graph file and build the
graphics.
+ @param nested_data the nested flow graph data
+ """
+ find_data = ParseXML.find_data
+ flow_graph = find_data([nested_data], 'flow_graph')
+ vars = find_data(flow_graph, 'vars')
+ signal_blocks = find_data(flow_graph, 'signal_blocks')
+ connections = find_data(flow_graph, 'connections')
+ self.var_keys = Variables.from_nested_data(vars)
+ signal_blocks_dict = dict()
+ for signal_block in signal_blocks:
+ signal_block,runnable_signal_block =
SignalBlock.from_nested_data(None, signal_block, SignalBlock)
+ data_type_params = list()
+ data_type_params.append(self)#put the flow graph in the
front of the list
+ for param in signal_block.get_params(): #load the list
of arguments to the runnable block
+ data_type_params.append(param.get_data_type())
+ signal_blocks_dict[signal_block.get_id()] =
runnable_signal_block(*data_type_params)
+ for connection in connections:
+ connection = find_data([connection], 'connection')
+ input_signal_block_id = find_data(connection,
'input_signal_block_id')
+ input_socket_index = int(find_data(connection,
'input_socket_index'))
+ output_signal_block_id = find_data(connection,
'output_signal_block_id')
+ output_socket_index = int(find_data(connection,
'output_socket_index'))
+ input_signal_block =
signal_blocks_dict[input_signal_block_id]
+ output_signal_block =
signal_blocks_dict[output_signal_block_id]
+ self.connect(# use this flow graph's connect method
#
+ (output_signal_block, output_socket_index),
+ (input_signal_block, input_socket_index))
+
+##############################################################################################
+# Option Parser for running a flow graph
+##############################################################################################
+class FlowGraphOptionParser(OptionParser):
+ """This flow graph option parser provides a basic help,
+ and ensures that a flow graph is passed on the command line."""
+
+ def __init__(self):
+ """Create the base option parser and add usage and basic
options."""
+ usage = "usage: %prog [options]
flow_graph"+FLOW_GRAPH_FILE_EXTENSION
+ OptionParser.__init__(self, usage=usage)
+ self.add_option("-p", "--pid_file", action="store",
type="string", dest="pid_file", help="record process id")
+
+ def parse_args(self):
+ """Call the base parse_args, handle the basic options,
+ and ensure a flow graph was passed in args. Return the
(options, args)."""
+ (options, args) = OptionParser.parse_args(self)
+ if options.pid_file:
+ try: open(options.pid_file, 'w').write('%d\n' %
os.getpid())
+ except:
+ print '\nCould not create pid file:
"%s".\nExiting!'%options.pid_file
+ exit(-1)
+ if not len(args):
+ self.print_help()
+ exit(-1)
+ return options, args
+
+##############################################################################################
+# Main
+##############################################################################################
+if __name__ == '__main__':
+ parser = FlowGraphOptionParser()
+ (options, args) = parser.parse_args()
+ fg = FlowGraphBuilder(args[0])
+ fg.start()
+ raw_input('Flow Graph Running...\nPress Enter to Exit: ')
+ fg.stop()
+ exit(0)
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/Graphics/Dialogs.py
Copied: grc/tags/grc_0.69/src/Graphics/Dialogs.py (from rev 6449,
grc/trunk/src/Graphics/Dialogs.py)
===================================================================
--- grc/tags/grc_0.69/src/Graphics/Dialogs.py (rev 0)
+++ grc/tags/grc_0.69/src/Graphics/Dialogs.py 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,286 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Graphics.Dialogs
+#Misc dialogs.
address@hidden Josh Blum
+
+import Colors
+import pygtk
+pygtk.require('2.0')
+import gtk
+from DataTypes import *
+from Constants import *
+from Elements import GraphicalParam
+import Preferences
+
+class TextDisplay(gtk.TextView):
+ """A non editable gtk text view."""
+
+ def __init__(self, text=''):
+ """!
+ TextDisplay constructor.
+ @param text the text to display (string)
+ """
+ text_buffer = gtk.TextBuffer()
+ text_buffer.set_text(text)
+ self.set_text = text_buffer.set_text
+ self.insert = lambda line:
text_buffer.insert(text_buffer.get_end_iter(), line)
+ gtk.TextView.__init__(self, text_buffer)
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+ self.set_wrap_mode(gtk.WRAP_WORD)
+
+######################################################################################################
+class PreferencesDialog(gtk.Dialog):
+ """A dialog box to display the preferences."""
+
+ def __init__(self):
+ """PreferencesDialog constructor."""
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title("Preferences")
+ self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT)
+ notebook = gtk.Notebook()
+ for title,notes,params in Preferences.PREFS_LIST:
+ if title:
+ vbox = gtk.VBox()
+ vbox.pack_start(gtk.Label(), False) #blank
label for spacing
+ for param, key in params:
vbox.pack_start(param.get_input_object(), False)
+ if notes: vbox.pack_start(TextDisplay(notes),
False, padding=5)
+ notebook.append_page(vbox, gtk.Label(title))
+ self.vbox.pack_start(notebook, True)
+ self.show_all()
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class FlowGraphWindowSizeDialog(gtk.Dialog):
+ """A dialog box to set the window size, width and heigh in pixels."""
+
+ def __init__(self, dimensions):
+ """!
+ FlowGraphWindowSizeDialog constructor.
+ @param dimensions the (width,height) tuple from the flow graph
+ """
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title("Set the Window Size")
+ # the helpful dimension constraints label #
+ window_size_label = gtk.Label()
+ window_size_label.set_markup("""<i>
+Minimum window (width/height) in pixels is (%d/%d).
+Maximum window (width/height) in pixels is (%d/%d).
+</i>"""%(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, MAX_WINDOW_WIDTH,
MAX_WINDOW_HEIGHT))
+ self.vbox.pack_end(window_size_label, False)
+ self.original_dimensions = width,height = dimensions
+ self.width = Int(width, min=MIN_WINDOW_WIDTH,
max=MAX_WINDOW_WIDTH)
+ self.height = Int(height, min=MIN_WINDOW_HEIGHT,
max=MAX_WINDOW_HEIGHT)
+ self.vbox.pack_start(GraphicalParam('width (pixels)',
self.width).get_input_object(), False)
+ self.vbox.pack_start(GraphicalParam('height (pixels)',
self.height).get_input_object(), False)
+ self.show_all()
+
+ def run(self):
+ """!
+ Get the new dimensions.
+ @return the new dimensions (width,height) or None if invalid.
+ """
+ self.dimensions = None
+ gtk.Dialog.run(self)
+ if self.width.is_valid() and self.height.is_valid():
+ self.dimensions = (self.width.parse(),
self.height.parse())
+ self.destroy()
+ if self.original_dimensions == self.dimensions: return None
# do not return dimensions if no change
+ return self.dimensions
+
+######################################################################################################
+def MessageDialogHelper(type, buttons, title=None, markup=None):
+ """!
+ Create a modal message dialog and run it.
+ @param type the type of message: gtk.MESSAGE_INFO, gtk.MESSAGE_WARNING,
gtk.MESSAGE_QUESTION or gtk.MESSAGE_ERROR
+ @param buttons the predefined set of buttons to use: gtk.BUTTONS_NONE,
gtk.BUTTONS_OK, gtk.BUTTONS_CLOSE, gtk.BUTTONS_CANCEL, gtk.BUTTONS_YES_NO,
gtk.BUTTONS_OK_CANCEL
+ @param tittle the title of the window (string)
+ @param markup the message text with pango markup
+ @return the gtk response from run()
+ """
+ message_dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, type,
buttons)
+ if title != None: message_dialog.set_title(title)
+ if markup != None: message_dialog.set_markup(markup)
+ response = message_dialog.run()
+ message_dialog.destroy()
+ return response
+
+######################################################################################################
+class AboutDialog(gtk.AboutDialog):
+ """A cute little about dialog."""
+
+ def __init__(self):
+ """AboutDialog constructor."""
+ gtk.AboutDialog.__init__(self)
+ self.set_version(VERSION)
+ self.set_name(MAIN_WINDOW_PREFIX)
+ self.set_license(__doc__)
+ self.set_copyright('Copyright 2007 Free Software Foundation,
Inc.')
+
self.set_website('http://gnuradio.org/trac/wiki/GNURadioCompanion')
+ self.set_comments("""\
+Thank you to all those from the mailing list who tested GNU Radio Companion
and offered advice.
+--
+Special Thanks:
+A. Brinton Cooper -> starting the project
+CER Technology Fellowship Grant -> initial funding
+William R. Kenan Jr. Fund -> usrp & computers
+Patrick Strasser -> the GRC icon
+Achilleas Anastasopoulos -> trellis support
+--""")
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class DataTypesDialog(gtk.Dialog):
+ """Display each data type with its associated color."""
+
+ def __init__(self):
+ """DataTypesDialog constructor."""
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title('Data Types')
+ self.set_size_request(170, -1)
+ markup = ''
+ for color_spec in (
+ 'Regular Types:',
+ ('Complex', Colors.COMPLEX_COLOR_SPEC),
+ ('Float', Colors.FLOAT_COLOR_SPEC),
+ ('Int', Colors.INT_COLOR_SPEC),
+ ('Short', Colors.SHORT_COLOR_SPEC),
+ ('Byte', Colors.BYTE_COLOR_SPEC),
+ 'Vector Types:',
+ ('Complex Vector', Colors.COMPLEX_VECTOR_COLOR_SPEC),
+ ('Float Vector', Colors.FLOAT_VECTOR_COLOR_SPEC),
+ ('Int Vector', Colors.INT_VECTOR_COLOR_SPEC),
+ ('Short Vector', Colors.SHORT_VECTOR_COLOR_SPEC),
+ ('Byte Vector', Colors.BYTE_VECTOR_COLOR_SPEC),
+ ):
+ width = 20 #width in monospace characters
+ if type(color_spec) == type(str()): markup =
'%s\n\n<b>%s</b>'%(markup, color_spec.center(width, ' '))
+ else:
+ tag,spec = color_spec
+ markup = '%s\n<span
background="%s">%s</span>'%(markup, spec, tag.center(width, ' '))
+ label = gtk.Label()
+ label.set_markup('<tt>%s</tt>\n'%markup[1:]) #strip 1st
newline, append newline
+ self.vbox.pack_start(label, False)
+ self.show_all()
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class HotKeysDialog(gtk.Dialog):
+ """Display each action with the associated hotkey."""
+
+ def __init__(self):
+ """HotKeysDialog constructor."""
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ self.set_title('Hot Keys')
+ markup = ''
+ for action, hotkey in (
+ ('New Flow Graph', 'Ctrl + n'),
+ ('Open Flow Graph', 'Ctrl + o'),
+ ('Save Flow Graph', 'Ctrl + s'),
+ ('Undo Change', 'Ctrl + z'),
+ ('Redo Change', 'Ctrl + y'),
+ ('Redo Change', 'Ctrl + Z'),
+ ('Delete Block', 'Delete'),
+ ('Rotate Block', 'Right'),
+ ('Rotate Block', 'Left'),
+ ('Modify Data Type', 'Up'),
+ ('Modify Data Type', 'Down'),
+ ('Add a Socket', '+'),
+ ('Remove a Socket', '-'),
+ ('Close Dialog', 'Esc'),
+ ('Flow Graph Run', 'F5'),
+ ('Flow Graph Stop', 'F7'),
+ ('Screen Shot', 'PrintScreen'),
+ ): markup = '%s\n<b>%s:</b>%s'%(markup, action,
hotkey.rjust(25-len(action),' '))
+ label = gtk.Label()
+ label.set_markup('<tt>%s</tt>\n'%markup) #append newline
+ self.vbox.pack_start(label, False)
+ self.show_all()
+ self.run()
+ self.destroy()
+
+######################################################################################################
+class MathExprDialog(gtk.Dialog):
+ """A dialog to test math expressions for the parser."""
+
+ ##the help message
+ HELP_MSG = """\
+<b>Operators - Complex <i>(complex arguments)</i></b>
+ + - * / ^
+<b>Trigonometric Functions <i>(complex arguments, radians)</i></b>
+ sin(z) cos(z) tan(z) asin(z) acos(z) atan(z)
+ sinh(z) cosh(z) tanh(z) asinh(z) acosh(z) atanh(z)
+<b>Complex Components <i>(complex arguments)</i></b>
+ mag(z*) real(z*) imag(z*) conj(z*) arg(z)
+<b>Misc Functions <i>(complex arguments)</i></b>
+ abs(z*) pow(b, p) sqrt(z) log10(z) log(z, [b=e]) ln(z) exp(z)
+<b>Misc Functions <i>(floating point arguments)</i></b>
+ floor(f) ceil(f) radians(deg) degrees(rad) mod(f1, f2) atan2(y, x)
sgn(f) min(f*) max(f*)
+<b>Filter Taps Generators <i>(floating point arguments, rates and
frequencies in Hz)</i></b>
+ low_pass(gain, samp_rate, cutoff_freq, width, [window=hamming],
[beta=6.76])
+ high_pass(gain, samp_rate, cutoff_freq, width, [window=hamming],
[beta=6.76])
+ band_pass(gain, samp_rate, low_cutoff_freq, high_cutoff_freq, width,
[window=hamming], [beta=6.76])
+ complex_band_pass(gain, samp_rate, low_cutoff_freq, high_cutoff_freq,
width, [window=hamming], [beta=6.76])
+ band_reject(gain, samp_rate, low_cutoff_freq, high_cutoff_freq, width,
[window=hamming], [beta=6.76])
+ gaussian(gain, spb, bt, int ntaps)
+ hilbert(int ntaps, [window=rectangular], [beta=6.76])
+ root_raised_cosine(gain, samp_rate, symbol_rate, alpha, int ntaps)
+ window(window, int ntaps, beta)
+<b>Window Types for Filters</b>
+ hamming hann blackman rectangular kaiser
+<b>Other Constants</b>
+ pi e j
+<b>Using Vectors</b>
+ () (num1,) (num2, num2, ...)
+<b>Test Your Expressions Below:</b>\
+"""
+
+ def __init__(self):
+ """MathExprDialog constrcutor. Create a new gtk Dialog with a
close button, an extry box, and an output text box."""
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ # Create the title and label #
+ self.set_title('Mathematical Expressions')
+ label = gtk.Label()
+ label.set_markup(self.HELP_MSG)
+ self.vbox.pack_start(label, False)
+ self.set_size_request(800, 600)
+ # create a text box for parser output #
+ self.text_box = TextDisplay()
+ self.text_box.set_text('')
+ # create the entry box and give it the change handler #
+ self.param = GraphicalParam('Expression', RawExpr(''))
+ self.input_obj =
self.param.get_input_object(self._handle_changed)
+ self.vbox.pack_start(self.input_obj, False)
+ # add the scrolled window for the text box #
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(self.text_box)
+ self.vbox.pack_start(scrolled_window, True)
+ self.show_all()
+ self.run()
+ self.destroy()
+
+ def _handle_changed(self, param=None):
+ """Handle changed in the param's entry box by updating the text
box."""
+ self.text_box.set_text(str(self.param.get_data_type()))
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/Graphics/FlowGraph.py
Copied: grc/tags/grc_0.69/src/Graphics/FlowGraph.py (from rev 6460,
grc/trunk/src/Graphics/FlowGraph.py)
===================================================================
--- grc/tags/grc_0.69/src/Graphics/FlowGraph.py (rev 0)
+++ grc/tags/grc_0.69/src/Graphics/FlowGraph.py 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,502 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Graphics.FlowGraph
+#A flow graph structure for storing signal blocks and their connections.
address@hidden Josh Blum
+
+from Constants import *
+from Actions import *
+from Colors import BACKGROUND_COLOR, TXT_COLOR
+from Elements import GraphicalSignalBlock,GraphicalConnection
+from Elements import Utils
+from Elements.Connection import ConnectionException
+import Variables
+import pygtk
+pygtk.require('2.0')
+import gtk
+import time,socket #for tagging saved files
+import SignalBlockDefs
+from SignalBlockParamsDialog import SignalBlockParamsDialog
+import random
+import Messages
+import Preferences
+import ParseXML
+import Messages
+
+class FlowGraph(gtk.DrawingArea):
+ """
+ FlowGraph is the data structure to store graphical signal blocks,
+ graphical inputs and outputs,
+ and the connections between inputs and outputs.
+ """
+
+ def __init__(self, handle_states, variable_modification_window):
+ """!
+ FlowGraph contructor.
+ Create a list for signal blocks and connections. Connect mouse
handlers.
+ @param handle_states the callback function
+ @param variable_modification_window var mod window also for
callbacks
+ """
+ #setup
+ self.elements = list()
+ self.remove_element = lambda e: self.elements.remove(e)
+ self.gc = None
+ self.handle_states = handle_states
+ self.variable_modification_window = variable_modification_window
+ gtk.DrawingArea.__init__(self)
+ self.connect('expose-event', self._handle_window_expose)
+ self.connect('motion-notify-event', self._handle_mouse_motion)
+ self.connect('button-press-event',
self._handle_mouse_button_press)
+ self.connect('button-release-event',
self._handle_mouse_button_release)
+ self.set_events(
+ gtk.gdk.BUTTON_PRESS_MASK | \
+ gtk.gdk.POINTER_MOTION_MASK | \
+ gtk.gdk.BUTTON_RELEASE_MASK | \
+ gtk.gdk.LEAVE_NOTIFY_MASK | \
+ gtk.gdk.ENTER_NOTIFY_MASK
+ )
+ # setup the focus flag #
+ self.focus_flag = False
+ self.get_focus_flag = lambda: self.focus_flag
+ self.connect("leave-notify-event", self._handle_focus_event,
False)
+ self.connect("enter-notify-event", self._handle_focus_event,
True)
+ # important vars dealing with mouse event tracking
#
+ self.has_moved = False
+ self.mouse_pressed = False
+ self.coordinate = (0,0)
+ self.selected_element = None
+ self.is_selected = lambda: self.selected_element != None
+ self.count = 0
+ self.pixmap = None
+
+###########################################################################
+# Flow Graph Access Methods
+###########################################################################
+
+ def _handle_focus_event(self, widget, event, focus_flag):
+ """Record the focus state of the flow graph window."""
+ self.focus_flag = focus_flag
+
+ def add_signal_block(self, tag):
+ """!
+ Add a signal block of the given tag to this flow graph.
+ @param tag the signal block tag
+ """
+ index = 0
+ while True:
+ id = tag+str(index)
+ index = index + 1
+ if not [
+ None for element in self.elements if
Utils.is_signal_block(element) and id == element.get_id()
+ ]: #make sure that the id is not used by
another signal block
+ rot = 0
+ vAdj =
self.get_parent().get_vadjustment().get_value()
+ hAdj =
self.get_parent().get_hadjustment().get_value()
+ x = random.randint(100,400)+int(hAdj)
+ y = random.randint(100,400)+int(vAdj)
+ self.elements.append(
+ SignalBlockDefs.get_signal_block(self,
(x, y), rot, tag, id, GraphicalSignalBlock)[0]
+ )
+ self.handle_states(SIGNAL_BLOCK_CREATE)
+ self.update()
+ return
+
+ def type_controller_modify_selected(self, direction):
+ """
+ !Change the registered type controller for the selected signal
block.
+ @param direction +1 or -1
+ @return true for success
+ """
+ if Utils.is_socket(self.selected_element):
self.selected_element = self.selected_element.get_parent()
+ if Utils.is_signal_block(self.selected_element): return
self.selected_element.modify_type_controller(direction)
+ return False
+
+ def socket_controller_modify_selected(self, direction):
+ """!
+ Change socket controller for the selected signal block.
+ @param direction +1 or -1
+ @return true for success
+ """
+ if Utils.is_socket(self.selected_element):
self.selected_element = self.selected_element.get_parent()
+ if Utils.is_signal_block(self.selected_element): return
self.selected_element.modify_socket_controller(direction)
+ return False
+
+ def param_modify_selected(self):
+ """!
+ Create and show a param modification dialog for the selected
element (socket and signal block only).
+ @return true if parameters were changed
+ """
+ if Utils.is_socket(self.selected_element):
self.selected_element = self.selected_element.get_parent()
+ if Utils.is_signal_block(self.selected_element):
+ signal_block_params_dialog =
SignalBlockParamsDialog(self.selected_element)
+ changed = signal_block_params_dialog.run()
+ self.update()
+ return changed #changes were made?
+ return False
+
+ def connect_sockets(self, s1, s2):
+ """!
+ Connect input and output sockets. Ignore state change if
creation of connection fails.
+ @param s1 a socket
+ @param s2 another socket
+ """
+ try:
+ connection = GraphicalConnection(self, s1, s2)
+ self.elements.append(connection)
+ self.selected_element = None
+ self.handle_states(CONNECTION_CREATE)
+ self.update()
+ except ConnectionException:
+ Messages.send_fail_connection()
+ self.handle_states(NOTHING_SELECT)
+
+ def move_selected(self, delta_coordinate):
+ """!
+ Move the element and by the change in coordinates.
+ @param delta_coordinate the change in coordinates
+ """
+ if self.selected_element != None:
+ self.selected_element.move(delta_coordinate)
+ self.has_moved = True
+ self.draw()
+
+ def rotate_selected(self, direction):
+ """!
+ Rotate the selected element by 90 degrees. Only rotate
SignalBlocks and Sockets.
+ @param direction DIR_LEFT or DIR_RIGHT
+ @return true if rotated, otherwise false.
+ """
+ if self.selected_element != None and
(Utils.is_signal_block(self.selected_element) or
Utils.is_socket(self.selected_element)):
+ self.selected_element.rotate(direction)
+ self.draw()
+ return True
+ return False
+
+ def delete_selected(self):
+ """!
+ If an element is selected, remove it and its attached parts
from the element list.
+ @return true if the element was deleted, otherwise false.
+ """
+ if self.selected_element != None:
+ if Utils.is_socket(self.selected_element): # found
a socket, set to parent signal block
+ self.selected_element =
self.selected_element.get_parent()
+ if Utils.is_signal_block(self.selected_element):
# delete a signal block
+ connections =
self.selected_element.get_connections()
+ for connection in connections:
connection.disconnect()
+ self.remove_element(self.selected_element)
+ elif Utils.is_connection(self.selected_element):
# delete a connection
+ self.selected_element.disconnect()
+ self.selected_element = None
+ self.update()
+ return True
+ return False
+
+ def unselect(self):
+ """If an element is selected, un-highlight it and set selected
to None."""
+ if self.selected_element != None:
+ self.selected_element.set_highlighted(False)
+ self.selected_element = None
+ self.update()
+
+ def what_is_selected(self, coor):
+ """!
+ What is selected?
+ At the given coordinate, return the first element found to be
selected
+ - iterate though the elements backwards since top elements are
at the end of the list
+ - if an element is selected, place it at the end of the list so
that is is drawn last,
+ and hence on top.
+ @param coor the coordinate of the mouse click
+ @return the selected element or None
+ """
+ # check the elements #
+ for element in reversed(self.elements):
+ if element.what_is_selected(coor) != None:
+ self.elements.remove(element)
+ self.elements.append(element)
+ return element.what_is_selected(coor)
+ return None
+
+ def draw(self, drawable=None):
+ """Draw the background and then all of the Elements in this
FlowGraph on the pixmap,
+ then draw the pixmap to the drawable window of this
FlowGraph."""
+ if self.gc != None:
+ # draw the background #
+ W,H = self.get_size_request()
+ self.gc.foreground = BACKGROUND_COLOR
+ self.pixmap.draw_rectangle(self.gc, True, 0, 0, W, H)
+ if Preferences.show_grid():
+ grid_size = Preferences.get_grid_size()
+ points = list()
+ for i in range(W/grid_size):
+ for j in range(H/grid_size):
+
points.append((i*grid_size,j*grid_size))
+ self.gc.foreground = TXT_COLOR
+ self.pixmap.draw_points(self.gc, points)
+ # draw the foreground #
+ for element in filter(Utils.is_signal_block,
self.elements) + filter(Utils.is_connection, self.elements):
+ element.draw(self.pixmap) # draw signal
blocks first, then connections on the top
+ if self.mouse_pressed and self.selected_element != None:
+ self.selected_element.draw(self.pixmap)
+ self.window.draw_drawable(self.gc, self.pixmap, 0, 0,
0, 0, -1, -1)
+
+ def is_valid(self):
+ """!
+ Is the flow graph valid, ie: are all elements valid?
+ @return true if flow graph is valid
+ """
+ for element in self.elements:
+ if not element.is_valid(): return False
+ return True
+ #return all([element.is_valid() for element in self.elements])
#python 2.5 and higher
+
+ def update(self):
+ """Call update on all elements."""
+ for element in self.elements: element.update()
+ self.draw()
+
+
##########################################################################
+ ## Handlers
+
##########################################################################
+
+ def _handle_mouse_button_press(self, widget, event):
+ """ A mouse button is pressed. Record the state of the mouse,
find the selected element,
+ set the Element highlighted, handle the state change, and
redraw the FlowGraph."""
+ # unselect anything in the vars mod window #
+ self.variable_modification_window.unselect_all()
+ if event.button == 1:
+ if self.selected_element != None:
self.selected_element.set_highlighted(False)
+ self.count = 0
+ self.mouse_pressed = True
+ self.coordinate = (event.x, event.y)
+ old_selection = self.selected_element
+ self.selected_element = self.what_is_selected((event.x,
event.y))
+ # handle the state change with the new selection
#
+ if Utils.is_connection(self.selected_element):
self.handle_states(CONNECTION_SELECT)
+ elif Utils.is_socket(self.selected_element):
self.handle_states(SOCKET_SELECT)
+ elif Utils.is_signal_block(self.selected_element):
self.handle_states(SIGNAL_BLOCK_SELECT)
+ elif self.selected_element == None:
self.handle_states(NOTHING_SELECT)
+ # this selection and the last were Sockets, try
to connect them #
+ if Utils.is_socket(old_selection) and
Utils.is_socket(self.selected_element) and\
+ old_selection is not self.selected_element:
#cannot be the same socket
+ self.connect_sockets(old_selection,
self.selected_element)
+ if self.selected_element != None:
self.selected_element.set_highlighted(True)
+ # double click detected, bring up params dialog
if possible #
+ if event.type == gtk.gdk._2BUTTON_PRESS and
Utils.is_signal_block(self.selected_element):
+ self.mouse_pressed = False
+ self.handle_states(SIGNAL_BLOCK_PARAM_MODIFY)
+ self.draw()
+ return True
+
+ def _handle_mouse_button_release(self, widget, event):
+ """A mouse button is released, record the state."""
+ if event.button == 1:
+ self.mouse_pressed = False
+ if self.has_moved:
+ if Preferences.snap_to_grid():
+ grid_size = Preferences.get_grid_size()
+ X,Y =
self.selected_element.get_coordinate()
+ deltaX = X%grid_size
+ if deltaX < grid_size/2: deltaX = -1 *
deltaX
+ else: deltaX = grid_size - deltaX
+ deltaY = Y%grid_size
+ if deltaY < grid_size/2: deltaY = -1 *
deltaY
+ else: deltaY = grid_size - deltaY
+ self.move_selected((deltaX,deltaY))
+ self.handle_states(SIGNAL_BLOCK_MOVE)
+ self.has_moved = False
+ return True
+
+ def _handle_mouse_motion(self, widget, event):
+ """The mouse has moved. If mouse_pressed is true, react to the
motions:
+ - if an Element is highlighted, this will move the
Element by redrawing it at the new position."""
+ fgW,fgH = self.get_size_request()
+ self.count = (1 +
self.count)%MOTION_DETECT_REDRAWING_SENSITIVITY
+ # to perform a movement, the mouse must be pressed, an
element selected, count of zero. #
+ if self.mouse_pressed and\
+ self.count == 0 and\
+ self.selected_element != None:
+ # The event coordinates must be within 10 pixels
away from the bounds of the flow graph. #
+ x = event.x
+ if x <= BORDER_PROXIMITY_SENSITIVITY:
+ x = BORDER_PROXIMITY_SENSITIVITY
+ if x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
+ x = fgW - BORDER_PROXIMITY_SENSITIVITY
+ y = event.y
+ if y <= BORDER_PROXIMITY_SENSITIVITY:
+ y = BORDER_PROXIMITY_SENSITIVITY
+ if y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
+ y = fgH - BORDER_PROXIMITY_SENSITIVITY
+ # get the change in coordinates #
+ X,Y = self.coordinate
+ deltaX = int(x - X)
+ deltaY = int(y - Y)
+ vAdj = self.get_parent().get_vadjustment().get_value()
+ hAdj = self.get_parent().get_hadjustment().get_value()
+ width = self.get_parent().get_hadjustment().page_size
+ height = self.get_parent().get_vadjustment().page_size
+ # scroll horizontal if we moved near the border #
+ if x-hAdj > width-SCROLL_PROXIMITY_SENSITIVITY and\
+ hAdj+SCROLL_DISTANCE < fgW - width:
+
self.get_parent().get_hadjustment().set_value(hAdj+SCROLL_DISTANCE)
+ elif x-hAdj < SCROLL_PROXIMITY_SENSITIVITY:
+
self.get_parent().get_hadjustment().set_value(hAdj-SCROLL_DISTANCE)
+ # scroll vertical if we moved near the border #
+ if y-vAdj > height-SCROLL_PROXIMITY_SENSITIVITY and\
+ vAdj+SCROLL_DISTANCE < fgH - height:
+
self.get_parent().get_vadjustment().set_value(vAdj+SCROLL_DISTANCE)
+ elif y-vAdj < SCROLL_PROXIMITY_SENSITIVITY:
+
self.get_parent().get_vadjustment().set_value(vAdj-SCROLL_DISTANCE)
+ # move the selected element and record the new
coordinate #
+ self.move_selected((deltaX, deltaY))
+ self.coordinate = (x, y)
+
+ def _handle_window_expose(self, widget, event):
+ """Called when the window initially appears or is resized:
create a new pixmap, draw the flow graph."""
+ self.gc = self.window.new_gc()
+ width, height = self.get_size_request()
+ if self.pixmap == None or (width, height) !=
self.pixmap.get_size():
+ self.pixmap = gtk.gdk.Pixmap(self.window, width,
height, -1)
+ self.draw()
+
+##########################################################################
+##
+## Export the Flow Graph
+##
+##########################################################################
+ def to_nested_data(self):
+ """!
+ Dump all the values in this flow graph into a nested data
format.
+ @return nested data representing a flow graph
+ """
+ vars_list = list()
+ signal_blocks_list = list()
+ connections_list = list()
+ W,H = self.get_size_request()
+ nested_data = ('flow_graph', [
+ ('timestamp', str(time.time())),
+ ('hostname', socket.gethostname()),
+ ('version', VERSION),
+ ('valid', str(self.is_valid())),
+ ('window_width', str(W)),
+ ('window_height', str(H)),
+ ('vars', vars_list),
+ ('signal_blocks', signal_blocks_list),
+ ('connections', connections_list)
+ ])
+
##########################################################################
+ ## Export the Variables
+
##########################################################################
+ for key in self.variable_modification_window.to_key_list():
+ row = (key,) + Variables.get_values(key)
+ vars_list.append(('var', [
+ ('key', row[0]),
+ ('value', row[1]),
+ ('min', row[2]),
+ ('max', row[3]),
+ ('step', row[4]),
+ ]))
+
##########################################################################
+ ## Export the Signal Blocks
+
##########################################################################
+ for element in filter(Utils.is_signal_block, self.elements):
+ params_list = list()
+ signal_blocks_list.append(('signal_block', [
+ ('tag', element.get_tag()),
+ ('id', element.get_id()),
+ ('x_coordinate',
str(element.get_coordinate()[0])),
+ ('y_coordinate',
str(element.get_coordinate()[1])),
+ ('rotation', str(element.get_rotation())),
+ ('params', params_list)
+ ]))
+ for param in element.get_params():
+ params_list.append(('param',
str(param.get_data_type().get_data())) )
+
##########################################################################
+ ## Export the Connections
+
##########################################################################
+ for element in filter(Utils.is_connection, self.elements):
+ connections_list.append(('connection', [
+ ('input_signal_block_id',
str(element.get_input_socket().get_parent().get_id())),
+ ('input_socket_index',
str(element.get_input_socket().get_index())),
+ ('output_signal_block_id',
str(element.get_output_socket().get_parent().get_id())),
+ ('output_socket_index',
str(element.get_output_socket().get_index()))
+ ]))
+ #print 'To',nested_data
+ return nested_data
+
+##########################################################################
+##
+## Import the Flow Graph
+##
+##########################################################################
+ def from_nested_data(self, nested_data):
+ """!
+ Set all the values in this flow graph using the nested data.
+ @param nested_data nested data representing a flow graph
+ """
+ #print 'From',nested_data
+ #TODO: use a non-destructive method to clear the elements list
+ self.elements = list() #clear the elements
+ find_data = ParseXML.find_data
+ flow_graph = find_data([nested_data], 'flow_graph')
+ # window width and height are optional #
+ window_width = find_data(flow_graph, 'window_width')
+ if window_width == None: window_width = MAX_WINDOW_WIDTH
+ window_height = find_data(flow_graph, 'window_height')
+ if window_height == None: window_height = MAX_WINDOW_HEIGHT
+ self.set_size_request(int(window_width),int(window_height))
+ vars = find_data(flow_graph, 'vars')
+ signal_blocks = find_data(flow_graph, 'signal_blocks')
+ connections = find_data(flow_graph, 'connections')
+
##########################################################################
+ ## Import the Variables
+
##########################################################################
+ keys = Variables.from_nested_data(vars)
+ self.variable_modification_window.from_key_list(keys)
+
##########################################################################
+ ## Import the Signal Blocks
+
##########################################################################
+ for signal_block in signal_blocks:
+ signal_block =
GraphicalSignalBlock.from_nested_data(self, signal_block,
GraphicalSignalBlock)[0] #index 0 for just signal block
+ if signal_block: self.elements.append(signal_block)
+
##########################################################################
+ ## Import the Connections
+
##########################################################################
+ for connection in connections:
+ connection = find_data([connection], 'connection')
+ input_signal_block_id = find_data(connection,
'input_signal_block_id')
+ input_socket_index = int(find_data(connection,
'input_socket_index'))
+ output_signal_block_id = find_data(connection,
'output_signal_block_id')
+ output_socket_index = int(find_data(connection,
'output_socket_index'))
+ input_socket = output_socket = None
+ for element in filter(Utils.is_signal_block,
self.elements):
+ if element.get_id() == input_signal_block_id:
input_socket = element.get_input_socket(input_socket_index)
+ if element.get_id() == output_signal_block_id:
output_socket = element.get_output_socket(output_socket_index)
+ try: self.elements.append(GraphicalConnection(self,
input_socket, output_socket))
+ except ConnectionException:
+ Messages.send_error_load('Could not connect
"%s" input[%d] and "%s" output[%d].'%(
+ input_signal_block_id,
+ input_socket_index,
+ output_signal_block_id,
+ output_socket_index,
+ )
+ )
+ self.selected_element = None
+ self.update()
+ # done importing the flow graph #
+
Deleted: grc/tags/grc_0.69/src/Graphics/MainWindow.py
Copied: grc/tags/grc_0.69/src/Graphics/MainWindow.py (from rev 6460,
grc/trunk/src/Graphics/MainWindow.py)
===================================================================
--- grc/tags/grc_0.69/src/Graphics/MainWindow.py
(rev 0)
+++ grc/tags/grc_0.69/src/Graphics/MainWindow.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,411 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Graphics.MainWindow
+#The main window, containing all windows, tool bars, and menu bars.
address@hidden Josh Blum
+
+from Constants import *
+from Actions import *
+import pygtk
+pygtk.require('2.0')
+import gtk
+import Bars
+from FlowGraph import FlowGraph
+from SignalBlockSelectionWindow import SignalBlockSelectionWindow
+from VariableModificationWindow import VariableModificationWindow
+from Dialogs import TextDisplay,MessageDialogHelper
+from StateCache import StateCache
+import Preferences
+import Messages
+import ParseXML
+import os
+
+############################################################
+## Notebook Page
+############################################################
+
+class Page(gtk.HBox):
+ """A page in the notebook."""
+
+ def __init__(self, main_window, file_path=''):
+ """
+ Page constructor.
+ @param main_window main window
+ @param file_path path to a flow graph file
+ """
+ #import the file
+ self.main_window = main_window
+ initial_state = ParseXML.from_xml(ParseXML.from_file(file_path
or INITIAL_FLOW_GRAPH_FILE))
+
self.main_window.get_flow_graph().from_nested_data(initial_state)
+ self.state_cache =
StateCache(self.main_window.get_flow_graph().to_nested_data())
+ self.set_pid_file('')
+ self.set_file_path(file_path)
+ self.set_saved(True)
+ #import success, initialize page
+ gtk.HBox.__init__(self, False, 0)
+ self.show()
+ #tab box to hold label and close button
+ self.tab = gtk.HBox(False, 0)
+ #setup tab label
+ self.label = gtk.Label()
+ self.tab.pack_start(self.label, True, False, 0)
+ #setup button image
+ image = gtk.Image()
+ image.set_from_stock('gtk-close', gtk.ICON_SIZE_MENU)
+ #setup image box
+ image_box = gtk.HBox(False, 0)
+ image_box.pack_start(image, True, False, 0)
+ #setup the button
+ button = gtk.Button()
+ button.connect("clicked", self._handle_button)
+ button.set_relief(gtk.RELIEF_NONE)
+ button.add(image_box)
+ #button size
+ w, h = gtk.icon_size_lookup_for_settings(button.get_settings(),
gtk.ICON_SIZE_MENU)
+ button.set_size_request(w+6, h+6)
+ self.tab.pack_start(button)
+ self.tab.show_all()
+
+ def _handle_button(self, button):
+ """
+ The button was clicked.
+ Make the current page selected, then close.
+ @param the button
+ """
+ self.main_window.page_to_be_closed = self
+ self.main_window.handle_states(FLOW_GRAPH_CLOSE)
+
+ def set_text(self, text):
+ """
+ Set the text in this label.
+ @param text the new text
+ """
+ self.label.set_text(text)
+
+ def get_tab(self):
+ """
+ Get the gtk widget for this page's tab.
+ @return gtk widget
+ """
+ return self.tab
+
+ def get_pid_file(self):
+ """!
+ Get the pid file for the flow graph.
+ @return the pid file or ''
+ """
+ return self.pid_file
+
+ def set_pid_file(self, pid_file=''):
+ """!
+ Set the pid file, '' for no pid file.
+ @param pid_file file path string
+ """
+ self.pid_file = pid_file
+
+ def get_file_path(self):
+ """!
+ Get the file path for the flow graph.
+ @return the file path or ''
+ """
+ return self.file_path
+
+ def set_file_path(self, file_path=''):
+ """!
+ Set the file path, '' for no file path.
+ @param file_path file path string
+ """
+ if file_path: self.file_path = os.path.abspath(file_path)
+ else: self.file_path = ''
+
+ def get_saved(self):
+ """!
+ Get the saved status for the flow graph.
+ @return true if saved
+ """
+ return self.saved
+
+ def set_saved(self, saved=True):
+ """!
+ Set the saved status.
+ @param saved boolean status
+ """
+ self.saved = saved
+
+ def get_state_cache(self):
+ """!
+ Get the state cache for the flow graph.
+ @return the state cache
+ """
+ return self.state_cache
+
+############################################################
+## Main window
+############################################################
+
+class MainWindow(gtk.Window):
+ """The topmost window with menus, the tool bar, and other major
windows."""
+
+ def __init__(self, handle_states):
+ """!
+ MainWindow contructor.
+ @param handle_states the callback function
+ """
+ #setup window
+ self.handle_states = handle_states
+ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+ vbox = gtk.VBox()
+ hbox = gtk.HBox()
+ self.add(vbox)
+ #create the menu bar and toolbar
+ vbox.pack_start(Bars.MenuBar(), False)
+ vbox.pack_start(Bars.Toolbar(), False)
+ # create variable modification window #
+ self.variable_modification_window =
VariableModificationWindow(self.handle_states)
+ self.flow_graph = FlowGraph(self.handle_states,
self.variable_modification_window)
+ #setup scrolled window
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH,
MIN_WINDOW_HEIGHT)
+ self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.add_with_viewport(self.flow_graph)
+ # create the notebook #
+ self.notebook = gtk.Notebook()
+ self.page_to_be_closed = None
+ self.current_page = None
+ self.notebook.set_show_border(False)
+ self.notebook.set_scrollable(True) #scroll arrows for page
tabs
+ self.notebook.connect("switch-page", self._handle_page_change)
+ fg_and_report_box = gtk.VBox(False, 0)
+ fg_and_report_box.pack_start(self.notebook, False, False, 0)
+ fg_and_report_box.pack_start(self.scrolled_window)
+ hbox.pack_start(fg_and_report_box)
+ vbox.pack_start(hbox)
+ #create the side windows
+ side_box = gtk.VBox()
+ hbox.pack_start(side_box, False)
+ side_box.pack_start(self.variable_modification_window, False)
#dont allow resize
+
side_box.pack_start(SignalBlockSelectionWindow(self.get_flow_graph)) #all
resize, selection window can have more space
+ #create the reports window
+ self.text_display = TextDisplay()
+ #house the reports in a scrolled window
+ self.reports_scrolled_window = gtk.ScrolledWindow()
+ self.reports_scrolled_window.set_size_request(-1,
REPORTS_WINDOW_HEIGHT)
+ self.reports_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
gtk.POLICY_AUTOMATIC)
+
self.reports_scrolled_window.add_with_viewport(self.text_display)
+ fg_and_report_box.pack_end(self.reports_scrolled_window, False)
#dont allow resize, fg should get all the space
+ # show all but the main window container and the reports window
+ vbox.show_all()
+ self.show_reports_window(False)
+ # load preferences and show the main window
+ Preferences.load(self)
+ self.show()#show after resize in preferences
+
+ ############################################################
+ ## Event Handlers
+ ############################################################
+
+ def _quit(self, window, event):
+ """!
+ Handle the delete event from the main window.
+ Generated by pressing X to close, alt+f4, or right click+close.
+ This method in turns calls the state handler to quit.
+ @return true
+ """
+ self.handle_states(APPLICATION_QUIT)
+ return True
+
+ def _handle_page_change(self, notebook, page, page_num):
+ """!
+ Handle a page change. When the user clicks on a new tab,
+ reload the flow graph to update the vars window and
+ call handle states (select nothing) to update the buttons.
+ @param notebook the notebook
+ @param page new page
+ @param page_num new page number
+ """
+ self.current_page = self.notebook.get_nth_page(page_num)
+ state = self.get_page().get_state_cache().get_current_state()
+ self.get_flow_graph().from_nested_data(state)
+ self.handle_states(NOTHING_SELECT)
+
+ ############################################################
+ ## Report Window
+ ############################################################
+
+ def add_report_line(self, line):
+ """!
+ Place line plus a newline at the end of the text buffer, then
scroll its window all the way down.
+ @param line the new text
+ """
+ self.text_display.insert(line)
+ vadj = self.reports_scrolled_window.get_vadjustment()
+ vadj.set_value(vadj.upper)
+
+ def show_reports_window(self, show):
+ """!
+ Show the reports window when show is True.
+ Hide the reports window when show is False.
+ @param show boolean flag
+ """
+ if show: self.reports_scrolled_window.show()
+ else: self.reports_scrolled_window.hide()
+
+ ############################################################
+ ## Pages: create and close
+ ############################################################
+
+ def new_page(self, file_path=''):
+ """!
+ Create a new notebook page.
+ Set the tab to be selected.
+ @param file_path optional file to load into the flow graph
+ """
+ if file_path and file_path in self._get_files(): #already open
+ page =
self.notebook.get_nth_page(self._get_files().index(file_path))
+ self._set_page(page)
+ return
+ try: #try to load from file
+ if file_path: Messages.send_start_load(file_path)
+ page = Page(self, file_path)
+ if file_path: Messages.send_end_load()
+ except Exception, e:
+ Messages.send_fail_load(e)
+ return
+ self.notebook.append_page(page, page.get_tab())
+ self._set_page(page)
+
+ def close_pages(self):
+ """
+ Close all the pages in this notebook.
+ @return true if all closed
+ """
+ files = filter(lambda file: file, self._get_files()) #filter
blank files
+ for page in self._get_pages():
+ self.page_to_be_closed = page
+ self.close_page(False)
+ if self.notebook.get_n_pages(): return False
+ Preferences.save_files_open(files)
+ return True
+
+ def close_page(self, ensure=True):
+ """
+ Close the current page.
+ If ensure: ensure there is at least one page in the notebook,
+ call new page if get page is none.
+ @param ensure boolean
+ """
+ if not self.page_to_be_closed: self.page_to_be_closed =
self.get_page()
+ #show the page if it has an executing flow graph or is unsaved
+ if self.page_to_be_closed.get_pid_file() or not
self.page_to_be_closed.get_saved():
+ self._set_page(self.page_to_be_closed)
+ #unsaved? ask the user
+ if not self.page_to_be_closed.get_saved() and
self._save_changes():
+ self.handle_states(FLOW_GRAPH_SAVE) #try to save
+ if not self.page_to_be_closed.get_saved(): #still
unsaved?
+ self.page_to_be_closed = None #set the page
to be closed back to None
+ return
+ #stop the flow graph if executing
+ if self.page_to_be_closed.get_pid_file():
self.handle_states(FLOW_GRAPH_STOP)
+ #remove the page
+
self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed))
+ if ensure and self.notebook.get_n_pages() == 0: self.new_page()
#no pages, make a new one
+ self.page_to_be_closed = None #set the page to be closed back
to None
+
+ ############################################################
+ ## Misc
+ ############################################################
+
+ def update(self):
+ """!
+ Set the title of the main window.
+ Set the titles on the page tabs.
+ Show/hide the reports window.
+ @param title the window title
+ """
+ if self.get_page():
+ title = ''.join((
+ MAIN_WINDOW_PREFIX,
+ ' - Editing: ',
+ (self.get_page().get_file_path() or
NEW_FLOGRAPH_TITLE),
+ (self.get_page().get_saved() and ' ' or
'*'), #blank must be non empty
+ )
+ )
+ else: title = MAIN_WINDOW_PREFIX + ' - Editor '
+ gtk.Window.set_title(self, title)
+ #set tab titles
+ for page in self._get_pages():
+ page.set_text(''.join((
+
(os.path.split(page.get_file_path())[1] or NEW_FLOGRAPH_TITLE),
+ (page.get_saved() and ' ' or
'*'), #blank must be non empty
+ )
+ )
+ )
+ #reports window
+ Preferences.show_reports_window(self)
+
+ def get_flow_graph(self):
+ """
+ Get the flow graph in this main window.
+ @return the flow graph
+ """
+ return self.flow_graph
+
+ def get_page(self):
+ """!
+ Get the selected page.
+ @return the selected page
+ """
+ return self.current_page
+
+ ############################################################
+ ## Helpers
+ ############################################################
+
+ def _set_page(self, page):
+ """
+ Set the current page.
+ @param page the page widget
+ """
+ self.current_page = page
+
self.notebook.set_current_page(self.notebook.page_num(self.current_page))
+
+ def _save_changes(self):
+ """!
+ Save changes to flow graph?
+ @return true if yes
+ """
+ return MessageDialogHelper(
+ gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Unsaved
Changes!',
+ 'Would you like to save changes before closing?'
+ ) == gtk.RESPONSE_YES
+
+ def _get_files(self):
+ """
+ Get the file names for all the pages, in order.
+ @return list of file paths
+ """
+ return map(lambda page: page.get_file_path(), self._get_pages())
+
+ def _get_pages(self):
+ """
+ Get a list of all pages in the notebook.
+ @return list of pages
+ """
+ return [self.notebook.get_nth_page(page_num) for page_num in
range(self.notebook.get_n_pages())]
+
Deleted: grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py
Copied: grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py (from rev 6449,
grc/trunk/src/Graphics/USRPDiagnostics.py)
===================================================================
--- grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py
(rev 0)
+++ grc/tags/grc_0.69/src/Graphics/USRPDiagnostics.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,105 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Graphics.USRPDiagnostics
+#A dialog for querying USRP subdevices. USRP interfacing methods encapsulated
here.
address@hidden Josh Blum
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from Actions import USRP_DIAGNOSTICS_DISPLAY,get_action_from_name
+from Elements import GraphicalParam
+from DataTypes import *
+from Dialogs import TextDisplay
+
+def enable_usrp_diagnostics():
+ """Enable the action for USRP diganostics if gnuradio.usrp can be
imported."""
+ try:
+ from gnuradio import usrp
+
get_action_from_name(USRP_DIAGNOSTICS_DISPLAY).set_sensitive(True)
+ except ImportError: print "USRP support missing -> USRP diagnostics
disabled..."
+
+class USRPDiagnosticsDialog(gtk.Dialog):
+ """
+ The main dialog window for USRP Dignostics.
+ The USRP parameters and feedback will be located inside this dialog.
+ """
+
+ def __init__(self):
+ """USRPDiagnosticsDialog contructor.
+ Create a new gtk Dialog with a close button, USRP input
paramaters, and output labels."""
+ gtk.Dialog.__init__(self, buttons=('gtk-close',
gtk.RESPONSE_CLOSE))
+ # Create the title label #
+ self.set_title('USRP Diagnostics')
+ self.USRP_number = Int(0, min=0)
+ self.USRP_type = Enum([('Receive', 'rx'), ('Transmit', 'tx'),])
+ self.USRP_subdev = Enum([
+ ('Side A:0', (0, 0)),
+ ('Side B:0', (1, 0)),
+ ('Side A:1', (0, 1)),
+ ('Side B:1', (1, 1)),
+ ]
+ )
+ self.vbox.pack_start(GraphicalParam('Unit Number',
self.USRP_number).get_input_object(), False)
+ self.vbox.pack_start(GraphicalParam('Transmit/Receive',
self.USRP_type).get_input_object(), False)
+ self.vbox.pack_start(GraphicalParam('Side:Subdevice',
self.USRP_subdev).get_input_object(), False)
+ self.diagnose_button = gtk.Button('Query')
+ self.diagnose_button.connect('clicked', self._diagnose_usrp)
+ self.vbox.pack_start(self.diagnose_button, False)
+ # Create a text box for USRP queries #
+ self.query_buffer = TextDisplay()
+ self.query_buffer.set_text('Press "Query" to retrieve USRP
information...')
+ self.vbox.pack_start(self.query_buffer)
+ self.show_all()
+ self.run()
+ self.destroy()
+
+ def _diagnose_usrp(self, widget=None):
+ """Query the USRP device and copy the results into the query
text box."""
+ from gnuradio import usrp
+ type = self.USRP_type.parse()
+ if type == 'rx': #for the rx query, use the source and
rx methods
+ make = usrp.source_c
+ get_mux = usrp.determine_rx_mux_value
+ elif type == 'tx': #for the tx query, use the sink and tx
methods
+ make = usrp.sink_c
+ get_mux = usrp.determine_tx_mux_value
+ try:
+ u = make(self.USRP_number.parse())
+ subdev_spec = self.USRP_subdev.parse()
+ subdev = usrp.selected_subdev(u, subdev_spec)#get the
subdev
+ msg = ">>> USRP Query\n"
+ msg = "%s\nName:\n\t%s\n"%(msg,str(subdev.name()))
+ msg = "%s\nAutomated Mux:\n\t0x%08x\n"%(msg,
0xFFFFFFFFL & long(get_mux(u, subdev_spec))) #ensure that the value is
displayed as: 8 nibbles, unsigned, hex
+ msg = "%s\nConverter
Rate:\n\t%s\n"%(msg,u.converter_rate())
+ msg = "%s\nUses Quadrature:\n\t%s\n"%(msg,
str(subdev.is_quadrature()))
+ gain_min, gain_max, gain_step = subdev.gain_range()
+ msg = "%s\nGain Range (min, max, step
size):\n\t%s\n\t%s\n\t%s\n"%(msg, gain_min, gain_max, gain_step)
+ freq_min, freq_max, freq_step = subdev.freq_range()
+ msg = "%s\nFreq Range (min, max, step
size):\n\t%s\n\t%s\n\t%s\n"%(msg, freq_min, freq_max, freq_step)
+ self.query_buffer.set_text(msg)
+ except Exception, e: #display the error message
+ self.query_buffer.set_text('''\
+>>> Error\n%s
+
+If the USRP cannot be found, make sure that the USRP is plugged-in and restart
this program. \
+If the problem persists, there may be a problem with you gnuradio installation
or USB 2.0.
+'''%str(e))
+
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/Preferences.py
Copied: grc/tags/grc_0.69/src/Preferences.py (from rev 6375,
grc/trunk/src/Preferences.py)
===================================================================
--- grc/tags/grc_0.69/src/Preferences.py (rev 0)
+++ grc/tags/grc_0.69/src/Preferences.py 2007-09-20 01:49:24 UTC (rev
6483)
@@ -0,0 +1,194 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden Preferences
+#Holds global preferences stored as GraphicalParams.
address@hidden Josh Blum
+
+from DataTypes import Bool,Enum,Int,String
+from Elements import GraphicalParam, Param
+import time,socket #for tagging saved files
+from Constants import *
+import ParseXML
+import Messages
+
+PARAM_CHECKING_PREF = GraphicalParam('Parameter Checking', Bool(true='Verify
Parameters', false='Ignore Invalid Params', default=True))
+CONNECTION_CHECKING_PREF = GraphicalParam('Connection Checking',
Bool(true='Match Data Types', false='Ignore Data Types', default=True))
+SOCKET_CHECKING_PREF = GraphicalParam('Socket Checking', Bool(true='Require
Connections', false='Allow Open Sockets', default=True))
+FILES_OPEN_PREF = Param('Files Open', String())
+RESTORE_FILES_PREF = GraphicalParam('Restore Files', Bool(true='Restore
Previous Files', false='Restore Nothing', default=True))
+SNAP_TO_GRID_PREF = GraphicalParam('Snap to Grid', Bool(true='On',
false='Off', default=False))
+GRID_SIZE_PREF = GraphicalParam('Grid Size (pixels)', Enum([
+ ('10 pixels', 10),
+ ('20 pixels', 20),
+ ('30 pixels', 30),
+ ('40 pixels', 40),
+ ('50 pixels', 50),
+ ('60 pixels', 60),
+ ('70 pixels', 70),
+ ('80 pixels', 80),
+ ('90 pixels', 90),
+ ('100 pixels', 100),], 2))
+SHOW_GRID_PREF = GraphicalParam('Grid Points', Bool(true='Show Grid',
false='Hide Grid', default=False))
+REPORTS_WIN_SHOW_PREF = GraphicalParam('Reports Window', Bool(true='Show
Reports Window', false='Hide Reports Window', default=True))
+MAIN_WINDOW_WIDTH_PREF = Param('Main Window Width',
Int(DEFAULT_MAIN_WINDOW_WIDTH))
+MAIN_WINDOW_HEIGHT_PREF = Param('Main Window Height',
Int(DEFAULT_MAIN_WINDOW_HEIGHT))
+
+###########################################################################
+# List of Preferences
+###########################################################################
+
+PREFS_LIST = [ #(title, notes, list of preferences)
+ ("Verification", '''\
+Verification ensures that:
+ signal block parameters pass validation,
+ data types on either side of a connection match,
+ and input/output sockets connect.
+
+You may disable any one of these validation checks. \
+However, the resulting flow graph may fail execution. \
+''', [
+ (PARAM_CHECKING_PREF, 'param_check'),
+ (CONNECTION_CHECKING_PREF, 'connection_check'),
+ (SOCKET_CHECKING_PREF, 'socket_check'),
+ ]
+ ),
+ ("Grid Options", '''\
+Snap to Grid forces the upper right corner of the signal block to align with a
grid point. \
+''', [
+ (SNAP_TO_GRID_PREF, 'snap_to_grid'),
+ (GRID_SIZE_PREF, 'grid_size'),
+ (SHOW_GRID_PREF, 'show_grid'),
+ ]
+ ),
+ ("Misc Options", '', [
+ (REPORTS_WIN_SHOW_PREF, 'show_reports_window'),
+ (RESTORE_FILES_PREF, 'restore_files'),
+ ]
+ ),
+ ('', '', [ #put hidden prefs here
+ (FILES_OPEN_PREF, 'files_open'),
+ (MAIN_WINDOW_WIDTH_PREF, 'window_width'),
+ (MAIN_WINDOW_HEIGHT_PREF, 'window_height'),
+ ]
+ ),
+]
+
+PREFS_DICT = dict((key, param) for param, key in reduce(lambda l1, l2: l1 +
l2, zip(*PREFS_LIST)[2]))
+
+###########################################################################
+# Preference Access Methods
+###########################################################################
+
+def _get_value(param):
+ """!
+ Get the value of the given parameter.
+ If the param is valid, return the parsed value of the param, otherwise
return a blank string.
+ @param param the parameter
+ @return the value of the parameter
+ """
+ if param.get_data_type().is_valid(): return
param.get_data_type().parse()
+ else: return ''
+
+def _to_nested():
+ """!
+ Convert the param's data to nested format.
+ @return the nested format
+ """
+ prefs = [('pref', [('key', key), ('value',
param.get_data_type().get_data())]) for key,param in PREFS_DICT.iteritems()]
+ nested_data = ('preferences', [
+ ('timestamp', str(time.time())),
+ ('hostname', socket.gethostname()),
+ ('version', VERSION),
+ ('prefs', prefs),
+ ]
+ )
+ return nested_data
+
+def _from_nested(nested_data):
+ """!
+ Parse the nested data to retrieve each preference.
+ @param nested_data the nested data
+ """
+ find_data = ParseXML.find_data
+ preferences = find_data([nested_data], 'preferences')
+ prefs = find_data(preferences, 'prefs')
+ for pref in prefs:
+ pref = find_data([pref], 'pref')
+ key = find_data(pref, 'key')
+ value = find_data(pref, 'value')
+ try: PREFS_DICT[key].get_data_type().set_data(value)
+ except: pass
+
+def load(window=None):
+ """!
+ Load the preferences from the preferences file.
+ @param window optional flow graph window
+ """
+ try:
+
_from_nested(ParseXML.from_xml(ParseXML.from_file(PREFERENCES_FILE_PATH)))
+ if window: window.resize(_get_value(MAIN_WINDOW_WIDTH_PREF),
_get_value(MAIN_WINDOW_HEIGHT_PREF))
+ except: Messages.send_fail_load_preferences()
+
+def save(window=None):
+ """!
+ Save the preferences to the preferences file.
+ @param window optional flow graph window
+ """
+ if window:
+ width,height = window.get_size()
+ MAIN_WINDOW_WIDTH_PREF.get_data_type().set_data(width)
+ MAIN_WINDOW_HEIGHT_PREF.get_data_type().set_data(height)
+ try: ParseXML.to_file(ParseXML.to_xml(_to_nested()),
PREFERENCES_FILE_PATH)
+ except IOError: Messages.send_fail_save_preferences()
+
+###########################################################################
+# Special methods for specific program functionalities
+###########################################################################
+
+def restore_files():
+ return _get_value(RESTORE_FILES_PREF)
+
+def files_open():
+ return _get_value(FILES_OPEN_PREF).split('\n')
+
+def save_files_open(files):
+ FILES_OPEN_PREF.get_data_type().set_data('\n'.join(files))
+
+def check_connections():
+ return _get_value(CONNECTION_CHECKING_PREF)
+
+def check_sockets():
+ return _get_value(SOCKET_CHECKING_PREF)
+
+def check_params():
+ return _get_value(PARAM_CHECKING_PREF)
+
+def show_reports_window(window):
+ return window.show_reports_window(_get_value(REPORTS_WIN_SHOW_PREF))
+
+def get_grid_size():
+ return _get_value(GRID_SIZE_PREF)
+
+def snap_to_grid():
+ return _get_value(SNAP_TO_GRID_PREF)
+
+def show_grid():
+ return _get_value(SHOW_GRID_PREF)
+
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py (from rev 6347,
grc/trunk/src/SignalBlockDefs/Filters.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/Filters.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,489 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.Filters
+#Taps generators are from gr.firdes. Most FIR filters are implemented and a
few misc ones.
address@hidden Josh Blum
+
+from DataTypes import *
+from gnuradio import gr,gru,blks2
+from SignalBlockConstants import default_samp_rate,all_choices
+
+###########################################################################
+# Generic filters with taps parameters
+###########################################################################
+def FIRFilter(sb):
+ filters = Enum([
+ ('Complex->Complex (Complex Taps)', (gr.fir_filter_ccc,
gr.interp_fir_filter_ccc, Complex(), Complex(), ComplexVector())),
+ ('Complex->Complex (Float Taps)', (gr.fir_filter_ccf,
gr.interp_fir_filter_ccf, Complex(), Complex(), FloatVector())),
+ ('Float->Complex (Complex Taps)', (gr.fir_filter_fcc,
gr.interp_fir_filter_fcc, Float(), Complex(), ComplexVector())),
+ ('Float->Float (Float Taps)', (gr.fir_filter_fff,
gr.interp_fir_filter_fff, Float(), Float(), FloatVector())),
+ ('Float->Short (Float Taps)', (gr.fir_filter_fsf,
gr.interp_fir_filter_fsf, Float(), Short(), FloatVector())),
+ ('Short->Complex (Complex Taps)', (gr.fir_filter_scc,
gr.interp_fir_filter_scc, Short(), Complex(), ComplexVector())),
+ ])
+ sb.add_input_socket('in', Variable(filters, index=2))
+ sb.add_output_socket('out', Variable(filters, index=3))
+ sb.add_param('Filter Type', filters, False, type=True)
+ sb.add_param('Type', Enum([('Decimating', 0), ('Interpolating', 1)]))
#this parses into an index for the filters Enum
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Taps', Variable(filters, index=4, min=1), variable=True)
+ sb.set_docs('''\
+The decimation parameter becomes interpolation if the filter type is set to
interpolation. ''')
+ def make(fg, filter_type, type, decim, taps):
+ block = filter_type.parse()[type.parse()](decim.parse(),
taps.parse())
+ fg.add_callback(block.set_taps, taps)
+ return block
+ return sb,make
+
+def FreqXlatingFIRFilter(sb):
+ filters = Enum([
+ ('Complex', (gr.freq_xlating_fir_filter_ccc,
gr.freq_xlating_fir_filter_ccf, Complex())),
+ ('Float', (gr.freq_xlating_fir_filter_fcc,
gr.freq_xlating_fir_filter_fcf, Float())),
+ ('Short', (gr.freq_xlating_fir_filter_scc,
gr.freq_xlating_fir_filter_scf, Short())),
+ ])
+ taps = Enum([
+ ('Complex', (0, ComplexVector())),
+ ('Float', (1, FloatVector())),
+ ])
+ sb.add_input_socket('in', Variable(filters, index=2))
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Input Type', filters, False, type=True)
+ sb.add_param('Taps Type', taps) #this parses into an index for the
filters Enum
+ sb.add_param('Samp Rate', Float(default_samp_rate))
+ sb.add_param('Center Freq', Float(), variable=True)
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Taps', Variable(taps, index=1, min=1), variable=True)
+ def make(fg, filter_type, taps_type, samp_rate, center_freq, decim,
taps):
+ block =
filter_type.parse()[taps_type.parse()[0]](decim.parse(), taps.parse(),
center_freq.parse(), samp_rate.parse())
+ fg.add_callback(block.set_taps, taps)
+ fg.add_callback(block.set_center_freq, center_freq)
+ return block
+ return sb,make
+
+def FFTFilter(sb):
+ filters = Enum([
+ ('Complex', (gr.fft_filter_ccc, Complex(), ComplexVector())),
+ ('Float', (gr.fft_filter_fff, Float(), FloatVector())),
+ ])
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=1))
+ sb.add_param('Type', filters, False, type=True)
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Taps', Variable(filters, index=2, min=1), variable=True)
+ sb.set_docs('''The type selection controls the data type of the input,
output, and taps.''')
+ def make(fg, type, decim, taps):
+ block = type.parse()[0](decim.parse(), taps.parse())
+ fg.add_callback(block.set_taps, taps)
+ return block
+ return sb,make
+
+def RationalResampler(sb):
+ filters = Enum([
+ ('Complex->Complex (Complex Taps)',
(gr.rational_resampler_base_ccc, Complex(), Complex(), ComplexVector())),
+ ('Complex->Complex (Float Taps)',
(gr.rational_resampler_base_ccf, Complex(), Complex(), FloatVector())),
+ ('Float->Complex (Complex Taps)',
(gr.rational_resampler_base_fcc, Float(), Complex(), ComplexVector())),
+ ('Float->Float (Float Taps)', (gr.rational_resampler_base_fff,
Float(), Float(), FloatVector())),
+ ('Float->Short (Float Taps)', (gr.rational_resampler_base_fsf,
Float(), Short(), FloatVector())),
+ ('Short->Complex (Complex Taps)',
(gr.rational_resampler_base_scc, Short(), Complex(), ComplexVector())),
+ ])
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=2))
+ sb.add_param('Filter Type', filters, False, type=True)
+ sb.add_param('Interpolation', Int(1, min=1))
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Taps', Variable(filters, index=3, min=1), variable=True)
+ def make(fg, filter_type, interp, decim, taps):
+ block = filter_type.parse()[0](interp.parse(), decim.parse(),
taps.parse())
+ fg.add_callback(block.set_taps, taps)
+ return block
+ return sb,make
+
+def IIRFiler(sb):
+ fcn = gr.iir_filter_ffd
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Float())
+ sb.add_param('FF Taps', FloatVector())
+ sb.add_param('FB Taps', FloatVector())
+ return sb, lambda fg, fftaps, fbtaps: fcn(fftaps.parse(),
fbtaps.parse())
+
+def FilterDelay(sb):
+ fcn = gr.filter_delay_fc
+ sb.add_input_socket('in1', Float())
+ sb.add_input_socket('in2', Float(), optional=True)
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Taps', FloatVector())
+ sb.set_docs('''\
+The block takes one or two float stream and outputs a complex stream. \
+If only one float stream is input, \
+the real output is a delayed version of this input and the imaginary output is
the filtered output. \
+If two floats are connected to the input, \
+then the real output is the delayed version of the first input, \
+the imaginary output is the filtered output. \
+The delay in the real path accounts for the group delay introduced by the
filter in the imaginary path.\
+''')
+ return sb, lambda fg, taps: fcn(taps.parse())
+
+def ChannelModel(sb):
+ fcn = blks2.channel_model
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Noise Voltage', Float(0.0), variable=True)
+ sb.add_param('Freq Offset', Float(0.0), variable=True)
+ sb.add_param('Epsilon', Float(1.0))
+ sb.add_param('Taps', ComplexVector('1.0,0.0'), variable=True)
+ sb.set_docs('''\
+Creates a channel model that includes:
+ - AWGN noise power in terms of noise voltage
+ - A frequency offest in the channel in ratio
+ - A timing offset ratio to model clock difference (epsilon)
+ - Multipath taps
+''')
+ def make(fg, noise_voltage, frequency_offset, epsilon, taps):
+ block = fcn(noise_voltage.parse(), frequency_offset.parse(),
epsilon.parse(), taps.parse())
+ fg.add_callback(block.set_noise_voltage, noise_voltage)
+ fg.add_callback(block.set_frequency_offset, frequency_offset)
+ fg.add_callback(block.set_taps, taps)
+ return block
+ return sb, make
+
+###########################################################################
+# Special filters using taps generators
+###########################################################################
+def make_filter(fg, filter_type, decimation, taps_maker, taps_args):
+ filter = filter_type.parse()[0]
+ decimation = decimation.parse()
+ taps = taps_maker(*map(lambda data:data.parse(), taps_args))
+ block = filter(decimation, taps)
+ fg.add_callback(lambda *args: block.set_taps(taps_maker(*args)),
*taps_args)
+ return block
+
+window_choices = [
+ ('Hamming', gr.firdes.WIN_HAMMING),
+ ('Hann', gr.firdes.WIN_HANN),
+ ('Blackman', gr.firdes.WIN_BLACKMAN),
+ ('Rectangular', gr.firdes.WIN_RECTANGULAR),
+ ('Kaiser', gr.firdes.WIN_KAISER),
+]
+filter_choices = [
+ ('FFT: Float->Float', (gr.fft_filter_fff, Float(), Float())),
+ ('FIR: Complex->Complex', (gr.fir_filter_ccf, Complex(), Complex())),
+ ('FIR: Float->Float', (gr.fir_filter_fff, Float(), Float())),
+ ('FIR: Float->Short', (gr.fir_filter_fsf, Float(), Short())),
+ ('Interp FIR: Complex->Complex', (gr.interp_fir_filter_ccf, Complex(),
Complex())),
+ ('Interp FIR: Float->Float', (gr.interp_fir_filter_fff, Float(),
Float())),
+ ('Interp FIR: Float->Short', (gr.interp_fir_filter_fsf, Float(),
Short())),
+]
+
+def LowPassFilter(sb):
+ taps_maker = gr.firdes.low_pass
+ pass_filter_helper(sb, taps_maker)
+ def make(fg, filter_type, gain, samp_freq, cutoff_freq,
transition_width, decimation, window, beta):
+ taps_args = (gain, samp_freq, cutoff_freq, transition_width,
window, beta)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+def HighPassFilter(sb):
+ taps_maker = gr.firdes.high_pass
+ pass_filter_helper(sb, taps_maker)
+ def make(fg, filter_type, gain, samp_freq, cutoff_freq,
transition_width, decimation, window, beta):
+ taps_args = (gain, samp_freq, cutoff_freq, transition_width,
window, beta)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+def BandPassFilter(sb):
+ taps_maker = gr.firdes.band_pass
+ pass_filter_helper(sb, taps_maker)
+ def make(fg, filter_type, gain, samp_freq, low_cutoff_freq,
high_cutoff_freq, transition_width, decimation, window, beta):
+ taps_args = (gain, samp_freq, low_cutoff_freq,
high_cutoff_freq, transition_width, window, beta)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+def BandRejectFilter(sb):
+ taps_maker = gr.firdes.band_reject
+ pass_filter_helper(sb, taps_maker)
+ def make(fg, filter_type, gain, samp_freq, low_cutoff_freq,
high_cutoff_freq, transition_width, decimation, window, beta):
+ taps_args = (gain, samp_freq, low_cutoff_freq,
high_cutoff_freq, transition_width, window, beta)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+def pass_filter_helper(sb, taps_maker):
+ filters = Enum(filter_choices, 2)
+ windows = Enum(window_choices, 1)
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=2))
+ sb.add_param('Filter Type', filters, type=True)
+ sb.add_param('Gain', Float(1), variable=True)
+ sb.add_param('Sampling Rate', Float(default_samp_rate), variable=True)
+ if taps_maker in (gr.firdes.low_pass, gr.firdes.high_pass):
+ sb.add_param('Cutoff Freq', Float(1000), variable=True)
+ elif taps_maker in (gr.firdes.band_pass, gr.firdes.band_reject):
+ sb.add_param('Low Cutoff Freq', Float(500), variable=True)
+ sb.add_param('High Cutoff Freq', Float(1500), variable=True)
+ sb.add_param('Transition Width', Float(100), variable=True)
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Window Type', windows)
+ sb.add_param('Beta', Float(6.76), variable=True)
+ sb.set_docs('''\
+The decimation parameter becomes interpolation if the filter type is set to
interpolation.''')
+
+def Window(sb):
+ taps_maker = gr.firdes.window
+ filters = Enum(filter_choices, 2)
+ windows = Enum(window_choices, 1)
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=2))
+ sb.add_param('Filter Type', filters, type=True)
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Window Type', windows)
+ sb.add_param('Num Taps', Int(20, min=0), variable=True)
+ sb.add_param('Beta', Float(6.76), variable=True)
+ def make(fg, filter_type, decimation, window, ntaps, beta):
+ taps_args = (window, ntaps, beta)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+def RootRaisedCosine(sb):
+ taps_maker = gr.firdes.root_raised_cosine
+ filters = Enum(filter_choices, 2)
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=2))
+ sb.add_param('Filter Type', filters, type=True)
+ sb.add_param('Decimation', Int(1, min=1))
+ sb.add_param('Gain', Float(1), variable=True)
+ sb.add_param('Sampling Rate', Float(default_samp_rate), variable=True)
+ sb.add_param('Symbol Rate', Float(100), variable=True)
+ sb.add_param('Alpha', Float(6.76), variable=True)
+ sb.add_param('Num Taps', Int(20, min=0), variable=True)
+ def make(fg, filter_type, decimation, gain, samp_freq, symbol_rate,
alpha, ntaps):
+ taps_args = (gain, samp_freq, symbol_rate, alpha, ntaps)
+ return make_filter(fg, filter_type, decimation, taps_maker,
taps_args)
+ return sb, make
+
+###########################################################################
+# Other filters
+###########################################################################
+def Hilbert(sb):
+ fcn = gr.hilbert_fc
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Num Taps', Int(10, min=0))
+ return sb, lambda fg, num_taps: fcn(num_taps.parse())
+
+def Goertzel(sb):
+ fcn = gr.goertzel_fc
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Rate', Int())
+ sb.add_param('Length', Int())
+ sb.add_param('Frequency', Float())
+ return sb, lambda fg, rate, len, freq:
fcn(rate.parse(),len.parse(),freq.parse())
+
+def PowerSquelch(sb):
+ fcn = gr.simple_squelch_cc
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Threshold (dB)', Float(30), variable=True)
+ sb.add_param('Alpha', Float(.5), variable=True)
+ sb.set_docs('''Power levels below the threshold are not passed
through.''')
+ def make(fg, threshold, alpha):
+ block = fcn(threshold.parse(), alpha.parse())
+ fg.add_callback(block.set_threshold, threshold)
+ fg.add_callback(block.set_alpha, alpha)
+ return block
+ return sb, make
+
+def SinglePoleIIRFilter(sb):
+ vlen = Int(1, min=1)
+ type = Enum([
+ ('Float', (gr.single_pole_iir_filter_ff, Float())),
+ ('Complex', (gr.single_pole_iir_filter_cc, Complex())),
+ ])
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Variable(type, index=1), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Alpha', Float(1), variable=True)
+ sb.add_param('Vector Length', vlen)
+ def make(fg, type, alpha, vlen):
+ block = type.parse()[0](alpha.parse(), vlen.parse())
+ fg.add_callback(block.set_taps, alpha)
+ return block
+ return sb, make
+
+def AutomaticGainControl(sb):
+ type = Enum([('Complex', (gr.agc_cc, Complex())), ('Float', (gr.agc_ff,
Float())),], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Rate', Float(1e-4))
+ sb.add_param('Reference', Float(1))
+ sb.add_param('Gain', Float(1))
+ sb.add_param('Max Gain', Float(0))
+ return sb, lambda fg, type, rate, ref, gain, max_gain: \
+ type.parse()[0](rate.parse(), ref.parse(), gain.parse(),
max_gain.parse())
+
+def AutomaticGainControl2(sb):
+ type = Enum([('Complex', (gr.agc2_cc, Complex())), ('Float',
(gr.agc2_ff, Float())),], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Attack Rate', Float(1e-1))
+ sb.add_param('Decay Rate', Float(1e-2))
+ sb.add_param('Reference', Float(1))
+ sb.add_param('Gain', Float(1))
+ sb.add_param('Max Gain', Float(0))
+ return sb, lambda fg, type, attack_rate, decay_rate, ref, gain,
max_gain: \
+ type.parse()[0](attack_rate.parse(), decay_rate.parse(),
ref.parse(), gain.parse(), max_gain.parse())
+
+def FeedForwardAGC(sb):
+ fcn = gr.feedforward_agc_cc
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Num Samples', Int(100, min=1))
+ sb.add_param('Reference', Float(0))
+ sb.set_docs('''Non-causal AGC which computes required gain based on max
absolute value over nsamples.''')
+ return sb, lambda fg, nsamps, ref: fcn(nsamps.parse(), ref.parse())
+
+def CMAFilter(sb):
+ fcn = gr.cma_equalizer_cc
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Num Taps', Int(10, min=0))
+ sb.add_param('Modulus', Float())
+ sb.add_param('Mu', Float())
+ sb.set_docs('''Constant Modulus Adaptive Filter.''')
+ return sb, lambda fg, num_taps, mod, mu: fcn(num_taps.parse(),
mod.parse(), mu.parse())
+
+def ClockRecovery(sb):
+ type = Enum([
+ ('Complex', (gr.clock_recovery_mm_cc, Complex())),
+ ('Float', (gr.clock_recovery_mm_ff, Float())),
+ ])
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Omega', Float(), variable=True)
+ sb.add_param('Gain Omega', Float(), variable=True)
+ sb.add_param('Mu', Float(), variable=True)
+ sb.add_param('Gain Mu', Float(), variable=True)
+ sb.add_param('Omega Relative Limit', Float())
+ sb.set_docs('''Mueller & Mueller clock recovery.''')
+ def make(fg, type, omega, gain_omega, mu, gain_mu, omega_rel_limit):
+ block = type.parse()[0](omega.parse(), gain_omega.parse(),
mu.parse(), gain_mu.parse(), omega_rel_limit.parse())
+ fg.add_callback(block.set_gain_mu, gain_mu)
+ fg.add_callback(block.set_gain_omega, gain_omega)
+ fg.add_callback(block.set_mu, mu)
+ fg.add_callback(block.set_omega, omega)
+ return block
+ return sb,make
+
+def FFT(sb):
+ taps_maker = gr.firdes.window
+ type = Enum([
+ ('Complex', (gr.fft_vcc, ComplexVector())),
+ ('Float', (gr.fft_vfc, FloatVector())),
+ ])
+ sb.add_input_socket('vin', Variable(type, index=1))
+ sb.add_output_socket('vout', ComplexVector())
+ sb.add_param('Input Type', type, False, type=True)
+ sb.add_param('FFT Size', Int(512, min=1))
+ sb.add_param('Window', Enum(window_choices, 1))
+ sb.add_param('Beta', Float(6.76))
+ return sb, lambda fg, type, size, window, beta: \
+ type.parse()[0](size.parse(), True, taps_maker(window.parse(),
size.parse(), beta.parse()))
+
+def IFFT(sb):
+ fcn = gr.fft_vcc
+ taps_maker = gr.firdes.window
+ sb.add_input_socket('vin', ComplexVector())
+ sb.add_output_socket('vout', ComplexVector())
+ sb.add_param('FFT Size', Int(512, min=1))
+ sb.add_param('Window', Enum(window_choices, 1), type=True)
+ sb.add_param('Beta', Float(6.76))
+ return sb, lambda fg, size, window, beta: \
+ fcn(size.parse(), False, taps_maker(window.parse(),
size.parse(), beta.parse()))
+
+def Upsample(sb):
+ taps_maker = gr.firdes.window
+ type = Enum([
+ ('Complex', (gr.rational_resampler_base_ccf, Complex())),
+ ('Float', (gr.rational_resampler_base_fff, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Interpolation (L)', Int(1, min=1))
+ sb.set_docs('''\
+Add L-1 zeros between each sample in f(k).
+>>> Implements a gr.rational_resampler_base_**f(decim=1, taps=[1.0])''')
+ return sb, lambda fg, type, interp: type.parse()[0](interp.parse(), 1,
[1.0])
+
+def Downsample(sb):
+ fcn = gr.keep_one_in_n
+ type = Enum(all_choices, 1)
+ sb.add_input_socket('in', Variable(type))
+ sb.add_output_socket('out', Variable(type))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Decimation (M)', Int(1, min=1), variable=True)
+ sb.set_docs('''\
+Reduce the sample rate by keeping every Mth sample.
+>>> Implements the gr.keep_one_in_n block.''')
+ def make(fg, type, decimation):
+ type = type.parse()
+ block = fcn(type.get_num_bytes(), decimation.parse())
+ fg.add_callback(block.set_n, decimation)
+ return block
+ return sb, make
+
+def FractionalResampler(sb):
+ lcm = gru.lcm
+ filters = Enum([
+ ('Complex', (blks2.rational_resampler_ccc, Complex())),
+ ('Float', (blks2.rational_resampler_fff, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=1))
+ sb.add_param('Type', filters, False, type=True)
+ sb.add_param('Input Rate', Int(100e3))
+ sb.add_param('Output Rate', Int(100e3))
+ sb.add_param('Fractional Bandwidth', Float(0.4, min=0.0, max=0.5))
+ sb.set_docs('''\
+Rational Resampler with a low pass FIR filter. \
+The fractional bandwidth must be a number between 0 and 0.5. \
+The fractional bandwidth controls the transition width of the low pass filter.
''')
+ def make(fg, filter_type, inrate, outrate, fractional_bw):
+ in_rate = inrate.parse()
+ out_rate = outrate.parse()
+ interp = int(lcm(in_rate, out_rate)/in_rate)
+ decim = int(lcm(in_rate, out_rate)/out_rate)
+ return filter_type.parse()[0](interp, decim, taps=None,
fractional_bw=fractional_bw.parse())
+ return sb, make
+
+def FractionalInterpolator(sb):
+ filters = Enum([
+ ('Complex', (gr.fractional_interpolator_cc, Complex())),
+ ('Float', (gr.fractional_interpolator_ff, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(filters, index=1))
+ sb.add_output_socket('out', Variable(filters, index=1))
+ sb.add_param('Type', filters, False, type=True)
+ sb.add_param('Phase Shift', Float())
+ sb.add_param('Interp Ratio', Float())
+ def make(fg, filter_type, phase_shit, interp_ratio):
+ return filter_type.parse()[0](phase_shift.parse(),
interp_ratio.parse())
+ return sb, make
+
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py (from rev 6476,
grc/trunk/src/SignalBlockDefs/GraphicalSinks.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/GraphicalSinks.py 2007-09-20
01:49:24 UTC (rev 6483)
@@ -0,0 +1,192 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.GraphicalSinks
+#Various graphical sinks.
address@hidden Josh Blum
+
+from DataTypes import *
+from gnuradio import gr
+from SignalBlockConstants import default_samp_rate
+
+number_display_pritority = 0
+fft_display_priority = 1
+scope_display_priority = 2
+constellation_display_pritority = 3
+waterfall_display_priority = 4
+
+def FFTSink(sb):
+ from gnuradio.wxgui import fftsink2
+ type = Enum([
+ ('Complex', (fftsink2.fft_sink_c, Complex())),
+ ('Float', (fftsink2.fft_sink_f, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Title', String('FFT'))
+ sb.add_param('Sampling Rate', Int(default_samp_rate))
+ sb.add_param('Y per div', Int(20), variable=True)
+ sb.add_param('Reference Level', Int(20), variable=True)
+ sb.add_param('FFT Size', Int(512))
+ sb.add_param('FFT Rate', Int(15))
+ sb.add_param('Options', Enum([('Off', None), ('Average Values', 1),
('Peak Hold', 2)]))
+ sb.set_docs('''The fft sink has a throttle automatically attatched to
it at runtime to save the CPU.''')
+ def make(fg, type, title, samp_rate, y_per_div, ref_lvl, fft_size,
fft_rate, options):
+ options = options.parse()
+ peak_hold = (options == 2)
+ average = (options == 1)
+ block = type.parse()[0](fg.get_panel(), title=title.parse(),
y_per_div=y_per_div.parse(),
+ ref_level=ref_lvl.parse(), fft_size=fft_size.parse(),
sample_rate=samp_rate.parse(),
+ fft_rate=fft_rate.parse())
+ block.set_peak_hold(peak_hold) #set the peak hold option
outside the contructor
+ block.set_average(average) #set the
average option outside the contructor
+ fg.add_window(block.win, fft_display_priority, title.parse())
+ fg.add_callback(block.set_ref_level, ref_lvl)
+ fg.add_callback(block.set_y_per_div, y_per_div)
+ throttle = gr.throttle(type.parse()[1].get_num_bytes(),
samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+def WaterfallSink(sb):
+ from gnuradio.wxgui import waterfallsink2
+ type = Enum([
+ ('Complex', (waterfallsink2.waterfall_sink_c, Complex())),
+ ('Float', (waterfallsink2.waterfall_sink_f, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Title', String('Waterfall'))
+ sb.add_param('Sampling Rate', Int(default_samp_rate))
+ sb.add_param('Baseband Freq', Int(0), variable=True)
+ sb.add_param('Y per div', Int(20))
+ sb.add_param('Reference Level', Int(20))
+ sb.add_param('FFT Size', Int(512))
+ sb.add_param('FFT Rate', Int(15))
+ sb.add_param('Options', Enum([('Off', None), ('Average Values', 1)]))
+ sb.set_docs('''The waterfall sink has a throttle automatically
attatched to it at runtime to save the CPU.''')
+ def make(fg, type, title, samp_rate, baseband_freq, y_per_div, ref_lvl,
fft_size, fft_rate, options):
+ options = options.parse()
+ average = (options == 1)
+ block = type.parse()[0](fg.get_panel(), title=title.parse(),
y_per_div=y_per_div.parse(),
+ ref_level=ref_lvl.parse(), fft_size=fft_size.parse(),
sample_rate=samp_rate.parse(),
+ baseband_freq=baseband_freq.parse(),
fft_rate=fft_rate.parse())
+ block.set_average(average) #set the
average option outside the contructor
+ fg.add_window(block.win, waterfall_display_priority,
title.parse())
+ fg.add_callback(block.set_baseband_freq, baseband_freq)
+ throttle = gr.throttle(type.parse()[1].get_num_bytes(),
samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+def ScopeSink(sb):
+ from gnuradio.wxgui import scopesink2
+ type = Enum([
+ ('Complex', (scopesink2.scope_sink_c, Complex())),
+ ('Float', (scopesink2.scope_sink_f, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Title', String('Scope'))
+ sb.add_param('Sampling Rate', Int(default_samp_rate))
+ sb.add_param('Frame Decimation', Int(1))
+ sb.add_param('Vertical Scale', Float(0))
+ sb.add_param('Time Scale', Float(.001))
+ sb.set_docs('''\
+The scope sink has a throttle automatically attatched to it at runtime to save
the CPU. \
+Complex inputs to the scope show up as 2 channels (real and imaginary). \
+A Vertical Scale of 0, sets the scope to auto-scale.''')
+ def make(fg, type, title, samp_rate, frame_decim, v_scale, t_scale):
+ v_scale = v_scale.parse()
+ if v_scale == 0: v_scale = None # v_scale = None means
auto-scale
+ block = type.parse()[0](fg.get_panel(), title=title.parse(),
+ sample_rate=samp_rate.parse(),
frame_decim=frame_decim.parse(),
+ v_scale=v_scale, t_scale=t_scale.parse())
+ fg.add_window(block.win, scope_display_priority, title.parse())
+ throttle = gr.throttle(type.parse()[1].get_num_bytes(),
samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+def ConstellationSink(sb):
+ from gnuradio.wxgui import scopesink2
+ fcn = scopesink2.scope_sink_c #dont tell anyone that its really a
scope sink
+ sb.add_input_socket('in', Complex())
+ sb.add_param('Title', String('Constellation'))
+ sb.add_param('Sampling Rate', Int(default_samp_rate))
+ sb.add_param('Frame Decimation', Int(1))
+ sb.add_param('Marker', Enum([('Plus', 0), ('Dot', 1), ('Line', 2)]))
+ sb.set_docs('''\
+The constellation sink has a throttle automatically attatched to it at runtime
to save the CPU. ''')
+ def make(fg, title, samp_rate, frame_decim, marker):
+ block = fcn(fg.get_panel(), title=title.parse(),
+ sample_rate=samp_rate.parse(),
frame_decim=frame_decim.parse())
+ block.win.info.xy = True #true for X:Y
+ marker = marker.parse()
+ if marker == 0: block.win.set_format_plus()
+ elif marker == 1: block.win.set_format_dot()
+ elif marker == 2: block.win.set_format_line()
+ fg.add_window(block.win, constellation_display_pritority,
title.parse())
+ throttle = gr.throttle(Complex().get_num_bytes(),
samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+def NumericalSink(sb):
+ from gnuradio.wxgui import numbersink2
+ type = Enum([
+ ('Complex', (numbersink2.number_sink_c, Complex())),
+ ('Float', (numbersink2.number_sink_f, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Title', String('Number'))
+ sb.add_param('Unit', String('Units'))
+ sb.add_param('Sampling Rate', Int(default_samp_rate))
+ sb.add_param('Base Value', Float(0.0), variable=True)
+ sb.add_param('Min Value', Float(-100))
+ sb.add_param('Max Value', Float(100))
+ sb.add_param('Factor', Float(1.0))
+ sb.add_param('Decimal Places', Int(6), variable=True)
+ sb.add_param('Reference Level', Int(50), variable=True)
+ sb.add_param('Number Rate', Int(15))
+ sb.add_param('Options', Enum([('Off', None), ('Average Values', 1),
('Peak Hold', 2)]))
+ sb.add_param('Gauge', Bool(true='Show', false='Hide', default=True))
+ sb.set_docs('''\
+The number sink has a throttle automatically attatched to it at runtime to
save the CPU. ''')
+ def make(fg, type, label, unit, samp_rate, base, min, max, factor,
decimals, ref_lvl, num_rate, options, gauge):
+ options = options.parse()
+ peak_hold = (options == 2)
+ average = (options == 1)
+ block = type.parse()[0](fg.get_panel(), unit=unit.parse(),
+ base_value=base.parse(), minval=min.parse(),
maxval=max.parse(), factor=factor.parse(),
+ decimal_places=decimals.parse(),
ref_level=ref_lvl.parse(), sample_rate=samp_rate.parse(), #number_size=512,
+ number_rate=num_rate.parse(), label=label.parse())
+ block.set_show_gauge(gauge.parse())
+ block.set_peak_hold(peak_hold) #set the peak hold option
outside the contructor
+ block.set_average(average) #set the
average option outside the contructor
+ fg.add_window(block.win, number_display_pritority,
label.parse()+unit.parse())
+ fg.add_callback(block.set_base_value, base)
+ fg.add_callback(block.set_ref_level, ref_lvl)
+ fg.add_callback(block.set_decimal_places, decimals)
+ throttle = gr.throttle(type.parse()[1].get_num_bytes(),
samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py (from rev 6449,
grc/trunk/src/SignalBlockDefs/Misc.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/Misc.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,223 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.Misc
+#These blocks were not categorized. Try to keep the number of misc blocks
small.
address@hidden Josh Blum
+
+import gnuradio.gr.gr_threading as threading
+from DataTypes import *
+from gnuradio import gr,blks
+from SignalBlockConstants import default_samp_rate,all_choices,MAX_NUM_SOCKETS
+
+def Throttle(sb):
+ fcn = gr.throttle
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_output_socket('out', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Sampling Rate', Float(default_samp_rate))
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''Connect a throttle to control the actual rate of the
data.''')
+ return sb, lambda fg, type, samp_rate, vlen:
fcn(type.parse().get_num_bytes()*vlen.parse(), samp_rate.parse())
+
+def Head(sb):
+ fcn = gr.head
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_output_socket('out', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Num Items', Int(1000, min=0))
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''Copies the first num items to the output then stops.''')
+ return sb, lambda fg, type, num_items, vlen:
fcn(type.parse().get_num_bytes()*vlen.parse(), num_items.parse())
+
+def SkipHead(sb):
+ fcn = gr.skiphead
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_output_socket('out', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Num Items', Int(1000, min=0))
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''Skips the first num items, and then copies input to
output.''')
+ return sb, lambda fg, type, num_items, vlen:
fcn(type.parse().get_num_bytes()*vlen.parse(), num_items.parse())
+
+def RMS(sb):
+ type = Enum([
+ ('Complex', (gr.rms_cf, Complex())),
+ ('Float', (gr.rms_ff, Float())),
+ ], 1)
+ sb.add_input_socket('in', Variable(type, index=1))
+ sb.add_output_socket('out', Float())
+ sb.add_param('Input Type', type, False, type=True)
+ sb.add_param('Alpha', Float(0.0001), variable=True)
+ def make(fg, type, alpha):
+ block = type.parse()[0](alpha.parse())
+ fg.add_callback(block.set_alpha, alpha)
+ return block
+ return sb, make
+
+def About(sb):
+ sb.add_param('Title', String(''))
+ sb.add_param('Author', String(''))
+ return sb, lambda *args: None
+
+def Note(sb):
+ sb.add_param('Note', String(''))
+ return sb, lambda *args: None
+
+#######################################################################################
+## Selector Def, and Helper Block
+#######################################################################################
+
+class SelectorHelper(gr.hier_block2):
+ """A hier2 block with N inputs and M outputs, where data is only
forwarded through input n to output m."""
+ def __init__(self, item_size, num_inputs, num_outputs, input_index,
output_index):
+ """!
+ SelectorHelper constructor.
+ @param item_size the size of the gr data stream in bytes
+ @param num_inputs the number of inputs (integer)
+ @param num_outputs the number of outputs (integer)
+ @param input_index the index for the source data
+ @param output_index the index for the destination data
+ """
+ gr.hier_block2.__init__(
+ self, 'selector',
+ gr.io_signature(num_inputs, num_inputs, item_size),
+ gr.io_signature(num_outputs, num_outputs, item_size),
+ )
+ #terminator blocks for unused inputs and outputs
+ self.input_terminators = [gr.null_sink(item_size) for i in
range(num_inputs)]
+ self.output_terminators = [gr.head(item_size, 0) for i in
range(num_outputs)]
+ self.copy = None
+ #connections
+ for i in range(num_inputs): self.connect((self, i),
self.input_terminators[i])
+ for i in range(num_outputs):
self.connect(gr.null_source(item_size), self.output_terminators[i], (self, i))
+ self.item_size = item_size
+ self.input_index = input_index
+ self.output_index = output_index
+ self.num_inputs = num_inputs
+ self.num_outputs = num_outputs
+ self._connect_current()
+
+ def _indexes_valid(self):
+ """!
+ Are the input and output indexes within range of the number of
inputs and outputs?
+ @return true if input index and output index are in range
+ """
+ return self.input_index in range(self.num_inputs) and
self.output_index in range(self.num_outputs)
+
+ def _connect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from their
terminators,
+ and connect them to one another. Then connect the terminators
to one another."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index),
self.input_terminators[self.input_index])
+
self.disconnect(self.output_terminators[self.output_index], (self,
self.output_index))
+ self.copy = gr.skiphead(self.item_size, 0)
+ self.connect((self, self.input_index), self.copy)
+ self.connect(self.copy, (self, self.output_index))
+
self.connect(self.output_terminators[self.output_index],
self.input_terminators[self.input_index])
+
+ def _disconnect_current(self):
+ """If the input and output indexes are valid:
+ disconnect the blocks at the input and output index from one
another,
+ and the terminators at the input and output index from one
another.
+ Reconnect the blocks to the terminators."""
+ if self._indexes_valid():
+ self.disconnect((self, self.input_index), self.copy)
+ self.disconnect(self.copy, (self, self.output_index))
+
self.disconnect(self.output_terminators[self.output_index],
self.input_terminators[self.input_index])
+ del self.copy
+ self.copy = None
+ self.connect((self, self.input_index),
self.input_terminators[self.input_index])
+
self.connect(self.output_terminators[self.output_index], (self,
self.output_index))
+
+ def set_input_index(self, input_index):
+ """!
+ Change the block to the new input index if the index changed.
+ @param input_index the new input index
+ """
+ if self.input_index != input_index:
+ self.lock()
+ self._disconnect_current()
+ self.input_index = input_index
+ self._connect_current()
+ self.unlock()
+
+ def set_output_index(self, output_index):
+ """!
+ Change the block to the new output index if the index changed.
+ @param output_index the new output index
+ """
+ if self.output_index != output_index:
+ self.lock()
+ self._disconnect_current()
+ self.output_index = output_index
+ self._connect_current()
+ self.unlock()
+
+def Selector(sb):
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_output_socket('out', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Input Index', Int(0), variable=True)
+ sb.add_param('Output Index', Int(0), variable=True)
+ sb.add_param('Num Inputs', Int(1, min=1, max=MAX_NUM_SOCKETS),
+ show_label=False, input_sockets_controller=True)
+ sb.add_param('Num Outputs', Int(1, min=1, max=MAX_NUM_SOCKETS),
+ show_label=False, output_sockets_controller=True)
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''Forward data from the input index to the output
index.''')
+ def make(fg, type, input_index, output_index, num_inputs, num_outputs,
vlen):
+ item_size = type.parse().get_num_bytes()*vlen.parse()
+ block = SelectorHelper(
+ item_size,
+ num_inputs.parse(),
+ num_outputs.parse(),
+ input_index.parse(),
+ output_index.parse(),
+ )
+ fg.add_callback_locked(block.set_input_index, input_index)
+ fg.add_callback_locked(block.set_output_index, output_index)
+ return block
+ return sb, make
+
+def Valve(sb):
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_output_socket('out', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Open', Int(0), variable=True)
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''When open is 0, the valve will forward data.''')
+ def make(fg, type, open, vlen):
+ item_size = type.parse().get_num_bytes()*vlen.parse()
+ block = SelectorHelper(item_size, 1, 1, 0, open.parse())
+ fg.add_callback_locked(block.set_output_index, open)
+ return block
+ return sb, make
+
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py (from rev 6449,
grc/trunk/src/SignalBlockDefs/Modulators.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/Modulators.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,289 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.Modulations
+#Various modulation schemes.
address@hidden Josh Blum
+
+from DataTypes import *
+from gnuradio import gr,blks2
+
+def FrequencyMod(sb):
+ fcn = gr.frequency_modulator_fc
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Sensitivity', Float(.01))
+ return sb, lambda fg, sensitivity: fcn(sensitivity.parse())
+
+def PhaseMod(sb):
+ fcn = gr.phase_modulator_fc
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Sensitivity', Float(.01))
+ return sb, lambda fg, sensitivity: fcn(sensitivity.parse())
+
+def QuadratureDemod(sb):
+ fcn = gr.quadrature_demod_cf
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Float())
+ sb.add_param('Gain', Float(1))
+ return sb, lambda fg, gain: fcn(gain.parse())
+
+###########################################################################
+# Narrow band and Wide band FM
+###########################################################################
+
+def WFMReceive(sb):
+ fcn = blks2.wfm_rcv
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Float())
+ sb.add_param('Quad Rate', Float(100e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.set_docs('''\
+Wide Band FM Receiver.
+The audio rate is the quad rate/audio decimation.''')
+ return sb, lambda fg, quad_rate, audio_dec: fcn(quad_rate.parse(),
audio_dec.parse())
+
+def WFMTransmit(sb):
+ fcn = blks2.wfm_tx
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Quad Rate', Int(100e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.add_param('Tau', Float(75e-6))
+ sb.add_param('Max Deviation', Float(75e3))
+ sb.set_docs('''\
+Wide Band FM Transmitter.
+The audio rate is the quad rate/audio decimation.''')
+ def make(fg, quad_rate, audio_decimation, tau, max_dev):
+ quad_rate = quad_rate.parse()
+ audio_decimation = audio_decimation.parse()
+ # make sure that the quad rate is an integer multiple of
the audio rate #
+ audio_rate = quad_rate/audio_decimation
+ quad_rate = audio_decimation * (quad_rate/audio_decimation)
+ return fcn(audio_rate, quad_rate, tau.parse(), max_dev.parse())
+ return sb, make
+
+def NBFMReceive(sb):
+ fcn = blks2.nbfm_rx
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Float())
+ sb.add_param('Quad Rate', Int(100e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.add_param('Tau', Float(75e-6))
+ sb.add_param('Max Deviation', Float(5e3))
+ sb.set_docs('''\
+Narrow Band FM Receiver.
+The audio rate is the quad rate/audio decimation.''')
+ def make(fg, quad_rate, audio_decimation, tau, max_dev):
+ quad_rate = quad_rate.parse()
+ audio_decimation = audio_decimation.parse()
+ # make sure that the quad rate is an integer multiple of
the audio rate #
+ audio_rate = quad_rate/audio_decimation
+ quad_rate = audio_decimation * (quad_rate/audio_decimation)
+ return fcn(audio_rate, quad_rate, tau.parse(), max_dev.parse())
+ return sb, make
+
+def NBFMTransmit(sb):
+ fcn = blks2.nbfm_tx
+ sb.add_input_socket('in', Float())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Quad Rate', Int(100e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.add_param('Tau', Float(75e-6))
+ sb.add_param('Max Deviation', Float(5e3))
+ sb.set_docs('''\
+Narrow Band FM Transmitter.
+The audio rate is the quad rate/audio decimation.''')
+ def make(fg, quad_rate, audio_decimation, tau, max_dev):
+ quad_rate = quad_rate.parse()
+ audio_decimation = audio_decimation.parse()
+ # make sure that the quad rate is an integer multiple of
the audio rate #
+ audio_rate = quad_rate/audio_decimation
+ quad_rate = audio_decimation * (quad_rate/audio_decimation)
+ return fcn(audio_rate, quad_rate, tau.parse(), max_dev.parse())
+ return sb, make
+
+###########################################################################
+# AM and FM demodulation
+###########################################################################
+
+def AMDemod(sb):
+ fcn = blks2.am_demod_cf
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Float())
+ sb.add_param('Channel Rate', Int(100e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.add_param('Audio Passband (Hz)', Float(5e3))
+ sb.add_param('Audio Stopband (Hz)', Float(5.5e3))
+ return sb, lambda fg, *args: fcn(*map(lambda a: a.parse(), args))
+
+def FMDemod(sb):
+ fcn = blks2.fm_demod_cf
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Float())
+ sb.add_param('Channel Rate', Int(100e3))
+ sb.add_param('FM Deviation (Hz)', Int(5e3))
+ sb.add_param('Audio Decimation', Int(1, min=1))
+ sb.add_param('Audio Passband (Hz)', Float(3e3))
+ sb.add_param('Audio Stopband (Hz)', Float(4e3))
+ sb.add_param('Gain', Float(1))
+ sb.add_param('Tau', Float(75e-6))
+ return sb, lambda fg, *args: fcn(*map(lambda a: a.parse(), args))
+
+###########################################################################
+# Phase shift keying
+###########################################################################
+
+def PSKMod(sb):
+ sb.add_input_socket('in', Byte())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Type', Enum([
+ ('DBPSK', blks2.dbpsk_mod),
+ ('DQPSK', blks2.dqpsk_mod),
+ ('D8PSK', blks2.d8psk_mod),
+ ]), type=True)
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Excess BW', Float(0.35))
+ sb.add_param('Use Gray Code', Bool(true='Yes', false='No',
default=True))
+ return sb, lambda fg, type, *args: type.parse()(*map(lambda a:
a.parse(), args))
+
+def PSKDemod(sb):
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Byte())
+ sb.add_param('Type', Enum([
+ ('DBPSK', blks2.dbpsk_demod),
+ ('DQPSK', blks2.dqpsk_demod),
+ ('D8PSK', blks2.d8psk_demod),
+ ]), type=True)
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Excess BW', Float(0.35))
+ sb.add_param('Costas Alpha', Float(0.03))
+ sb.add_param('Gain Mu', Float(0.05))
+ sb.add_param('Mu', Float(0.005))
+ sb.add_param('Omega Relative Limit', Float(0.05))
+ sb.add_param('Use Gray Code', Bool(true='Yes', false='No',
default=True))
+ return sb, lambda fg, type, *args: type.parse()(*map(lambda a:
a.parse(), args))
+
+###########################################################################
+# Gaussian minimum shift keying
+###########################################################################
+
+def GMSKMod(sb):
+ fcn = blks2.gmsk_mod
+ sb.add_input_socket('in', Byte())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Filter BW', Float(0.35))
+ return sb, lambda fg, *args: fcn(*map(lambda a: a.parse(), args))
+
+def GMSKDemod(sb):
+ fcn = blks2.gmsk_demod
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Byte())
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Gain Mu', Float(0.05))
+ sb.add_param('Mu', Float(0.5, min=0, max=1))
+ sb.add_param('Omega Relative Limit', Float(0.005))
+ sb.add_param('Frequency Error', Float(0))
+ sb.set_docs('''Mu is the fractional delay between 0 and 1''')
+ return sb, lambda fg, *args: fcn(*map(lambda a: a.parse(), args))
+
+###########################################################################
+# Quadrature amplitude modulation
+###########################################################################
+
+def QAMMod(sb):
+ sb.add_input_socket('in', Byte())
+ sb.add_output_socket('out', Complex())
+ sb.add_param('Type', Enum([
+ ('QAM 8', blks2.qam8_mod),
+ ('QAM 16', blks2.qam16_mod),
+ ('QAM 64', blks2.qam64_mod),
+ ('QAM 256', blks2.qam256_mod),
+ ]), type=True)
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Excess BW', Float(0.35))
+ sb.add_param('Use Gray Code', Bool(true='Yes', false='No',
default=True))
+ return sb, lambda fg, type, *args: type.parse()(*map(lambda a:
a.parse(), args))
+
+def QAMDemod(sb):
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Byte())
+ sb.add_param('Type', Enum([
+ ('QAM 8', blks2.qam8_demod),
+ ('QAM 16', blks2.qam16_demod),
+ ('QAM 64', blks2.qam64_demod),
+ ('QAM 256', blks2.qam256_demod),
+ ]), type=True)
+ sb.add_param('Samples/Symbol', Int(2, min=2))
+ sb.add_param('Excess BW', Float(0.35))
+ sb.add_param('Costas Alpha', Float(0.03))
+ sb.add_param('Gain Mu', Float(0.05))
+ sb.add_param('Mu', Float(0.005))
+ sb.add_param('Omega Relative Limit', Float(0.05))
+ sb.add_param('Use Gray Code', Bool(true='Yes', false='No',
default=True))
+ return sb, lambda fg, type, *args: type.parse()(*map(lambda a:
a.parse(), args))
+
+###########################################################################
+# Phase Locked Loops
+###########################################################################
+
+def CostasLoop(sb):
+ fcn = gr.costas_loop_cc
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('bout', Complex())
+ sb.add_output_socket('nout', Complex(), optional=True)
+ sb.add_param('Alpha', Float())
+ sb.add_param('Beta', Float())
+ sb.add_param('Max Freq', Float())
+ sb.add_param('Min Freq', Float())
+ sb.add_param('Order', Enum([('2', 2), ('4', 4)]))
+ sb.set_docs('''\
+Carrier tracking PLL for QPSK input. \
+The Costas loop has two output streams: \
+"bout" is the baseband I stream, "nout" is the normalized frequency of the
loop. \
+The "nout" may be left open. ''')
+ return sb, lambda fg, *args: fcn(*map(lambda a: a.parse(), args))
+
+def PLL(sb):
+ type = Enum([ #fcn, output
type
+ ('Carrier Tracking', (gr.pll_carriertracking_cc, Complex())),
+ ('Freq Det', (gr.pll_freqdet_cf, Float())),
+ ('Ref Out', (gr.pll_refout_cc, Complex())),
+ ])
+ sb.add_input_socket('in', Complex())
+ sb.add_output_socket('out', Variable(type, index=1))
+ sb.add_param('Type', type, type=True)
+ sb.add_param('Alpha', Float())
+ sb.add_param('Beta', Float())
+ sb.add_param('Max Freq', Float())
+ sb.add_param('Min Freq', Float())
+ sb.set_docs('''\
+All settings max_freq and min_freq are in terms of radians per sample, NOT
HERTZ. \
+Alpha is the phase gain (first order, units of radians per radian), and \
+beta is the frequency gain (second order, units of radians per sample per
radian).
+
+Carrier Tracking - This PLL locks onto a [possibly noisy] reference carrier on
the input and outputs that signal, downconverted to DC.
+
+Freq Det - This PLL locks onto a [possibly noisy] reference carrier on the
input and outputs an estimate of that frequency in radians per sample.
+
+Ref Out - This PLL locks onto a [possibly noisy] reference carrier on the
input and outputs a clean version which is phase and frequency aligned to it.
+''')
+ return sb, lambda fg, type, *args: type.parse()[0](*map(lambda a:
a.parse(), args))
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py (from rev 6460,
grc/trunk/src/SignalBlockDefs/Packet.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/Packet.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,359 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.Packet
+#Support for the gr packet framework.
address@hidden Josh Blum
+
+import struct
+import os
+from DataTypes import *
+from gnuradio import gr, packet_utils
+import gnuradio.gr.gr_threading as threading
+from SignalBlockConstants import all_choices
+
+##payload length in bytes
+DEFAULT_PAYLOAD_LEN = 512
+
+##how many messages in a queue
+DEFAULT_MSGQ_LIMIT = 2
+
+##threshold for unmaking packets
+DEFAULT_THRESHOLD = 12
+
+#######################################################################################
+## Packet Mod
+#######################################################################################
+
+class PacketModThread(threading.Thread):
+ """
+ Sample the input message queue and call send payload.
+ """
+
+ def __init__(self, msgq, payload_length, send_payload):
+ """!
+ Create the packet_mod_thread.
+ @param msgq the message queue to sample
+ @param payload_length number of bytes in a data-stream slice
+ @param send_payload a function that takes a payload
+ """
+ self._msgq = msgq
+ self._payload_length = payload_length
+ self._send_payload = send_payload
+ threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.keep_running = True
+ self.start()
+
+ def run(self):
+ """
+ Run this thread by sampling the message queue in and cutting
out chunks of size payload.
+ """
+ sample = '' #residual sample
+ while self.keep_running:
+ msg = self._msgq.delete_head() #blocking read of
message queue
+ sample = sample + msg.to_string() #get the body of the
msg as a string
+ while len(sample) >= self._payload_length:
+ payload = sample[0:self._payload_length]
+ sample = sample[self._payload_length:]
+ self._send_payload(payload)
+
+class PacketModHelper(gr.hier_block2):
+ """
+ Hierarchical block for sending packet based data.
+ """
+
+ def __init__(self, item_size, samples_per_symbol, bits_per_symbol,
payload_length=None, access_code=None, pad_for_usrp=True):
+ """!
+ PacketModHelper constructor.
+ @param item_size the size of the input data stream in bytes
+ @param samples_per_symbol number of samples per symbol
+ @param bits_per_symbol number of bits per symbol
+ @param payload_length number of bytes in a data-stream slice
+ @param access_code AKA sync vector
+ @param pad_for_usrp If true, packets are padded such that they
end up a multiple of 128 samples
+ """
+ #setup parameters
+ self._item_size = item_size
+ self._samples_per_symbol = samples_per_symbol
+ self._bits_per_symbol = bits_per_symbol
+ self._pad_for_usrp = pad_for_usrp
+ if access_code is None: #get access code
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be
string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+ if payload_length is None: #get packet length
+ payload_length = DEFAULT_PAYLOAD_LEN
+ if payload_length%self._item_size != 0: #verify that packet
length is a multiple of the stream size
+ raise ValueError, 'The packet length: "%d" is not a
mutiple of the stream size: "%d".'%(payload_length, item_size)
+ self._payload_length = payload_length
+ self._pad_for_usrp = pad_for_usrp
+ #create message queues and message blocks
+ self._msgq_in = gr.msg_queue(DEFAULT_MSGQ_LIMIT)
+ msg_sink = gr.message_sink(self._item_size,
self._msgq_in, False) #False -> blocking
+ msg_source = gr.message_source(gr.sizeof_char,
DEFAULT_MSGQ_LIMIT)
+ self._msgq_out = msg_source.msgq()
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "packet_mod",
+ gr.io_signature(1, 1, self._item_size), # Input
signature
+ gr.io_signature(1, 1, gr.sizeof_char) # Output signature
+ )
+ #connect
+ self.connect(self, msg_sink)
+ self.connect(msg_source, self)
+ #start thread
+ PacketModThread(self._msgq_in, self._payload_length,
self._send_payload)
+
+ def _send_payload(self, payload):
+ """!
+ Wrap the payload in a packet and push onto the message queue.
+ @param payload data to send
+ """
+ packet = packet_utils.make_packet(
+ payload,
+ self._samples_per_symbol,
+ self._bits_per_symbol,
+ self._access_code,
+ self._pad_for_usrp
+ )
+ msg = gr.message_from_string(packet)
+ self._msgq_out.insert_tail(msg)
+
+def PacketMod(sb):
+ type = Enum(all_choices, 1)
+ sb.add_input_socket('in', Variable(type))
+ sb.add_output_socket('out', Byte())
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Samples/Symbol', Int(1))
+ sb.add_param('Bits/Symbol', Int(1))
+ sb.add_param('Payload Length', Int(DEFAULT_PAYLOAD_LEN))
+ sb.add_param('Access Code', String())
+ sb.add_param('Pad for USRP', Bool(true='Yes', false='No', default=True))
+ sb.set_docs("""\
+Packet modulator block, for use with the gnuradio modulator blocks: gmsk, psk,
qam.
+
+Access Code: string of 1's and 0's, leave blank for default.
+
+Bits/Symbol should be set accordingly:
+ gmsk -> 1
+ dbpsk -> 1
+ dqpsk -> 2
+ d8psk -> 3
+ qam8 -> 3
+ qam16 -> 4
+ qam64 -> 6
+ qam256 -> 8
+""")
+ def make(fg, type, samples_per_symbol, bits_per_symbol, payload_length,
access_code, pad_for_usrp):
+ access_code = access_code.parse()
+ if not access_code: access_code = None
+ return PacketModHelper(
+ item_size = type.parse().get_num_bytes(),
+ samples_per_symbol=samples_per_symbol.parse(),
+ bits_per_symbol=bits_per_symbol.parse(),
+ payload_length=payload_length.parse(),
+ access_code=access_code,
+ pad_for_usrp=pad_for_usrp.parse(),
+ )
+ return sb, make
+
+#######################################################################################
+## Packet Demod
+#######################################################################################
+
+class PacketDemodThread(threading.Thread):
+ """
+ Sample the input message queue and call send packet.
+ """
+
+ def __init__(self, msgq, recv_packet):
+ """!
+ Create the packet_mod_thread.
+ @param msgq the message queue to sample
+ @param recv_packet a function that takes a packet
+ """
+ self._msgq = msgq
+ self._recv_packet = recv_packet
+ threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.keep_running = True
+ self.start()
+
+ def run(self):
+ """
+ Run this thread by sampling the message queue and calling send
payload
+ """
+ while self.keep_running:
+ msg = self._msgq.delete_head() #blocking read of
message queue
+ packet = msg.to_string()
+ self._recv_packet(packet)
+
+class PacketDemodHelper(gr.hier_block2):
+ """
+ Hierarchical block for demodulating and deframing packets.
+ """
+
+ def __init__(self, item_size, access_code=None, threshold=-1):
+ """!
+ PacketDemodHelper contructor.
+ @param item_size the size of the input data stream in bytes
+ @param access_code AKA sync vector
+ @param threshold detect access_code with up to threshold bits
wrong (-1 -> use default)
+ """
+ #setup parameters
+ self._item_size = item_size
+ #access code
+ if access_code is None: #get access code
+ access_code = packet_utils.default_access_code
+ if not packet_utils.is_1_0_string(access_code):
+ raise ValueError, "Invalid access_code %r. Must be
string of 1's and 0's" % (access_code,)
+ self._access_code = access_code
+ #threshold
+ if threshold == -1: threshold = DEFAULT_THRESHOLD
+ self._threshold = threshold
+ #initialize hier2
+ gr.hier_block2.__init__(
+ self,
+ "packet_demod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, self._item_size), # Output
signature
+ )
+ #blocks
+ self._msgq_in = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #
holds packets from the PHY
+ correlator = gr.correlate_access_code_bb(self._access_code,
self._threshold)
+ framer_sink = gr.framer_sink_1(self._msgq_in)
+ msg_source = gr.message_source(self._item_size,
DEFAULT_MSGQ_LIMIT)
+ self._msgq_out = msg_source.msgq()
+ #connect
+ self.connect(self, correlator, framer_sink)
+ self.connect(msg_source, self)
+ #start thread
+ PacketDemodThread(self._msgq_in, self._recv_packet)
+
+ def _recv_packet(self, packet):
+ """!
+ Extract the payload from the packet and push onto message queue.
+ @param packet data received
+ """
+ ok, payload = packet_utils.unmake_packet(packet)
+ msg = gr.message_from_string(payload, 0, self._item_size,
len(payload)/self._item_size)
+ if ok: self._msgq_out.insert_tail(msg)
+
+def PacketDemod(sb):
+ type = Enum(all_choices, 1)
+ sb.add_input_socket('in', Byte())
+ sb.add_output_socket('out', Variable(type))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Access Code', String())
+ sb.add_param('Threshold', Int(-1))
+ sb.set_docs("""\
+Packet demodulator block, for use with the gnuradio demodulator blocks: gmsk,
psk, qam.
+
+Access Code: string of 1's and 0's, leave blank for default.
+""")
+ def make(fg, type, access_code, threshold):
+ access_code = access_code.parse()
+ if not access_code: access_code = None
+ return PacketDemodHelper(
+ item_size = type.parse().get_num_bytes(),
+ access_code=access_code,
+ threshold=threshold.parse(),
+ )
+ return sb, make
+
+#######################################################################################
+## TUN/TAP
+#######################################################################################
+
+IFF_TUN = 0x0001 # tunnel IP packets
+IFF_TAP = 0x0002 # tunnel ethernet frames
+IFF_NO_PI = 0x1000 # don't pass extra packet info
+IFF_ONE_QUEUE = 0x2000 # beats me ;)
+DEFAULT_TUN_DEVICE = '/dev/net/tun'
+DEFAULT_VIRTUAL_DEVICE = 'tun%d'
+DEFAULT_IP_ADDR = '10.0.0.1'
+
+def open_tun_interface(tun_device_filename=DEFAULT_TUN_DEVICE,
virtual_device_filename=DEFAULT_VIRTUAL_DEVICE):
+ """!
+ Open a virtual ethernet interface via the Tun/Tap framework.
+ An alternative function can be found: "from eunuchs.tuntap import
opentuntap"
+ @param tun_device_filename the path to the tun device
+ @param virtual_device_filename the name of the virtual device (to be
created)
+ @return a file descriptor to rw the device, name of the virtual device
(created)
+ """
+ from fcntl import ioctl
+ mode = IFF_TAP | IFF_NO_PI
+ TUNSETIFF = 0x400454ca
+ tun_fd = os.open(tun_device_filename, os.O_RDWR)
+ ifs = ioctl(tun_fd, TUNSETIFF, struct.pack("16sH",
virtual_device_filename, mode))
+ ifname = ifs[:16].strip("\x00")
+ return tun_fd, ifname
+
+class TunTapHelper(gr.hier_block2):
+ """Make the tun tap hier2 block."""
+ def __init__(self, item_size, tun_fd):
+ """!
+ TunTapHelper constructor.
+ @param item_size the size in bytes of the IO data stream
+ @param tun_fd the file descriptor for the virtual device
+ """
+ #create hier block
+ gr.hier_block2.__init__(
+ self, 'tun_tap',
+ gr.io_signature(1, 1, item_size),
+ gr.io_signature(1, 1, item_size)
+ )
+ #I/O blocks
+ sink = gr.file_descriptor_sink(item_size, tun_fd)
+ source = gr.file_descriptor_source(item_size, tun_fd)
+ #connect
+ self.connect(self, sink)
+ self.connect(source, self)
+
+def TunTap(sb):
+ gr.file_descriptor_sink, gr.file_descriptor_source #uses
+ type = Enum(all_choices, 1)
+ sb.add_input_socket('in', Variable(type))
+ sb.add_output_socket('out', Variable(type))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Tun Device', String(DEFAULT_TUN_DEVICE))
+ sb.add_param('Virtual Device', String(DEFAULT_VIRTUAL_DEVICE))
+ sb.add_param('IP Address', String(DEFAULT_IP_ADDR))
+ sb.set_docs('''\
+Foward data between gnuradio and a virtual ethernet interface.
+---
+Tun Device: File path to the tun device.
+
+Virtual Device: Desired name for the virtual ethernet device. \
+"%d" will give the device a number starting at zero.
+
+IP Address: IP address for the virtual device, leave blank and device will not
be configured.
+''')
+ def make(fg, type, tun, virt, ip_addr):
+ item_size = type.parse().get_num_bytes()
+ tun_fd, ifname = open_tun_interface(tun.parse(), virt.parse())
+ #try to set the ip address
+ ip_addr = ip_addr.parse()
+ if ip_addr: os.system('ifconfig %s %s'%(ifname, ip_addr))
+ return TunTapHelper(item_size, tun_fd)
+ return sb, make
+
+
\ No newline at end of file
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py (from rev
6449, grc/trunk/src/SignalBlockDefs/SignalBlockTree.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/SignalBlockTree.py 2007-09-20
01:49:24 UTC (rev 6483)
@@ -0,0 +1,247 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.SignalBlockTree
+#The data structure to categorize the signal blocks, and to map id tags to
block building functions.
address@hidden Josh Blum
+
+from Elements import SignalBlock
+import Sources
+import Sinks
+import Audio
+import GraphicalSinks
+import Conversions
+import Operators
+import Filters
+import Modulators
+import Misc
+import USRP
+import Coders
+import Trellis
+import Packet
+import Custom
+
+##A categorized list of all signal blocks
+SB_TREE = [
+ ('Sources', [
+ ('Signal Source', Sources.SignalSource),
+ ('Noise Source', Sources.NoiseSource),
+ ('Vector Source', Sources.VectorSource),
+ ('Random Source', Sources.RandomVector),
+ ('Null Source', Sources.NullSource),
+ ('File Source', Sources.FileSource),
+ ('UDP Source', Sources.UDPSource),
+ ('Audio Source', Audio.AudioSource),
+ ('USRP Source', USRP.USRPSource),
+ ('USRP Dual Source', USRP.USRPDualSource),
+ ]),
+ ('Sinks', [
+ ('Variable Sink', Sinks.VariableSink),
+ ('Null Sink', Sinks.NullSink),
+ ('File Sink', Sinks.FileSink),
+ ('UDP Sink', Sinks.UDPSink),
+ ('Audio Sink', Audio.AudioSink),
+ ('USRP Sink', USRP.USRPSink),
+ ('USRP Dual Sink', USRP.USRPDualSink),
+ ]),
+ ('Graphical Sinks', [
+ ('Numerical Sink',
GraphicalSinks.NumericalSink),
+ ('Scope Sink', GraphicalSinks.ScopeSink),
+ ('FFT Sink', GraphicalSinks.FFTSink),
+ ('Waterfall Sink',
GraphicalSinks.WaterfallSink),
+ ('Constellation Sink',
GraphicalSinks.ConstellationSink),
+ ]),
+ ('Operators', [
+ ('Add', Operators.Add),
+ ('Subtract', Operators.Subtract),
+ ('Multiply', Operators.Multiply),
+ ('Divide', Operators.Divide),
+ ('nLog10', Operators.nLog10),
+ ('Add Vector', Operators.AddVector),
+ ('Multiply Vector', Operators.MultiplyVector),
+ ('Add Constant', Operators.AddConstant),
+ ('Multiply Constant',
Operators.MultiplyConstant),
+ ('Add Constant Vector',
Operators.AddConstantVector),
+ ('Multiply Constant Vector',
Operators.MultiplyConstantVector),
+ ]),
+ ('Conversions', [
+ ('Complex Components',
Conversions.ComplexComponents),
+ ('Complex Conjugate',
Conversions.ComplexConjugate),
+ ('Float to Complex',
Conversions.FloatToComplex),
+ ('Complex to Float',
Conversions.ComplexToFloat),
+ ('Float to Short', Conversions.FloatToShort),
+ ('Short to Float', Conversions.ShortToFloat),
+ ('Float to Char', Conversions.FloatToChar),
+ ('Char to Float', Conversions.CharToFloat),
+ ('Float to UChar', Conversions.FloatToUChar),
+ ('UChar to Float', Conversions.UCharToFloat),
+ ('Complex to IShort',
Conversions.ComplexToIShort),
+ ('IShort to Complex',
Conversions.IShortToComplex),
+ ('Unpacked to Packed',
Conversions.UnpackedToPacked),
+ ('Packed to Unpacked',
Conversions.PackedToUnpacked),
+ ('Unpack k Bits', Conversions.UnpackKBits),
+ ('Binary Slicer', Conversions.BinarySlicer),
+ ('Chunks to Symbols',
Conversions.ChunksToSymbols),
+ ('Map', Conversions.Map),
+ ('VCO', Conversions.VCO),
+ ('Interleave', Conversions.Interleave),
+ ('Deinterleave', Conversions.Deinterleave),
+ ('Streams to Stream',
Conversions.StreamsToStream),
+ ('Stream to Streams',
Conversions.StreamToStreams),
+ ('Streams to Vector',
Conversions.StreamsToVector),
+ ('Vector to Streams',
Conversions.VectorToStreams),
+ ('Stream to Vector',
Conversions.StreamToVector),
+ ('Vector to Stream',
Conversions.VectorToStream),
+ ]),
+ ('Generic Filters', [
+ ('FIR Filter', Filters.FIRFilter),
+ ('FFT Filter', Filters.FFTFilter),
+ ('Freq Xlating FIR Filter',
Filters.FreqXlatingFIRFilter),
+ ('Rational Resampler',
Filters.RationalResampler),
+ ('IIR Filer', Filters.IIRFiler),
+ ('Filter Delay', Filters.FilterDelay),
+ ('Channel Model', Filters.ChannelModel),
+ ]),
+ ('Filters', [
+ ('Low Pass Filter', Filters.LowPassFilter),
+ ('High Pass Filter', Filters.HighPassFilter),
+ ('Band Pass Filter', Filters.BandPassFilter),
+ ('Band Reject Filter',
Filters.BandRejectFilter),
+ ('Window', Filters.Window),
+ ('Root Raised Cosine',
Filters.RootRaisedCosine),
+ ('Single Pole IIR Filter',
Filters.SinglePoleIIRFilter),
+ ('Hilbert', Filters.Hilbert),
+ ('Goertzel', Filters.Goertzel),
+ ('Power Squelch', Filters.PowerSquelch),
+ ('Downsample', Filters.Downsample),
+ ('Upsample', Filters.Upsample),
+ ('Fractional Resampler',
Filters.FractionalResampler),
+ ('Fractional Interpolator',
Filters.FractionalInterpolator),
+ ('Automatic Gain Control',
Filters.AutomaticGainControl),
+ ('Automatic Gain Control2',
Filters.AutomaticGainControl2),
+ ('Feed Forward AGC', Filters.FeedForwardAGC),
+ ('CMA Filter', Filters.CMAFilter),
+ ('Clock Recovery', Filters.ClockRecovery),
+ ('FFT', Filters.FFT),
+ ('IFFT', Filters.IFFT),
+ ]),
+ ('Modulators', [
+ ('Frequency Modulator',
Modulators.FrequencyMod),
+ ('Phase Modulator', Modulators.PhaseMod),
+ ('Quadrature Demodulator',
Modulators.QuadratureDemod),
+ ('Costas Loop', Modulators.CostasLoop),
+ ('Phase Locked Loop', Modulators.PLL),
+ ('WFM Receive', Modulators.WFMReceive),
+ ('WFM Transmit', Modulators.WFMTransmit),
+ ('NBFM Receive', Modulators.NBFMReceive),
+ ('NBFM Transmit', Modulators.NBFMTransmit),
+ ('AM Demodulator', Modulators.AMDemod),
+ ('FM Demodulator', Modulators.FMDemod),
+ ('PSK Modulator', Modulators.PSKMod),
+ ('PSK Demodulator', Modulators.PSKDemod),
+ ('GMSK Modulator', Modulators.GMSKMod),
+ ('GMSK Demodulator', Modulators.GMSKDemod),
+ ('QAM Modulator', Modulators.QAMMod),
+ ('QAM Demodulator', Modulators.QAMDemod),
+ ('Packet Modulator', Packet.PacketMod),
+ ('Packet Demodulator', Packet.PacketDemod),
+ ]),
+ ('Coders', [
+ ('Constellation Decoder',
Coders.ConstellationDecoder),
+ ('Differential Encoder',
Coders.DifferentialEncoder),
+ ('Differential Decoder',
Coders.DifferentialDecoder),
+ ('Differential Phasor',
Coders.DifferentialPhasor),
+ ('Correlate Access Code',
Coders.CorrelateAccessCode),
+ ]),
+ ('Trellis', [
+ ('Trellis Encoder', Trellis.Encoder),
+ ('Metrics', Trellis.Metrics),
+ ('Viterbi Decoder', Trellis.Viterbi),
+ ('Viterbi Decoder Combined with Metric',
Trellis.Viterbi_Combined),
+ ('BCJR Algorithm', Trellis.Soft_In_Soft_Out),
+ ('BCJR Algorithm Combined with Metric',
Trellis.Soft_In_Soft_Out_Combined),
+ ('Interleaver', Trellis.Interleaver),
+ ('Deinterleaver', Trellis.Deinterleaver),
+ ]),
+ ('Misc', [
+ ('Throttle', Misc.Throttle),
+ ('Valve', Misc.Valve),
+ ('Selector', Misc.Selector),
+ ('Head', Misc.Head),
+ ('Skip Head', Misc.SkipHead),
+ ('Tun Tap', Packet.TunTap),
+ ('RMS', Misc.RMS),
+ ('About', Misc.About),
+ ('Note', Misc.Note),
+ ]),
+ ('Custom', Custom.CUSTOM_BLOCKS),
+ ]
+
+def get_signal_block(parent=None, coor=(0,0), rot=0, lookup_tag='', id='',
signal_block_constructor=SignalBlock):
+ """!
+ Create a new signal block.
+ @param parent the flow graph
+ @param coor the (x,y) corrdinate
+ @param rot the rotation in degrees
+ @param lookup_tag the tag of the desired signal block
+ @param id the unique id for the new signal block
+ @param signal_block_constructor the contructor for a new signal block
+ @throw TagNotFoundException tag not found
+ @return (the signal block, a gnuradio signal block builder function)
tuple
+ """
+ sb = signal_block_constructor(parent, coor, rot, lookup_tag, id)
+ for category, signal_blocks in SB_TREE:
+ for tag, builder in signal_blocks:
+ if lookup_tag == tag: return builder(sb)
+ raise TagNotFoundException(lookup_tag)
+
+# remove the bad tags #
+tags_set = set()
+for category,tags in SB_TREE:
+ tags_to_remove = list()
+ for tag in tags:
+ try:
+ get_signal_block(lookup_tag=tag[0])
+ if tag[0] in tags_set: # remove redundant tags
#
+ print 'Removing redundant tag "%s" in category
"%s"...'%(tag[0], category)
+ tags_to_remove.append(tag)
+ else: tags_set.add(tag[0])
+ except (ImportError, AttributeError), e:
+ print e, " in %s! -> continuing..."%tag[0]
+ tags_to_remove.append(tag)
+ for tag in tags_to_remove: tags.remove(tag)
+
+# remove empty categories #
+cats_to_remove = list()
+for category,tags in SB_TREE:
+ if len(tags) == 0:
+ print 'Removing empty category "%s"...'%category
+ cats_to_remove.append((category,tags))
+for cat in cats_to_remove: SB_TREE.remove(cat)
+
+
+class TagNotFoundException(Exception):
+ def __init__(self, value): self.value = value
+ def __str__(self): return 'Exception! The tag: %s could not be
found'%repr(self.value)
+
+def print_sb_tree():
+ """Print the signal block tree."""
+ for category,tags in TAGS:
+ print category
+ for tag in tags: print '\t%s'%tag[0]
+
Deleted: grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py
Copied: grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py (from rev 6476,
grc/trunk/src/SignalBlockDefs/Sinks.py)
===================================================================
--- grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py
(rev 0)
+++ grc/tags/grc_0.69/src/SignalBlockDefs/Sinks.py 2007-09-20 01:49:24 UTC
(rev 6483)
@@ -0,0 +1,144 @@
+"""
+Copyright 2007 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion 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 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion 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
+"""
address@hidden SignalBlockDefs.Sinks
+#Various data sinks.
address@hidden Josh Blum
+
+from DataTypes import *
+from gnuradio import gr
+from SignalBlockConstants import *
+from Constants import DEFAULT_FILE_PATH,MUTEX
+
+def NullSink(sb):
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''\
+If the data stream is not throttled, the null sink will use 100% CPU. \
+Manually connect a throttle to the null sink to save the CPU.''')
+ return sb, lambda fg, type, vlen:
gr.null_sink(type.parse().get_num_bytes()*vlen.parse())
+
+def FileSink(sb):
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('File Path', FileSave(DEFAULT_FILE_PATH))
+ sb.add_param('Vector Length', vlen)
+ sb.set_docs('''\
+If the data stream is not throttled, the file sink will use 100% CPU. \
+Manually connect a throttle to the file sink to save the CPU.''')
+ return sb, lambda fg, type, file_path, vlen:
gr.file_sink(type.parse().get_num_bytes()*vlen.parse(), file_path.parse())
+
+def UDPSink(sb):
+ fcn = gr.udp_sink
+ type = Enum(all_choices, 1)
+ vlen = Int(1, min=1)
+ sb.add_input_socket('in', Variable(type), vlen=vlen)
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Source Addr', String(''))
+ sb.add_param('Source Port', Short(default_udp_port, min=1))
+ sb.add_param('Destination Addr', String(''))
+ sb.add_param('Destination Port', Short(default_udp_port, min=1))
+ sb.add_param('Payload Size', Int(512, min=1))
+ sb.add_param('Vector Length', vlen)
+ return sb, lambda fg, type, s_addr, s_port, d_addr, d_port, size, vlen:
fcn(
+ type.parse().get_num_bytes()*vlen.parse(),
+ s_addr.parse(), s_port.parse(),
+ d_addr.parse(), d_port.parse(),
+ size.parse())
+
+#######################################################################################
+## Variable Sink definition and thread class
+#######################################################################################
+
+import threading
+import Variables
+import numpy
+
+class VariableSinkThread(threading.Thread):
+ """
+ This thread will read the vector sink,
+ write the numeric value back to the variable,
+ and re-parse the flow graph's callbacks.
+ """
+ def __init__(self, fg, var_key, msgq):
+ """!
+ VariableSinkThread constructor.
+ @param fg the gr flow graph
+ @param var_key the variable key
+ @param msgq the message queue
+ """
+ self.fg = fg
+ self.var_key = var_key
+ self.msgq = msgq
+ threading.Thread.__init__(self)
+ self.setDaemon(1)
+ self.keep_running = True
+ self.start()
+ print 'Created variable sink thread for variable "%s".'%var_key
+
+ def run(self):
+ """
+ In an endless while loop: read the vector sink,
+ write to the variable, and parse the callbacks.
+ """
+ while self.keep_running:
+ msg = self.msgq.delete_head() # blocking read of
message queue
+ itemsize = int(msg.arg1())
+ nitems = int(msg.arg2())
+ s = msg.to_string() # get the body of the
msg as a string
+ # There may be more than one number in the message.
+ # If so, we take only the last one
+ if nitems > 1:
+ start = itemsize * (nitems - 1)
+ s = s[start:start+itemsize]
+ # parse the data to a complex or float/int string
#
+ complex_data = numpy.fromstring (s, numpy.float32)
+ if len(complex_data) == 2: new_value = "%f +
%fj"%(complex_data[0], complex_data[1])
+ else: new_value = "%f"%(complex_data[0],)
+ # write the new value #
+ Variables.reregister(self.var_key, new_value)
+ # parse the call backs #
+ self.fg.parse_callbacks()
+
+def VariableSink(sb):
+ type = Enum(all_choices, 1)
+ sb.add_input_socket('in', Variable(type))
+ sb.add_param('Type', type, False, type=True)
+ sb.add_param('Variable', VariableKeySelector())
+ sb.add_param('Samp Rate', Float(default_samp_rate))
+ sb.set_docs('''\
+A thread reads a message sink and writes to the variable. \
+The variable cannot have a range. \
+The variable must be specified using its name without the "$" symbol. \
+The variable sink has a throttle automatically attatched to it at runtime to
save the CPU.''')
+ def make(fg, type, var_key, samp_rate):
+ msgq = gr.msg_queue(DEFAULT_QUEUE_LIMIT)
+ item_size = type.parse().get_num_bytes()
+ block = gr.message_sink(item_size, msgq, True)
+ var_sink_thread = VariableSinkThread(fg, var_key.parse(), msgq)
+ throttle = gr.throttle(item_size, samp_rate.parse())
+ fg.connect(throttle, block)
+ return throttle
+ return sb, make
+
+
\ No newline at end of file
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r6483 - in grc/tags: . grc_0.69 grc_0.69/examples grc_0.69/notes grc_0.69/src grc_0.69/src/Graphics grc_0.69/src/SignalBlockDefs,
jblum <=