summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
Diffstat (limited to 'grc')
-rw-r--r--grc/Makefile.inc4
-rw-r--r--grc/base/Block.py41
-rw-r--r--grc/base/Element.py23
-rw-r--r--grc/base/FlowGraph.py28
-rw-r--r--grc/base/Param.py134
-rw-r--r--grc/base/Platform.py5
-rw-r--r--grc/base/Port.py32
-rw-r--r--grc/blocks/Makefile.am2
-rw-r--r--grc/blocks/band_pass_filter.xml19
-rw-r--r--grc/blocks/band_reject_filter.xml19
-rw-r--r--grc/blocks/block_tree.xml2
-rw-r--r--grc/blocks/gr_noise_source_x.xml2
-rw-r--r--grc/blocks/gr_sig_source_x.xml2
-rw-r--r--grc/blocks/high_pass_filter.xml19
-rw-r--r--grc/blocks/low_pass_filter.xml19
-rw-r--r--grc/blocks/options.xml9
-rw-r--r--grc/blocks/pad_sink.xml3
-rw-r--r--grc/blocks/pad_source.xml6
-rw-r--r--grc/blocks/parameter.xml9
-rw-r--r--grc/blocks/virtual_sink.xml21
-rw-r--r--grc/blocks/virtual_source.xml21
-rw-r--r--grc/blocks/wxgui_fftsink2.xml7
-rw-r--r--grc/blocks/wxgui_waterfallsink2.xml7
-rw-r--r--grc/gui/ActionHandler.py10
-rw-r--r--grc/gui/Actions.py4
-rw-r--r--grc/gui/Bars.py2
-rw-r--r--grc/gui/Block.py8
-rw-r--r--grc/gui/Dialogs.py4
-rw-r--r--grc/gui/FlowGraph.py2
-rw-r--r--grc/gui/Param.py77
-rw-r--r--grc/gui/Platform.py32
-rw-r--r--grc/gui/Port.py2
-rw-r--r--grc/python/Block.py14
-rw-r--r--grc/python/Connection.py9
-rw-r--r--grc/python/FlowGraph.py20
-rw-r--r--grc/python/Param.py54
-rw-r--r--grc/python/Platform.py9
-rw-r--r--grc/python/Port.py93
-rw-r--r--grc/python/flow_graph.tmpl44
-rw-r--r--grc/todo.txt7
40 files changed, 477 insertions, 348 deletions
diff --git a/grc/Makefile.inc b/grc/Makefile.inc
index 96ee11b67..c45d1ce1f 100644
--- a/grc/Makefile.inc
+++ b/grc/Makefile.inc
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -20,5 +20,5 @@
#
include $(top_srcdir)/Makefile.common
-grc_src_prefix = $(pythondir)/gnuradio/grc
+grc_src_prefix = $(pkgpythondir)/grc
grc_blocksdir = $(pkgdatadir)/grc/blocks
diff --git a/grc/base/Block.py b/grc/base/Block.py
index d5e104785..fc501205f 100644
--- a/grc/base/Block.py
+++ b/grc/base/Block.py
@@ -47,7 +47,9 @@ class TemplateArg(UserDict):
return self._param.get_evaluated()
def _get_keys(lst): return [elem.get_key() for elem in lst]
-def _get_elem(lst, key): return lst[_get_keys(lst).index(key)]
+def _get_elem(lst, key):
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Block(Element):
@@ -72,16 +74,16 @@ class Block(Element):
self._params = list()
#add the id param
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'ID',
'key': 'id',
'type': 'id',
})
))
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'Enabled',
'key': '_enabled',
'type': 'raw',
@@ -89,7 +91,7 @@ class Block(Element):
'hide': 'all',
})
))
- for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
+ for param in map(lambda n: self.get_parent().get_parent().Param(block=self, n=n), params):
key = param.get_key()
#test against repeated keys
try: assert key not in self.get_param_keys()
@@ -98,7 +100,7 @@ class Block(Element):
self.get_params().append(param)
#create the source objects
self._sources = list()
- for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
+ for source in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='source'), sources):
key = source.get_key()
#test against repeated keys
try: assert key not in self.get_source_keys()
@@ -107,21 +109,13 @@ class Block(Element):
self.get_sources().append(source)
#create the sink objects
self._sinks = list()
- for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), sinks):
+ for sink in map(lambda n: self.get_parent().get_parent().Port(block=self, n=n, dir='sink'), sinks):
key = sink.get_key()
#test against repeated keys
try: assert key not in self.get_sink_keys()
except AssertionError: raise Exception, 'Key "%s" already exists in sinks'%key
#store the port
self.get_sinks().append(sink)
- #begin the testing
- self.test()
-
- def test(self):
- """
- Call test on all children.
- """
- map(lambda c: c.test(), self.get_params() + self.get_sinks() + self.get_sources())
def get_enabled(self):
"""
@@ -138,18 +132,25 @@ class Block(Element):
"""
self.get_param('_enabled').set_value(str(enabled))
+ def rewrite(self):
+ """
+ Rewrite critical structures.
+ Call rewrite on all sub elements.
+ """
+ Element.rewrite(self)
+ for elem in self.get_ports() + self.get_params(): elem.rewrite()
+
def validate(self):
"""
Validate the block.
All ports and params must be valid.
All checks must evaluate to true.
+ Validate the params, ports, and the connections to this block.
"""
Element.validate(self)
for c in self.get_params() + self.get_ports() + self.get_connections():
- try:
- c.validate()
- assert c.is_valid()
- except AssertionError:
+ c.validate()
+ if not c.is_valid():
for msg in c.get_error_messages():
self.add_error_message('>>> %s:\n\t%s'%(c, msg))
diff --git a/grc/base/Element.py b/grc/base/Element.py
index 16000c46c..43cee886c 100644
--- a/grc/base/Element.py
+++ b/grc/base/Element.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -21,14 +21,6 @@ class Element(object):
def __init__(self, parent=None):
self._parent = parent
- self.flag()
-
- def test(self):
- """
- Test the element against failures.
- Overload this method in sub-classes.
- """
- pass
##################################################
# Element Validation API
@@ -38,22 +30,13 @@ class Element(object):
def add_error_message(self, msg): self._error_messages.append(msg)
def get_error_messages(self): return self._error_messages
+ def rewrite(self): pass
+
def get_enabled(self): return True
def get_parent(self): return self._parent
##############################################
- ## Update flagging
- ##############################################
- def is_flagged(self): return self._flag
- def flag(self):
- self._flag = True
- if self.get_parent(): self.get_parent().flag()
- def deflag(self):
- self._flag = False
- if self.get_parent(): self.get_parent().deflag()
-
- ##############################################
## Type testing methods
##############################################
def is_element(self): return True
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
index ea489e948..b24f13b09 100644
--- a/grc/base/FlowGraph.py
+++ b/grc/base/FlowGraph.py
@@ -102,7 +102,6 @@ class FlowGraph(Element):
@param key the block key
@return the new block or None if not found
"""
- self.flag()
if key not in self.get_parent().get_block_keys(): return None
block = self.get_parent().get_new_block(self, key)
self.get_elements().append(block)
@@ -116,8 +115,7 @@ class FlowGraph(Element):
@throw Exception bad connection
@return the new connection
"""
- self.flag()
- connection = self.get_parent().Connection(self, porta, portb)
+ connection = self.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
self.get_elements().append(connection)
return connection
@@ -128,7 +126,6 @@ class FlowGraph(Element):
If the element is a block, remove its connections.
If the element is a connection, just remove the connection.
"""
- self.flag()
if element not in self.get_elements(): return
#found a port, set to parent signal block
if element.is_port():
@@ -147,17 +144,25 @@ class FlowGraph(Element):
"""
raise NotImplementedError
+ def rewrite(self):
+ """
+ Rewrite critical structures.
+ Call rewrite on all sub elements.
+ """
+ Element.rewrite(self)
+ for elem in self.get_elements(): elem.rewrite()
+
def validate(self):
"""
Validate the flow graph.
- All connections and blocks must be valid.
+ Validate only the blocks.
+ Connections will be validated within the blocks.
"""
Element.validate(self)
- for c in self.get_elements():
- try:
- c.validate()
- assert c.is_valid()
- except AssertionError: self.add_error_message('Element "%s" is not valid.'%c)
+ for c in self.get_blocks():
+ c.validate()
+ if not c.is_valid():
+ self.add_error_message('Element "%s" is not valid.'%c)
##############################################
## Import/Export Methods
@@ -198,7 +203,7 @@ class FlowGraph(Element):
#only load the block when the block key was valid
if block: block.import_data(block_n)
else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent()))
- self.validate() #validate all blocks before connections are made (in case of nports)
+ self.rewrite() #rewrite all blocks before connections are made (ex: nports)
#build the connections
for connection_n in connections_n:
#try to make the connection
@@ -225,3 +230,4 @@ class FlowGraph(Element):
#build the connection
self.connect(source, sink)
except AssertionError: Messages.send_error_load('Connection between %s(%s) and %s(%s) could not be made.'%(source_block_id, source_key, sink_block_id, sink_key))
+ self.rewrite() #global rewrite
diff --git a/grc/base/Param.py b/grc/base/Param.py
index 93c1c52bd..e56eac36e 100644
--- a/grc/base/Param.py
+++ b/grc/base/Param.py
@@ -19,74 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from . import odict
from Element import Element
-import pygtk
-pygtk.require('2.0')
-import gtk
-class InputParam(gtk.HBox):
- """The base class for an input parameter inside the input parameters dialog."""
-
- def __init__(self, param, _handle_changed):
- gtk.HBox.__init__(self)
- self.param = param
- self._handle_changed = _handle_changed
- self.label = gtk.Label('') #no label, markup is added by set_markup
- self.label.set_size_request(150, -1)
- self.pack_start(self.label, False)
- self.set_markup = lambda m: self.label.set_markup(m)
- self.tp = None
- def set_color(self, color): pass
-
-class EntryParam(InputParam):
- """Provide an entry box for strings and numbers."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self.entry = input = gtk.Entry()
- input.set_text(self.param.get_value())
- input.connect('changed', self._handle_changed)
- self.pack_start(input, True)
- self.get_text = input.get_text
- #tool tip
- self.tp = gtk.Tooltips()
- self.tp.set_tip(self.entry, '')
- self.tp.enable()
- def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
-
-class EnumParam(InputParam):
- """Provide an entry box for Enum types with a drop down menu."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- self._input.connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
-
-class EnumEntryParam(InputParam):
- """Provide an entry box and drop down menu for Raw Enum types."""
-
- def __init__(self, *args, **kwargs):
- InputParam.__init__(self, *args, **kwargs)
- self._input = gtk.combo_box_entry_new_text()
- for option in self.param.get_options(): self._input.append_text(option.get_name())
- try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
- except:
- self._input.set_active(-1)
- self._input.get_child().set_text(self.param.get_value())
- self._input.connect('changed', self._handle_changed)
- self._input.get_child().connect('changed', self._handle_changed)
- self.pack_start(self._input, False)
- def get_text(self):
- if self._input.get_active() == -1: return self._input.get_child().get_text()
- return self.param.get_option_keys()[self._input.get_active()]
- def set_color(self, color):
- if self._input.get_active() == -1: #custom entry, use color
- self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
- else: #from enum, make white background
- self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
+def _get_keys(lst): return [elem.get_key() for elem in lst]
+def _get_elem(lst, key):
+ try: return lst[_get_keys(lst).index(key)]
+ except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
class Option(Element):
@@ -123,15 +60,11 @@ class Option(Element):
class Param(Element):
- ##possible param types
- TYPES = ['enum', 'raw']
-
def __init__(self, block, n):
"""
Make a new param from nested data.
@param block the parent element
@param n the nested odict
- @return a new param
"""
#grab the data
self._name = n.find('name')
@@ -142,22 +75,22 @@ class Param(Element):
#build the param
Element.__init__(self, block)
#create the Option objects from the n data
- self._options = odict()
- for option in map(lambda o: Option(self, o), n.findall('option')):
+ self._options = list()
+ for option in map(lambda o: Option(param=self, n=o), n.findall('option')):
key = option.get_key()
#test against repeated keys
try: assert key not in self.get_option_keys()
except AssertionError: raise Exception, 'Key "%s" already exists in options'%key
#store the option
- self._options[key] = option
+ self.get_options().append(option)
#test the enum options
if self.is_enum():
#test against options with identical keys
- try: assert len(set(self.get_option_keys())) == len(self._options)
+ try: assert len(set(self.get_option_keys())) == len(self.get_options())
except AssertionError: raise Exception, 'Options keys "%s" are not unique.'%self.get_option_keys()
#test against inconsistent keys in options
- opt_keys = self._options.values()[0].get_opt_keys()
- for option in self._options.values():
+ opt_keys = self.get_options()[0].get_opt_keys()
+ for option in self.get_options():
try: assert set(opt_keys) == set(option.get_opt_keys())
except AssertionError: raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
#if a value is specified, it must be in the options keys
@@ -165,14 +98,6 @@ class Param(Element):
try: assert self.get_value() in self.get_option_keys()
except AssertionError: raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
else: self._value = value or ''
- #begin the testing
- self.test()
-
- def test(self):
- """
- call test on all children
- """
- map(lambda c: c.test(), self.get_options())
def validate(self):
"""
@@ -180,7 +105,7 @@ class Param(Element):
The value must be evaluated and type must a possible type.
"""
Element.validate(self)
- try: assert self.get_type() in self.TYPES
+ try: assert self.get_type() in self.get_types()
except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
def get_evaluated(self): raise NotImplementedError
@@ -192,12 +117,19 @@ class Param(Element):
"""
raise NotImplementedError
+ def get_types(self):
+ """
+ Get a list of all possible param types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
def get_color(self): return '#FFFFFF'
def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
def is_param(self): return True
def get_name(self): return self._name
def get_key(self): return self._key
- def get_hide(self): return self.get_parent().resolve_dependencies(self._hide)
+ def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
def get_value(self):
value = self._value
@@ -206,9 +138,7 @@ class Param(Element):
self.set_value(value)
return value
- def set_value(self, value):
- self.flag()
- self._value = str(value) #must be a string
+ def set_value(self, value): self._value = str(value) #must be a string
def get_type(self): return self.get_parent().resolve_dependencies(self._type)
def is_enum(self): return self._type == 'enum'
@@ -223,31 +153,19 @@ class Param(Element):
if self.is_enum(): return self.get_option(self.get_value()).get_name()
return self.get_value()
- def get_input_class(self):
- """
- Get the graphical gtk class to represent this parameter.
- An enum requires and combo parameter.
- A non-enum with options gets a combined entry/combo parameter.
- All others get a standard entry parameter.
- @return gtk input class
- """
- if self.is_enum(): return EnumParam
- if self.get_options(): return EnumEntryParam
- return EntryParam
-
##############################################
# Access Options
##############################################
- def get_option_keys(self): return self._options.keys()
- def get_option(self, key): return self._options[key]
- def get_options(self): return self._options.values()
+ def get_option_keys(self): return _get_keys(self.get_options())
+ def get_option(self, key): return _get_elem(self.get_options(), key)
+ def get_options(self): return self._options
##############################################
# Access Opts
##############################################
- def get_opt_keys(self): return self._options[self.get_value()].get_opt_keys()
- def get_opt(self, key): return self._options[self.get_value()].get_opt(key)
- def get_opts(self): return self._options[self.get_value()].get_opts()
+ def get_opt_keys(self): return self.get_option(self.get_value()).get_opt_keys()
+ def get_opt(self, key): return self.get_option(self.get_value()).get_opt(key)
+ def get_opts(self): return self.get_option(self.get_value()).get_opts()
##############################################
## Import/Export Methods
diff --git a/grc/base/Platform.py b/grc/base/Platform.py
index 02d6d2319..51a3b2f87 100644
--- a/grc/base/Platform.py
+++ b/grc/base/Platform.py
@@ -146,7 +146,7 @@ class Platform(_Element):
def is_platform(self): return True
- def get_new_flow_graph(self): return self.FlowGraph(self)
+ def get_new_flow_graph(self): return self.FlowGraph(platform=self)
def get_generator(self): return self._generator
@@ -171,6 +171,5 @@ class Platform(_Element):
FlowGraph = _FlowGraph
Connection = _Connection
Block = _Block
- Source = _Port
- Sink = _Port
+ Port = _Port
Param = _Param
diff --git a/grc/base/Port.py b/grc/base/Port.py
index f4e8e5e1f..494ea894f 100644
--- a/grc/base/Port.py
+++ b/grc/base/Port.py
@@ -21,25 +21,20 @@ from Element import Element
class Port(Element):
- ##possible port types
- TYPES = []
-
- def __init__(self, block, n):
+ def __init__(self, block, n, dir):
"""
Make a new port from nested data.
@param block the parent element
@param n the nested odict
- @return a new port
+ @param dir the direction source or sink
"""
- #grab the data
- name = n['name']
- key = n['key']
- type = n['type']
#build the port
Element.__init__(self, block)
- self._name = name
- self._key = key
- self._type = type
+ #grab the data
+ self._name = n['name']
+ self._key = n['key']
+ self._type = n['type']
+ self._dir = dir
def validate(self):
"""
@@ -47,7 +42,7 @@ class Port(Element):
The port must be non-empty and type must a possible type.
"""
Element.validate(self)
- try: assert self.get_type() in self.TYPES
+ try: assert self.get_type() in self.get_types()
except AssertionError: self.add_error_message('Type "%s" is not a possible type.'%self.get_type())
def __str__(self):
@@ -56,12 +51,19 @@ class Port(Element):
if self.is_sink():
return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
+ def get_types(self):
+ """
+ Get a list of all possible port types.
+ @throw NotImplementedError
+ """
+ raise NotImplementedError
+
def is_port(self): return True
def get_color(self): return '#FFFFFF'
def get_name(self): return self._name
def get_key(self): return self._key
- def is_sink(self): return self in self.get_parent().get_sinks()
- def is_source(self): return self in self.get_parent().get_sources()
+ def is_sink(self): return self._dir == 'sink'
+ def is_source(self): return self._dir == 'source'
def get_type(self): return self.get_parent().resolve_dependencies(self._type)
def get_connections(self):
diff --git a/grc/blocks/Makefile.am b/grc/blocks/Makefile.am
index caae6ce75..32ddc6567 100644
--- a/grc/blocks/Makefile.am
+++ b/grc/blocks/Makefile.am
@@ -218,6 +218,8 @@ dist_ourdata_DATA = \
variable_slider.xml \
variable_static_text.xml \
variable_text_box.xml \
+ virtual_sink.xml \
+ virtual_source.xml \
wxgui_constellationsink2.xml \
wxgui_fftsink2.xml \
wxgui_histosink2.xml \
diff --git a/grc/blocks/band_pass_filter.xml b/grc/blocks/band_pass_filter.xml
index e2e9acf4e..af083473d 100644
--- a/grc/blocks/band_pass_filter.xml
+++ b/grc/blocks/band_pass_filter.xml
@@ -10,8 +10,8 @@
<import>from gnuradio import gr</import>
<import>from gnuradio.gr import firdes</import>
<make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.$(type.fcn)(
- $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make>
- <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback>
+ $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make>
+ <callback>set_taps(firdes.$(type.fcn)($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback>
<param>
<name>FIR Type</name>
<key>type</key>
@@ -118,27 +118,28 @@
</param>
<param>
<name>Window</name>
- <key>window</key>
- <type>enum</type>
+ <key>win</key>
+ <value>firdes.WIN_HAMMING</value>
+ <type>int</type>
<option>
<name>Hamming</name>
- <key>WIN_HAMMING</key>
+ <key>firdes.WIN_HAMMING</key>
</option>
<option>
<name>Hann</name>
- <key>WIN_HANN</key>
+ <key>firdes.WIN_HANN</key>
</option>
<option>
<name>Blackman</name>
- <key>WIN_BLACKMAN</key>
+ <key>firdes.WIN_BLACKMAN</key>
</option>
<option>
<name>Rectangular</name>
- <key>WIN_RECTANGULAR</key>
+ <key>firdes.WIN_RECTANGULAR</key>
</option>
<option>
<name>Kaiser</name>
- <key>WIN_KAISER</key>
+ <key>firdes.WIN_KAISER</key>
</option>
</param>
<param>
diff --git a/grc/blocks/band_reject_filter.xml b/grc/blocks/band_reject_filter.xml
index 3b58f0b51..dd5e7a9d7 100644
--- a/grc/blocks/band_reject_filter.xml
+++ b/grc/blocks/band_reject_filter.xml
@@ -10,8 +10,8 @@
<import>from gnuradio import gr</import>
<import>from gnuradio.gr import firdes</import>
<make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.band_reject(
- $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</make>
- <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, firdes.$window, $beta))</callback>
+ $gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</make>
+ <callback>set_taps(firdes.band_reject($gain, $samp_rate, $low_cutoff_freq, $high_cutoff_freq, $width, $win, $beta))</callback>
<param>
<name>FIR Type</name>
<key>type</key>
@@ -84,27 +84,28 @@
</param>
<param>
<name>Window</name>
- <key>window</key>
- <type>enum</type>
+ <key>win</key>
+ <value>firdes.WIN_HAMMING</value>
+ <type>int</type>
<option>
<name>Hamming</name>
- <key>WIN_HAMMING</key>
+ <key>firdes.WIN_HAMMING</key>
</option>
<option>
<name>Hann</name>
- <key>WIN_HANN</key>
+ <key>firdes.WIN_HANN</key>
</option>
<option>
<name>Blackman</name>
- <key>WIN_BLACKMAN</key>
+ <key>firdes.WIN_BLACKMAN</key>
</option>
<option>
<name>Rectangular</name>
- <key>WIN_RECTANGULAR</key>
+ <key>firdes.WIN_RECTANGULAR</key>
</option>
<option>
<name>Kaiser</name>
- <key>WIN_KAISER</key>
+ <key>firdes.WIN_KAISER</key>
</option>
</param>
<param>
diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml
index 5b45466f5..5a989cc01 100644
--- a/grc/blocks/block_tree.xml
+++ b/grc/blocks/block_tree.xml
@@ -22,6 +22,7 @@
<block>gr_wavfile_source</block>
<block>gr_message_source</block>
<block>pad_source</block>
+ <block>virtual_source</block>
</cat>
<cat>
<name>Sinks</name>
@@ -35,6 +36,7 @@
<block>gr_wavfile_sink</block>
<block>gr_message_sink</block>
<block>pad_sink</block>
+ <block>virtual_sink</block>
</cat>
<cat>
<name>Graphical Sinks</name>
diff --git a/grc/blocks/gr_noise_source_x.xml b/grc/blocks/gr_noise_source_x.xml
index 4fcef5148..4789b4400 100644
--- a/grc/blocks/gr_noise_source_x.xml
+++ b/grc/blocks/gr_noise_source_x.xml
@@ -40,7 +40,7 @@
<name>Noise Type</name>
<key>noise_type</key>
<value>gr.GR_GAUSSIAN</value>
- <type>raw</type>
+ <type>int</type>
<option>
<name>Uniform</name>
<key>gr.GR_UNIFORM</key>
diff --git a/grc/blocks/gr_sig_source_x.xml b/grc/blocks/gr_sig_source_x.xml
index c329dba67..644cf52d0 100644
--- a/grc/blocks/gr_sig_source_x.xml
+++ b/grc/blocks/gr_sig_source_x.xml
@@ -53,7 +53,7 @@
<name>Waveform</name>
<key>waveform</key>
<value>gr.GR_COS_WAVE</value>
- <type>raw</type>
+ <type>int</type>
<option>
<name>Constant</name>
<key>gr.GR_CONST_WAVE</key>
diff --git a/grc/blocks/high_pass_filter.xml b/grc/blocks/high_pass_filter.xml
index 5be916fa9..0e29cbb36 100644
--- a/grc/blocks/high_pass_filter.xml
+++ b/grc/blocks/high_pass_filter.xml
@@ -10,8 +10,8 @@
<import>from gnuradio import gr</import>
<import>from gnuradio.gr import firdes</import>
<make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.high_pass(
- $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make>
- <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback>
+ $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make>
+ <callback>set_taps(firdes.high_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback>
<param>
<name>FIR Type</name>
<key>type</key>
@@ -79,27 +79,28 @@
</param>
<param>
<name>Window</name>
- <key>window</key>
- <type>enum</type>
+ <key>win</key>
+ <value>firdes.WIN_HAMMING</value>
+ <type>int</type>
<option>
<name>Hamming</name>
- <key>WIN_HAMMING</key>
+ <key>firdes.WIN_HAMMING</key>
</option>
<option>
<name>Hann</name>
- <key>WIN_HANN</key>
+ <key>firdes.WIN_HANN</key>
</option>
<option>
<name>Blackman</name>
- <key>WIN_BLACKMAN</key>
+ <key>firdes.WIN_BLACKMAN</key>
</option>
<option>
<name>Rectangular</name>
- <key>WIN_RECTANGULAR</key>
+ <key>firdes.WIN_RECTANGULAR</key>
</option>
<option>
<name>Kaiser</name>
- <key>WIN_KAISER</key>
+ <key>firdes.WIN_KAISER</key>
</option>
</param>
<param>
diff --git a/grc/blocks/low_pass_filter.xml b/grc/blocks/low_pass_filter.xml
index 27120c047..26435fd4d 100644
--- a/grc/blocks/low_pass_filter.xml
+++ b/grc/blocks/low_pass_filter.xml
@@ -10,8 +10,8 @@
<import>from gnuradio import gr</import>
<import>from gnuradio.gr import firdes</import>
<make>gr.$(type)(#if str($type).startswith('interp') then $interp else $decim#, firdes.low_pass(
- $gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</make>
- <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, firdes.$window, $beta))</callback>
+ $gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</make>
+ <callback>set_taps(firdes.low_pass($gain, $samp_rate, $cutoff_freq, $width, $win, $beta))</callback>
<param>
<name>FIR Type</name>
<key>type</key>
@@ -79,27 +79,28 @@
</param>
<param>
<name>Window</name>
- <key>window</key>
- <type>enum</type>
+ <key>win</key>
+ <value>firdes.WIN_HAMMING</value>
+ <type>int</type>
<option>
<name>Hamming</name>
- <key>WIN_HAMMING</key>
+ <key>firdes.WIN_HAMMING</key>
</option>
<option>
<name>Hann</name>
- <key>WIN_HANN</key>
+ <key>firdes.WIN_HANN</key>
</option>
<option>
<name>Blackman</name>
- <key>WIN_BLACKMAN</key>
+ <key>firdes.WIN_BLACKMAN</key>
</option>
<option>
<name>Rectangular</name>
- <key>WIN_RECTANGULAR</key>
+ <key>firdes.WIN_RECTANGULAR</key>
</option>
<option>
<name>Kaiser</name>
- <key>WIN_KAISER</key>
+ <key>firdes.WIN_KAISER</key>
</option>
</param>
<param>
diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml
index 18d6e2f0c..1798a69f8 100644
--- a/grc/blocks/options.xml
+++ b/grc/blocks/options.xml
@@ -9,16 +9,17 @@
<block>
<name>Options</name>
<key>options</key>
- <import>from gnuradio import gr
-#if $generate_options() == 'wx_gui'
+ <import>from gnuradio import gr</import>
+ <import>from gnuradio.gr import firdes</import>
+ <import>#if $generate_options() == 'wx_gui'
from grc_gnuradio import wxgui as grc_wxgui
import wx
#end if
#if $generate_options() != 'hb'
from optparse import OptionParser
from gnuradio.eng_option import eng_option
-#end if
-</import>
+from gnuradio import eng_notation
+#end if</import>
<make></make>
<callback>if $run: self.start()
else: self.stop(); self.wait()</callback>
diff --git a/grc/blocks/pad_sink.xml b/grc/blocks/pad_sink.xml
index 477f2ad13..734526793 100644
--- a/grc/blocks/pad_sink.xml
+++ b/grc/blocks/pad_sink.xml
@@ -59,10 +59,7 @@
<nports>$nports</nports>
</sink>
<doc>
-This is a sink pad block for creating hierarchical flow graphs. \
The inputs of this block will become the outputs to this flow graph when it is instantiated as a hierarchical block. \
Limit one sink pad block per flow graph.
-
-Remember to set the generate options to hier block.
</doc>
</block>
diff --git a/grc/blocks/pad_source.xml b/grc/blocks/pad_source.xml
index b6ef2c55d..f44d96238 100644
--- a/grc/blocks/pad_source.xml
+++ b/grc/blocks/pad_source.xml
@@ -59,10 +59,8 @@
<nports>$nports</nports>
</source>
<doc>
-This is a source pad block for creating hierarchical flow graphs. \
The outputs of this block will become the inputs to this flow graph when it is instantiated as a hierarchical block. \
-Limit one source pad block per flow graph.
-
-Remember to set the generate options to hier block.
+Limit one source pad block per flow graph. \
+The "pad sink id" will be ignored in this mode.
</doc>
</block>
diff --git a/grc/blocks/parameter.xml b/grc/blocks/parameter.xml
index 5d08c4b39..e35b8f4d1 100644
--- a/grc/blocks/parameter.xml
+++ b/grc/blocks/parameter.xml
@@ -45,7 +45,7 @@
</option>
<option>
<name>Int</name>
- <key>int</key>
+ <key>intx</key>
<opt>type:int</opt>
</option>
<option>
@@ -58,6 +58,13 @@
<key>string</key>
<opt>type:string</opt>
</option>
+ <!-- not supported yet in tmpl
+ <option>
+ <name>Boolean</name>
+ <key>bool</key>
+ <opt>type:bool</opt>
+ </option>
+ -->
</param>
<param>
<name>Short ID</name>
diff --git a/grc/blocks/virtual_sink.xml b/grc/blocks/virtual_sink.xml
new file mode 100644
index 000000000..35fb27e67
--- /dev/null
+++ b/grc/blocks/virtual_sink.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Virtual Sink
+###################################################
+ -->
+<block>
+ <name>Virtual Sink</name>
+ <key>virtual_sink</key>
+ <make></make>
+ <param>
+ <name>Stream ID</name>
+ <key>stream_id</key>
+ <value></value>
+ <type>stream_id</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type></type>
+ </sink>
+</block>
diff --git a/grc/blocks/virtual_source.xml b/grc/blocks/virtual_source.xml
new file mode 100644
index 000000000..e0c775449
--- /dev/null
+++ b/grc/blocks/virtual_source.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Virtual Source
+###################################################
+ -->
+<block>
+ <name>Virtual Source</name>
+ <key>virtual_source</key>
+ <make></make>
+ <param>
+ <name>Stream ID</name>
+ <key>stream_id</key>
+ <value></value>
+ <type>stream_id</type>
+ </param>
+ <source>
+ <name>out</name>
+ <type></type>
+ </source>
+</block>
diff --git a/grc/blocks/wxgui_fftsink2.xml b/grc/blocks/wxgui_fftsink2.xml
index faeca37e3..6f19f1aa4 100644
--- a/grc/blocks/wxgui_fftsink2.xml
+++ b/grc/blocks/wxgui_fftsink2.xml
@@ -15,6 +15,7 @@ fftsink2.$(type.fcn)(
y_per_div=$y_per_div,
y_divs=$y_divs,
ref_level=$ref_level,
+ ref_scale=$ref_scale,
sample_rate=$samp_rate,
fft_size=$fft_size,
fft_rate=$fft_rate,
@@ -103,6 +104,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos()))))
<type>real</type>
</param>
<param>
+ <name>Ref Scale (p2p)</name>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ <type>real</type>
+ </param>
+ <param>
<name>FFT Size</name>
<key>fft_size</key>
<value>1024</value>
diff --git a/grc/blocks/wxgui_waterfallsink2.xml b/grc/blocks/wxgui_waterfallsink2.xml
index 79ca356f7..35790f820 100644
--- a/grc/blocks/wxgui_waterfallsink2.xml
+++ b/grc/blocks/wxgui_waterfallsink2.xml
@@ -14,6 +14,7 @@ waterfallsink2.$(type.fcn)(
baseband_freq=$baseband_freq,
dynamic_range=$dynamic_range,
ref_level=$ref_level,
+ ref_scale=$ref_scale,
sample_rate=$samp_rate,
fft_size=$fft_size,
fft_rate=$fft_rate,
@@ -75,6 +76,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos()))))
<type>real</type>
</param>
<param>
+ <name>Ref Scale (p2p)</name>
+ <key>ref_scale</key>
+ <value>2.0</value>
+ <type>real</type>
+ </param>
+ <param>
<name>FFT Size</name>
<key>fft_size</key>
<value>512</value>
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index ff137f669..8f317d6a8 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -30,7 +30,6 @@ from threading import Thread
import Messages
from .. base import ParseXML
import random
-from Platform import Platform
from MainWindow import MainWindow
from ParamsDialog import ParamsDialog
import Dialogs
@@ -53,7 +52,6 @@ class ActionHandler:
@param platform platform module
"""
self.clipboard = None
- platform = Platform(platform)
for action in Actions.get_all_actions(): action.connect('activate', self._handle_actions)
#setup the main window
self.main_window = MainWindow(self.handle_states, platform)
@@ -133,7 +131,7 @@ class ActionHandler:
Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
- Actions.COLORS_WINDOW_DISPLAY,
+ Actions.TYPES_WINDOW_DISPLAY,
): Actions.get_action_from_name(action).set_sensitive(True)
if not self.init_file_paths:
self.init_file_paths = Preferences.files_open()
@@ -221,13 +219,11 @@ class ActionHandler:
elif state == Actions.PORT_CONTROLLER_INC:
if self.get_flow_graph().port_controller_modify_selected(1):
self.get_flow_graph().update()
- self.get_flow_graph().update() #2 times
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
elif state == Actions.PORT_CONTROLLER_DEC:
if self.get_flow_graph().port_controller_modify_selected(-1):
self.get_flow_graph().update()
- self.get_flow_graph().update() #2 times
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
self.get_page().set_saved(False)
##################################################
@@ -237,8 +233,8 @@ class ActionHandler:
Dialogs.AboutDialog(self.get_flow_graph().get_parent())
elif state == Actions.HELP_WINDOW_DISPLAY:
Dialogs.HelpDialog()
- elif state == Actions.COLORS_WINDOW_DISPLAY:
- Dialogs.ColorsDialog(self.get_flow_graph().get_parent())
+ elif state == Actions.TYPES_WINDOW_DISPLAY:
+ Dialogs.TypesDialog(self.get_flow_graph().get_parent())
##################################################
# Param Modifications
##################################################
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 3695e09ef..c3ef2711a 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -57,7 +57,7 @@ FLOW_GRAPH_KILL = 'flow graph kill'
FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture'
ABOUT_WINDOW_DISPLAY = 'about window display'
HELP_WINDOW_DISPLAY = 'help window display'
-COLORS_WINDOW_DISPLAY = 'colors window display'
+TYPES_WINDOW_DISPLAY = 'types window display'
######################################################################################################
# Action Key Map
@@ -132,7 +132,7 @@ _actions_list = (
gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE),
gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT),
gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP),
- gtk.Action(COLORS_WINDOW_DISPLAY, '_Colors', 'Color Mapping', gtk.STOCK_DIALOG_INFO),
+ gtk.Action(TYPES_WINDOW_DISPLAY, '_Types', 'Types Color Mapping', gtk.STOCK_DIALOG_INFO),
gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT),
gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE),
gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP),
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index e0c547eba..697d48a3c 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -88,7 +88,7 @@ MENU_BAR_LIST = (
]),
(gtk.Action('Help', '_Help', None, None), [
Actions.HELP_WINDOW_DISPLAY,
- Actions.COLORS_WINDOW_DISPLAY,
+ Actions.TYPES_WINDOW_DISPLAY,
None,
Actions.ABOUT_WINDOW_DISPLAY,
]),
diff --git a/grc/gui/Block.py b/grc/gui/Block.py
index 4add3aa19..0f3e511d8 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -44,8 +44,8 @@ class Block(Element):
"""
#add the position param
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'GUI Coordinate',
'key': '_coordinate',
'type': 'raw',
@@ -54,8 +54,8 @@ class Block(Element):
})
))
self.get_params().append(self.get_parent().get_parent().Param(
- self,
- odict({
+ block=self,
+ n=odict({
'name': 'GUI Rotation',
'key': '_rotation',
'type': 'raw',
diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py
index 8d764e28e..3cf617b92 100644
--- a/grc/gui/Dialogs.py
+++ b/grc/gui/Dialogs.py
@@ -98,8 +98,8 @@ COLORS_DIALOG_MARKUP_TMPL = """\
#end if
"""
-def ColorsDialog(platform): MessageDialogHelper(
+def TypesDialog(platform): MessageDialogHelper(
type=gtk.MESSAGE_INFO,
buttons=gtk.BUTTONS_CLOSE,
- title='Colors',
+ title='Types',
markup=Utils.parse_template(COLORS_DIALOG_MARKUP_TMPL, colors=platform.get_colors()))
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index f8028f199..5e645be72 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -291,8 +291,10 @@ class FlowGraph(Element):
def update(self):
"""
+ Do a global rewrite and validate.
Call update on all elements.
"""
+ self.rewrite()
self.validate()
for element in self.get_elements(): element.update()
diff --git a/grc/gui/Param.py b/grc/gui/Param.py
index a11fd9065..4955d3336 100644
--- a/grc/gui/Param.py
+++ b/grc/gui/Param.py
@@ -23,6 +23,71 @@ import pygtk
pygtk.require('2.0')
import gtk
+class InputParam(gtk.HBox):
+ """The base class for an input parameter inside the input parameters dialog."""
+
+ def __init__(self, param, _handle_changed):
+ gtk.HBox.__init__(self)
+ self.param = param
+ self._handle_changed = _handle_changed
+ self.label = gtk.Label('') #no label, markup is added by set_markup
+ self.label.set_size_request(150, -1)
+ self.pack_start(self.label, False)
+ self.set_markup = lambda m: self.label.set_markup(m)
+ self.tp = None
+ def set_color(self, color): pass
+
+class EntryParam(InputParam):
+ """Provide an entry box for strings and numbers."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self.entry = input = gtk.Entry()
+ input.set_text(self.param.get_value())
+ input.connect('changed', self._handle_changed)
+ self.pack_start(input, True)
+ self.get_text = input.get_text
+ #tool tip
+ self.tp = gtk.Tooltips()
+ self.tp.set_tip(self.entry, '')
+ self.tp.enable()
+ def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+
+class EnumParam(InputParam):
+ """Provide an entry box for Enum types with a drop down menu."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self._input = gtk.combo_box_new_text()
+ for option in self.param.get_options(): self._input.append_text(option.get_name())
+ self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+ self._input.connect('changed', self._handle_changed)
+ self.pack_start(self._input, False)
+ def get_text(self): return self.param.get_option_keys()[self._input.get_active()]
+
+class EnumEntryParam(InputParam):
+ """Provide an entry box and drop down menu for Raw Enum types."""
+
+ def __init__(self, *args, **kwargs):
+ InputParam.__init__(self, *args, **kwargs)
+ self._input = gtk.combo_box_entry_new_text()
+ for option in self.param.get_options(): self._input.append_text(option.get_name())
+ try: self._input.set_active(self.param.get_option_keys().index(self.param.get_value()))
+ except:
+ self._input.set_active(-1)
+ self._input.get_child().set_text(self.param.get_value())
+ self._input.connect('changed', self._handle_changed)
+ self._input.get_child().connect('changed', self._handle_changed)
+ self.pack_start(self._input, False)
+ def get_text(self):
+ if self._input.get_active() == -1: return self._input.get_child().get_text()
+ return self.param.get_option_keys()[self._input.get_active()]
+ def set_color(self, color):
+ if self._input.get_active() == -1: #custom entry, use color
+ self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
+ else: #from enum, make white background
+ self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse('#ffffff'))
+
PARAM_MARKUP_TMPL="""\
#set $foreground = $param.is_valid() and 'black' or 'red'
<span foreground="$foreground" font_desc="Sans 7.5"><b>$encode($param.get_name()): </b>$encode(repr($param))</span>"""
@@ -49,6 +114,18 @@ Error:
class Param(Element):
"""The graphical parameter."""
+ def get_input_class(self):
+ """
+ Get the graphical gtk class to represent this parameter.
+ An enum requires and combo parameter.
+ A non-enum with options gets a combined entry/combo parameter.
+ All others get a standard entry parameter.
+ @return gtk input class
+ """
+ if self.is_enum(): return EnumParam
+ if self.get_options(): return EnumEntryParam
+ return EntryParam
+
def update(self):
"""
Called when an external change occurs.
diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py
index a32b0209f..8f0aa533d 100644
--- a/grc/gui/Platform.py
+++ b/grc/gui/Platform.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,32 +17,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
-from FlowGraph import FlowGraph
-from Connection import Connection
-from Block import Block
-from Port import Port
-from Param import Param
+from Element import Element
-def conjoin_classes(name, c1, c2):
- exec("""
-class %s(c1, c2):
- def __init__(self, *args, **kwargs):
- c1.__init__(self, *args, **kwargs)
- c2.__init__(self, *args, **kwargs)
-"""%name, locals())
- return locals()[name]
-
-def Platform(platform):
- #combine with gui class
- for attr, value in (
- ('FlowGraph', FlowGraph),
- ('Connection', Connection),
- ('Block', Block),
- ('Source', Port),
- ('Sink', Port),
- ('Param', Param),
- ):
- old_value = getattr(platform, attr)
- c = conjoin_classes(attr, old_value, value)
- setattr(platform, attr, c)
- return platform
+class Platform(Element): pass
diff --git a/grc/gui/Port.py b/grc/gui/Port.py
index d1f36f8b9..6fc2c4b15 100644
--- a/grc/gui/Port.py
+++ b/grc/gui/Port.py
@@ -1,5 +1,5 @@
"""
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
diff --git a/grc/python/Block.py b/grc/python/Block.py
index 47fe13a3c..dd39b095d 100644
--- a/grc/python/Block.py
+++ b/grc/python/Block.py
@@ -18,10 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from .. base.Block import Block as _Block
+from .. gui.Block import Block as _GUIBlock
import extract_docs
import extract_category
-class Block(_Block):
+class Block(_Block, _GUIBlock):
+
+ def is_virtual_sink(self): return self.get_key() == 'virtual_sink'
+ def is_virtual_source(self): return self.get_key() == 'virtual_source'
##for make source to keep track of indexes
_source_count = 0
@@ -48,13 +52,13 @@ class Block(_Block):
flow_graph=flow_graph,
n=n,
)
+ _GUIBlock.__init__(self)
def validate(self):
"""
Validate this block.
Call the base class validate.
Evaluate the checks: each check must evaluate to True.
- Adjust the nports.
"""
_Block.validate(self)
#evaluate the checks
@@ -65,6 +69,12 @@ class Block(_Block):
try: assert check_eval
except AssertionError: self.add_error_message('Check "%s" failed.'%check)
except: self.add_error_message('Check "%s" did not evaluate.'%check)
+
+ def rewrite(self):
+ """
+ Add and remove ports to adjust for the nports.
+ """
+ _Block.rewrite(self)
#adjust nports
for get_ports, get_port in (
(self.get_sources, self.get_source),
diff --git a/grc/python/Connection.py b/grc/python/Connection.py
index 5eba9f24d..edc18841a 100644
--- a/grc/python/Connection.py
+++ b/grc/python/Connection.py
@@ -1,5 +1,5 @@
"""
-Copyright 2008 Free Software Foundation, Inc.
+Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
GNU Radio Companion is free software; you can redistribute it and/or
@@ -18,8 +18,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from .. base.Connection import Connection as _Connection
+from .. gui.Connection import Connection as _GUIConnection
-class Connection(_Connection):
+class Connection(_Connection, _GUIConnection):
+
+ def __init__(self, **kwargs):
+ _Connection.__init__(self, **kwargs)
+ _GUIConnection.__init__(self)
def is_msg(self):
return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
index 8cad8be49..6b2936c75 100644
--- a/grc/python/FlowGraph.py
+++ b/grc/python/FlowGraph.py
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import expr_utils
from .. base.FlowGraph import FlowGraph as _FlowGraph
+from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
from Block import Block
from Connection import Connection
import re
@@ -26,9 +27,13 @@ import re
_variable_matcher = re.compile('^(variable\w*)$')
_parameter_matcher = re.compile('^(parameter)$')
-class FlowGraph(_FlowGraph):
+class FlowGraph(_FlowGraph, _GUIFlowGraph):
+
+ def __init__(self, **kwargs):
+ _FlowGraph.__init__(self, **kwargs)
+ _GUIFlowGraph.__init__(self)
+ self._eval_cache = dict()
- _eval_cache = dict()
def _eval(self, code, namespace, namespace_hash):
"""
Evaluate the code with the given namespace.
@@ -109,6 +114,13 @@ class FlowGraph(_FlowGraph):
parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.get_enabled_blocks())
return parameters
+ def rewrite(self):
+ """
+ Flag the namespace to be renewed.
+ """
+ self._renew_eval_ns = True
+ _FlowGraph.rewrite(self)
+
def evaluate(self, expr):
"""
Evaluate the expression.
@@ -116,8 +128,8 @@ class FlowGraph(_FlowGraph):
@throw Exception bad expression
@return the evaluated data
"""
- if self.is_flagged():
- self.deflag()
+ if self._renew_eval_ns:
+ self._renew_eval_ns = False
#reload namespace
n = dict()
#load imports
diff --git a/grc/python/Param.py b/grc/python/Param.py
index f971d0c3f..e61779136 100644
--- a/grc/python/Param.py
+++ b/grc/python/Param.py
@@ -18,7 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
import expr_utils
-from .. base.Param import Param as _Param, EntryParam
+from .. base.Param import Param as _Param
+from .. gui.Param import Param as _GUIParam
+from .. gui.Param import EntryParam
import Constants
import numpy
import os
@@ -83,21 +85,24 @@ COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
INT_TYPES = tuple(INT_TYPES)
-class Param(_Param):
+class Param(_Param, _GUIParam):
- _init = False
- _hostage_cells = list()
+ def __init__(self, **kwargs):
+ _Param.__init__(self, **kwargs)
+ _GUIParam.__init__(self)
+ self._init = False
+ self._hostage_cells = list()
- ##possible param types
- TYPES = _Param.TYPES + [
+ def get_types(self): return (
+ 'raw', 'enum',
'complex', 'real', 'int',
'complex_vector', 'real_vector', 'int_vector',
'hex', 'string', 'bool',
'file_open', 'file_save',
- 'id',
+ 'id', 'stream_id',
'grid_pos', 'notebook',
'import',
- ]
+ )
def __repr__(self):
"""
@@ -150,7 +155,7 @@ class Param(_Param):
def get_input_class(self):
if self.get_type() in ('file_open', 'file_save'): return FileParam
- return _Param.get_input_class(self)
+ return _GUIParam.get_input_class(self)
def get_color(self):
"""
@@ -172,6 +177,7 @@ class Param(_Param):
'hex': Constants.INT_COLOR_SPEC,
'string': Constants.BYTE_VECTOR_COLOR_SPEC,
'id': Constants.ID_COLOR_SPEC,
+ 'stream_id': Constants.ID_COLOR_SPEC,
'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
'notebook': Constants.INT_VECTOR_COLOR_SPEC,
'raw': Constants.WILDCARD_COLOR_SPEC,
@@ -310,14 +316,31 @@ class Param(_Param):
#can python use this as a variable?
try: assert _check_id_matcher.match(v)
except AssertionError: raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
- params = self.get_all_params('id')
- keys = [param.get_value() for param in params]
- try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled
+ ids = [param.get_value() for param in self.get_all_params(t)]
+ try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled
except: raise Exception, 'ID "%s" is not unique.'%v
try: assert v not in ID_BLACKLIST
except: raise Exception, 'ID "%s" is blacklisted.'%v
return v
#########################
+ # Stream ID Type
+ #########################
+ elif t == 'stream_id':
+ #get a list of all stream ids used in the virtual sinks
+ ids = [param.get_value() for param in filter(
+ lambda p: p.get_parent().is_virtual_sink(),
+ self.get_all_params(t),
+ )]
+ #check that the virtual sink's stream id is unique
+ if self.get_parent().is_virtual_sink():
+ try: assert ids.count(v) <= 1 #id should only appear once, or zero times if block is disabled
+ except: raise Exception, 'Stream ID "%s" is not unique.'%v
+ #check that the virtual source's steam id is found
+ if self.get_parent().is_virtual_source():
+ try: assert v in ids
+ except: raise Exception, 'Stream ID "%s" is not found.'%v
+ return v
+ #########################
# Grid Position Type
#########################
elif t == 'grid_pos':
@@ -380,17 +403,18 @@ class Param(_Param):
def to_code(self):
"""
Convert the value to code.
+ For string and list types, check the init flag, call evaluate().
+ This ensures that evaluate() was called to set the xxxify_flags.
@return a string representing the code
"""
- #run init tasks in evaluate
- #such as setting flags
- if not self._init: self.evaluate()
v = self.get_value()
t = self.get_type()
if t in ('string', 'file_open', 'file_save'): #string types
+ if not self._init: self.evaluate()
if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
else: return v
elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types
+ if not self._init: self.evaluate()
if self._lisitify_flag: return '(%s, )'%v
else: return '(%s)'%v
else: return v
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
index d55dbf4ce..bb56d361b 100644
--- a/grc/python/Platform.py
+++ b/grc/python/Platform.py
@@ -20,10 +20,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
import os
from gnuradio import gr
from .. base.Platform import Platform as _Platform
+from .. gui.Platform import Platform as _GUIPlatform
from FlowGraph import FlowGraph as _FlowGraph
from Connection import Connection as _Connection
from Block import Block as _Block
-from Port import Source,Sink
+from Port import Port as _Port
from Param import Param as _Param
from Generator import Generator
from Constants import \
@@ -46,7 +47,7 @@ COLORS = (#title, #color spec
('Message', Constants.MSG_COLOR_SPEC),
)
-class Platform(_Platform):
+class Platform(_Platform, _GUIPlatform):
def __init__(self):
"""
@@ -70,6 +71,7 @@ class Platform(_Platform):
generator=Generator,
colors=COLORS,
)
+ _GUIPlatform.__init__(self)
##############################################
# Constructors
@@ -77,6 +79,5 @@ class Platform(_Platform):
FlowGraph = _FlowGraph
Connection = _Connection
Block = _Block
- Source = Source
- Sink = Sink
+ Port = _Port
Param = _Param
diff --git a/grc/python/Port.py b/grc/python/Port.py
index daf8f9ca3..33426d905 100644
--- a/grc/python/Port.py
+++ b/grc/python/Port.py
@@ -18,41 +18,100 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
"""
from .. base.Port import Port as _Port
+from .. gui.Port import Port as _GUIPort
import Constants
-class Port(_Port):
-
- ##possible port types
- TYPES = ['complex', 'float', 'int', 'short', 'byte', 'msg']
-
- def __init__(self, block, n):
+def _get_source_from_virtual_sink_port(vsp):
+ """
+ Resolve the source port that is connected to the given virtual sink port.
+ Use the get source from virtual source to recursively resolve subsequent ports.
+ """
+ try: return _get_source_from_virtual_source_port(
+ vsp.get_enabled_connections()[0].get_source())
+ except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
+
+def _get_source_from_virtual_source_port(vsp, traversed=[]):
+ """
+ Recursively resolve source ports over the virtual connections.
+ Keep track of traversed sources to avoid recursive loops.
+ """
+ if not vsp.get_parent().is_virtual_source(): return vsp
+ if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp
+ try: return _get_source_from_virtual_source_port(
+ _get_source_from_virtual_sink_port(
+ filter(#get all virtual sinks with a matching stream id
+ lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
+ filter(#get all enabled blocks that are also virtual sinks
+ lambda b: b.is_virtual_sink(),
+ vsp.get_parent().get_parent().get_enabled_blocks(),
+ ),
+ )[0].get_sink(vsp.get_key())
+ ), traversed + [vsp],
+ )
+ except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
+
+class Port(_Port, _GUIPort):
+
+ def __init__(self, block, n, dir):
"""
Make a new port from nested data.
@param block the parent element
@param n the nested odict
+ @param dir the direction
"""
+ self._n = n
+ if n['type'] == 'msg': n['key'] = 'msg'
+ if dir == 'source' and not n.find('key'):
+ n['key'] = str(block._source_count)
+ block._source_count += 1
+ if dir == 'sink' and not n.find('key'):
+ n['key'] = str(block._sink_count)
+ block._sink_count += 1
#build the port
_Port.__init__(
self,
block=block,
n=n,
+ dir=dir,
)
+ _GUIPort.__init__(self)
self._nports = n.find('nports') or ''
self._vlen = n.find('vlen') or ''
self._optional = bool(n.find('optional'))
+ def get_types(self): return ('complex', 'float', 'int', 'short', 'byte', 'msg', '')
+
def validate(self):
_Port.validate(self)
try: assert self.get_enabled_connections() or self.get_optional()
except AssertionError: self.add_error_message('Port is not connected.')
try: assert self.is_source() or len(self.get_enabled_connections()) <= 1
except AssertionError: self.add_error_message('Port has too many connections.')
+ #message port logic
if self.get_type() == 'msg':
try: assert not self.get_nports()
except AssertionError: self.add_error_message('A port of type "msg" cannot have "nports" set.')
try: assert self.get_vlen() == 1
except AssertionError: self.add_error_message('A port of type "msg" must have a "vlen" of 1.')
+ def rewrite(self):
+ """
+ Handle the port cloning for virtual blocks.
+ """
+ _Port.rewrite(self)
+ if self.get_parent().is_virtual_sink() or self.get_parent().is_virtual_source():
+ try: #clone type and vlen
+ source = self.resolve_virtual_source()
+ self._type = str(source.get_type())
+ self._vlen = str(source.get_vlen())
+ except: #reset type and vlen
+ self._type = ''
+ self._vlen = ''
+
+ def resolve_virtual_source(self):
+ if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self)
+ if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self)
+
def get_vlen(self):
"""
Get the vector length.
@@ -109,24 +168,4 @@ class Port(_Port):
def copy(self, new_key=None):
n = self._n.copy()
if new_key: n['key'] = new_key
- return self.__class__(self.get_parent(), n)
-
-class Source(Port):
-
- def __init__(self, block, n):
- self._n = n #save n
- if n['type'] == 'msg': n['key'] = 'msg'
- if not n.find('key'):
- n['key'] = str(block._source_count)
- block._source_count = block._source_count + 1
- Port.__init__(self, block, n)
-
-class Sink(Port):
-
- def __init__(self, block, n):
- self._n = n #save n
- if n['type'] == 'msg': n['key'] = 'msg'
- if not n.find('key'):
- n['key'] = str(block._sink_count)
- block._sink_count = block._sink_count + 1
- Port.__init__(self, block, n)
+ return self.__class__(self.get_parent(), n, self._dir)
diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl
index df346dd16..dce4037d5 100644
--- a/grc/python/flow_graph.tmpl
+++ b/grc/python/flow_graph.tmpl
@@ -154,6 +154,13 @@ class $(class_name)(gr.hier_block2):
## The port name should be the id of the parent block.
## However, port names for IO pads should be self.
########################################################
+#def make_port_name($port)
+ #if $port.get_parent().get_key().startswith('pad_')
+self#slurp
+ #else
+self.$port.get_parent().get_id()#slurp
+ #end if
+#end def
#if $connections
$DIVIDER
@@ -163,17 +170,14 @@ class $(class_name)(gr.hier_block2):
#for $con in $connections
#set $source = $con.get_source()
#set $sink = $con.get_sink()
- #if $source.get_parent().get_key() == 'pad_source'
- #set $source_name = 'self'
- #else
- #set $source_name = 'self.' + $source.get_parent().get_id()
+ ##resolve virtual sources to the actual sources
+ #if $source.get_parent().is_virtual_source()
+ #set $source = $source.resolve_virtual_source()
#end if
- #if $sink.get_parent().get_key() == 'pad_sink'
- #set $sink_name = 'self'
- #else
- #set $sink_name = 'self.' + $sink.get_parent().get_id()
+ ##do not generate connections with virtual sinks
+ #if not $sink.get_parent().is_virtual_sink()
+ self.connect(($make_port_name($source), $source.get_key()), ($make_port_name($sink), $sink.get_key()))
#end if
- self.connect(($source_name, $source.get_key()), ($sink_name, $sink.get_key()))
#end for
########################################################
@@ -194,6 +198,20 @@ class $(class_name)(gr.hier_block2):
## For top block code, generate a main routine.
## Instantiate the top block and run as gui or cli.
########################################################
+#def make_default($type, $param)
+ #if $type == 'eng_float'
+eng_notation.num_to_str($param.get_make())#slurp
+ #else
+$param.get_make()#slurp
+ #end if
+#end def
+#def make_short_id($param)
+ #set $short_id = $param.get_param('short_id').get_evaluated()
+ #if $short_id
+ #set $short_id = '-' + $short_id
+ #end if
+$short_id#slurp
+#end def
#if $generate_options != 'hb'
if __name__ == '__main__':
parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
@@ -202,12 +220,8 @@ if __name__ == '__main__':
#set $type = $param.get_param('type').get_value()
#if $type
#silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
- #set $short_id = $param.get_param('short_id').get_evaluated()
- #if $short_id
- #set $short_id = '-' + $short_id
- #end if
- parser.add_option("$short_id", "--$param.get_id()", dest="$param.get_id()", type="$type", default=$param.get_make(),
- help="Set $($param.get_param('label').evaluate() or $param.get_id()) [default=%default]")
+ parser.add_option("$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
+ help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
#end if
#end for
(options, args) = parser.parse_args()
diff --git a/grc/todo.txt b/grc/todo.txt
index bb40e1f16..ffc9d64db 100644
--- a/grc/todo.txt
+++ b/grc/todo.txt
@@ -25,8 +25,7 @@
* size params for the graphical sinks
* callbacks for set average on fft, waterfall, number sinks
* add units to params: Sps, Hz, dB...
-* command line options should replace _ with - for the --option
- * add bool type to command line option store_true or store_false
+* add bool type to command line option store_true or store_false
##################################################
# Features
@@ -59,6 +58,8 @@
##################################################
# Problems
##################################################
+* msg ports dont work with virtual connections
+ * dont fix this until pmts are used?
* hier block generation
* auto generate hier library on changes
* auto clean hier library when block removed
@@ -66,7 +67,6 @@
* dont generate py files in saved flowgraph dir
* save/restore cwd
* threads dont die on exit in probe and variable sink
-* overloaded gui classes for each platform, move param input objects into overloaded
* align param titles in paramsdialog
* better error for blank string params
* weird grid params misbehaving
@@ -74,7 +74,6 @@
* will not update for non-enum params
* needs to account for added or removed params
* example with grid params need update after notebook change
-* use .strip() on the hide property so we can do away with #slurp(s) in the templates
##################################################
# Future