summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry May <terrydmay@gmail.com>2019-09-09 19:45:41 -0400
committerMartin Braun <martin@gnuradio.org>2020-02-18 22:04:15 -0800
commit64ee803068269fe3b9563fd415c420fb513a1c9b (patch)
treed27e9b5560b5bb4377f964e39772cd1395a7bff0
parent012870af22ae873b3b998691de8e81752179d266 (diff)
grc: Fix C++ code generation
- Added support for C++ std::map<> from python dict - Fixed default initialization of parameters in main() - Added missing include for realtime scheduling - Added default CMake option for std=c++11 as this is required for gnuradio >= 3.8 - Fixed mako template to add initialization to parameter declarations in main() - Fixed C++ constructor initialization list generation - Fixed parameter type determination when an lvalue is used in an rvalue expression - Improved determining type of C++ variables - Added C++ support for gr_complex parameters - Fixed C++ generation of nested container types - Added C++ support for virtual source/sink - Moved cmake CMAKE_CXX_STANDARD 11 option from options.yml to CMakeLists.txt.mako - Fixed qtqui_sink to allow multiple instances - Revised virtual connection processing in cpp_top_block.py Reviewed-By: HÃ¥kon Vagsether <hauk142@gmail.com>
-rw-r--r--gr-blocks/grc/blocks_socket_pdu.block.yml2
-rw-r--r--gr-blocks/grc/blocks_wavfile_sink.block.yml6
-rw-r--r--gr-blocks/grc/blocks_wavfile_source.block.yml3
-rw-r--r--gr-qtgui/grc/qtgui_sink_x.block.yml28
-rw-r--r--grc/blocks/message.domain.yml2
-rw-r--r--grc/blocks/parameter.block.yml2
-rw-r--r--grc/core/blocks/_build.py2
-rw-r--r--grc/core/blocks/block.py130
-rw-r--r--grc/core/blocks/virtual.py8
-rw-r--r--grc/core/generator/FlowGraphProxy.py4
-rw-r--r--grc/core/generator/cpp_templates/CMakeLists.txt.mako5
-rw-r--r--grc/core/generator/cpp_templates/flow_graph.cpp.mako26
-rw-r--r--grc/core/generator/cpp_templates/flow_graph.hpp.mako2
-rw-r--r--grc/core/generator/cpp_top_block.py69
14 files changed, 219 insertions, 70 deletions
diff --git a/gr-blocks/grc/blocks_socket_pdu.block.yml b/gr-blocks/grc/blocks_socket_pdu.block.yml
index 13d4d3b7a4..74108accb5 100644
--- a/gr-blocks/grc/blocks_socket_pdu.block.yml
+++ b/gr-blocks/grc/blocks_socket_pdu.block.yml
@@ -45,7 +45,7 @@ templates:
cpp_templates:
includes: ['#include <gnuradio/blocks/socket_pdu.h>']
declarations: 'blocks::socket_pdu::sptr ${id};'
- make: 'this->${id} = blocks::socket_pdu::make(${type}, ${host}, ${port}, ${mtu}, ${tcp_no_delay});'
+ make: 'this->${id} = blocks::socket_pdu::make("${type}", ${host}, ${port}, ${mtu}, ${tcp_no_delay});'
translations:
'True': 'true'
'False': 'false'
diff --git a/gr-blocks/grc/blocks_wavfile_sink.block.yml b/gr-blocks/grc/blocks_wavfile_sink.block.yml
index 20d956faaf..5139a17244 100644
--- a/gr-blocks/grc/blocks_wavfile_sink.block.yml
+++ b/gr-blocks/grc/blocks_wavfile_sink.block.yml
@@ -37,8 +37,10 @@ templates:
cpp_templates:
includes: ['#include <gnuradio/blocks/wavfile_sink.h>']
declarations: 'blocks::wavfile_sink::sptr ${id};'
- make: 'this->${id} = blocks::wavfile_sink::make(${file}, ${nchan}, ${samp_rate}, ${bits_per_sample});'
+ make: |-
+ this->${id} = blocks::wavfile_sink::make(${file}${'.c_str()' if str(file)[0] != "'" and str(file)[0] != "\"" else ''}, ${nchan}, ${samp_rate}, ${bits_per_sample});
callbacks:
- - open(${file})
+ ## TODO Handle std::string type when const char* argument is needed
+ - this->${id}->open(${file})
file_format: 1
diff --git a/gr-blocks/grc/blocks_wavfile_source.block.yml b/gr-blocks/grc/blocks_wavfile_source.block.yml
index 387bef3afb..04db7b87db 100644
--- a/gr-blocks/grc/blocks_wavfile_source.block.yml
+++ b/gr-blocks/grc/blocks_wavfile_source.block.yml
@@ -33,7 +33,8 @@ templates:
cpp_templates:
includes: ['#include <gnuradio/blocks/wavfile_source.h>']
declarations: 'blocks::wavfile_source::sptr ${id};'
- make: 'this->${id} = blocks::wavfile_source::make(${file}, ${repeat});'
+ make: |-
+ this->${id} = blocks::wavfile_source::make(${file}${'.c_str()' if str(file)[0] != "'" and str(file)[0] != "\"" else ''}, ${repeat});
translations:
'True': 'true'
'False': 'false'
diff --git a/gr-qtgui/grc/qtgui_sink_x.block.yml b/gr-qtgui/grc/qtgui_sink_x.block.yml
index af3fefb3ca..0424769169 100644
--- a/gr-qtgui/grc/qtgui_sink_x.block.yml
+++ b/gr-qtgui/grc/qtgui_sink_x.block.yml
@@ -1,6 +1,6 @@
id: qtgui_sink_x
label: QT GUI Sink
-flags: [ python ]
+flags: [ python, cpp ]
parameters:
- id: type
@@ -129,6 +129,32 @@ templates:
${gui_hint() % win}
+
+cpp_templates:
+ includes: ['#include <gnuradio/qtgui/${type.fcn}.h>', '#include <gnuradio/filter/firdes.h>']
+ declarations: gr::qtgui::${type.fcn}::sptr ${id};
+ make: |-
+ ${id} = gr::qtgui::${type.fcn}::make(
+ ${fftsize}, //fftsize
+ gr::filter::${wintype.replace('.', '::win_type::')}, //wintype
+ ${fc}, //fc
+ ${bw}, //bw
+ ${name}, //name
+ ${plotfreq}, //plotfreq
+ ${plotwaterfall}, //plotwaterfall
+ ${plottime}, //plottime
+ ${plotconst} //plotconst
+ );
+ ${id}->set_update_time(1.0/${rate});
+ ${id}->enable_rf_freq(${showrf});
+ ## Attempt to replicate logic of Python gui_hint() method
+ this->top_grid_layout->addWidget(${id + '->qwidget()' + (', ' + str(gui_hint)[1:-1] if len(gui_hint) > 2 else '')});
+
+ link: ['gnuradio-qtgui', 'Qt5Widgets', 'Qt5Core']
+ translations:
+ 'True': 'true'
+ 'False': 'false'
+
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/grc/blocks/message.domain.yml b/grc/blocks/message.domain.yml
index 7e6cc529d9..d4b79d0200 100644
--- a/grc/blocks/message.domain.yml
+++ b/grc/blocks/message.domain.yml
@@ -8,3 +8,5 @@ multiple_connections_per_output: true
templates:
- type: [message, message]
connect: self.msg_connect(${ make_port_sig(source) }, ${ make_port_sig(sink) })
+ cpp_connect: hier_block2::msg_connect(${ make_port_sig(source) }, ${ make_port_sig(sink) })
+
diff --git a/grc/blocks/parameter.block.yml b/grc/blocks/parameter.block.yml
index f37ca1923f..d7fa926aac 100644
--- a/grc/blocks/parameter.block.yml
+++ b/grc/blocks/parameter.block.yml
@@ -39,7 +39,7 @@ templates:
make: ${value}
cpp_templates:
- var_make: ${type.type} ${id} = ${id};
+ var_make: ${id} = ${value};
make: ${value}
documentation: |-
diff --git a/grc/core/blocks/_build.py b/grc/core/blocks/_build.py
index f8406f9d6b..151fa3274f 100644
--- a/grc/core/blocks/_build.py
+++ b/grc/core/blocks/_build.py
@@ -53,7 +53,7 @@ def build(id, label='', category='', flags='', documentation='',
cpp_templates = cpp_templates or {}
cls.cpp_templates = MakoTemplates(
- includes=cpp_templates.get('includes', ''),
+ includes=cpp_templates.get('includes', []),
make=cpp_templates.get('make', ''),
callbacks=cpp_templates.get('callbacks', []),
var_make=cpp_templates.get('var_make', ''),
diff --git a/grc/core/blocks/block.py b/grc/core/blocks/block.py
index e51b730cdd..fe16f710cc 100644
--- a/grc/core/blocks/block.py
+++ b/grc/core/blocks/block.py
@@ -77,7 +77,7 @@ class Block(Element):
self.states = {'state': True, 'bus_source': False, 'bus_sink': False, 'bus_structure': None}
- if 'cpp' in self.flags:
+ if 'cpp' in self.flags and not (self.is_virtual_source() or self.is_virtual_sink()):
self.orig_cpp_templates = self.cpp_templates # The original template, in case we have to edit it when transpiling to C++
self.current_bus_structure = {'source': None, 'sink': None}
@@ -400,7 +400,7 @@ class Block(Element):
return [make_callback(c) for c in self.cpp_templates.render('callbacks')]
- def decide_type(self):
+ def format_expr(self, py_type):
"""
Evaluate the value of the variable block and decide its type.
@@ -410,60 +410,112 @@ class Block(Element):
value = self.params['value'].value
self.cpp_templates = copy.copy(self.orig_cpp_templates)
- def get_type(element):
+ # Determine the lvalue type
+ def get_type(element, _vtype):
+ evaluated = None
try:
evaluated = ast.literal_eval(element)
+ if _vtype == None:
+ _vtype = type(evaluated)
+ except ValueError or SyntaxError as excp:
+ if _vtype == None:
+ print(excp)
+
+ if _vtype in [int, float, bool, list, dict, str, complex]:
+ if _vtype == (int or long):
+ return 'int'
+
+ if _vtype == float:
+ return 'double'
+
+ if _vtype == bool:
+ return 'bool'
+
+ if _vtype == complex:
+ return 'gr_complex'
+
+ if _vtype == list:
+ try:
+ # For container types we must also determine the type of the template parameter(s)
+ return 'std::vector<' + get_type(str(evaluated[0]), type(evaluated[0])) + '>'
+
+ except IndexError: # empty list
+ return 'std::vector<std::string>'
+
+ if _vtype == dict:
+ try:
+ # For container types we must also determine the type of the template parameter(s)
+ key = list(evaluated)[0]
+ val = list(evaluated.values())[0]
+ return 'std::map<' + get_type(str(key), type(key)) + ', ' + get_type(str(val), type(val)) +'>'
+
+ except IndexError: # empty dict
+ return 'std::map<std::string, std::string>'
- except ValueError or SyntaxError:
- if re.match(r'^(numpy|np|scipy|sp)\.pi$', value):
- return 'pi'
else:
return 'std::string'
- else:
- _vtype = type(evaluated)
- if _vtype in [int, float, bool, list]:
- if _vtype == (int or long):
- return 'int'
-
- if _vtype == float:
- return 'double'
+ # Get the lvalue type
+ self.vtype = get_type(value, py_type)
+
+ # The r-value for these types must be transformed to create legal C++ syntax.
+ if self.vtype in ['bool', 'gr_complex'] or 'std::map' in self.vtype or 'std::vector' in self.vtype:
+ evaluated = ast.literal_eval(value)
+ self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', self.get_cpp_value(evaluated))
- if _vtype == bool:
- return 'bool'
+ if 'string' in self.vtype:
+ self.cpp_templates['includes'].append('#include <string>')
- if _vtype == list:
- try:
- first_element_type = type(evaluated[0])
- if first_element_type != str:
- list_type = get_type(str(evaluated[0]))
- else:
- list_type = get_type(evaluated[0])
- except IndexError: # empty list
- return 'std::vector<std::string>'
+ def get_cpp_value(self, pyval):
- else:
- return 'std::vector<' + list_type + '>'
+ if type(pyval) == int or type(pyval) == float:
+ val_str = str(pyval)
- else:
- return 'std::string'
+ # Check for PI and replace with C++ constant
+ pi_re = r'^(math|numpy|np|scipy|sp)\.pi$'
+ if re.match(pi_re, str(pyval)):
+ val_str = re.sub(pi_re, 'boost::math::constants::pi<double>()', val_str)
+ self.cpp_templates['includes'].append('#include <boost/math/constants/constants.hpp>')
+
+ return str(pyval)
- self.vtype = get_type(value)
- if self.vtype == 'bool':
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', (value[0].lower() + value[1:]))
+ elif type(pyval) == bool:
+ return str(pyval)[0].lower() + str(pyval)[1:]
- elif self.vtype == 'pi':
- self.vtype = 'double'
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', 'boost::math::constants::pi<double>()')
- self.cpp_templates['includes'].append('#include <boost/math/constants/constants.hpp>')
+ elif type(pyval) == complex:
+ self.cpp_templates['includes'].append('#include <gnuradio/gr_complex.h>')
+ evaluated = ast.literal_eval(str(pyval).strip())
+ return '{' + str(evaluated.real) + ', ' + str(evaluated.imag) + '}'
- elif 'std::vector' in self.vtype:
+ elif type(pyval) == list:
self.cpp_templates['includes'].append('#include <vector>')
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', '{' + value[1:-1] + '}')
+ val_str = '{'
+ for element in pyval:
+ val_str += self.get_cpp_value(element) + ', '
- if 'string' in self.vtype:
+ if len(val_str) > 1:
+ # truncate to trim superfluous ', ' from the end
+ val_str = val_str[0:-2]
+
+ return val_str + '}'
+
+ elif type(pyval) == dict:
+ self.cpp_templates['includes'].append('#include <map>')
+ val_str = '{'
+ for key in pyval:
+ val_str += '{' + self.get_cpp_value(key) + ', ' + self.get_cpp_value(pyval[key]) + '}, '
+
+ if len(val_str) > 1:
+ # truncate to trim superfluous ', ' from the end
+ val_str = val_str[0:-2]
+
+ return val_str + '}'
+
+ if type(self.vtype) == str:
self.cpp_templates['includes'].append('#include <string>')
+ return '"' + pyval + '"'
+
def is_virtual_sink(self):
return self.key == 'virtual_sink'
diff --git a/grc/core/blocks/virtual.py b/grc/core/blocks/virtual.py
index a742419d27..598e8371d5 100644
--- a/grc/core/blocks/virtual.py
+++ b/grc/core/blocks/virtual.py
@@ -18,10 +18,12 @@ class VirtualSink(Block):
key = 'virtual_sink'
label = 'Virtual Sink'
+ flags = Block.flags
+ flags.set('cpp')
parameters_data = build_params(
params_raw=[dict(label='Stream ID', id='stream_id', dtype='stream_id')],
- have_inputs=False, have_outputs=False, flags=Block.flags, block_id=key
+ have_inputs=False, have_outputs=False, flags=flags, block_id=key
)
inputs_data = [dict(domain='stream', dtype='', direction='sink', id="0")]
@@ -40,10 +42,12 @@ class VirtualSource(Block):
key = 'virtual_source'
label = 'Virtual Source'
+ flags = Block.flags
+ flags.set('cpp')
parameters_data = build_params(
params_raw=[dict(label='Stream ID', id='stream_id', dtype='stream_id')],
- have_inputs=False, have_outputs=False, flags=Block.flags, block_id=key
+ have_inputs=False, have_outputs=False, flags=flags, block_id=key
)
outputs_data = [dict(domain='stream', dtype='', direction='source', id="0")]
diff --git a/grc/core/generator/FlowGraphProxy.py b/grc/core/generator/FlowGraphProxy.py
index da95417b1b..0003cb5012 100644
--- a/grc/core/generator/FlowGraphProxy.py
+++ b/grc/core/generator/FlowGraphProxy.py
@@ -140,7 +140,7 @@ class FlowGraphProxy(object): # TODO: move this in a refactored Generator
Returns:
a list of #include statements
"""
- return [block.cpp_templates.render('includes') for block in self.iter_enabled_blocks()]
+ return [block.cpp_templates.render('includes') for block in self.iter_enabled_blocks() if not (block.is_virtual_sink() or block.is_virtual_source())]
def links(self):
"""
@@ -149,7 +149,7 @@ class FlowGraphProxy(object): # TODO: move this in a refactored Generator
Returns:
a list of GNU Radio modules
"""
- return [block.cpp_templates.render('link') for block in self.iter_enabled_blocks()]
+ return [block.cpp_templates.render('link') for block in self.iter_enabled_blocks() if not (block.is_virtual_sink() or block.is_virtual_source())]
def get_hier_block_io(flow_graph, direction, domain=None):
"""
diff --git a/grc/core/generator/cpp_templates/CMakeLists.txt.mako b/grc/core/generator/cpp_templates/CMakeLists.txt.mako
index 1b212e7bcc..a1f1b3f822 100644
--- a/grc/core/generator/cpp_templates/CMakeLists.txt.mako
+++ b/grc/core/generator/cpp_templates/CMakeLists.txt.mako
@@ -16,6 +16,7 @@ class_name = flow_graph.get_option('id')
%>\
cmake_minimum_required(VERSION 3.8)
+set(CMAKE_CXX_STANDARD 11)
% if generate_options == 'qt_gui':
find_package(Qt5Widgets REQUIRED)
@@ -25,14 +26,14 @@ include_directories(
${'$'}{GNURADIO_ALL_INCLUDE_DIRS}
${'$'}{Boost_INCLUDE_DIRS}
% if generate_options == 'qt_gui':
- ${'$'}{Qt5Widgets_INCLUDES}
+ ${'$'}{Qt5Widgets_INCLUDE_DIRS}
% endif
$ENV{HOME}/.grc_gnuradio
)
% if generate_options == 'qt_gui':
add_definitions(${'$'}{Qt5Widgets_DEFINITIONS})
-
+set(CMAKE_CXX_FLAGS "${'$'}{CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_AUTOMOC TRUE)
% endif
diff --git a/grc/core/generator/cpp_templates/flow_graph.cpp.mako b/grc/core/generator/cpp_templates/flow_graph.cpp.mako
index 208ec97bbe..7dabf7b0ed 100644
--- a/grc/core/generator/cpp_templates/flow_graph.cpp.mako
+++ b/grc/core/generator/cpp_templates/flow_graph.cpp.mako
@@ -13,6 +13,10 @@ GNU Radio version: ${version}
********************/
#include "${flow_graph.get_option('id')}.hpp"
+% if flow_graph.get_option('realtime_scheduling'):
+#include <gnuradio/realtime.h>
+% endif
+
% if parameters:
namespace po = boost::program_options;
@@ -25,12 +29,18 @@ class_name = flow_graph.get_option('id') + ('_' if flow_graph.get_option('id') =
param_str = ", ".join((param.vtype + " " + param.name) for param in parameters)
param_str_without_types = ", ".join(param.name for param in parameters)
+initializer_str = ",\n ".join((param.name + "(" + param.name + ")") for param in parameters)
+
+if generate_options == 'qt_gui':
+ initializer_str = 'QWidget()' + (',\n ' if len(parameters) > 0 else '') + initializer_str
+
+if len(initializer_str) > 0:
+ initializer_str = '\n: ' + initializer_str
%>\
-% if generate_options == 'no_gui':
-${class_name}::${class_name} (${param_str}) {
-% elif generate_options == 'qt_gui':
-${class_name}::${class_name} (${param_str}) : QWidget() {
+${class_name}::${class_name} (${param_str}) ${initializer_str} {
+
+% if generate_options == 'qt_gui':
this->setWindowTitle("${title}");
// check_set_qss
// set icon
@@ -47,17 +57,13 @@ ${class_name}::${class_name} (${param_str}) : QWidget() {
this->top_layout->addLayout(this->top_grid_layout);
this->settings = new QSettings("GNU Radio", "${class_name}");
-
% endif
% if flow_graph.get_option('thread_safe_setters'):
## self._lock = threading.RLock()
% endif
-
-
this->tb = gr::make_top_block("${title}");
-
% if blocks:
// Blocks:
% for blk, blk_make, declarations in blocks:
@@ -113,7 +119,7 @@ void ${class_name}::set_${var.name} (${var.vtype} ${var.name}) {
int main (int argc, char **argv) {
% if parameters:
% for parameter in parameters:
- ${parameter.vtype} ${parameter.name};
+ ${parameter.vtype} ${parameter.name} = ${parameter.cpp_templates.render('make')};
% endfor
po::options_description desc("Options");
@@ -140,7 +146,7 @@ int main (int argc, char **argv) {
% endif
% if generate_options == 'no_gui':
- ${class_name}* top_block = new ${class_name}();
+ ${class_name}* top_block = new ${class_name}(${param_str_without_types});
## TODO: params
% if flow_graph.get_option('run_options') == 'prompt':
top_block->tb->start();
diff --git a/grc/core/generator/cpp_templates/flow_graph.hpp.mako b/grc/core/generator/cpp_templates/flow_graph.hpp.mako
index b9f3ce60be..b5b9d51b00 100644
--- a/grc/core/generator/cpp_templates/flow_graph.hpp.mako
+++ b/grc/core/generator/cpp_templates/flow_graph.hpp.mako
@@ -77,7 +77,7 @@ ${indent(declarations)}
% if parameters:
// Parameters:
% for param in parameters:
- ${param.get_cpp_var_make()}
+ ${param.vtype} ${param.cpp_templates.render('var_make')}
% endfor
% endif
diff --git a/grc/core/generator/cpp_top_block.py b/grc/core/generator/cpp_top_block.py
index c24e855d48..9b5a8ecc1b 100644
--- a/grc/core/generator/cpp_top_block.py
+++ b/grc/core/generator/cpp_top_block.py
@@ -5,6 +5,7 @@ import os
import tempfile
import textwrap
import re
+import ast
from mako.template import Template
@@ -232,7 +233,7 @@ class CppTopBlockGenerator(TopBlockGenerator):
blocks = [
b for b in fg.blocks
- if b.enabled and not (b.get_bypassed() or b.is_import or b in parameters or b.key == 'options')
+ if b.enabled and not (b.get_bypassed() or b.is_import or b in parameters or b.key == 'options' or b.is_virtual_source() or b.is_virtual_sink())
]
blocks = expr_utils.sort_objects(blocks, operator.attrgetter('name'), _get_block_sort_text)
@@ -263,17 +264,61 @@ class CppTopBlockGenerator(TopBlockGenerator):
fg = self._flow_graph
variables = fg.get_cpp_variables()
+ type_translation = {'complex': 'gr_complex', 'real': 'double', 'float': 'float', 'int': 'int', 'complex_vector': 'std::vector<gr_complex>', 'real_vector': 'std::vector<double>', 'float_vector': 'std::vector<float>', 'int_vector': 'std::vector<int>', 'string': 'std::string', 'bool': 'bool'}
+ # If the type is explcitly specified, translate to the corresponding C++ type
+ for var in list(variables):
+ if var.params['value'].dtype != 'raw':
+ var.vtype = type_translation[var.params['value'].dtype]
+ variables.remove(var)
+
+ # If the type is 'raw', we'll need to evaluate the variable to infer the type.
+ # Create an executable fragment of code containing all 'raw' variables in
+ # order to infer the lvalue types.
+ #
+ # Note that this differs from using ast.literal_eval() as literal_eval evaluates one
+ # variable at a time. The code fragment below evaluates all varaibles together which
+ # allows the variables to reference each other (i.e. a = b * c).
+ prog = 'def get_decl_types():\n'
+ prog += '\tvar_types = {}\n'
for var in variables:
- var.decide_type()
+ prog += '\t' + str(var.params['id'].value) + '=' + str(var.params['value'].value) + '\n'
+ prog += '\tvar_types = {}\n';
+ for var in variables:
+ prog += '\tvar_types[\'' + str(var.params['id'].value) + '\'] = type(' + str(var.params['id'].value) + ')\n'
+ prog += '\treturn var_types'
+
+ # Execute the code fragment in a separate namespace and retrieve the lvalue types
+ var_types = {}
+ namespace = {}
+ try:
+ exec(prog, namespace)
+ var_types = namespace['get_decl_types']()
+ except Exception as excp:
+ print('Failed to get parameter lvalue types: %s' %(excp))
+
+ # Format the rvalue of each variable expression
+ for var in variables:
+ var.format_expr(var_types[str(var.params['id'].value)])
def _parameter_types(self):
fg = self._flow_graph
parameters = fg.get_parameters()
for param in parameters:
- type_translation = {'eng_float' : 'double', 'intx' : 'int', 'std' : 'std::string'};
+ type_translation = {'eng_float' : 'double', 'intx' : 'int', 'str' : 'std::string', 'complex': 'gr_complex'};
param.vtype = type_translation[param.params['type'].value]
+ if param.vtype == 'gr_complex':
+ evaluated = ast.literal_eval(param.params['value'].value.strip())
+ cpp_cmplx = '{' + str(evaluated.real) + ', ' + str(evaluated.imag) + '}'
+
+ # Update the 'var_make' entry in the cpp_templates dictionary
+ d = param.cpp_templates
+ cpp_expr = d['var_make'].replace('${value}', cpp_cmplx)
+ d.update({'var_make':cpp_expr})
+ param.cpp_templates = d
+
+
def _callbacks(self):
fg = self._flow_graph
variables = fg.get_cpp_variables()
@@ -286,7 +331,8 @@ class CppTopBlockGenerator(TopBlockGenerator):
callbacks_all = []
for block in fg.iter_enabled_blocks():
- callbacks_all.extend(expr_utils.expr_replace(cb, replace_dict) for cb in block.get_cpp_callbacks())
+ if not (block.is_virtual_sink() or block.is_virtual_source()):
+ callbacks_all.extend(expr_utils.expr_replace(cb, replace_dict) for cb in block.get_cpp_callbacks())
# Map var id to callbacks
def uses_var_id(callback):
@@ -313,7 +359,13 @@ class CppTopBlockGenerator(TopBlockGenerator):
key = port.key
if not key.isdigit():
- key = re.findall(r'\d+', key)[0]
+ # TODO What use case is this supporting?
+ toks = re.findall(r'\d+', key)
+ if len(toks) > 0:
+ key = toks[0]
+ else:
+ # Assume key is a string
+ key = '"' + key + '"'
return '{block}, {key}'.format(block=block, key=key)
@@ -321,12 +373,15 @@ class CppTopBlockGenerator(TopBlockGenerator):
# Get the virtual blocks and resolve their connections
connection_factory = fg.parent_platform.Connection
- virtual = [c for c in connections if isinstance(c.source_block, blocks.VirtualSource)]
- for connection in virtual:
+ virtual_source_connections = [c for c in connections if isinstance(c.source_block, blocks.VirtualSource)]
+ for connection in virtual_source_connections:
sink = connection.sink_port
for source in connection.source_port.resolve_virtual_source():
resolved = connection_factory(fg.orignal_flowgraph, source, sink)
connections.append(resolved)
+
+ virtual_connections = [c for c in connections if (isinstance(c.source_block, blocks.VirtualSource) or isinstance(c.sink_block, blocks.VirtualSink))]
+ for connection in virtual_connections:
# Remove the virtual connection
connections.remove(connection)