Commit c884b329 authored by Jean Meurice's avatar Jean Meurice
Browse files

New JSON/Binary serialization, library_interface & server_adapter structure

parent 5fd91f60
......@@ -25,5 +25,3 @@ buildNumber.properties
.project
.vscode/
.settings/
temp/
\ No newline at end of file
......@@ -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()));
......
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");
// 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)");
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("");
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");
addFileDependencyOwnCpp("server_adapter.cpp");
// create adapter executable
cmake.addCMakeCommandEnd("# ServerAdapter for the EMA component");
cmake.addCMakeCommandEnd("add_executable("+targetNameServer+" server_adapter.cpp network.cpp)");
cmake.addCMakeCommandEnd("target_link_libraries("+targetNameServer+" PUBLIC "+targetNameWithSerialization+")");
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.HashMap;
import java.util.HashSet;
import java.util.List;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.cpp.dynamic_interface.DynamicInterfaceGenerator.SocketInfo;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.rwth.montisim.commons.dynamicinterface.*;
import de.rwth.montisim.commons.dynamicinterface.PortInformation.PortType;
import de.rwth.montisim.commons.utils.json.SerializationException;
public class TcpCommunication {
static final int BASE_INDENT = 2;
final DynamicInterfaceGenerator gen;
FileBuilder b = new FileBuilder();
public TcpCommunication(DynamicInterfaceGenerator gen) {
this.gen = gen;
}
public List<FileContent> generate(boolean hasDDC) throws SerializationException {
List<FileContent> files = new ArrayList<>();
List<String> setInputCases = new ArrayList<>();
List<String> sendOutputCalls = new ArrayList<>();
List<String> sendOutputCases = new ArrayList<>();
List<String> sendSocketOutputsCases = new ArrayList<>();
List<String> initDataCalls = new ArrayList<>();
int i = 0;
for (PortInformation portInfo : gen.programInterface.ports){
initDataCalls.add(generateInitData(portInfo));
if (portInfo.isInput()){
setInputCases.add(generateSetInputCase(i, portInfo));
}
if (portInfo.isOutput()) {
if (portInfo.port_type == PortType.DATA) {
sendOutputCalls.add(String.format("send_output(%d);", i));
sendOutputCases.add(generateSendOutputCase(i, portInfo));
} else {
sendOutputCalls.add(String.format("send_socket_outputs(%d);", i));
sendSocketOutputsCases.add(generateSendSocketOutputsCase(i, portInfo));
}
}
++i;
}
HashMap<String, Object> templateData = new HashMap<>();
templateData.put("mainModelName", gen.componentName);
templateData.put("interfaceDescription", gen.progInterfaceString);
templateData.put("setInputCases", setInputCases);
templateData.put("sendOutputCalls", sendOutputCalls);
templateData.put("sendOutputCases", sendOutputCases);
templateData.put("sendSocketOutputsCases", sendSocketOutputsCases);
templateData.put("initDataCalls", initDataCalls);
templateData.put("useDDC", hasDDC);
files.add(new FileContent(AllTemplates.generate(AllTemplates.TCP_ADAPTER_H, templateData), "server_adapter.h"));
files.add(new FileContent(AllTemplates.generate(AllTemplates.TCP_ADAPTER_CPP, templateData), "server_adapter.cpp"));
gen.addCppFileDependency("json.h");
gen.addCppFileDependency("json.cpp");
gen.addCppFileDependency("printf.h");
gen.addCppFileDependency("printf.cpp");
gen.addCppFileDependency("utils.h");
gen.addCppFileDependency("network.h");
gen.addCppFileDependency("network.cpp");
gen.addCppFileDependency("tcp_protocol.h");
return files;
}
public void getSources(HashSet<String> sources) {
sources.add("json.cpp");
sources.add("printf.cpp");
sources.add("network.cpp");
sources.add("server_adapter.cpp");
}
public void getLibs(HashSet<String> libs) {
}
public String generateSetInputCase(int id, PortInformation portInfo){
b.init();
if (portInfo.port_type == PortType.DATA) {
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;");
} else {
SocketInfo sockInf = gen.getSocketInfo(portInfo);
b.a(BASE_INDENT, "case %d: { // %s", id, portInfo.name);
int indent = BASE_INDENT+1;
b.a(indent, "auto id = get_socket_id(input_packet, %d);", sockInf.array_length);
b.a(indent, "if (id < 0) return;");
b.a(indent, "auto &target = program_instance.%s[id];", sockInf.input_name);
generateSetter(((SimplePacketType) portInfo.data_type).getPayloadType(), BASE_INDENT+1, 1, "target");
b.a(BASE_INDENT, "} break;");
}
return b.getContent();
}
public String generateSendOutputCase(int id, PortInformation portInfo){
b.init();
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;");
return b.getContent();
}
public class BinarySerializationGenerator extends SerializationGenerator {
private String generateSendSocketOutputsCase(int id, PortInformation portInfo) {
b.init();
b.a(BASE_INDENT, "case %d: { // %s", id, portInfo.name);
SocketInfo sockInf = gen.getSocketInfo(portInfo);
if (sockInf.is_bc) {
b.a(BASE_INDENT+1, "PacketWriter packet(buffer, BUFFER_SIZE, PACKET_OUTPUT);");
b.a(BASE_INDENT+1, "packet.write_u16(port_id);");
b.a(BASE_INDENT+1, "// Payload");
b.a(BASE_INDENT+1, "packet.write_str(N_TO_N_BROADCAST_ADDR); // Write address");
generateGetter(((SimplePacketType) portInfo.data_type).getPayloadType(), BASE_INDENT+1, 1, "program_instance."+sockInf.output_name);
b.a(BASE_INDENT+1, "packet.send(socket);");
} else {
b.a(BASE_INDENT+1, "for (int i = 0; i < %d; ++i) {", sockInf.array_length);
b.a(BASE_INDENT+1, " PacketWriter packet(buffer, BUFFER_SIZE, PACKET_OUTPUT);");
b.a(BASE_INDENT+1, " packet.write_u16(port_id);");
b.a(BASE_INDENT+1, " // Payload");
b.a(BASE_INDENT+1, " packet.write_str(N_TO_N_PREFIX + to_string(i+1)); // Write address");
b.a(BASE_INDENT+1, " auto &target = program_instance.%s[i];", sockInf.output_name);
generateGetter(((SimplePacketType) portInfo.data_type).getPayloadType(), BASE_INDENT+2, 1, "target");
b.a(BASE_INDENT+1, " packet.send(socket);");
b.a(BASE_INDENT+1, "}");
}
b.a(BASE_INDENT, "} break;");
return b.getContent();
BinarySerializationGenerator(AdapterGenerator gen) {
super(gen);
}
private String generateInitData(PortInformation portInfo) {
b.init();
if (portInfo.port_type == PortType.DATA) {
generateInitData(portInfo.data_type, 1, 1, "program_instance."+portInfo.name);
} else {
DataType dt = ((SimplePacketType) portInfo.data_type).getPayloadType();
SocketInfo sockInf = gen.getSocketInfo(portInfo);
if (portInfo.isInput()) {
for (int i =0; i < sockInf.array_length; ++i) {
String varName = sockInf.input_name + Integer.toString(i);
b.a(1, "auto &%s = program_instance.%s[%d];", varName, sockInf.input_name, i);
generateInitData(dt, 1, 1, varName);
}
}
if (portInfo.isOutput()) {
if (sockInf.is_bc) {
generateInitData(dt, 1, 1, "program_instance."+sockInf.output_name);
} else {
for (int i =0; i < sockInf.array_length; ++i) {
String varName = sockInf.output_name + Integer.toString(i);
b.a(1, "auto &%s = program_instance.%s[%d];", varName, sockInf.output_name, i);
generateInitData(dt, 1, 1, varName);
}
}
}
}
return b.getContent();
String getType() {
return "Binary";
}
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 = input_packet.read_f64();", varReference);
b.a(indent, "%s = reader.read_f64();", varReference);
break;
case Z:
case N:
case N1: // TOTO check range for N1 & N ?
b.a(indent, "%s = (int32_t) input_packet.read_u32();", varReference);
b.a(indent, "%s = (int32_t) reader.read_u32();", varReference);
break;
case C:
b.a(indent, "%s = input_packet.read_f64();", varReference);
b.a(indent, "%s = input_packet.read_f64();", varReference); // TODO correct complex number native case
b.a(indent, "%s = reader.read_f64();", varReference);
b.a(indent, "%s = reader.read_f64();", varReference); // TODO correct complex number native case
throw new IllegalStateException("Unimplemented");
case BOOLEAN:
b.a(indent, "%s = input_packet.read_u8() != 0;", varReference);
b.a(indent, "%s = reader.read_u8() != 0;", varReference);
break;
case EMPTY:
break;
case VEC2:
b.a(indent, "%s(0) = input_packet.read_f64();", varReference);
b.a(indent, "%s(1) = input_packet.read_f64();", varReference);
b.a(indent, "%s(0) = reader.read_f64();", varReference);
b.a(indent, "%s(1) = reader.read_f64();", varReference);
break;
case VEC3:
b.a(indent, "%s(0) = input_packet.read_f64();", varReference);
b.a(indent, "%s(1) = input_packet.read_f64();", varReference);
b.a(indent, "%s(2) = input_packet.read_f64();", varReference);
b.a(indent, "%s(0) = reader.read_f64();", varReference);
b.a(indent, "%s(1) = reader.read_f64();", varReference);
b.a(indent, "%s(2) = reader.read_f64();", varReference);
break;
default:
throw new IllegalArgumentException("Missing case");
......@@ -230,7 +56,7 @@ public class TcpCommunication {
String ref = String.format("res%d", depth);
// TODO check in code if the received size is within the declared max size?
b.a(indent, "auto %s = input_packet.read_u16();", sizeVar);
b.a(indent, "auto %s = reader.read_u16();", sizeVar);
b.a(indent, "for (int %s=0; %s < %s; ++%s) {", iVar, iVar, sizeVar, iVar);
b.a(indent, " auto &%s = %s(%s);", ref, varReference, iVar);
generateSetter(vt.getBaseType(), newIndent, depth+1, ref);
......@@ -270,42 +96,42 @@ public class TcpCommunication {
int variantCount = et.getVariantCount();
if (variantCount > 256) throw new IllegalArgumentException("Too much Enum variants for enu