Merged branch 'msgq' from http://gnuradio.org/git/jblum.git
authorJohnathan Corgan <jcorgan@corganenterprises.com>
Sat, 15 Aug 2009 17:48:39 +0000 (10:48 -0700)
committerJohnathan Corgan <jcorgan@corganenterprises.com>
Sat, 15 Aug 2009 17:48:39 +0000 (10:48 -0700)
This adds the ability to GRC to gave blocks with message ports.

Signed-off-by: Johnathan Corgan <jcorgan@corganenterprises.com>
16 files changed:
Makefile.am
grc/base/Block.py
grc/base/Param.py
grc/blocks/Makefile.am
grc/blocks/block_tree.xml
grc/blocks/gr_message_sink.xml [new file with mode: 0644]
grc/blocks/gr_message_source.xml [new file with mode: 0644]
grc/gui/Block.py
grc/python/Block.py
grc/python/Connection.py
grc/python/Constants.py
grc/python/Generator.py
grc/python/Platform.py
grc/python/Port.py
grc/python/flow_graph.tmpl
grc/todo.txt

index e8328c263963e6e5b043138246b751af6484cb9e..ec71be725bff59bd746c9f6d8e4b5b667ce6fca7 100644 (file)
@@ -37,3 +37,16 @@ EXTRA_DIST = \
 
 SUBDIRS = @build_dirs@
 DIST_SUBDIRS = @build_dirs@ @skipped_dirs@ @with_dirs@
+
+if PYTHON
+
+export pythondir
+
+install-data-hook:
+       @if ! python -c "import gnuradio" > /dev/null 2>&1; then\
+               printf "\n*** Post-Install Message ***\
+               \nWarning: python could not find the gnuradio module.\
+               \nMake sure that $${pythondir} is in your PYTHONPATH\n\n";\
+       fi
+
+endif
index 867a14f57b9de30f2ef97619c823d7ee9a1cece4..d5e1047852b7df5bfcd71b89135483debc183f18 100644 (file)
@@ -46,6 +46,9 @@ class TemplateArg(UserDict):
        def __call__(self):
                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)]
+
 class Block(Element):
 
        def __init__(self, flow_graph, n):
@@ -66,17 +69,17 @@ class Block(Element):
                self._category = n.find('category') or ''
                self._block_wrapper_path = n.find('block_wrapper_path')
                #create the param objects
-               self._params = odict()
+               self._params = list()
                #add the id param
-               self._params['id'] = self.get_parent().get_parent().Param(
+               self.get_params().append(self.get_parent().get_parent().Param(
                        self,
                        odict({
                                'name': 'ID',
                                'key': 'id',
                                'type': 'id',
                        })
-               )
-               self._params['_enabled'] = self.get_parent().get_parent().Param(
+               ))
+               self.get_params().append(self.get_parent().get_parent().Param(
                        self,
                        odict({
                                'name': 'Enabled',
@@ -85,32 +88,32 @@ class Block(Element):
                                'value': 'True',
                                'hide': 'all',
                        })
-               )
+               ))
                for param in map(lambda n: self.get_parent().get_parent().Param(self, n), params):
                        key = param.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_param_keys()
                        except AssertionError: raise Exception, 'Key "%s" already exists in params'%key
                        #store the param
-                       self._params[key] = param
+                       self.get_params().append(param)
                #create the source objects
-               self._sources = odict()
+               self._sources = list()
                for source in map(lambda n: self.get_parent().get_parent().Source(self, n), sources):
                        key = source.get_key()
                        #test against repeated keys
                        try: assert key not in self.get_source_keys()
                        except AssertionError: raise Exception, 'Key "%s" already exists in sources'%key
                        #store the port
-                       self._sources[key] = source
+                       self.get_sources().append(source)
                #create the sink objects
-               self._sinks = odict()
+               self._sinks = list()
                for sink in map(lambda n: self.get_parent().get_parent().Sink(self, n), 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._sinks[key] = sink
+                       self.get_sinks().append(sink)
                #begin the testing
                self.test()
 
@@ -164,23 +167,23 @@ class Block(Element):
        ##############################################
        # Access Params
        ##############################################
-       def get_param_keys(self): return self._params.keys()
-       def get_param(self, key): return self._params[key]
-       def get_params(self): return self._params.values()
+       def get_param_keys(self): return _get_keys(self._params)
+       def get_param(self, key): return _get_elem(self._params, key)
+       def get_params(self): return self._params
 
        ##############################################
        # Access Sinks
        ##############################################
-       def get_sink_keys(self): return self._sinks.keys()
-       def get_sink(self, key): return self._sinks[key]
-       def get_sinks(self): return self._sinks.values()
+       def get_sink_keys(self): return _get_keys(self._sinks)
+       def get_sink(self, key): return _get_elem(self._sinks, key)
+       def get_sinks(self): return self._sinks
 
        ##############################################
        # Access Sources
        ##############################################
-       def get_source_keys(self): return self._sources.keys()
-       def get_source(self, key): return self._sources[key]
-       def get_sources(self): return self._sources.values()
+       def get_source_keys(self): return _get_keys(self._sources)
+       def get_source(self, key): return _get_elem(self._sources, key)
+       def get_sources(self): return self._sources
 
        def get_connections(self):
                return sum([port.get_connections() for port in self.get_ports()], [])
index 8166d54ecca0d1a6bf892ea3cc0f98c80b6e7322..93c1c52bdef38114ccc948c9d08dfe1b5856e9dd 100644 (file)
@@ -165,6 +165,8 @@ 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):
                """
index 025c261f4fe420ca3cadddd8c5704591bce7e6ec..fbd8f4bb4dace7e169f4a3f640691815e703c1f3 100644 (file)
@@ -123,6 +123,8 @@ dist_ourdata_DATA = \
        gr_kludge_copy.xml \
        gr_map_bb.xml \
        gr_max_xx.xml \
+       gr_message_sink.xml \
+       gr_message_source.xml \
        gr_moving_average_xx.xml \
        gr_mpsk_receiver_cc.xml \
        gr_mpsk_sync_cc.xml \
index 9eda2fdcf80fa113638e63dcba8fc9d92c1bf627..2cedb45a2a7dbb376f54a7cc0ccf53b24b9a1b9c 100644 (file)
@@ -20,6 +20,7 @@
                <block>gr_udp_source</block>
                <block>audio_source</block>
                <block>gr_wavfile_source</block>
+               <block>gr_message_source</block>
                <block>pad_source</block>
        </cat>
        <cat>
@@ -32,6 +33,7 @@
                <block>gr_udp_sink</block>
                <block>audio_sink</block>
                <block>gr_wavfile_sink</block>
+               <block>gr_message_sink</block>
                <block>pad_sink</block>
        </cat>
        <cat>
diff --git a/grc/blocks/gr_message_sink.xml b/grc/blocks/gr_message_sink.xml
new file mode 100644 (file)
index 0000000..76537f2
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Message Sink (the source port is a message)
+###################################################
+ -->
+<block>
+       <name>Message Sink</name>
+       <key>gr_message_sink</key>
+       <import>from gnuradio import gr</import>
+       <make>gr.message_sink($type.size*$vlen, $(id)_msgq, $dont_block)</make>
+       <param>
+               <name>Input Type</name>
+               <key>type</key>
+               <type>enum</type>
+               <option>
+                       <name>Complex</name>
+                       <key>complex</key>
+                       <opt>size:gr.sizeof_gr_complex</opt>
+               </option>
+               <option>
+                       <name>Float</name>
+                       <key>float</key>
+                       <opt>size:gr.sizeof_float</opt>
+               </option>
+               <option>
+                       <name>Int</name>
+                       <key>int</key>
+                       <opt>size:gr.sizeof_int</opt>
+               </option>
+               <option>
+                       <name>Short</name>
+                       <key>short</key>
+                       <opt>size:gr.sizeof_short</opt>
+               </option>
+               <option>
+                       <name>Byte</name>
+                       <key>byte</key>
+                       <opt>size:gr.sizeof_char</opt>
+               </option>
+       </param>
+       <param>
+               <name>Don't Block</name>
+               <key>dont_block</key>
+               <value>False</value>
+               <type>enum</type>
+               <option>
+                       <name>Don't Block</name>
+                       <key>True</key>
+               </option>
+               <option>
+                       <name>Block</name>
+                       <key>False</key>
+               </option>
+       </param>
+       <param>
+               <name>Vec Length</name>
+               <key>vlen</key>
+               <value>1</value>
+               <type>int</type>
+       </param>
+       <check>$vlen &gt; 0</check>
+       <sink>
+               <name>in</name>
+               <type>$type</type>
+               <vlen>$vlen</vlen>
+       </sink>
+       <source>
+               <name>out</name>
+               <type>msg</type>
+       </source>
+</block>
diff --git a/grc/blocks/gr_message_source.xml b/grc/blocks/gr_message_source.xml
new file mode 100644 (file)
index 0000000..44378ae
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Message Source (the sink port is a message)
+###################################################
+ -->
+<block>
+       <name>Message Source</name>
+       <key>gr_message_source</key>
+       <import>from gnuradio import gr</import>
+       <make>gr.message_source($type.size*$vlen, $(id)_msgq)</make>
+       <param>
+               <name>Output Type</name>
+               <key>type</key>
+               <type>enum</type>
+               <option>
+                       <name>Complex</name>
+                       <key>complex</key>
+                       <opt>size:gr.sizeof_gr_complex</opt>
+               </option>
+               <option>
+                       <name>Float</name>
+                       <key>float</key>
+                       <opt>size:gr.sizeof_float</opt>
+               </option>
+               <option>
+                       <name>Int</name>
+                       <key>int</key>
+                       <opt>size:gr.sizeof_int</opt>
+               </option>
+               <option>
+                       <name>Short</name>
+                       <key>short</key>
+                       <opt>size:gr.sizeof_short</opt>
+               </option>
+               <option>
+                       <name>Byte</name>
+                       <key>byte</key>
+                       <opt>size:gr.sizeof_char</opt>
+               </option>
+       </param>
+       <param>
+               <name>Vec Length</name>
+               <key>vlen</key>
+               <value>1</value>
+               <type>int</type>
+       </param>
+       <check>$vlen &gt; 0</check>
+       <sink>
+               <name>in</name>
+               <type>msg</type>
+       </sink>
+       <source>
+               <name>out</name>
+               <type>$type</type>
+               <vlen>$vlen</vlen>
+       </source>
+</block>
index 0496f0a28432a0ce7cc871a8ddf50a82b4703b78..4add3aa195f9db8d34cd46c09104fd7bf78d2467 100644 (file)
@@ -43,7 +43,7 @@ class Block(Element):
                Add graphics related params to the block.
                """
                #add the position param
-               self._params['_coordinate'] = self.get_parent().get_parent().Param(
+               self.get_params().append(self.get_parent().get_parent().Param(
                        self,
                        odict({
                                'name': 'GUI Coordinate',
@@ -52,8 +52,8 @@ class Block(Element):
                                'value': '(0, 0)',
                                'hide': 'all',
                        })
-               )
-               self._params['_rotation'] = self.get_parent().get_parent().Param(
+               ))
+               self.get_params().append(self.get_parent().get_parent().Param(
                        self,
                        odict({
                                'name': 'GUI Rotation',
@@ -62,7 +62,7 @@ class Block(Element):
                                'value': '0',
                                'hide': 'all',
                        })
-               )
+               ))
                Element.__init__(self)
 
        def get_coordinate(self):
index 957fee18ef123aea408a7c5762c41a3121f22011..47fe13a3cc11ee6c87d81d605e5d2e7317eda4c2 100644 (file)
@@ -66,16 +66,16 @@ class Block(_Block):
                                except AssertionError: self.add_error_message('Check "%s" failed.'%check)
                        except: self.add_error_message('Check "%s" did not evaluate.'%check)
                #adjust nports
-               for ports, Port in (
-                       (self._sources, self.get_parent().get_parent().Source),
-                       (self._sinks, self.get_parent().get_parent().Sink),
+               for get_ports, get_port in (
+                       (self.get_sources, self.get_source),
+                       (self.get_sinks, self.get_sink),
                ):
-                       #how many ports?
-                       num_ports = len(ports)
+                       #how many streaming (non-message) ports?
+                       num_ports = len(filter(lambda p: p.get_type() != 'msg', get_ports()))
                        #do nothing for 0 ports
                        if not num_ports: continue
                        #get the nports setting
-                       port0 = ports[str(0)]
+                       port0 = get_port(str(0))
                        nports = port0.get_nports()
                        #do nothing for no nports
                        if not nports: continue
@@ -85,19 +85,21 @@ class Block(_Block):
                        if nports < num_ports:
                                #remove the connections
                                for key in map(str, range(nports, num_ports)):
-                                       port = ports[key]
+                                       port = get_port(key)
                                        for connection in port.get_connections():
                                                self.get_parent().remove_element(connection)
                                #remove the ports
-                               for key in map(str, range(nports, num_ports)): ports.pop(key)
+                               for key in map(str, range(nports, num_ports)):
+                                       get_ports().remove(get_port(key))
                                continue
                        #add more ports
                        if nports > num_ports:
                                for key in map(str, range(num_ports, nports)):
-                                       n = port0._n
-                                       n['key'] = key
-                                       port = Port(self, n)
-                                       ports[key] = port
+                                       prev_port = get_port(str(int(key)-1))
+                                       get_ports().insert(
+                                               get_ports().index(prev_port)+1,
+                                               prev_port.copy(new_key=key),
+                                       )
                                continue
 
        def port_controller_modify(self, direction):
index d8a894bb176a97556bde92b6f572fb680033567a..5eba9f24dd839ed0b6bbf65427bc4f5a2cd02475 100644 (file)
@@ -21,6 +21,9 @@ from .. base.Connection import Connection as _Connection
 
 class Connection(_Connection):
 
+       def is_msg(self):
+               return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
+
        def validate(self):
                """
                Validate the connections.
index 5f203237f30185e4f6d1a7dbad1daa2d9e78cddf..439a524209da7277526f81b1b0f6f92194345c0c 100644 (file)
@@ -61,3 +61,4 @@ SHORT_VECTOR_COLOR_SPEC = '#CCCC33'
 BYTE_VECTOR_COLOR_SPEC = '#CC66CC'
 ID_COLOR_SPEC = '#DDDDDD'
 WILDCARD_COLOR_SPEC = '#FFFFFF'
+MSG_COLOR_SPEC = '#777777'
index 33be4a72615e8c6a053e6a87f8de76dd8a75029f..ed7995716f1ecde6e25c5b433703f8708216c5ca 100644 (file)
@@ -98,7 +98,8 @@ Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''')
                #list of regular blocks (all blocks minus the special ones)
                blocks = filter(lambda b: b not in (imports + parameters + variables + probes + notebooks), blocks) + probes
                #list of connections where each endpoint is enabled
-               connections = self._flow_graph.get_enabled_connections()
+               connections = filter(lambda c: not c.is_msg(), self._flow_graph.get_enabled_connections())
+               messages = filter(lambda c: c.is_msg(), self._flow_graph.get_enabled_connections())
                #list of variable names
                var_ids = [var.get_id() for var in parameters + variables]
                #prepend self.
@@ -124,6 +125,7 @@ Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''')
                        'parameters': parameters,
                        'blocks': blocks,
                        'connections': connections,
+                       'messages': messages,
                        'generate_options': self._generate_options,
                        'var_id2cbs': var_id2cbs,
                }
index f56e3fb2df169dc0f7b218829f1ce1b88a1b48ce..d55dbf4ce71a224fa89fd710a396f466db7c2391 100644 (file)
@@ -42,7 +42,8 @@ COLORS = (#title, #color spec
        ('Integer Vector', Constants.INT_VECTOR_COLOR_SPEC),
        ('Short Vector', Constants.SHORT_VECTOR_COLOR_SPEC),
        ('Byte Vector', Constants.BYTE_VECTOR_COLOR_SPEC),
-       ('Wildcard Type', Constants.WILDCARD_COLOR_SPEC),
+       ('Wildcard', Constants.WILDCARD_COLOR_SPEC),
+       ('Message', Constants.MSG_COLOR_SPEC),
 )
 
 class Platform(_Platform):
index 5a2b047f0ef05c4017b5ddc447fd1001a141efb9..daf8f9ca34c1f687fffc3e54dac26af3dc35b6e3 100644 (file)
@@ -23,27 +23,23 @@ import Constants
 class Port(_Port):
 
        ##possible port types
-       TYPES = ['complex', 'float', 'int', 'short', 'byte']
+       TYPES = ['complex', 'float', 'int', 'short', 'byte', 'msg']
 
        def __init__(self, block, n):
                """
                Make a new port from nested data.
                @param block the parent element
                @param n the nested odict
-               @return a new port
                """
-               vlen = n.find('vlen') or '1'
-               nports = n.find('nports') or ''
-               optional = n.find('optional') or ''
                #build the port
                _Port.__init__(
                        self,
                        block=block,
                        n=n,
                )
-               self._nports = nports
-               self._vlen = vlen
-               self._optional = bool(optional)
+               self._nports = n.find('nports') or ''
+               self._vlen = n.find('vlen') or ''
+               self._optional = bool(n.find('optional'))
 
        def validate(self):
                _Port.validate(self)
@@ -51,6 +47,11 @@ class Port(_Port):
                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.')
+               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 get_vlen(self):
                """
@@ -94,6 +95,7 @@ class Port(_Port):
                                        'int': Constants.INT_COLOR_SPEC,
                                        'short': Constants.SHORT_COLOR_SPEC,
                                        'byte': Constants.BYTE_COLOR_SPEC,
+                                       'msg': Constants.MSG_COLOR_SPEC,
                                }[self.get_type()]
                        return {#vlen is non 1
                                'complex': Constants.COMPLEX_VECTOR_COLOR_SPEC,
@@ -104,26 +106,27 @@ class Port(_Port):
                        }[self.get_type()]
                except: return _Port.get_color(self)
 
+       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
-               #key is port index
-               n['key'] = str(block._source_count)
-               block._source_count = block._source_count + 1
+               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)
 
-       def __del__(self):
-               self.get_parent()._source_count = self.get_parent()._source_count - 1
-
 class Sink(Port):
 
        def __init__(self, block, n):
                self._n = n #save n
-               #key is port index
-               n['key'] = str(block._sink_count)
-               block._sink_count = block._sink_count + 1
+               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)
-
-       def __del__(self):
-               self.get_parent()._sink_count = self.get_parent()._sink_count - 1
index b537c43e2993707cb17f3b0ef24f5c5f445ab637..df346dd165567002a34fcfbcd2787818ef43cbea 100644 (file)
@@ -10,6 +10,7 @@
 ##@param parameters the paramater blocks
 ##@param blocks the signal blocks
 ##@param connections the connections
+##@param messages the msg type connections
 ##@param generate_options the type of flow graph
 ##@param var_id2cbs variable id map to callback strings
 ########################################################
@@ -125,6 +126,18 @@ class $(class_name)(gr.hier_block2):
                $indent($ctrl.get_make())
 #end for
 ########################################################
+##Create Message Queues
+########################################################
+#if $messages
+
+               $DIVIDER
+               # Message Queues
+               $DIVIDER
+#end if
+#for $msg in $messages
+               $(msg.get_source().get_parent().get_id())_msgq = $(msg.get_sink().get_parent().get_id())_msgq = gr.msg_queue(2)
+#end for
+########################################################
 ##Create Blocks
 ########################################################
 #if $blocks
index f8c8021b65fccf2834e24cd4dd125b43d8f2892a..bb40e1f160fe4009dec974596cefed2ca38f0284 100644 (file)
@@ -26,6 +26,7 @@
 * 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
 
 ##################################################
 # Features