diff --git a/pom.xml b/pom.xml
index a3702d7bd69871fec8ba5e184fc5ab1018fb5f36..37c9f6a0fa4ccf999046f6d931a4342246457f75 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,11 @@
0.0.1c-SNAPSHOT
+
+ de.monticore.lang.monticar
+ embedded-montiarc-math-rosmsg-generator
+ 0.0.1-SNAPSHOT
+
com.esotericsoftware.yamlbeans
diff --git a/src/main/java/de/monticore/lang/monticar/generator/master/DistributedTargetGenerator.java b/src/main/java/de/monticore/lang/monticar/generator/master/DistributedTargetGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..8aec6eaeba9f89a89c9d68e34186e34f58dafeff
--- /dev/null
+++ b/src/main/java/de/monticore/lang/monticar/generator/master/DistributedTargetGenerator.java
@@ -0,0 +1,159 @@
+package de.monticore.lang.monticar.generator.master;
+
+import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ConnectorSymbol;
+import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
+import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymbol;
+import de.monticore.lang.embeddedmontiarc.tagging.MiddlewareSymbol;
+import de.monticore.lang.embeddedmontiarc.tagging.RosConnectionSymbol;
+import de.monticore.lang.monticar.generator.roscpp.helper.TagHelper;
+import de.monticore.lang.monticar.generator.rosmsg.RosMsg;
+import de.monticore.lang.tagging._symboltable.TaggingResolver;
+import de.se_rwth.commons.logging.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class DistributedTargetGenerator extends CMakeMasterGenerator {
+ private RosMsgImpl rosMsgImpl;
+
+ public DistributedTargetGenerator(String generationTargetPath) {
+ setGenerationTargetPath(generationTargetPath);
+ rosMsgImpl = new RosMsgImpl("rosmsg");
+ //this.add(rosMsgImpl,"rosmsg/");
+ }
+
+ @Override
+ public List generate(ExpandedComponentInstanceSymbol componentInstanceSymbol, TaggingResolver taggingResolver) throws IOException {
+ Map resolvedTags = TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
+
+ Map generatorMap = new HashMap<>();
+
+ fixComponentInstance(componentInstanceSymbol);
+ Collection subComps = getSubComponentInstances(componentInstanceSymbol);
+
+ //TODO: cluster non mw subcomps together with mw subcomps
+
+ boolean allSubsMwOnly = subComps.stream()
+ .flatMap(comp -> comp.getPorts().stream())
+ .allMatch(p -> p.getMiddlewareSymbol().isPresent());
+
+ if (allSubsMwOnly) {
+ subComps.forEach(comp ->
+ generatorMap.put(comp, createFullGenerator(comp.getFullName().replace(".", "_")))
+ );
+ } else {
+ generatorMap.put(componentInstanceSymbol, createFullGenerator(componentInstanceSymbol.getFullName().replace(".", "_")));
+ }
+
+ List files = new ArrayList<>();
+
+ CMakeMasterGenerator cmakeListsGenerator = new CMakeMasterGenerator();
+ cmakeListsGenerator.setGenerationTargetPath(generationTargetPath);
+ for (ExpandedComponentInstanceSymbol comp : generatorMap.keySet()) {
+ files.addAll(generatorMap.get(comp).generate(comp, taggingResolver));
+ //add empty generator to cmakeListsGenerator so that CMakeLists.txt will be generated
+ cmakeListsGenerator.add(new GeneratorImpl() {
+ }, comp.getFullName().replace(".", "_"));
+ }
+
+ files.addAll(cmakeListsGenerator.generate(componentInstanceSymbol, taggingResolver));
+ return files;
+ }
+
+ private GeneratorImpl createFullGenerator(String subdir) {
+ MiddlewareMasterGenerator res = new MiddlewareMasterGenerator();
+ res.setGenerationTargetPath(generationTargetPath + (subdir.endsWith("/") ? subdir : subdir + "/"));
+
+ this.getGeneratorImpls().forEach(gen -> res.add(gen, this.getImplSubfolder(gen)));
+
+ return res;
+ }
+
+ private void fixComponentInstance(ExpandedComponentInstanceSymbol componentInstanceSymbol) {
+ fixRosTopics(componentInstanceSymbol);
+ }
+
+ private void fixRosTopics(ExpandedComponentInstanceSymbol componentInstanceSymbol) {
+ componentInstanceSymbol.getConnectors().stream()
+ .filter(connectorSymbol -> connectorSymbol.getSourcePort().isRosPort() && connectorSymbol.getTargetPort().isRosPort())
+ .forEach(connectorSymbol -> {
+ if (Objects.equals(connectorSymbol.getSourcePort().getComponentInstance().orElse(null), componentInstanceSymbol)) {
+ //In port of supercomp
+ inferRosConnectionIfPossible(connectorSymbol.getSourcePort(), connectorSymbol.getTargetPort());
+ } else if (Objects.equals(connectorSymbol.getTargetPort().getComponentInstance().orElse(null), componentInstanceSymbol)) {
+ //out port of supercomp
+ inferRosConnectionIfPossible(connectorSymbol.getTargetPort(), connectorSymbol.getSourcePort());
+ } else {
+ //In between subcomps
+ generateRosConnectionIfPossible(connectorSymbol);
+ }
+
+ });
+ }
+
+ private void generateRosConnectionIfPossible(ConnectorSymbol connectorSymbol) {
+ MiddlewareSymbol sourceTag = connectorSymbol.getSourcePort().getMiddlewareSymbol().orElse(null);
+ MiddlewareSymbol targetTag = connectorSymbol.getTargetPort().getMiddlewareSymbol().orElse(null);
+ if (sourceTag == null || targetTag == null || !sourceTag.isKindOf(RosConnectionSymbol.KIND) || !targetTag.isKindOf(RosConnectionSymbol.KIND)) {
+ Log.debug("Both sourcePort and targetPort need to have a RosConnectionSymbol", "RosConnectionSymbol");
+ return;
+ }
+ RosConnectionSymbol rosConnectionA = (RosConnectionSymbol) sourceTag;
+ RosConnectionSymbol rosConnectionB = (RosConnectionSymbol) targetTag;
+ RosConnectionSymbol emptyRosConnection = new RosConnectionSymbol();
+ if (!rosConnectionA.equals(emptyRosConnection) || !rosConnectionB.equals(emptyRosConnection)) {
+ Log.debug("Will not override rosConnections that are not empty!", "RosConnectionSymbol");
+ return;
+ }
+
+ //target port name is unique: each in port can only have one connection!
+ String topicName = connectorSymbol.getTargetPort().getFullName().replace(".", "_");
+ RosMsg rosTypeA = rosMsgImpl.getRosType(connectorSymbol.getTargetPort().getTypeReference());
+ RosMsg rosTypeB = rosMsgImpl.getRosType(connectorSymbol.getSourcePort().getTypeReference());
+ if (!rosTypeA.equals(rosTypeB)) {
+ Log.error("topicType mismatch! "
+ + connectorSymbol.getSourcePort().getFullName() + " has " + rosTypeB + " and "
+ + connectorSymbol.getTargetPort().getFullName() + " has " + rosTypeA);
+ return;
+ }
+
+ rosMsgImpl.addRosTypeToGenerate(connectorSymbol.getTargetPort().getTypeReference());
+ if (rosTypeA.getFields().size() == 1) {
+ connectorSymbol.getSourcePort().setMiddlewareSymbol(new RosConnectionSymbol(topicName, rosTypeB.getName(), rosTypeB.getFields().get(0).getName()));
+ connectorSymbol.getTargetPort().setMiddlewareSymbol(new RosConnectionSymbol(topicName, rosTypeA.getName(), rosTypeA.getFields().get(0).getName()));
+ } else {
+ connectorSymbol.getSourcePort().setMiddlewareSymbol(new RosConnectionSymbol(topicName, rosTypeB.getName()));
+ connectorSymbol.getTargetPort().setMiddlewareSymbol(new RosConnectionSymbol(topicName, rosTypeA.getName()));
+ }
+ }
+
+ private void inferRosConnectionIfPossible(PortSymbol sourcePort, PortSymbol targetPort) {
+ MiddlewareSymbol sourceTag = sourcePort.getMiddlewareSymbol().orElse(null);
+ MiddlewareSymbol targetTag = targetPort.getMiddlewareSymbol().orElse(null);
+ if (sourceTag == null || targetTag == null || !sourceTag.isKindOf(RosConnectionSymbol.KIND) || !targetTag.isKindOf(RosConnectionSymbol.KIND)) {
+ Log.debug("Both sourcePort and targetPort need to have a RosConnectionSymbol", "RosConnectionSymbol");
+ return;
+ }
+
+ RosConnectionSymbol sourceRosConnection = (RosConnectionSymbol) sourceTag;
+ RosConnectionSymbol targetRosConnection = (RosConnectionSymbol) targetTag;
+
+ if (sourceRosConnection.getTopicName().isPresent() && !targetRosConnection.getTopicName().isPresent())
+ targetRosConnection.setTopicName(sourceRosConnection.getTopicName().get());
+
+ if (sourceRosConnection.getTopicType().isPresent() && !targetRosConnection.getTopicType().isPresent())
+ targetRosConnection.setTopicType(sourceRosConnection.getTopicType().get());
+
+ if (sourceRosConnection.getMsgField().isPresent() && !targetRosConnection.getMsgField().isPresent())
+ targetRosConnection.setMsgField(sourceRosConnection.getMsgField().get());
+ }
+
+ private Collection getSubComponentInstances(ExpandedComponentInstanceSymbol componentInstanceSymbol) {
+ //TODO: check which subcomponents are mw only
+ //TODO: (build clusters?)
+ return componentInstanceSymbol.getSubComponents();
+ }
+
+
+}
diff --git a/src/main/java/de/monticore/lang/monticar/generator/master/RosCppImpl.java b/src/main/java/de/monticore/lang/monticar/generator/master/RosCppImpl.java
index d7ab516db278287cbbfbb1011d94317679716bc7..e94bec147a10915a67bd2581e53a1df52bf7404e 100644
--- a/src/main/java/de/monticore/lang/monticar/generator/master/RosCppImpl.java
+++ b/src/main/java/de/monticore/lang/monticar/generator/master/RosCppImpl.java
@@ -2,7 +2,6 @@ package de.monticore.lang.monticar.generator.master;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.monticar.generator.roscpp.GeneratorRosCpp;
-import de.monticore.lang.monticar.generator.roscpp.helper.TagHelper;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
import java.io.File;
@@ -17,7 +16,7 @@ public class RosCppImpl implements GeneratorImpl {
GeneratorRosCpp generatorRosCpp = new GeneratorRosCpp();
generatorRosCpp.setGenerateCMake(true);
generatorRosCpp.setGenerationTargetPath(generationTargetPath);
- return TagHelper.generate(generatorRosCpp, taggingResolver, componentInstanceSymbol);
+ return generatorRosCpp.generateFiles(componentInstanceSymbol, taggingResolver);
}
@Override
diff --git a/src/main/java/de/monticore/lang/monticar/generator/master/RosMsgImpl.java b/src/main/java/de/monticore/lang/monticar/generator/master/RosMsgImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..5170da83363919cbfbe1dfb209b3e9b0c0895ba6
--- /dev/null
+++ b/src/main/java/de/monticore/lang/monticar/generator/master/RosMsgImpl.java
@@ -0,0 +1,46 @@
+package de.monticore.lang.monticar.generator.master;
+
+import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
+import de.monticore.lang.monticar.generator.rosmsg.GeneratorRosMsg;
+import de.monticore.lang.monticar.generator.rosmsg.RosMsg;
+import de.monticore.lang.monticar.ts.MCTypeSymbol;
+import de.monticore.lang.monticar.ts.references.MCTypeReference;
+import de.monticore.lang.tagging._symboltable.TaggingResolver;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RosMsgImpl implements GeneratorImpl {
+ private GeneratorRosMsg generatorRosMsg;
+ private List> rosTypesToGenerate = new ArrayList<>();
+ private String packageName;
+
+ public RosMsgImpl(String packageName) {
+ this.packageName = packageName;
+ generatorRosMsg = new GeneratorRosMsg();
+ }
+
+ @Override
+ public List generate(ExpandedComponentInstanceSymbol componentInstanceSymbol, TaggingResolver taggingResolver) throws IOException {
+ List files = new ArrayList<>();
+ for (MCTypeReference extends MCTypeSymbol> type : rosTypesToGenerate) {
+ files.addAll(generatorRosMsg.generate(type));
+ }
+ return files;
+ }
+
+ @Override
+ public void setGenerationTargetPath(String path) {
+ generatorRosMsg.setTarget(path, packageName);
+ }
+
+ public void addRosTypeToGenerate(MCTypeReference extends MCTypeSymbol> typeReference) {
+ rosTypesToGenerate.add(typeReference);
+ }
+
+ public RosMsg getRosType(MCTypeReference extends MCTypeSymbol> typeReference) {
+ return generatorRosMsg.getRosType(typeReference);
+ }
+}
diff --git a/src/test/java/de/monticore/lang/monticar/generator/master/GenerationTest.java b/src/test/java/de/monticore/lang/monticar/generator/master/GenerationTest.java
index 777f651e5d4ecc8a15cfb7ac439c4e6b12d0b628..8872eab5d3a221599d9784b6fea2f0cb084f10e6 100644
--- a/src/test/java/de/monticore/lang/monticar/generator/master/GenerationTest.java
+++ b/src/test/java/de/monticore/lang/monticar/generator/master/GenerationTest.java
@@ -2,7 +2,9 @@ package de.monticore.lang.monticar.generator.master;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.tagging.RosToEmamTagSchema;
+import de.monticore.lang.monticar.generator.roscpp.helper.TagHelper;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
+import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
@@ -11,6 +13,11 @@ import static org.junit.Assert.assertNotNull;
public class GenerationTest extends AbstractSymtabTest {
+ @Before
+ public void initTest() {
+ TagHelper.reset();
+ }
+
@Test
public void testBasicGeneration() throws IOException {
TaggingResolver taggingResolver = createSymTabAndTaggingResolver("src/test/resources/");
@@ -18,6 +25,7 @@ public class GenerationTest extends AbstractSymtabTest {
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.resolve("tests.a.compA", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
+ TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
MasterGenerator masterGenerator = new MasterGenerator();
masterGenerator.setGenerationTargetPath("./target/generated-sources/basicGeneration/");
@@ -34,6 +42,7 @@ public class GenerationTest extends AbstractSymtabTest {
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.resolve("tests.a.compA", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
+ TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
MasterGenerator masterGenerator = new CMakeMasterGenerator();
masterGenerator.setGenerationTargetPath("./target/generated-sources/CMakeGeneration/");
@@ -50,6 +59,7 @@ public class GenerationTest extends AbstractSymtabTest {
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.resolve("tests.a.addComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
+ TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
MasterGenerator masterGenerator = new MiddlewareMasterGenerator();
masterGenerator.setGenerationTargetPath("./target/generated-sources/middlewareMasterGenerator/src/");
@@ -58,7 +68,23 @@ public class GenerationTest extends AbstractSymtabTest {
masterGenerator.add(new DummyMiddlewareGenerator(), "dummy");
masterGenerator.generate(componentInstanceSymbol, taggingResolver);
+ }
+
+ @Test
+ public void testDistributedTargetGenerator() throws IOException {
+ TaggingResolver taggingResolver = createSymTabAndTaggingResolver("src/test/resources/");
+ RosToEmamTagSchema.registerTagTypes(taggingResolver);
+
+ ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.resolve("tests.dist.distComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
+ assertNotNull(componentInstanceSymbol);
+ TagHelper.resolveTags(taggingResolver, componentInstanceSymbol);
+ MasterGenerator masterGenerator = new DistributedTargetGenerator("./target/generated-sources/distributed/src/");
+
+ masterGenerator.add(new CPPImpl(), "cpp");
+ masterGenerator.add(new RosCppImpl(), "roscpp");
+
+ masterGenerator.generate(componentInstanceSymbol, taggingResolver);
}
}
diff --git a/src/test/resources/tests/dist/DistComp.emam b/src/test/resources/tests/dist/DistComp.emam
new file mode 100644
index 0000000000000000000000000000000000000000..68271d7efaa324638ff9b93ea06d03b525039acc
--- /dev/null
+++ b/src/test/resources/tests/dist/DistComp.emam
@@ -0,0 +1,19 @@
+package tests.dist;
+
+component DistComp{
+ component SubComp1{
+ ports out Q out1,
+ out Q out2;
+ }
+
+ component SubComp2{
+ ports in Q in1,
+ in Q in2;
+ }
+
+ instance SubComp1 sub1;
+ instance SubComp2 sub2;
+
+ connect sub1.out1 -> sub2.in1;
+ connect sub1.out2 -> sub2.in2;
+}
\ No newline at end of file
diff --git a/src/test/resources/tests/dist/SimpleDist.tag b/src/test/resources/tests/dist/SimpleDist.tag
new file mode 100644
index 0000000000000000000000000000000000000000..8499a3966b79a4e326798b043c1d23033fc4d9c0
--- /dev/null
+++ b/src/test/resources/tests/dist/SimpleDist.tag
@@ -0,0 +1,9 @@
+package tests.dist;
+conforms to de.monticore.lang.monticar.generator.roscpp.RosToEmamTagSchema;
+
+tags SimpleDist{
+tag distComp.sub1.out1 with RosConnection = {topic = (topicIn1, std_msgs/Float64), msgField = data};
+tag distComp.sub1.out2 with RosConnection = {topic = (topicIn2, std_msgs/Float64), msgField = data};
+tag distComp.sub2.in1 with RosConnection = {topic = (topicIn1, std_msgs/Float64), msgField = data};
+tag distComp.sub2.in2 with RosConnection = {topic = (topicIn2, std_msgs/Float64), msgField = data};
+}
\ No newline at end of file