Commit 4b0c5dd7 authored by Alexander Ryndin's avatar Alexander Ryndin
Browse files

issue-47: impl. server wrapper

parent 74a423b2
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<groupId>de.monticore.lang.monticar</groupId> <groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-generator</artifactId> <artifactId>embedded-montiarc-math-generator</artifactId>
<version>0.0.8-SNAPSHOT</version> <version>0.0.9-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= --> <!-- == PROJECT DEPENDENCIES ============================================= -->
...@@ -300,35 +300,29 @@ ...@@ -300,35 +300,29 @@
</configuration> </configuration>
</plugin> </plugin>
<!--plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>${assembly.plugin}</version> <version>3.1.0</version>
<dependencies>
<dependency>
<groupId>de.monticore</groupId>
<artifactId>mc-assemblies</artifactId>
<version>${mc.grammars.assembly.version}</version>
</dependency>
</dependencies>
<executions> <executions>
<execution> <execution>
<id>grammars</id> <id>jar-with-dependencies</id>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<descriptorRefs>
<descriptorRef>grammars-assembly</descriptorRef>
</descriptorRefs>
<formats>
<format>jar</format>
</formats>
</configuration>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>single</goal> <goal>single</goal>
</goals> </goals>
<configuration>
<archive>
<manifest>
<mainClass>de.monticore.lang.monticar.generator.cpp.GeneratorCppCli</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin --> </plugin>
<!-- Source Jar Configuration --> <!-- Source Jar Configuration -->
<plugin> <plugin>
......
...@@ -11,6 +11,7 @@ import de.monticore.lang.monticar.generator.cpp.converter.MathConverter; ...@@ -11,6 +11,7 @@ import de.monticore.lang.monticar.generator.cpp.converter.MathConverter;
import de.monticore.lang.monticar.generator.cpp.converter.TypeConverter; import de.monticore.lang.monticar.generator.cpp.converter.TypeConverter;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates; import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.viewmodel.AutopilotAdapterViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.AutopilotAdapterViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ServerWrapperViewModel;
import de.monticore.lang.monticar.ts.MCTypeSymbol; import de.monticore.lang.monticar.ts.MCTypeSymbol;
import de.monticore.lang.tagging._symboltable.TaggingResolver; import de.monticore.lang.tagging._symboltable.TaggingResolver;
import de.monticore.symboltable.Scope; import de.monticore.symboltable.Scope;
...@@ -34,6 +35,7 @@ public class GeneratorCPP implements Generator { ...@@ -34,6 +35,7 @@ public class GeneratorCPP implements Generator {
private Path modelsDirPath; private Path modelsDirPath;
private boolean isGenerateTests = false; private boolean isGenerateTests = false;
private boolean isGenerateAutopilotAdapter = false; private boolean isGenerateAutopilotAdapter = false;
private boolean isGenerateServerWrapper = false;
private final List<BluePrintCPP> bluePrints = new ArrayList<>(); private final List<BluePrintCPP> bluePrints = new ArrayList<>();
protected String generationTargetPath = "./target/generated-sources-cpp/"; protected String generationTargetPath = "./target/generated-sources-cpp/";
...@@ -154,6 +156,9 @@ public class GeneratorCPP implements Generator { ...@@ -154,6 +156,9 @@ public class GeneratorCPP implements Generator {
if (isGenerateAutopilotAdapter()) { if (isGenerateAutopilotAdapter()) {
fileContents.addAll(getAutopilotAdapterFiles(componentSymbol)); fileContents.addAll(getAutopilotAdapterFiles(componentSymbol));
} }
if (isGenerateServerWrapper()) {
fileContents.addAll(getServerWrapperFiles(componentSymbol));
}
//System.out.println(fileContents); //System.out.println(fileContents);
if (getGenerationTargetPath().charAt(getGenerationTargetPath().length() - 1) != '/') { if (getGenerationTargetPath().charAt(getGenerationTargetPath().length() - 1) != '/') {
setGenerationTargetPath(getGenerationTargetPath() + "/"); setGenerationTargetPath(getGenerationTargetPath() + "/");
...@@ -307,6 +312,14 @@ public class GeneratorCPP implements Generator { ...@@ -307,6 +312,14 @@ public class GeneratorCPP implements Generator {
isGenerateAutopilotAdapter = generateAutopilotAdapter; isGenerateAutopilotAdapter = generateAutopilotAdapter;
} }
public boolean isGenerateServerWrapper() {
return isGenerateServerWrapper;
}
public void setGenerateServerWrapper(boolean generateServerWrapper) {
isGenerateServerWrapper = generateServerWrapper;
}
public boolean isCheckModelDir() { public boolean isCheckModelDir() {
return checkModelDir; return checkModelDir;
} }
...@@ -337,4 +350,25 @@ public class GeneratorCPP implements Generator { ...@@ -337,4 +350,25 @@ public class GeneratorCPP implements Generator {
String fileContents = AllTemplates.generateAutopilotAdapter(vm); String fileContents = AllTemplates.generateAutopilotAdapter(vm);
return new FileContent(fileContents, "AutopilotAdapter.cpp"); return new FileContent(fileContents, "AutopilotAdapter.cpp");
} }
private static List<FileContent> getServerWrapperFiles(ExpandedComponentInstanceSymbol componentSymbol) {
List<FileContent> result = new ArrayList<>();
String[] filesToCopy = new String[]{
"Makefile",
"model.proto"
};
for (String file : filesToCopy) {
String resourcePath = String.format("/template/serverwrapper/%s", file);
result.add(FileUtil.getResourceAsFile(resourcePath, file));
}
result.add(generateServerWrapper(componentSymbol));
return result;
}
private static FileContent generateServerWrapper(ExpandedComponentInstanceSymbol componentSymbol) {
ServerWrapperViewModel vm = new ServerWrapperViewModel();
vm.setMainModelName(GeneralHelperMethods.getTargetLanguageComponentName(componentSymbol.getFullName()));
String fileContents = AllTemplates.generateServerWrapper(vm);
return new FileContent(fileContents, "server.cc");
}
} }
...@@ -70,6 +70,7 @@ public final class GeneratorCppCli { ...@@ -70,6 +70,7 @@ public final class GeneratorCppCli {
.hasArg(false) .hasArg(false)
.required(false) .required(false)
.build(); .build();
public static final Option OPTION_FLAG_CHECK_MODEL_DIR = Option.builder() public static final Option OPTION_FLAG_CHECK_MODEL_DIR = Option.builder()
.longOpt("check-model-dir") .longOpt("check-model-dir")
.desc("optional flag indicating if model dir should be checked for creation of component and stream list") .desc("optional flag indicating if model dir should be checked for creation of component and stream list")
...@@ -77,6 +78,13 @@ public final class GeneratorCppCli { ...@@ -77,6 +78,13 @@ public final class GeneratorCppCli {
.required(false) .required(false)
.build(); .build();
public static final Option OPTION_FLAG_SERVER_WRAPPER = Option.builder()
.longOpt("flag-generate-server-wrapper")
.desc("optional flag indicating if model should be wrapped into a server")
.hasArg(false)
.required(false)
.build();
private GeneratorCppCli() { private GeneratorCppCli() {
} }
...@@ -98,6 +106,7 @@ public final class GeneratorCppCli { ...@@ -98,6 +106,7 @@ public final class GeneratorCppCli {
options.addOption(OPTION_FLAG_ARMADILLO); options.addOption(OPTION_FLAG_ARMADILLO);
options.addOption(OPTION_FLAG_AUTOPILOT_ADAPTER); options.addOption(OPTION_FLAG_AUTOPILOT_ADAPTER);
options.addOption(OPTION_FLAG_CHECK_MODEL_DIR); options.addOption(OPTION_FLAG_CHECK_MODEL_DIR);
options.addOption(OPTION_FLAG_SERVER_WRAPPER);
return options; return options;
} }
...@@ -129,6 +138,7 @@ public final class GeneratorCppCli { ...@@ -129,6 +138,7 @@ public final class GeneratorCppCli {
g.useArmadilloBackend(); g.useArmadilloBackend();
} }
g.setCheckModelDir(cliArgs.hasOption(OPTION_FLAG_CHECK_MODEL_DIR.getLongOpt())); g.setCheckModelDir(cliArgs.hasOption(OPTION_FLAG_CHECK_MODEL_DIR.getLongOpt()));
g.setGenerateServerWrapper(cliArgs.hasOption(OPTION_FLAG_SERVER_WRAPPER.getLongOpt()));
g.setGenerateAutopilotAdapter(cliArgs.hasOption(OPTION_FLAG_AUTOPILOT_ADAPTER.getLongOpt())); g.setGenerateAutopilotAdapter(cliArgs.hasOption(OPTION_FLAG_AUTOPILOT_ADAPTER.getLongOpt()));
try { try {
if (componentSymbol != null) { if (componentSymbol != null) {
......
package de.monticore.lang.monticar.generator.cpp.template; package de.monticore.lang.monticar.generator.cpp.template;
import de.monticore.lang.monticar.generator.cpp.GeneratorCPP;
import de.monticore.lang.monticar.generator.cpp.viewmodel.AutopilotAdapterViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.AutopilotAdapterViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ComponentStreamTestViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.ComponentStreamTestViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.EnumViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.EnumViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ServerWrapperViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.StructViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.StructViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.TestsMainEntryViewModel; import de.monticore.lang.monticar.generator.cpp.viewmodel.TestsMainEntryViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ViewModelBase; import de.monticore.lang.monticar.generator.cpp.viewmodel.ViewModelBase;
...@@ -24,6 +24,7 @@ public final class AllTemplates { ...@@ -24,6 +24,7 @@ public final class AllTemplates {
private static final Template STRUCT; private static final Template STRUCT;
private static final Template ENUM; private static final Template ENUM;
private static final Template AUTOPILOT_ADAPTER; private static final Template AUTOPILOT_ADAPTER;
private static final Template SERVER_WRAPPER;
static { static {
Configuration conf = new Configuration(Configuration.VERSION_2_3_23); Configuration conf = new Configuration(Configuration.VERSION_2_3_23);
...@@ -38,6 +39,7 @@ public final class AllTemplates { ...@@ -38,6 +39,7 @@ public final class AllTemplates {
STRUCT = conf.getTemplate("/type/Struct.ftl"); STRUCT = conf.getTemplate("/type/Struct.ftl");
ENUM = conf.getTemplate("/type/Enum.ftl"); ENUM = conf.getTemplate("/type/Enum.ftl");
AUTOPILOT_ADAPTER = conf.getTemplate("/autopilotadapter/AutopilotAdapter.ftl"); AUTOPILOT_ADAPTER = conf.getTemplate("/autopilotadapter/AutopilotAdapter.ftl");
SERVER_WRAPPER = conf.getTemplate("/serverwrapper/ServerWrapper.ftl");
} catch (IOException e) { } catch (IOException e) {
String msg = "could not load templates"; String msg = "could not load templates";
Log.error(msg, e); Log.error(msg, e);
...@@ -71,6 +73,10 @@ public final class AllTemplates { ...@@ -71,6 +73,10 @@ public final class AllTemplates {
return generate(AUTOPILOT_ADAPTER, viewModel); return generate(AUTOPILOT_ADAPTER, viewModel);
} }
public static String generateServerWrapper(ServerWrapperViewModel viewModel) {
return generate(SERVER_WRAPPER, viewModel);
}
private static String generate(Template template, ViewModelBase viewModelBase) { private static String generate(Template template, ViewModelBase viewModelBase) {
return generate(template, TemplateHelper.getDataForTemplate(viewModelBase)); return generate(template, TemplateHelper.getDataForTemplate(viewModelBase));
} }
......
package de.monticore.lang.monticar.generator.cpp.viewmodel;
public final class ServerWrapperViewModel extends ViewModelBase {
private String mainModelName;
public String getMainModelName() {
return mainModelName;
}
public void setMainModelName(String mainModelName) {
this.mainModelName = mainModelName;
}
}
CXX = g++
CPPFLAGS += `pkg-config --cflags protobuf grpc`
CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++`\
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
-ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
all: server
server: model.pb.o model.grpc.pb.o server.o
$(CXX) $^ $(LDFLAGS) -o $@
.PRECIOUS: %.grpc.pb.cc
%.grpc.pb.cc: %.proto
$(PROTOC) -I . --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
.PRECIOUS: %.pb.cc
%.pb.cc: %.proto
$(PROTOC) -I . --cpp_out=. $<
clean:
rm -f *.o *.pb.cc *.pb.h server
<#include "/Common.ftl">
#include <chrono>
#include <iostream>
#include <memory>
#include <string>
#include "spdlog/spdlog.h"
#include <armadillo>
#include <grpcpp/grpcpp.h>
#include "model.grpc.pb.h"
#include "${viewModel.mainModelName}.h"
using arma::mat;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using model::Actuation;
using model::Model;
using model::ModelInputs;
using model::ModelOutputs;
using model::SensorData;
using model::Trajectory;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::chrono::time_point;
Actuation make_actuation(double engine, double steering_angle, double brakes)
{
Actuation p;
p.set_engine(engine);
p.set_steering_angle(steering_angle);
p.set_brakes(brakes);
return p;
}
class ServiceImplementation final : public Model::Service
{
private:
time_point<high_resolution_clock> start_time_;
int number_of_calls_;
const int calls_stats_frequency_;
std::shared_ptr<spdlog::logger> logger_;
${viewModel.mainModelName} model_;
void pass_inputs_to_model_(const ModelInputs *request)
{
model_.timeIncrement = request->time_increment();
if (request->has_sensor_data())
{
pass_sensor_data_(request->sensor_data());
}
else
{
logger_->warn("no sensor data is provided");
}
if (request->has_actuation())
{
pass_actuation_(request->actuation());
}
else
{
logger_->warn("no actuation is provided");
}
if (request->has_trajectory())
{
pass_trajectory_(request->trajectory());
}
else
{
logger_->warn("no trajectory is provided");
}
}
void pass_sensor_data_(const SensorData &sensor_data)
{
model_.currentVelocity = sensor_data.velocity();
if (sensor_data.has_position())
{
auto p = sensor_data.position();
model_.x = p.x();
model_.y = p.y();
}
else
{
logger_->warn("no position is provided");
}
model_.compass = sensor_data.compass();
}
void pass_actuation_(const Actuation &actuation)
{
model_.currentEngine = actuation.engine();
model_.currentSteering = actuation.steering_angle();
model_.currentBrakes = actuation.brakes();
}
void pass_trajectory_(const Trajectory &trajectory)
{
auto len = trajectory.points_size();
model_.trajectory_length = len;
if (len > 0)
{
mat &xs = model_.trajectory_x;
mat &ys = model_.trajectory_y;
for (auto i = 0; i < len; i++)
{
auto p = trajectory.points(i);
xs(0, i) = p.x();
ys(0, i) = p.y();
}
}
else
{
logger_->warn("trajectory is empty");
}
}
void log_call_()
{
number_of_calls_++;
if (number_of_calls_ % calls_stats_frequency_ == 0)
{
auto duration = duration_cast<milliseconds>(high_resolution_clock::now() - start_time_);
logger_->info("average response time = {} milliseconds", duration.count());
number_of_calls_ = 0;
start_time_ = high_resolution_clock::now();
}
}
public:
ServiceImplementation() : calls_stats_frequency_(10000), start_time_(high_resolution_clock::now())
{
number_of_calls_ = 0;
logger_ = spdlog::basic_logger_mt("ServiceImplementation", "/var/www/html/ServiceImplementation.log");
model_.init();
}
Status Execute(ServerContext *context, const ModelInputs *request, ModelOutputs *response) override
{
log_call_();
pass_inputs_to_model_(request);
model_.execute();
auto engine = model_.engine;
auto steering_angle = model_.steering;
auto brakes = model_.brakes;
response->mutable_actuation()->CopyFrom(make_actuation(engine, steering_angle, brakes));
return Status::OK;
}
};
void run_server()
{
std::cout << "initializing..." << std::endl
<< std::flush;
ServerBuilder builder;
std::string server_address("0.0.0.0:10247");
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
ServiceImplementation service;
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "server is listening on " << server_address << std::endl
<< std::flush;
server->Wait();
}
int main(int argc, char **argv)
{
run_server();
return 0;
}
syntax = "proto3";
option java_multiple_files = true;
option java_package = "de.rwth.modelling";
option java_outer_classname = "ModelProtos";
package model;
service Model {
rpc Execute (ModelInputs) returns (ModelOutputs) {}
}
message ModelInputs {
double time_increment = 1;
Actuation actuation = 2;
SensorData sensor_data = 3;
Trajectory trajectory = 4;
}
message ModelOutputs {
Actuation actuation = 1;
}
message Actuation {
double engine = 1;
double steering_angle = 2;
double brakes = 3;
}
message SensorData {
double velocity = 1;
Point position = 2;
double compass = 3;
}
message Trajectory {
repeated Point points = 1;
}
message Point {
double x = 1;
double y = 2;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment