Commit 436b1694 authored by Alexander David Hellwig's avatar Alexander David Hellwig
Browse files

Added generation of ROS/ROS2 Projects containing messges generated from structs

parent 86ac6853
Pipeline #116329 passed with stages
in 2 minutes and 37 seconds
......@@ -9,7 +9,7 @@
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-rosmsg-generator</artifactId>
<version>0.1.2-SNAPSHOT</version>
<version>0.1.3-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= -->
......
package de.monticore.lang.monticar.generator.rosmsg;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAPortInstanceSymbol;
import de.monticore.lang.monticar.common2._ast.ASTCommonMatrixType;
import de.monticore.lang.monticar.generator.rosmsg.util.FileContent;
import de.monticore.lang.monticar.struct._symboltable.StructFieldDefinitionSymbol;
......@@ -8,11 +10,13 @@ import de.monticore.lang.monticar.ts.MCASTTypeSymbol;
import de.monticore.lang.monticar.ts.MCTypeSymbol;
import de.monticore.lang.monticar.ts.MontiCarTypeSymbol;
import de.monticore.lang.monticar.ts.references.MCTypeReference;
import de.monticore.symboltable.references.SymbolReference;
import de.se_rwth.commons.logging.Log;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
......@@ -53,7 +57,7 @@ public class GeneratorRosMsg {
public List<FileContent> generateStrings(MCTypeReference<? extends MCTypeSymbol> typeReference) {
//is typeReference basic type or struct?
if (getRosType(currentPackageName, typeReference) != null) {
if (getRosType(currentPackageName, typeReference, ros2mode) != null) {
MCTypeSymbol type = typeReference.getReferencedSymbol();
List<FileContent> res = new ArrayList<>();
if (type instanceof StructSymbol) {
......@@ -77,7 +81,7 @@ public class GeneratorRosMsg {
String definition = structSymbol.getStructFieldDefinitions().stream()
.filter(sfds -> sfds.getType().existsReferencedSymbol())
.map(sfds -> getInMsgRosType(currentPackageName, sfds.getType().getReferencedSymbol(), ros2mode) + " " + sfds.getName())
.map(sfds -> getInMsgRosType(currentPackageName, sfds.getType().getReferencedSymbol(), ros2mode) + " " + getFieldName(sfds,ros2mode))
.collect(Collectors.joining("\n"));
FileContent fc = new FileContent();
......@@ -114,10 +118,9 @@ public class GeneratorRosMsg {
}
private static String getFieldName(StructFieldDefinitionSymbol sfds, boolean ros2mode) {
if (ros2mode){
if (ros2mode) {
return sfds.getName().toLowerCase();
}
else{
} else {
return sfds.getName();
}
......@@ -229,13 +232,12 @@ public class GeneratorRosMsg {
}
private static String getTargetName(StructSymbol structSymbol, boolean ros2mode) {
if (ros2mode){
if (ros2mode) {
return Arrays.stream(structSymbol.getFullName()
.split("\\."))
.map(fn -> fn.substring(0, 1).toUpperCase() + fn.substring(1))
.collect(Collectors.joining());
}
else{
} else {
return structSymbol.getFullName().replace(".", "_");
}
}
......@@ -243,4 +245,124 @@ public class GeneratorRosMsg {
private static String getFullTargetName(String packageName, StructSymbol structSymbol, boolean ros2mode) {
return ros2mode ? packageName + "/msg/" + getTargetName(structSymbol, ros2mode) : packageName + "/" + getTargetName(structSymbol, ros2mode);
}
public List<FileContent> generateProjectStrings(List<MCTypeReference<? extends MCTypeSymbol>> typeReferences) {
ArrayList<FileContent> res = new ArrayList<>();
// .msg files
for (MCTypeReference<? extends MCTypeSymbol> tr : typeReferences) {
for (FileContent fc : generateStrings(tr)) {
fc.setFileName("msg/" + fc.getFileName());
res.add(fc);
}
}
if (!ros2mode) {
res.add(getRosCMakeLists(res));
} else {
res.add(getRos2CMakeLists(res));
res.add(getRos2PackageXml());
}
return res;
}
private FileContent getRos2CMakeLists(ArrayList<FileContent> res) {
FileContent cmakeLists = new FileContent();
cmakeLists.setFileName("CMakeLists.txt");
StringBuilder content = new StringBuilder();
content.append("cmake_minimum_required(VERSION 3.5)\n");
content.append("project(struct_msgs)\n");
content.append("find_package(ament_cmake REQUIRED)\n");
content.append("find_package(rosidl_default_generators REQUIRED)\n");
content.append("# declare the message files to generate code for\n");
for (FileContent fc : res) {
content.append("LIST(APPEND msg_files \"")
.append(fc.getFileName())
.append("\")\n");
}
content.append("rosidl_generate_interfaces(${PROJECT_NAME} ${msg_files})\n");
content.append("ament_export_dependencies(rosidl_default_runtime)\n");
content.append("ament_package()\n");
content.append("set(struct_msgs_LIBRARIES struct_msgs__rosidl_typesupport_cpp struct_msgs__rosidl_typesupport_fastrtps_cpp struct_msgs__rosidl_typesupport_introspection_cpp PARENT_SCOPE)\n");
content.append("export(TARGETS struct_msgs__rosidl_typesupport_cpp struct_msgs__rosidl_typesupport_fastrtps_cpp struct_msgs__rosidl_typesupport_introspection_cpp FILE struct_msgs.cmake)\n");
cmakeLists.setFileContent(content.toString());
return cmakeLists;
}
private FileContent getRos2PackageXml(){
String res = "<?xml version=\"1.0\"?>\n" +
"<?xml-model href=\"http://download.ros.org/schema/package_format2.xsd\" schematypens=\"http://www.w3.org/2001/XMLSchema\"?>\n" +
"<package format=\"3\">\n" +
" <name>struct_msgs</name>\n" +
" <version>0.0.0</version>\n" +
" <description>Generated Messages from Struct</description>\n" +
" <maintainer email=\"unknown@unknown.com\">Unknown</maintainer>\n" +
" <license>Unknown</license>\n" +
"\n" +
" <buildtool_depend>ament_cmake</buildtool_depend>\n" +
" <buildtool_depend>rosidl_default_generators</buildtool_depend>\n" +
" <exec_depend>rosidl_default_runtime</exec_depend>\n" +
"\n" +
" <export>\n" +
" <build_type>ament_cmake</build_type>\n" +
" </export>\n" +
" <member_of_group>rosidl_interface_packages</member_of_group>\n" +
"</package>";
FileContent fileContent = new FileContent();
fileContent.setFileName("package.xml");
fileContent.setFileContent(res);
return fileContent;
}
private FileContent getRosCMakeLists(ArrayList<FileContent> res) {
FileContent cmakeLists = new FileContent();
cmakeLists.setFileName("CMakeLists.txt");
StringBuilder content = new StringBuilder();
content.append("cmake_minimum_required(VERSION 2.8.12)\n");
content.append("project(struct_msgs)\n");
content.append("find_package(genmsg REQUIRED)\n\n");
res.stream()
.map(FileContent::getFileName)
.map(fn -> Paths.get(fn).getFileName().toString())
.map(fn -> "add_message_files(FILES " + fn + ")\n")
.forEach(content::append);
content.append("generate_messages()\n");
content.append("set(struct_msgs_INCLUDE_DIRS ${struct_msgs_INCLUDE_DIRS} PARENT_SCOPE)\n");
cmakeLists.setFileContent(content.toString());
return cmakeLists;
}
public List<File> generateProject(List<MCTypeReference<? extends MCTypeSymbol>> typeReferences) throws IOException {
List<File> res = new ArrayList<>();
List<FileContent> fileContents = generateProjectStrings(typeReferences);
for (FileContent fileContent : fileContents) {
File file = new File(path + "/" + fileContent.getFileName());
FileUtils.write(file, fileContent.getFileContent());
res.add(file);
}
return res;
}
public List<File> generateProject(EMAComponentInstanceSymbol component) throws IOException {
List<MCTypeReference<? extends MCTypeSymbol>> typeReferences = component.getPortInstanceList().stream()
.map(EMAPortInstanceSymbol::getTypeReference)
.filter(SymbolReference::existsReferencedSymbol)
.filter(mcTypeReference -> mcTypeReference.getReferencedSymbol() instanceof StructSymbol)
.collect(Collectors.toList());
return generateProject(typeReferences);
}
}
package de.monticore.lang.monticar.generator.rosmsg;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAComponentInstanceSymbol;
import de.monticore.symboltable.Scope;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import static org.junit.Assert.assertNotNull;
public class ProjectTest extends AbstractSymtabTest{
@Test
public void testRosProjectGeneration() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
EMAComponentInstanceSymbol component = symtab.<EMAComponentInstanceSymbol>resolve("tests.basicStructComp", EMAComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
generatorRosMsg.setTarget("target/projects/ros/basicStructComp","struct_msgs");
List<File> files = generatorRosMsg.generateProject(component);
checkFilesAreEqual(files, Paths.get("target/projects/ros/basicStructComp"),"projects/ros/basicStructComp/");
}
@Test
public void testRos2ProjectGeneration() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
EMAComponentInstanceSymbol component = symtab.<EMAComponentInstanceSymbol>resolve("tests.basicStructComp", EMAComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
generatorRosMsg.setTarget("target/projects/ros2/basicStructComp","struct_msgs");
generatorRosMsg.setRos2mode(true);
List<File> files = generatorRosMsg.generateProject(component);
checkFilesAreEqual(files, Paths.get("target/projects/ros2/basicStructComp"),"projects/ros2/basicStructComp/");
}
}
cmake_minimum_required(VERSION 2.8.12)
project(struct_msgs)
find_package(genmsg REQUIRED)
add_message_files(FILES structs_BasicStruct.msg)
generate_messages()
set(struct_msgs_INCLUDE_DIRS ${struct_msgs_INCLUDE_DIRS} PARENT_SCOPE)
float64 fieldQ1
float64 fieldQ2
int32 fieldZ1
int32 fieldZ2
bool fieldB1
\ No newline at end of file
cmake_minimum_required(VERSION 3.5)
project(struct_msgs)
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
# declare the message files to generate code for
LIST(APPEND msg_files "msg/StructsBasicStruct.msg")
rosidl_generate_interfaces(${PROJECT_NAME} ${msg_files})
ament_export_dependencies(rosidl_default_runtime)
ament_package()
set(struct_msgs_LIBRARIES struct_msgs__rosidl_typesupport_cpp struct_msgs__rosidl_typesupport_fastrtps_cpp struct_msgs__rosidl_typesupport_introspection_cpp PARENT_SCOPE)
export(TARGETS struct_msgs__rosidl_typesupport_cpp struct_msgs__rosidl_typesupport_fastrtps_cpp struct_msgs__rosidl_typesupport_introspection_cpp FILE struct_msgs.cmake)
float64 fieldq1
float64 fieldq2
int32 fieldz1
int32 fieldz2
bool fieldb1
\ No newline at end of file
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>struct_msgs</name>
<version>0.0.0</version>
<description>Generated Messages from Struct</description>
<maintainer email="unknown@unknown.com">Unknown</maintainer>
<license>Unknown</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
<member_of_group>rosidl_interface_packages</member_of_group>
</package>
\ No newline at end of file
Supports Markdown
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