summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
authorHåkon Vågsether <haakonsv@gmail.com>2017-12-21 00:07:28 +0100
committerHåkon Vågsether <haakonsv@gmail.com>2018-12-18 23:17:34 +0100
commit612c65091a748eb85a8dea2d9414f0486777fb17 (patch)
treebb83a329c3f15ddfa3b2f19abc24f38c5638e356 /grc
parentbac53b29f7008b33667a7c2c481ace02d73f3264 (diff)
Added C++ support to gr-analog, gr-blocks and grc
Diffstat (limited to 'grc')
-rw-r--r--grc/blocks/import.block.yml1
-rw-r--r--grc/blocks/note.block.yml1
-rw-r--r--grc/blocks/options.block.yml4
-rw-r--r--grc/blocks/pad_sink.block.yml1
-rw-r--r--grc/blocks/pad_source.block.yml1
-rw-r--r--grc/blocks/parameter.block.yml5
-rw-r--r--grc/blocks/stream.domain.yml2
-rw-r--r--grc/blocks/variable.block.yml2
-rw-r--r--grc/blocks/variable_config.block.yml1
-rw-r--r--grc/blocks/variable_function_probe.block.yml1
-rw-r--r--grc/core/blocks/_flags.py4
-rw-r--r--grc/core/blocks/block.py9
-rw-r--r--grc/core/generator/cpp_templates/CMakeLists.txt.mako7
-rw-r--r--grc/core/generator/cpp_templates/flow_graph.cpp.mako54
-rw-r--r--grc/core/generator/cpp_templates/flow_graph.hpp.mako29
-rw-r--r--grc/core/generator/cpp_top_block.py11
-rw-r--r--grc/core/generator/top_block.py3
-rw-r--r--grc/core/schema_checker/block.py1
-rw-r--r--grc/core/schema_checker/domain.py1
-rw-r--r--grc/gui/Executor.py57
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):