Aufgrund einer Wartung wird GitLab am 21.09. zwischen 8:00 und 9:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 21.09. between 8:00 and 9:00 am.

Commit 15504b17 authored by Evgeny Kusmenko's avatar Evgeny Kusmenko
Browse files

Merge branch 'sim_dev' into 'master'

Library-interface & server-adapter updates

See merge request !54
parents 53a62635 f56b4c00
Pipeline #494528 passed with stage
in 1 minute and 36 seconds
......@@ -25,5 +25,3 @@ buildNumber.properties
.project
.vscode/
.settings/
temp/
\ No newline at end of file
# In order to update the 'shared_cpp' submodule
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- linux
#- windows
......
[submodule "src/main/resources/shared_cpp"]
path = src/main/resources/shared_cpp
url = ../../simulators/shared_cpp
......@@ -10,7 +10,7 @@
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-generator</artifactId>
<version>0.4.7</version>
<version>0.4.8</version>
<!-- == PROJECT DEPENDENCIES ============================================= -->
......
......@@ -14,7 +14,7 @@ import de.monticore.lang.monticar.generator.cmake.CMakeFindModule;
import de.monticore.lang.monticar.generator.cpp.Dynamics.DynamicHelper;
import de.monticore.lang.monticar.generator.cpp.Dynamics.EventPortValueCheck;
import de.monticore.lang.monticar.generator.cpp.converter.*;
import de.monticore.lang.monticar.generator.cpp.dynamic_interface.DynamicInterfaceGenerator;
import de.monticore.lang.monticar.generator.cpp.dynamic_interface.AdapterGenerator;
import de.monticore.lang.monticar.generator.cpp.loopSolver.CPPEquationSystemHelper;
import de.monticore.lang.monticar.generator.cpp.loopSolver.EquationSystemComponentInstanceSymbol;
import de.monticore.lang.monticar.generator.cpp.loopSolver.NumericSolverOptions;
......@@ -49,9 +49,8 @@ public class GeneratorCPP implements EMAMGenerator {
public static GeneratorCPP currentInstance;
private Path modelsDirPath;
private boolean isGenerateTests = false;
private boolean genDynamicInterface = false;
private boolean genLibraryInterface = false;
private boolean genServerAdapter = false;
private boolean genDDCAdapter = false;
private boolean importArmadillo = false;
private String outputName = "";
private boolean isGenerateServerWrapper = false;
......@@ -391,16 +390,15 @@ public class GeneratorCPP implements EMAMGenerator {
public void generateAdapters(List<FileContent> fileContents, EMAComponentInstanceSymbol component) {
if (genDynamicInterface || genServerAdapter || genDDCAdapter) {
if (genLibraryInterface || genServerAdapter) {
try {
fileContents.addAll(
new DynamicInterfaceGenerator(
new AdapterGenerator(
component,
cMakeConfig,
outputName,
genDynamicInterface,
genServerAdapter,
genDDCAdapter
genLibraryInterface,
genServerAdapter
).getFiles()
);
} catch (SerializationException | IOException e) {
......@@ -541,8 +539,8 @@ public class GeneratorCPP implements EMAMGenerator {
isGenerateTests = generateTests;
}
public boolean isGenerateDynamicInterface() {
return genDynamicInterface;
public boolean isGenerateLibraryInterface() {
return genLibraryInterface;
}
public void setImportArmadillo(boolean doImport) {
......@@ -553,8 +551,8 @@ public class GeneratorCPP implements EMAMGenerator {
return importArmadillo;
}
public void setGenerateDynamicInterface(boolean gen) {
genDynamicInterface = gen;
public void setGenerateLibraryInterface(boolean gen) {
genLibraryInterface = gen;
}
public boolean isGenerateServerAdapter() {
......@@ -565,14 +563,6 @@ public class GeneratorCPP implements EMAMGenerator {
genServerAdapter = gen;
}
public boolean isGenerateDDCAdapter() {
return genDDCAdapter;
}
public void setGenerateDDCAdapter(boolean gen) {
genDDCAdapter = gen;
}
public void setOutputName(String name) {
this.outputName = name;
}
......
......@@ -106,9 +106,9 @@ public final class GeneratorCppCli {
.build();
public static final Option OPTION_FLAG_DYNAMIC_INTERFACE = Option.builder("di")
.longOpt("dyn-interface")
.desc("Enable autopilot adapter generation")
public static final Option OPTION_FLAG_LIBRARY_INTERFACE = Option.builder()
.longOpt("library-interface")
.desc("Enables the autopilot library-adapter generation")
.hasArg(false)
.required(false)
.build();
......@@ -120,13 +120,6 @@ public final class GeneratorCppCli {
.required(false)
.build();
public static final Option OPTION_FLAG_GEN_DDC_ADAPTER = Option.builder("ddc")
.longOpt("ddc-adapter")
.desc("Generate the DDC adapter for the model")
.hasArg(false)
.required(false)
.build();
public static final Option OPTION_FLAG_CHECK_MODEL_DIR = Option.builder()
.longOpt("check-model-dir")
.desc("optional flag indicating if model dir should be checked for creation of component and stream list")
......@@ -266,10 +259,9 @@ public final class GeneratorCppCli {
options.addOption(OPTION_FLAG_TESTS);
options.addOption(OPTION_FLAG_ARMADILLO);
options.addOption(OPTION_IMPORT_ARMADILLO);
options.addOption(OPTION_FLAG_DYNAMIC_INTERFACE);
options.addOption(OPTION_FLAG_LIBRARY_INTERFACE);
options.addOption(OPTION_OUTPUT_NAME);
options.addOption(OPTION_FLAG_GEN_TCP_SERVER);
options.addOption(OPTION_FLAG_GEN_DDC_ADAPTER);
options.addOption(OPTION_FLAG_CHECK_MODEL_DIR);
options.addOption(OPTION_FLAG_SERVER_WRAPPER);
options.addOption(OPTION_FLAG_ALGEBRAIC);
......@@ -321,9 +313,8 @@ public final class GeneratorCppCli {
}
g.setCheckModelDir(cliArgs.hasOption(OPTION_FLAG_CHECK_MODEL_DIR.getLongOpt()));
g.setGenerateServerWrapper(cliArgs.hasOption(OPTION_FLAG_SERVER_WRAPPER.getLongOpt()));
g.setGenerateDynamicInterface(cliArgs.hasOption(OPTION_FLAG_DYNAMIC_INTERFACE.getLongOpt()));
g.setGenerateLibraryInterface(cliArgs.hasOption(OPTION_FLAG_LIBRARY_INTERFACE.getLongOpt()));
g.setGenerateServerAdapter(cliArgs.hasOption(OPTION_FLAG_GEN_TCP_SERVER.getLongOpt()));
g.setGenerateDDCAdapter(cliArgs.hasOption(OPTION_FLAG_GEN_DDC_ADAPTER.getLongOpt()));
g.setOutputName(cliArgs.getOptionValue(OPTION_OUTPUT_NAME.getOpt()));
g.setUseAlgebraicOptimizations(cliArgs.hasOption(OPTION_FLAG_ALGEBRAIC.getLongOpt()));
......
......@@ -41,7 +41,7 @@ public final class TypesGeneratorCPP {
} else if (s instanceof EnumDeclarationSymbol) {
processEnum((EnumDeclarationSymbol) s);
} else {
Log.warn("unknown type symbol: " + s.getFullName());
//Log.warn("unknown type symbol: " + s.getFullName());
}
}
......
package de.monticore.lang.monticar.generator.cpp.dynamic_interface;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import de.rwth.montisim.commons.dynamicinterface.*;
import de.rwth.montisim.commons.dynamicinterface.PortInformation.PortType;
import de.rwth.montisim.commons.utils.json.SerializationException;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.cmake.CMakeConfig;
import de.monticore.lang.monticar.generator.cpp.FileUtil;
import de.monticore.lang.monticar.generator.cpp.dynamic_interface.ProgramInterfaceResolver.SocketInfo;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAComponentInstanceSymbol;
/*
Generates the CPP files necessary to build the 'library_interface' or the 'server_adapter' for the ema component.
*/
public class AdapterGenerator {
HashSet<String> fileDependenciesOwnCpp = new HashSet<>();
HashSet<String> fileDependenciesSharedCpp = new HashSet<>();
List<FileContent> files = new ArrayList<>();
ProgramInterfaceResolver interfaceResolver;
public AdapterGenerator(
EMAComponentInstanceSymbol componentSymbol,
CMakeConfig cmake,
String outputName,
boolean genLibInterface,
boolean genServerAdapter
) throws SerializationException, IOException {
if (outputName.length() == 0) outputName = componentSymbol.getName();
// Read the ProgramInterface from the model
interfaceResolver = new ProgramInterfaceResolver();
interfaceResolver.resolve(componentSymbol);
String targetNameWithSerialization = outputName+ "_with_serialization";
String targetNameLib = outputName+ "_lib";
String targetNameServer = outputName+ "_server";
// Generate the serialization code
HashMap<String, Object> serializationTemplateData = new HashMap<>();
serializationTemplateData.put("mainModelName", interfaceResolver.componentName);
serializationTemplateData.put("interfaceDescription", interfaceResolver.progInterfaceString);
serializationTemplateData.put("portCount", interfaceResolver.programInterface.ports.size());
serializationTemplateData.put("isSocket", getIsSocketList());
serializationTemplateData.put("isOutput", getIsOutputList());
new JsonSerializationGenerator(this).generate(serializationTemplateData);
new BinarySerializationGenerator(this).generate(serializationTemplateData);
new PortInitGenerator(this).generate(serializationTemplateData);;
files.add(new FileContent(AllTemplates.generate(AllTemplates.ADAPTER_PROGRAM_H, serializationTemplateData), "program.h"));
files.add(new FileContent(AllTemplates.generate(AllTemplates.ADAPTER_PROGRAM_CPP, serializationTemplateData), "program.cpp"));
addFileDependencySharedCpp("buffer.h");
addFileDependencySharedCpp("buffer.cpp");
addFileDependencySharedCpp("json.h");
addFileDependencySharedCpp("json.cpp");
addFileDependencySharedCpp("printf.h");
addFileDependencySharedCpp("printf.cpp");
addFileDependencySharedCpp("err_out.h");
addFileDependencySharedCpp("err_out.cpp");
// TODO "intermediate target" with serialization code ?
cmake.addCMakeCommandEnd("# A static library around the root EMA component with JSON/Binary serialization functions.");
cmake.addCMakeCommandEnd("add_library("+targetNameWithSerialization+" STATIC program.cpp buffer.cpp json.cpp printf.cpp err_out.cpp)");
cmake.addCMakeCommandEnd("target_include_directories("+targetNameWithSerialization+" PUBLIC ${INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})");
//cmake.addCMakeCommandEnd("target_link_libraries("+targetNameWithSerialization+" PUBLIC ${LIBS} -static-libgcc -static-libstdc++)");
cmake.addCMakeCommandEnd("target_link_libraries("+targetNameWithSerialization+" PRIVATE ${LIBS})");
cmake.addCMakeCommandEnd("target_compile_features("+targetNameWithSerialization+" PUBLIC cxx_std_11)");
cmake.addCMakeCommandEnd("set_target_properties("+targetNameWithSerialization+" PROPERTIES LINKER_LANGUAGE CXX POSITION_INDEPENDENT_CODE ON)");
cmake.addCMakeCommandEnd("");
cmake.addCMakeCommandEnd("");
// Generate the files
if (genLibInterface) {
addFileDependencySharedCpp("library_interface.h");
addFileDependencyOwnCpp("library_interface.cpp");
// CMake
// create shared lib for "library_interface"
cmake.addCMakeCommandEnd("# The library-interface based communication adapter (for the hardware_emulator)");
cmake.addCMakeCommandEnd("add_library("+targetNameLib+" SHARED library_interface.cpp)");
cmake.addCMakeCommandEnd("target_link_libraries("+targetNameLib+" PUBLIC -static-libgcc -static-libstdc++ "+targetNameWithSerialization+")");
cmake.addCMakeCommandEnd("set_target_properties("+targetNameLib+" PROPERTIES LINKER_LANGUAGE CXX POSITION_INDEPENDENT_CODE ON)");
cmake.addCMakeCommandEnd("set_target_properties("+targetNameLib+" PROPERTIES PREFIX \"\")");
// install shared lib
cmake.addCMakeCommandEnd("install(TARGETS "+targetNameLib+" DESTINATION $ENV{DLL_DIR})");
//cmake.addCMakeCommandEnd("export(TARGETS "+outputName+" FILE "+outputName+".cmake)");
cmake.addCMakeCommandEnd("");
}
if (genServerAdapter) {
addFileDependencySharedCpp("network.h");
addFileDependencySharedCpp("network.cpp");
addFileDependencySharedCpp("tcp_protocol.h");
addFileDependencyOwnCpp("server_adapter.h");
addFileDependencySharedCpp("standard_err_out.h");
addFileDependencySharedCpp("standard_err_out.cpp");
addFileDependencyOwnCpp("server_adapter.cpp");
// create adapter executable
cmake.addCMakeCommandEnd("# ServerAdapter for the EMA component");
cmake.addCMakeCommandEnd("add_executable("+targetNameServer+" server_adapter.cpp network.cpp standard_err_out.cpp)");
cmake.addCMakeCommandEnd("target_link_libraries("+targetNameServer+" PUBLIC "+targetNameWithSerialization+")");
cmake.addCMakeCommandEnd("if (CMAKE_HOST_WIN32)");
cmake.addCMakeCommandEnd(" target_link_libraries("+targetNameServer+" PUBLIC ws2_32)");
cmake.addCMakeCommandEnd("endif()");
cmake.addCMakeCommandEnd("");
}
// Add the common file dependencies
for (String f : fileDependenciesOwnCpp) {
files.add(FileUtil.getResourceAsFile("/template/adapters/"+f, f));
}
for (String f : fileDependenciesSharedCpp) {
files.add(FileUtil.getResourceAsFile("/shared_cpp/"+f, f));
}
}
String getIsSocketList() {
String isSocketList = "";
boolean first = true;
for (PortInformation portInfo : interfaceResolver.programInterface.ports) {
if (first) first = false;
else isSocketList += ", ";
isSocketList += portInfo.port_type == PortType.SOCKET ? "true" : "false";
}
return isSocketList;
}
String getIsOutputList() {
String isOutputList = "";
boolean first = true;
for (PortInformation portInfo : interfaceResolver.programInterface.ports) {
if (first) first = false;
else isOutputList += ", ";
isOutputList += portInfo.isOutput() ? "true" : "false";
}
return isOutputList;
}
public List<FileContent> getFiles() {
return files;
}
public void addFileDependencyOwnCpp(String name) {
fileDependenciesOwnCpp.add(name);
}
public void addFileDependencySharedCpp(String name) {
fileDependenciesSharedCpp.add(name);
}
}
package de.monticore.lang.monticar.generator.cpp.dynamic_interface;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import de.monticore.lang.monticar.generator.FileContent;
import de.rwth.montisim.commons.utils.json.SerializationException;
public class DDCCommunication {
static final String BASE_SPACES = " ";
final DynamicInterfaceGenerator gen;
FileBuilder b = new FileBuilder();
public DDCCommunication(DynamicInterfaceGenerator gen) {
this.gen = gen;
throw new IllegalArgumentException("DDCCommunication not implemented yet.");
}
public List<FileContent> generate() throws SerializationException {
List<FileContent> files = new ArrayList<>();
return files;
}
public void getSources(HashSet<String> sources) {
sources.add("ddc_mode.cpp");
}
public void getLibs(HashSet<String> libs) {
libs.add("ddc_load");
}
}
package de.monticore.lang.monticar.generator.cpp.dynamic_interface;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.cmake.CMakeConfig;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.dynamic_interface.ProgramInterfaceResolver.SocketInfo;
import de.rwth.montisim.commons.dynamicinterface.*;
import de.rwth.montisim.commons.dynamicinterface.PortInformation.PortDirection;
import de.rwth.montisim.commons.utils.json.SerializationException;
public class JsonCommunication {
static final int BASE_INDENT = 2;
//public static void generateCMake(CMakeConfig cmake,)
final DynamicInterfaceGenerator gen;
FileBuilder b = new FileBuilder();
public class JsonSerializationGenerator extends SerializationGenerator {
JsonCommunication(DynamicInterfaceGenerator gen) {
this.gen = gen;
JsonSerializationGenerator(AdapterGenerator gen) {
super(gen);
}
public List<FileContent> generate() throws SerializationException {
List<FileContent> files = new ArrayList<>();
List<String> getPortCases = new ArrayList<>();
List<String> setPortCases = new ArrayList<>();
int i = 0;
for (PortInformation portInfo : gen.programInterface.ports){
if (portInfo.direction == PortDirection.INPUT){
setPortCases.add(generateSetPortCase(i, portInfo));
} else {
getPortCases.add(generateGetPortCase(i, portInfo));
}
++i;
}
HashMap<String, Object> templateData = new HashMap<>();
templateData.put("mainModelName", gen.componentName);
templateData.put("interfaceDescription", gen.progInterfaceString);
templateData.put("getPortCases", getPortCases);
templateData.put("setPortCases", setPortCases);
files.add(new FileContent(AllTemplates.generate(AllTemplates.DYNAMIC_INTERFACE_H, templateData), "dynamic_interface.h"));
files.add(new FileContent(AllTemplates.generate(AllTemplates.DYNAMIC_INTERFACE_CPP, templateData), "dynamic_interface.cpp"));
gen.addCppFileDependency("json.h");
gen.addCppFileDependency("json.cpp");
gen.addCppFileDependency("printf.h");
gen.addCppFileDependency("printf.cpp");
gen.addCppFileDependency("utils.h");
String getType() {
return "Json";
}
return files;
boolean isJson() {
return true;
}
public void addCMake(CMakeConfig cmake, String outputName) {
// create shared lib
cmake.addCMakeCommandEnd("# The JSON/Dynamic-interface based communication adapter (for the hardware_emulator)");
cmake.addCMakeCommandEnd("add_library("+outputName+" SHARED dynamic_interface.cpp json.cpp printf.cpp)");
cmake.addCMakeCommandEnd("target_include_directories("+outputName+" PUBLIC ${INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})");
cmake.addCMakeCommandEnd("target_link_libraries("+outputName+" PUBLIC ${LIBS} -static-libgcc -static-libstdc++)");
cmake.addCMakeCommandEnd("set_target_properties("+outputName+" PROPERTIES LINKER_LANGUAGE CXX POSITION_INDEPENDENT_CODE ON)");
cmake.addCMakeCommandEnd("target_compile_features("+outputName+" PUBLIC cxx_std_11)");
cmake.addCMakeCommandEnd("set_target_properties("+outputName+" PROPERTIES PREFIX \"\")");
// install shared lib
cmake.addCMakeCommandEnd("install(TARGETS "+outputName+" DESTINATION $ENV{DLL_DIR})");
//cmake.addCMakeCommandEnd("export(TARGETS "+outputName+" FILE "+outputName+".cmake)");
cmake.addCMakeCommandEnd("");
}
public String generateSetPortCase(int id, PortInformation portInfo){
b.init();
b.a(BASE_INDENT, "case %d: { // %s", id, portInfo.name);
generateSetter(portInfo.data_type, BASE_INDENT+1, 1, "program_instance."+portInfo.name);
b.a(BASE_INDENT, "} break;");
return b.getContent();
void generateSocketSetter(PortInformation portInfo) {
SocketInfo sockInf = gen.interfaceResolver.getSocketInfo(portInfo);
int indent = BASE_INDENT+1;
b.a(indent, "auto as = reader.stream_array();");
b.a(indent, "auto it = as.begin();");
b.a(indent, "auto end = as.end();");
b.a(indent, "if (!(it != end)) {");
b.a(indent, " throw_error(\"PortIO\", \"Expected IP entry in array\");");
b.a(indent, " break;");
b.a(indent, "}");
b.a(indent, "auto ip = reader.get_string().get_json_string();");
b.a(indent, "auto id = get_socket_id(ip, %d);", sockInf.array_length);
b.a(indent, "if (id < 0) return;");
b.a(indent, "auto &target = program_instance.%s[id];", sockInf.input_name);
b.a(indent, "++it;");
b.a(indent, "if (!(it != end)) {");
b.a(indent, " throw_error(\"PortIO\", \"Expected IP entry in array\");");
b.a(indent, " break;");
b.a(indent, "}");
generateSetter(((SimplePacketType) portInfo.data_type).getPayloadType(), indent, 1, "target");
}
public String generateGetPortCase(int id, PortInformation portInfo){
b.init();
void generateSocketGetter(PortInformation portInfo) {
SocketInfo sockInf = gen.interfaceResolver.getSocketInfo(portInfo);
int indent = BASE_INDENT+1;
b.a(BASE_INDENT, "case %d: { // %s", id, portInfo.name);
generateGetter(portInfo.data_type, BASE_INDENT+1, 1, "program_instance."+portInfo.name);
b.a(BASE_INDENT, "} break;");
b.a(indent, "static int id = 0;");
b.a(indent, "if (id >= %d) {", sockInf.is_bc ? 1 : sockInf.array_length);
b.a(indent, " id = 0;");
b.a(indent, " return;");
b.a(indent, "}");
b.a(indent, "writer.start_array();");
return b.getContent();
}
if (sockInf.is_bc) {
b.a(indent, "writer.write_str(N_TO_N_BROADCAST_ADDR); // Write address");
b.a(indent, "auto &target = program_instance.%s;", sockInf.output_name);
} else {
b.a(indent, "writer.write_str(N_TO_N_PREFIX + std::to_string(id+1)); // Write address");
b.a(indent, "auto &target = program_instance.%s[id];", sockInf.output_name);
}
generateGetter(((SimplePacketType) portInfo.data_type).getPayloadType(), BASE_INDENT+1, 1, "target");
b.a(indent, "writer.end_array();");
b.a(indent, "++id;");
}
private void generateSetter(DataType type, int indent, int depth, String varReference){
protected void generateSetter(DataType type, int indent, int depth, String varReference){
if (type instanceof BasicType){
BasicType t = (BasicType) type;
switch (t.getType()){
case Q:
b.a(indent, "%s = traverser.get_double();", varReference);
b.a(indent, "%s = reader.get_double();", varReference);
break;
case Z:
b.a(indent, "%s = (int32_t) traverser.get_long();", varReference);
b.a(indent, "%s = (int32_t) reader.get_long();", varReference);
break;
case N: {
String varName = String.format("res%d", depth);
b.a(indent, "auto %s = traverser.get_long();", varName);
b.a(indent, "if (%s < 0) { %s = 0; } //TODO as error?", varName, varName);
b.a(indent, "auto %s = reader.get_long();", varName);
b.a(indent, "if (%s < 0) { %s = 0; throw_error(\"PortIO\", \"Received negative natural number (N): '%%\" PRIi64 \"'.\", %s); }", varName, varName, varName);
b.a(indent, "%s = %s;", varReference, varName);
} break;
case N1: {
String varName = String.format("res%d", depth);
b.a(indent, "auto %s = traverser.get_long();", varName);