Skip to content

Commit 40e30b4

Browse files
committed
Added an interfaces generator file
1 parent 7269ca1 commit 40e30b4

File tree

4 files changed

+138
-215
lines changed

4 files changed

+138
-215
lines changed

shared/src/main/scala/org/sireum/hamr/codegen/ros2/Generator.scala

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -275,101 +275,6 @@ object Generator {
275275
return (filePath, setupFileBody, F, IS(Marker(startMarker, endMarker)))
276276
}
277277

278-
//================================================
279-
// I n t e r f a c e s Setup Files
280-
//================================================
281-
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
282-
// The "Empty" datatype, which has no data fields, is used for event ports
283-
284-
def genMsgFiles(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
285-
var msg_files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
286-
for (datatype <- datatypeMap.entries) {
287-
msg_files = msg_files :+ genMsgFile(modelName, datatype._2._1, datatype._2._2)
288-
}
289-
msg_files = msg_files :+ (ISZ("src", s"${genCppPackageName(modelName)}_interfaces", "msg", "Empty.msg"), st"", T, IS())
290-
return msg_files
291-
}
292-
293-
def genMsgFile(modelName: String, datatypeName: String, datatypeContent: ISZ[String]): (ISZ[String], ST, B, ISZ[Marker]) = {
294-
val top_level_package_nameT: String = genCppPackageName(modelName)
295-
296-
val fileBody = st"${(datatypeContent, "\n")}"
297-
298-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", "msg", s"${datatypeName}.msg")
299-
300-
return (filePath, fileBody, T, IS())
301-
}
302-
303-
def genInterfacesCMakeListsFile(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): (ISZ[String], ST, B, ISZ[Marker]) = {
304-
val top_level_package_nameT: String = genCppPackageName(modelName)
305-
val fileName: String = "CMakeLists.txt"
306-
var msgTypes: ISZ[String] = IS()
307-
for (msg <- datatypeMap.valueSet.elements) {
308-
msgTypes = msgTypes :+ s"msg/${msg._1}.msg"
309-
}
310-
msgTypes = msgTypes :+ s"msg/Empty.msg"
311-
312-
val setupFileBody =
313-
st"""cmake_minimum_required(VERSION 3.8)
314-
|project(${top_level_package_nameT}_interfaces)
315-
|
316-
|if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
317-
| add_compile_options(-Wall -Wextra -Wpedantic)
318-
|endif()
319-
|
320-
|find_package(ament_cmake REQUIRED)
321-
|
322-
|find_package(rosidl_default_generators REQUIRED)
323-
|
324-
|rosidl_generate_interfaces($${PROJECT_NAME}
325-
| ${(msgTypes, "\n")}
326-
|)
327-
|
328-
|ament_export_dependencies(rosidl_default_runtime)
329-
|
330-
|ament_package()
331-
"""
332-
333-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
334-
335-
return (filePath, setupFileBody, T, IS())
336-
}
337-
338-
def genInterfacesPackageFile(modelName: String): (ISZ[String], ST, B, ISZ[Marker]) = {
339-
val top_level_package_nameT: String = genCppPackageName(modelName)
340-
val fileName: String = "package.xml"
341-
342-
val setupFileBody =
343-
st"""<?xml version="1.0"?>
344-
|<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
345-
|<package format="3">
346-
| <name>${top_level_package_nameT}_interfaces</name>
347-
| <version>0.0.0</version>
348-
| <description>TODO: Package description</description>
349-
| <maintainer email="[email protected]">sireum</maintainer>
350-
| <license>TODO: License declaration</license>
351-
|
352-
| <buildtool_depend>ament_cmake</buildtool_depend>
353-
|
354-
| <build_depend>rosidl_default_generators</build_depend>
355-
| <exec_depend>rosidl_default_runtime</exec_depend>
356-
| <member_of_group>rosidl_interface_packages</member_of_group>
357-
|
358-
| <test_depend>ament_lint_auto</test_depend>
359-
| <test_depend>ament_lint_common</test_depend>
360-
|
361-
| <export>
362-
| <build_type>ament_cmake</build_type>
363-
| </export>
364-
|</package>
365-
"""
366-
367-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
368-
369-
return (filePath, setupFileBody, T, IS())
370-
}
371-
372-
373278
//================================================
374279
// Node files (C++)
375280
// Example: https://github.com/santoslab/ros-examples/tree/main/tempControlcpp_ws/src/tc_cpp_pkg/src
@@ -2460,16 +2365,4 @@ object Generator {
24602365

24612366
return files
24622367
}
2463-
2464-
// The same datatype package will work regardless of other packages' types
2465-
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
2466-
def genInterfacesPkg(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
2467-
var files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
2468-
2469-
files = files ++ genMsgFiles(modelName, datatypeMap)
2470-
files = files :+ genInterfacesCMakeListsFile(modelName, datatypeMap)
2471-
files = files :+ genInterfacesPackageFile(modelName)
2472-
2473-
return files
2474-
}
24752368
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// #Sireum
2+
3+
package org.sireum.hamr.codegen.ros2
4+
5+
import org.sireum._
6+
import org.sireum.hamr.codegen.common.containers.Marker
7+
import org.sireum.hamr.codegen.common.types.AadlType
8+
9+
object GeneratorInterfaces {
10+
11+
val py_package_name_suffix: String = "_py_pkg"
12+
val cpp_package_name_suffix: String = "_cpp_pkg"
13+
14+
def genCppPackageName(packageNameS: String): String = {
15+
// create target package name
16+
val packageNameT: String = s"${packageNameS}${cpp_package_name_suffix}"
17+
return packageNameT
18+
}
19+
20+
def genPyPackageName(packageNameS: String): String = {
21+
// create target package name
22+
val packageNameT: String = s"${packageNameS}${py_package_name_suffix}"
23+
return packageNameT
24+
}
25+
26+
def genLaunchPackageType(modelName: String, launchType: String): String = {
27+
launchType match {
28+
case "Cpp" => return genCppPackageName(modelName)
29+
case "Python" => return genPyPackageName(modelName)
30+
}
31+
}
32+
33+
//================================================
34+
// I n t e r f a c e s Setup Files
35+
//================================================
36+
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
37+
// The "Empty" datatype, which has no data fields, is used for event ports
38+
39+
def genMsgFile(modelName: String, datatypeName: String, datatypeContent: ISZ[String], top_level_package_nameT: String): (ISZ[String], ST, B, ISZ[Marker]) = {
40+
41+
val fileBody = st"${(datatypeContent, "\n")}"
42+
43+
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", "msg", s"${datatypeName}.msg")
44+
45+
return (filePath, fileBody, T, IS())
46+
}
47+
48+
def genMsgFiles(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])], top_level_package_nameT: String): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
49+
var msg_files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
50+
for (datatype <- datatypeMap.entries) {
51+
msg_files = msg_files :+ genMsgFile(modelName, datatype._2._1, datatype._2._2, top_level_package_nameT)
52+
}
53+
msg_files = msg_files :+ (ISZ("src", s"${top_level_package_nameT}_interfaces", "msg", "Empty.msg"), st"", T, IS())
54+
return msg_files
55+
}
56+
57+
def genInterfacesCMakeListsFile(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])], top_level_package_nameT: String): (ISZ[String], ST, B, ISZ[Marker]) = {
58+
val fileName: String = "CMakeLists.txt"
59+
var msgTypes: ISZ[String] = IS()
60+
for (msg <- datatypeMap.valueSet.elements) {
61+
msgTypes = msgTypes :+ s"msg/${msg._1}.msg"
62+
}
63+
msgTypes = msgTypes :+ s"msg/Empty.msg"
64+
65+
val setupFileBody =
66+
st"""cmake_minimum_required(VERSION 3.8)
67+
|project(${top_level_package_nameT}_interfaces)
68+
|
69+
|if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
70+
| add_compile_options(-Wall -Wextra -Wpedantic)
71+
|endif()
72+
|
73+
|find_package(ament_cmake REQUIRED)
74+
|
75+
|find_package(rosidl_default_generators REQUIRED)
76+
|
77+
|rosidl_generate_interfaces($${PROJECT_NAME}
78+
| ${(msgTypes, "\n")}
79+
|)
80+
|
81+
|ament_export_dependencies(rosidl_default_runtime)
82+
|
83+
|ament_package()
84+
"""
85+
86+
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
87+
88+
return (filePath, setupFileBody, T, IS())
89+
}
90+
91+
def genInterfacesPackageFile(modelName: String, top_level_package_nameT: String): (ISZ[String], ST, B, ISZ[Marker]) = {
92+
val fileName: String = "package.xml"
93+
94+
val setupFileBody =
95+
st"""<?xml version="1.0"?>
96+
|<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
97+
|<package format="3">
98+
| <name>${top_level_package_nameT}_interfaces</name>
99+
| <version>0.0.0</version>
100+
| <description>TODO: Package description</description>
101+
| <maintainer email="[email protected]">sireum</maintainer>
102+
| <license>TODO: License declaration</license>
103+
|
104+
| <buildtool_depend>ament_cmake</buildtool_depend>
105+
|
106+
| <build_depend>rosidl_default_generators</build_depend>
107+
| <exec_depend>rosidl_default_runtime</exec_depend>
108+
| <member_of_group>rosidl_interface_packages</member_of_group>
109+
|
110+
| <test_depend>ament_lint_auto</test_depend>
111+
| <test_depend>ament_lint_common</test_depend>
112+
|
113+
| <export>
114+
| <build_type>ament_cmake</build_type>
115+
| </export>
116+
|</package>
117+
"""
118+
119+
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
120+
121+
return (filePath, setupFileBody, T, IS())
122+
}
123+
124+
// The same datatype package will work regardless of other packages' types
125+
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
126+
def genInterfacesPkg(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])], nodeLanguage: String): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
127+
val top_level_package_nameT: String = genLaunchPackageType(modelName, nodeLanguage)
128+
var files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
129+
130+
files = files ++ genMsgFiles(modelName, datatypeMap, top_level_package_nameT)
131+
files = files :+ genInterfacesCMakeListsFile(modelName, datatypeMap, top_level_package_nameT)
132+
files = files :+ genInterfacesPackageFile(modelName, top_level_package_nameT)
133+
134+
return files
135+
}
136+
}

shared/src/main/scala/org/sireum/hamr/codegen/ros2/GeneratorPy.scala

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -395,100 +395,6 @@ object GeneratorPy {
395395
return (filePath, setupFileBody, T, IS())
396396
}
397397

398-
//================================================
399-
// I n t e r f a c e s Setup Files
400-
//================================================
401-
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
402-
// The "Empty" datatype, which has no data fields, is used for event ports
403-
404-
def genMsgFiles(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
405-
var msg_files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
406-
for (datatype <- datatypeMap.entries) {
407-
msg_files = msg_files :+ genMsgFile(modelName, datatype._2._1, datatype._2._2)
408-
}
409-
msg_files = msg_files :+ (ISZ("src", s"${genPyPackageName(modelName)}_interfaces", "msg", "Empty.msg"), st"", T, IS())
410-
return msg_files
411-
}
412-
413-
def genMsgFile(modelName: String, datatypeName: String, datatypeContent: ISZ[String]): (ISZ[String], ST, B, ISZ[Marker]) = {
414-
val top_level_package_nameT: String = genPyPackageName(modelName)
415-
416-
val fileBody = st"${(datatypeContent, "\n")}"
417-
418-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", "msg", s"${datatypeName}.msg")
419-
420-
return (filePath, fileBody, T, IS())
421-
}
422-
423-
def genInterfacesCMakeListsFile(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): (ISZ[String], ST, B, ISZ[Marker]) = {
424-
val top_level_package_nameT: String = genPyPackageName(modelName)
425-
val fileName: String = "CMakeLists.txt"
426-
var msgTypes: ISZ[String] = IS()
427-
for (msg <- datatypeMap.valueSet.elements) {
428-
msgTypes = msgTypes :+ s"msg/${msg._1}.msg"
429-
}
430-
msgTypes = msgTypes :+ s"msg/Empty.msg"
431-
432-
val setupFileBody =
433-
st"""cmake_minimum_required(VERSION 3.8)
434-
|project(${top_level_package_nameT}_interfaces)
435-
|
436-
|if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
437-
| add_compile_options(-Wall -Wextra -Wpedantic)
438-
|endif()
439-
|
440-
|find_package(ament_cmake REQUIRED)
441-
|
442-
|find_package(rosidl_default_generators REQUIRED)
443-
|
444-
|rosidl_generate_interfaces($${PROJECT_NAME}
445-
| ${(msgTypes, "\n")}
446-
|)
447-
|
448-
|ament_export_dependencies(rosidl_default_runtime)
449-
|
450-
|ament_package()
451-
"""
452-
453-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
454-
455-
return (filePath, setupFileBody, T, IS())
456-
}
457-
458-
def genInterfacesPackageFile(modelName: String): (ISZ[String], ST, B, ISZ[Marker]) = {
459-
val top_level_package_nameT: String = genPyPackageName(modelName)
460-
val fileName: String = "package.xml"
461-
462-
val setupFileBody =
463-
st"""<?xml version="1.0"?>
464-
|<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
465-
|<package format="3">
466-
| <name>${top_level_package_nameT}_interfaces</name>
467-
| <version>0.0.0</version>
468-
| <description>TODO: Package description</description>
469-
| <maintainer email="[email protected]">sireum</maintainer>
470-
| <license>TODO: License declaration</license>
471-
|
472-
| <buildtool_depend>ament_cmake</buildtool_depend>
473-
|
474-
| <build_depend>rosidl_default_generators</build_depend>
475-
| <exec_depend>rosidl_default_runtime</exec_depend>
476-
| <member_of_group>rosidl_interface_packages</member_of_group>
477-
|
478-
| <test_depend>ament_lint_auto</test_depend>
479-
| <test_depend>ament_lint_common</test_depend>
480-
|
481-
| <export>
482-
| <build_type>ament_cmake</build_type>
483-
| </export>
484-
|</package>
485-
"""
486-
487-
val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_interfaces", fileName)
488-
489-
return (filePath, setupFileBody, T, IS())
490-
}
491-
492398
//================================================
493399
// Node files (Py)
494400
// Example: https://github.com/santoslab/ros-examples/tree/main/tempControl_ws/src/tc_py_pkg/tc_py_pkg
@@ -1714,16 +1620,4 @@ object GeneratorPy {
17141620

17151621
return files
17161622
}
1717-
1718-
// The same datatype package will work regardless of other packages' types
1719-
// ROS2 data/message types are defined in a "{package_name}_interfaces" package according to convention
1720-
def genInterfacesPkg(modelName: String, datatypeMap: Map[AadlType, (String, ISZ[String])]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
1721-
var files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
1722-
1723-
files = files ++ genMsgFiles(modelName, datatypeMap)
1724-
files = files :+ genInterfacesCMakeListsFile(modelName, datatypeMap)
1725-
files = files :+ genInterfacesPackageFile(modelName)
1726-
1727-
return files
1728-
}
17291623
}

shared/src/main/scala/org/sireum/hamr/codegen/ros2/Ros2Codegen.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,9 @@ object Ros2Codegen {
4949
case "Cpp" => files =
5050
Generator.genCppNodePkg(modelName, threadComponents, connectionMap, datatypeMap, options.strictAadlMode,
5151
options.invertTopicBinding, reporter)
52-
files = files ++ Generator.genInterfacesPkg(modelName, datatypeMap)
5352
case "Python" =>
5453
files = GeneratorPy.genPyNodePkg(modelName, threadComponents, connectionMap, datatypeMap, options.strictAadlMode,
5554
options.invertTopicBinding, reporter)
56-
files = files ++ GeneratorPy.genInterfacesPkg(modelName, datatypeMap)
5755
case _ => reporter.error(None(), toolName, s"Unknown code type: ${options.ros2NodesLanguage.name}")
5856
}
5957

@@ -63,6 +61,8 @@ object Ros2Codegen {
6361
case _ => reporter.error(None(), toolName, s"Unknown code type: ${options.ros2NodesLanguage.name}")
6462
}
6563

64+
files = files ++ GeneratorInterfaces.genInterfacesPkg(modelName, datatypeMap, options.ros2NodesLanguage.name)
65+
6666
for (file <- files) {
6767
var filePath: String = ""
6868
for (s <- file._1) {

0 commit comments

Comments
 (0)