diff options
author | Johnathan Corgan | 2009-09-04 15:47:49 -0700 |
---|---|---|
committer | Johnathan Corgan | 2009-09-04 15:47:49 -0700 |
commit | d80add605536891da950126b25b16ab89d8e7cae (patch) | |
tree | 10777578472d39e25a821284e1409be7a6caae89 | |
parent | 20006003431d7260b04964eb684b1746ffb0a85f (diff) | |
parent | 6b47cc3dc64d86cb19eb28ab4843a0f278db6d0a (diff) | |
download | gnuradio-d80add605536891da950126b25b16ab89d8e7cae.tar.gz gnuradio-d80add605536891da950126b25b16ab89d8e7cae.tar.bz2 gnuradio-d80add605536891da950126b25b16ab89d8e7cae.zip |
Merge branch 'grc' from http://gnuradio.org/git/jblum.git into master
we dont use test() -> remove it
Made the window for the pass band filters integers (take firdes.WIN_XXX).
Evaluation fix in param.to_code().
Removed the flagging api and usage from the base classes.
added ref scale param to fft and waterfall
Switched the python classes to inherit from the base and gui classes.
port and param types from an overloaded method
todo
Replaced TYPES in Port and Param with types parameter.
made is_virtual_xxx a block level function, used by port and param classes
added stream id type and checking in evaluate
avoid loops
Recursive resolution of virtual sources.
added virtual source and added stream ids, logic to clone in port
added rewrite methods to element to separate from validation logic
Added virtual sink and logic to clone port.
removed repurposing of pads
Work on command line options for generated code.
renamed the colors dialog to types
use pkgpythondir
...
42 files changed, 482 insertions, 371 deletions
diff --git a/gnuradio-core/src/python/gnuradio/eng_option.py b/gnuradio-core/src/python/gnuradio/eng_option.py index 09c3e1d87..e10235f14 100644 --- a/gnuradio-core/src/python/gnuradio/eng_option.py +++ b/gnuradio-core/src/python/gnuradio/eng_option.py @@ -23,29 +23,11 @@ from copy import copy from optparse import Option, OptionValueError - -scale_factor = {} -scale_factor['E'] = 1e18 -scale_factor['P'] = 1e15 -scale_factor['T'] = 1e12 -scale_factor['G'] = 1e9 -scale_factor['M'] = 1e6 -scale_factor['k'] = 1e3 -scale_factor['m'] = 1e-3 -scale_factor['u'] = 1e-6 -scale_factor['n'] = 1e-9 -scale_factor['p'] = 1e-12 -scale_factor['f'] = 1e-15 -scale_factor['a'] = 1e-18 - +import eng_notation def check_eng_float (option, opt, value): try: - scale = 1.0 - suffix = value[-1] - if scale_factor.has_key (suffix): - return float (value[0:-1]) * scale_factor[suffix] - return float (value) + return eng_notation.str_to_num(value) except: raise OptionValueError ( "option %s: invalid engineering notation value: %r" % (opt, value)) diff --git a/gr-wxgui/src/python/fft_window.py b/gr-wxgui/src/python/fft_window.py index 237c8940c..e025c28dd 100644 --- a/gr-wxgui/src/python/fft_window.py +++ b/gr-wxgui/src/python/fft_window.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 # @@ -156,9 +156,9 @@ class control_panel(wx.Panel): def _on_decr_ref_level(self, event): self.parent[REF_LEVEL_KEY] = self.parent[REF_LEVEL_KEY] - self.parent[Y_PER_DIV_KEY] def _on_incr_db_div(self, event): - self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, self.parent[Y_PER_DIV_KEY]*2) + self.parent[Y_PER_DIV_KEY] = min(DB_DIV_MAX, common.get_clean_incr(self.parent[Y_PER_DIV_KEY])) def _on_decr_db_div(self, event): - self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, self.parent[Y_PER_DIV_KEY]/2) + self.parent[Y_PER_DIV_KEY] = max(DB_DIV_MIN, common.get_clean_decr(self.parent[Y_PER_DIV_KEY])) ################################################## # FFT window with plotter and control panel 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 |