This adds the ability to GRC to gave blocks with message ports.
Signed-off-by: Johnathan Corgan <jcorgan@corganenterprises.com>
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
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):
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',
'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()
##############################################
# 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()], [])
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):
"""
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 \
<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>
<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>
--- /dev/null
+<?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 > 0</check>
+ <sink>
+ <name>in</name>
+ <type>$type</type>
+ <vlen>$vlen</vlen>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>msg</type>
+ </source>
+</block>
--- /dev/null
+<?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 > 0</check>
+ <sink>
+ <name>in</name>
+ <type>msg</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>$type</type>
+ <vlen>$vlen</vlen>
+ </source>
+</block>
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',
'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',
'value': '0',
'hide': 'all',
})
- )
+ ))
Element.__init__(self)
def get_coordinate(self):
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
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):
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.
BYTE_VECTOR_COLOR_SPEC = '#CC66CC'
ID_COLOR_SPEC = '#DDDDDD'
WILDCARD_COLOR_SPEC = '#FFFFFF'
+MSG_COLOR_SPEC = '#777777'
#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.
'parameters': parameters,
'blocks': blocks,
'connections': connections,
+ 'messages': messages,
'generate_options': self._generate_options,
'var_id2cbs': var_id2cbs,
}
('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):
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)
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):
"""
'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,
}[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
##@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
########################################################
$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
* 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