diff options
author | Håkon Vågsether <haakonsv@gmail.com> | 2017-12-21 00:07:28 +0100 |
---|---|---|
committer | Håkon Vågsether <haakonsv@gmail.com> | 2018-12-18 23:17:34 +0100 |
commit | 612c65091a748eb85a8dea2d9414f0486777fb17 (patch) | |
tree | bb83a329c3f15ddfa3b2f19abc24f38c5638e356 /grc | |
parent | bac53b29f7008b33667a7c2c481ace02d73f3264 (diff) |
Added C++ support to gr-analog, gr-blocks and grc
Diffstat (limited to 'grc')
-rw-r--r-- | grc/blocks/import.block.yml | 1 | ||||
-rw-r--r-- | grc/blocks/note.block.yml | 1 | ||||
-rw-r--r-- | grc/blocks/options.block.yml | 4 | ||||
-rw-r--r-- | grc/blocks/pad_sink.block.yml | 1 | ||||
-rw-r--r-- | grc/blocks/pad_source.block.yml | 1 | ||||
-rw-r--r-- | grc/blocks/parameter.block.yml | 5 | ||||
-rw-r--r-- | grc/blocks/stream.domain.yml | 2 | ||||
-rw-r--r-- | grc/blocks/variable.block.yml | 2 | ||||
-rw-r--r-- | grc/blocks/variable_config.block.yml | 1 | ||||
-rw-r--r-- | grc/blocks/variable_function_probe.block.yml | 1 | ||||
-rw-r--r-- | grc/core/blocks/_flags.py | 4 | ||||
-rw-r--r-- | grc/core/blocks/block.py | 9 | ||||
-rw-r--r-- | grc/core/generator/cpp_templates/CMakeLists.txt.mako | 7 | ||||
-rw-r--r-- | grc/core/generator/cpp_templates/flow_graph.cpp.mako | 54 | ||||
-rw-r--r-- | grc/core/generator/cpp_templates/flow_graph.hpp.mako | 29 | ||||
-rw-r--r-- | grc/core/generator/cpp_top_block.py | 11 | ||||
-rw-r--r-- | grc/core/generator/top_block.py | 3 | ||||
-rw-r--r-- | grc/core/schema_checker/block.py | 1 | ||||
-rw-r--r-- | grc/core/schema_checker/domain.py | 1 | ||||
-rw-r--r-- | grc/gui/Executor.py | 57 |
20 files changed, 112 insertions, 83 deletions
diff --git a/grc/blocks/import.block.yml b/grc/blocks/import.block.yml index 2d36b7396d..72da0cdd26 100644 --- a/grc/blocks/import.block.yml +++ b/grc/blocks/import.block.yml @@ -1,5 +1,6 @@ id: import_ label: Import +flags: python parameters: - id: imports diff --git a/grc/blocks/note.block.yml b/grc/blocks/note.block.yml index 3f21a75ceb..1b9b77ef03 100644 --- a/grc/blocks/note.block.yml +++ b/grc/blocks/note.block.yml @@ -1,5 +1,6 @@ id: note label: Note +flags: python, cpp parameters: - id: note diff --git a/grc/blocks/options.block.yml b/grc/blocks/options.block.yml index dec77a3f84..70ee13a45e 100644 --- a/grc/blocks/options.block.yml +++ b/grc/blocks/options.block.yml @@ -1,6 +1,6 @@ id: options label: Options -flags: has_python, has_cpp +flags: python, cpp parameters: - id: title @@ -156,7 +156,7 @@ templates: else: self.stop(); self.wait()' cpp_templates: - includes: '#include <gnuradio/top_block.h>' + includes: ['#include <gnuradio/top_block.h>'] documentation: |- The options block sets special parameters for the flow graph. Only one option block is allowed per flow graph. diff --git a/grc/blocks/pad_sink.block.yml b/grc/blocks/pad_sink.block.yml index 5c5679a155..0298b6039a 100644 --- a/grc/blocks/pad_sink.block.yml +++ b/grc/blocks/pad_sink.block.yml @@ -1,5 +1,6 @@ id: pad_sink label: Pad Sink +flags: python parameters: - id: label diff --git a/grc/blocks/pad_source.block.yml b/grc/blocks/pad_source.block.yml index 6600fa7d0b..3400c5d96a 100644 --- a/grc/blocks/pad_source.block.yml +++ b/grc/blocks/pad_source.block.yml @@ -1,5 +1,6 @@ id: pad_source label: Pad Source +flags: python parameters: - id: label diff --git a/grc/blocks/parameter.block.yml b/grc/blocks/parameter.block.yml index 387cbbf181..baaabd5865 100644 --- a/grc/blocks/parameter.block.yml +++ b/grc/blocks/parameter.block.yml @@ -1,5 +1,6 @@ id: parameter label: Parameter +flags: python, cpp parameters: - id: label @@ -37,6 +38,10 @@ templates: var_make: self.${id} = ${id} make: ${value} +cpp_templates: + var_make: ${type.type} ${id} = ${id}; + make: ${value} + documentation: |- This block represents a parameter to the flow graph. A parameter can be used to pass command line arguments into a top block. Or, parameters can pass arguments into an instantiated hierarchical block. diff --git a/grc/blocks/stream.domain.yml b/grc/blocks/stream.domain.yml index f97695b828..0a679cad01 100644 --- a/grc/blocks/stream.domain.yml +++ b/grc/blocks/stream.domain.yml @@ -7,5 +7,5 @@ multiple_connections_per_output: true templates: - type: [stream, stream] - connect: connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) + connect: self.connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) cpp_connect: hier_block2::connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) diff --git a/grc/blocks/variable.block.yml b/grc/blocks/variable.block.yml index 045511afb0..801ca645c1 100644 --- a/grc/blocks/variable.block.yml +++ b/grc/blocks/variable.block.yml @@ -1,6 +1,6 @@ id: variable label: Variable -flags: has_python, has_cpp +flags: python, cpp parameters: - id: value diff --git a/grc/blocks/variable_config.block.yml b/grc/blocks/variable_config.block.yml index bb64ea2a8f..969843d950 100644 --- a/grc/blocks/variable_config.block.yml +++ b/grc/blocks/variable_config.block.yml @@ -1,5 +1,6 @@ id: variable_config label: Variable Config +flags: python parameters: - id: value diff --git a/grc/blocks/variable_function_probe.block.yml b/grc/blocks/variable_function_probe.block.yml index 702ab5d60e..fd6de50ec0 100644 --- a/grc/blocks/variable_function_probe.block.yml +++ b/grc/blocks/variable_function_probe.block.yml @@ -1,5 +1,6 @@ id: variable_function_probe label: Function Probe +flags: python parameters: - id: block_id diff --git a/grc/core/blocks/_flags.py b/grc/core/blocks/_flags.py index ec590ebbb5..dedbb5a485 100644 --- a/grc/core/blocks/_flags.py +++ b/grc/core/blocks/_flags.py @@ -25,8 +25,8 @@ class Flags(object): NEED_QT_GUI = 'need_qt_gui' DEPRECATED = 'deprecated' NOT_DSP = 'not_dsp' - HAS_PYTHON = 'has_python' - HAS_CPP = 'has_cpp' + HAS_PYTHON = 'python' + HAS_CPP = 'cpp' def __init__(self, flags): self.data = set(flags) diff --git a/grc/core/blocks/block.py b/grc/core/blocks/block.py index 4df3ec9663..19b16b53d6 100644 --- a/grc/core/blocks/block.py +++ b/grc/core/blocks/block.py @@ -169,9 +169,14 @@ class Block(Element): """check if this block supports the selected output language""" current_output_language = self.parent.get_option('output_language') - if current_output_language == 'cpp' and 'has_cpp' not in self.flags: + if current_output_language == 'cpp': + if 'cpp' not in self.flags: self.add_error_message("This block does not support C++ output.") + if self.key == 'parameter': + if not self.params['type'].value: + self.add_error_message("C++ output requires you to choose a parameter type.") + def _validate_var_value(self): """or variables check the value (only if var_value is used)""" if self.is_variable and self.value != 'value': @@ -266,6 +271,8 @@ class Block(Element): a list of strings """ def make_callback(callback): + if self.is_variable: + return callback if 'this->' in callback: return callback return 'this->{}->{}'.format(self.name, callback) diff --git a/grc/core/generator/cpp_templates/CMakeLists.txt.mako b/grc/core/generator/cpp_templates/CMakeLists.txt.mako index 56f39c6b22..4e5c18637a 100644 --- a/grc/core/generator/cpp_templates/CMakeLists.txt.mako +++ b/grc/core/generator/cpp_templates/CMakeLists.txt.mako @@ -16,7 +16,7 @@ class_name = flow_graph.get_option('id') cmake_opt_list = flow_graph.get_option('cmake_opt').split(";") %>\ -# cmake_minimum_required(VERSION 3.8) Which version? +cmake_minimum_required(VERSION 3.8) # Which version? % if generate_options == 'qt_gui': find_package(Qt5Widgets REQUIRED) @@ -50,11 +50,14 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(GR_LIBRARIES boost_system + % if parameters: + boost_program_options + % endif gnuradio-blocks gnuradio-runtime gnuradio-pmt % for link in links: - % if link != '': + % if link: ${link} % endif % endfor diff --git a/grc/core/generator/cpp_templates/flow_graph.cpp.mako b/grc/core/generator/cpp_templates/flow_graph.cpp.mako index b919015f86..8a8987084c 100644 --- a/grc/core/generator/cpp_templates/flow_graph.cpp.mako +++ b/grc/core/generator/cpp_templates/flow_graph.cpp.mako @@ -1,3 +1,4 @@ +<%def name="doubleindent(code)">${ '\n '.join(str(code).splitlines()) }</%def>\ /******************** GNU Radio C++ Flow Graph Source File @@ -12,21 +13,24 @@ Generated: ${generated_time} ********************/ #include "${flow_graph.get_option('id')}.hpp" +% if parameters: +namespace po = boost::program_options; + +% endif using namespace gr; <% - class_name = flow_graph.get_option('id') -## TODO: param_str +class_name = 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) %>\ -<%def name="indent(code)">${ '\n '.join(str(code).splitlines()) }</%def> -## TODO: param_str % if generate_options == 'no_gui': -${class_name}::${class_name} () : top_block("${title}") { +${class_name}::${class_name} (${param_str}) { % elif generate_options.startswith('hb'): ## TODO: make_io_sig -${class_name}::${class_name} () : hier_block2("${title}") { +${class_name}::${class_name} (${param_str}) : hier_block2("${title}") { % for pad in flow_graph.get_hier_block_message_io('in'): message_port_register_hier_in("${pad['label']}") % endfor @@ -34,7 +38,7 @@ ${class_name}::${class_name} () : hier_block2("${title}") { message_port_register_hier_out("${pad['label']}") % endfor % elif generate_options == 'qt_gui': -${class_name}::${class_name} () : QWidget(), top_block("display_qt") { +${class_name}::${class_name} (${param_str}) : QWidget() { this->setWindowTitle("${title}"); // check_set_qss // set icon @@ -58,11 +62,15 @@ ${class_name}::${class_name} () : QWidget(), top_block("display_qt") { ## self._lock = threading.RLock() % endif +% if not generate_options.startswith('hb'): + this->tb = make_top_block("${title}"); +% endif + % if blocks: // Blocks: % for blk, blk_make, declarations in blocks: { - ${indent(blk_make)} + ${doubleindent(blk_make)} ## % if 'alias' in blk.params and blk.params['alias'].get_evaluated(): ## ${blk.name}.set_block_alias("${blk.params['alias'].get_evaluated()}") ## % endif @@ -107,11 +115,31 @@ void ${class_name}::set_${var.name} (${var.vtype} ${var.name}) { % endfor % endif } + % endfor int main (int argc, char **argv) { % if parameters: - ## parse args + % for parameter in parameters: + ${parameter.vtype} ${parameter.name}; + % endfor + + po::options_description desc("Options"); + desc.add_options() + ("help", "display help") + % for parameter in parameters: + ("${parameter.name}", po::value<${parameter.vtype}>(&${parameter.name}), "${parameter.label}") + % endfor + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << std::endl; + return 0; + } % endif % if flow_graph.get_option('realtime_scheduling'): if (enable_realtime_scheduling() != RT_OK) { @@ -123,7 +151,7 @@ int main (int argc, char **argv) { ${class_name}* top_block = new ${class_name}(); ## TODO: params % if flow_graph.get_option('run_options') == 'prompt': - top_block->start(); + top_block->tb->start(); % for m in monitors: (top_block->${m.name}).start(); % endfor @@ -131,7 +159,7 @@ int main (int argc, char **argv) { std::cin.ignore(); top_block->stop(); % elif flow_graph.get_option('run_options') == 'run': - top_block->start(); + top_block->tb->start(); % endif % for m in monitors: (top_block->${m.name}).start(); @@ -140,9 +168,9 @@ int main (int argc, char **argv) { % elif generate_options == 'qt_gui': QApplication app(argc, argv); - ${class_name} *top_block = new ${class_name}(); + ${class_name} *top_block = new ${class_name}(${param_str_without_types}); - top_block->start(); + top_block->tb->start(); top_block->show(); app.exec(); diff --git a/grc/core/generator/cpp_templates/flow_graph.hpp.mako b/grc/core/generator/cpp_templates/flow_graph.hpp.mako index 0acd90734a..7b117a45de 100644 --- a/grc/core/generator/cpp_templates/flow_graph.hpp.mako +++ b/grc/core/generator/cpp_templates/flow_graph.hpp.mako @@ -1,3 +1,4 @@ +<%def name="indent(code)">${ ' ' + '\n '.join(str(code).splitlines()) }</%def>\ #ifndef ${flow_graph.get_option('id').upper()}_HPP #define ${flow_graph.get_option('id').upper()}_HPP /******************** @@ -28,19 +29,25 @@ ${inc} #include <QSettings> % endif +% if parameters: +#include <iostream> +#include <boost/program_options.hpp> +% endif + using namespace gr; <% - class_name = flow_graph.get_option('id') -## TODO: param_str +class_name = flow_graph.get_option('id') +param_str = ", ".join((param.vtype + " " + param.name) for param in parameters) %>\ + % if generate_options == 'no_gui': -class ${class_name} : public top_block { +class ${class_name} { % elif generate_options.startswith('hb'): class ${class_name} : public hier_block2 { % elif generate_options == 'qt_gui': -class ${class_name} : public QWidget, public top_block { +class ${class_name} : public QWidget { Q_OBJECT % endif @@ -56,15 +63,15 @@ private: % for block, make, declarations in blocks: - % if declarations: - ${declarations} - % endif +% if declarations: +${indent(declarations)} +% endif % endfor % if parameters: // Parameters: % for param in parameters: - ${param.get_var_make()} + ${param.get_cpp_var_make()} % endfor % endif @@ -76,8 +83,10 @@ private: % endif public: - ${class_name}(); - ## TODO: param_str +% if not generate_options.startswith('hb'): + top_block_sptr tb; +% endif + ${class_name}(${param_str}); ~${class_name}(); % for var in parameters + variables: diff --git a/grc/core/generator/cpp_top_block.py b/grc/core/generator/cpp_top_block.py index 6991f22bf2..950a3cffba 100644 --- a/grc/core/generator/cpp_top_block.py +++ b/grc/core/generator/cpp_top_block.py @@ -60,6 +60,7 @@ class CppTopBlockGenerator(TopBlockGenerator): parameters = fg.get_parameters() monitors = fg.get_monitors() self._variable_types() + self._parameter_types() self.namespace = { 'flow_graph': fg, @@ -245,6 +246,14 @@ class CppTopBlockGenerator(TopBlockGenerator): for var in variables: var.decide_type() + 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'}; + param.vtype = type_translation[param.params['type'].value] + def _callbacks(self): fg = self._flow_graph variables = fg.get_cpp_variables() @@ -338,7 +347,7 @@ class CppTopBlockGenerator(TopBlockGenerator): for con in sorted(connections, key=by_domain_and_blocks): template = templates[con.type] code = template.render(make_port_sig=make_port_sig, source=con.source_port, sink=con.sink_port) - code = 'this->' + code + code = 'this->tb->' + code rendered.append(code) return rendered diff --git a/grc/core/generator/top_block.py b/grc/core/generator/top_block.py index cab1bf71cb..f2b485d641 100644 --- a/grc/core/generator/top_block.py +++ b/grc/core/generator/top_block.py @@ -266,6 +266,9 @@ class TopBlockGenerator(object): # Remove the virtual connection connections.remove(connection) + for connection in virtual_sink_connections: + connections.remove(connection) + # Bypassing blocks: Need to find all the enabled connections for the block using # the *connections* object rather than get_connections(). Create new connections # that bypass the selected block and remove the existing ones. This allows adjacent diff --git a/grc/core/schema_checker/block.py b/grc/core/schema_checker/block.py index 91ce906df2..e36865fed0 100644 --- a/grc/core/schema_checker/block.py +++ b/grc/core/schema_checker/block.py @@ -39,6 +39,7 @@ CPP_TEMPLATES_SCHEME = expand( includes=list, declarations=str_, make=str_, + var_make=str_, callbacks=list, link=list, translations=dict, diff --git a/grc/core/schema_checker/domain.py b/grc/core/schema_checker/domain.py index 86c29ed3c6..19b0a510d0 100644 --- a/grc/core/schema_checker/domain.py +++ b/grc/core/schema_checker/domain.py @@ -3,6 +3,7 @@ from .utils import Spec, expand, str_ DOMAIN_CONNECTION = expand( type=Spec(types=list, required=True, item_scheme=None), connect=str_, + cpp_connect=str_, ) DOMAIN_SCHEME = expand( diff --git a/grc/gui/Executor.py b/grc/gui/Executor.py index 79bb29f101..7d7caaaf98 100644 --- a/grc/gui/Executor.py +++ b/grc/gui/Executor.py @@ -79,49 +79,6 @@ class ExecFlowGraphThread(threading.Thread): shell=False, universal_newlines=True ) - def _cpp_run_cmake(self): - """ - Generate and compile this C++ flow graph. - """ - generator = self.page.get_generator() - - xterm_executable = find_executable(self.xterm_executable) - - dirname = generator.file_path - builddir = os.path.join(dirname, 'build') - - run_command_args = [ 'cmake', '..' ] - Messages.send_start_exec(' '.join(run_command_args)) - - return subprocess.Popen( - args=run_command_args, - cwd=builddir, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=False, universal_newlines=True - ) - - def _cpp_compile(self): - """ - Compile this C++ flow graph. - """ - generator = self.page.get_generator() - - xterm_executable = find_executable(self.xterm_executable) - - dirname = generator.file_path - builddir = os.path.join(dirname, 'build') - - run_command_args = [ 'make' ] - Messages.send_start_exec(' '.join(run_command_args)) - - return subprocess.Popen( - args=run_command_args, - cwd=builddir, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=False, universal_newlines=True - ) - - def _cpp_popen(self): """ Execute this C++ flow graph after generating and compiling it. @@ -129,22 +86,22 @@ class ExecFlowGraphThread(threading.Thread): generator = self.page.get_generator() run_command = generator.file_path + '/build/' + self.flow_graph.get_option('id') + dirname = generator.file_path + builddir = os.path.join(dirname, 'build') + if os.path.isfile(run_command): os.remove(run_command) xterm_executable = find_executable(self.xterm_executable) - process = self._cpp_run_cmake() - process.wait() - process = self._cpp_compile() - process.wait() - run_command_args = [xterm_executable, '-e', run_command] + run_command_args = ['cmake .. &&', 'make && ', xterm_executable, '-e', run_command] Messages.send_start_exec(' '.join(run_command_args)) return subprocess.Popen( - args=run_command_args, + args=' '.join(run_command_args), + cwd=builddir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=False, universal_newlines=True + shell=True, universal_newlines=True ) def run(self): |