From 7e2f8c41c58fa28509c5421f7d2c21de83d46fa4 Mon Sep 17 00:00:00 2001 From: Clint McKenzie Date: Wed, 8 Jan 2025 18:47:41 -0600 Subject: [PATCH] Overhauled launch files; also bug fixes --- jvm/src/test | 2 +- .../sireum/hamr/codegen/ros2/Generator.scala | 116 ++++++++++++++---- .../hamr/codegen/ros2/Ros2Codegen.scala | 13 +- 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/jvm/src/test b/jvm/src/test index 7a60371..c2f61a1 160000 --- a/jvm/src/test +++ b/jvm/src/test @@ -1 +1 @@ -Subproject commit 7a60371ab56259a1b4dd79b0b949d81ec99b337a +Subproject commit c2f61a1be8860ffcdc71b98fb61378bc0405c93a diff --git a/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Generator.scala b/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Generator.scala index 5cde50f..c4a8142 100644 --- a/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Generator.scala +++ b/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Generator.scala @@ -3,7 +3,7 @@ package org.sireum.hamr.codegen.ros2 import org.sireum._ -import org.sireum.hamr.codegen.common.symbols.{AadlDataPort, AadlEventDataPort, AadlPort, AadlThread, Dispatch_Protocol} +import org.sireum.hamr.codegen.common.symbols.{AadlComponent, AadlDataPort, AadlEventDataPort, AadlPort, AadlProcess, AadlSystem, AadlThread, Dispatch_Protocol} import org.sireum.hamr.codegen.common.types.{AadlType, ArrayType, BaseType, EnumType, RecordType} import org.sireum.hamr.ir.Direction import org.sireum.message.Reporter @@ -514,12 +514,12 @@ object Generator { // L a u n c h File (XML Format) //================================================ - // genLaunchNodeDecl() - generate node declaration + // Generate node launch code // Example: // def genXmlFormatLaunchNodeDecl(top_level_package_nameT: String, - component: AadlThread): ST = { - val node_executable_file_nameT = genExecutableFileName(genNodeName(component)) + thread: AadlThread): ST = { + val node_executable_file_nameT = genExecutableFileName(genNodeName(thread)) val s = st""" | @@ -528,27 +528,78 @@ object Generator { return s } - // For example, see https://github.com/santoslab/ros-examples/blob/main/tempControl_ws/src/tc_bringup/launch/tc.launch.py - def genXmlFormatLaunchFile(modelName: String, threadComponents: ISZ[AadlThread]): (ISZ[String], ST) = { - val fileName = genXmlLaunchFileName(modelName) + // Generate system launch code (including a system launch file) + // Example: + // + def genXmlFormatLaunchSystemDecl(top_level_package_nameT: String, + system: AadlSystem): ST = { + val launchFileName: String = genXmlLaunchFileName(system.identifier) + val s = + st""" + | + """ + return s + } + + def genXmlFormatLaunchDecls(component: AadlComponent, packageName: String): ISZ[ST] = { + var launch_decls: ISZ[ST] = IS() + + for (comp <- component.subComponents) { + comp match { + case thread: AadlThread => + launch_decls = launch_decls :+ genXmlFormatLaunchNodeDecl(packageName, thread) + case system: AadlSystem => + launch_decls = launch_decls :+ genXmlFormatLaunchSystemDecl(packageName, system) + case process: AadlProcess => + launch_decls = launch_decls ++ genXmlFormatLaunchDecls(process, packageName) + case _ => + } + } + + return launch_decls + } + // For example, see https://github.com/santoslab/ros-examples/blob/main/tempControl_ws/src/tc_bringup/launch/tc.launch.py + // Creates a launch file for each system component in the model + def genXmlFormatLaunchFiles(modelName: String, threadComponents: ISZ[AadlThread], + systemComponents: ISZ[AadlSystem]): ISZ[(ISZ[String], ST)] = { val top_level_package_nameT: String = genCppPackageName(modelName) - var node_decls: ISZ[ST] = IS() + var launchFiles: ISZ[(ISZ[String], ST)] = IS() - for (comp <- threadComponents) { - node_decls = node_decls :+ genXmlFormatLaunchNodeDecl(top_level_package_nameT, comp) - } + for (system <- systemComponents) { + val fileName = genXmlLaunchFileName(system.identifier) - val launchFileBody = - st""" - | ${(node_decls, "\n")} - | + + + val launch_decls: ISZ[ST] = genXmlFormatLaunchDecls(system, top_level_package_nameT) + + + +/* + var node_decls: ISZ[ST] = IS() + + for (thread <- threadComponents) { + val threadPath: String = thread.pathAsString(",") + val systemPath: String = system.pathAsString(",") + + if (threadPath.size > systemPath.size && ops.StringOps(threadPath).substring(0, systemPath.size) == systemPath) { + node_decls = node_decls :+ genXmlFormatLaunchNodeDecl(top_level_package_nameT, thread) + } + } +*/ + val launchFileBody = + st""" + | ${(launch_decls, "\n")} + | """ - val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_bringup", "launch", fileName) + val filePath: ISZ[String] = IS("src", s"${top_level_package_nameT}_bringup", "launch", fileName) - return (filePath, launchFileBody) + launchFiles = launchFiles :+ (filePath, launchFileBody) + } + + return launchFiles } @@ -1503,6 +1554,11 @@ object Generator { val inputPorts = connectionMap.get(p.path).get publisherHeaders = publisherHeaders :+ genCppTopicPublisherVarHeader(p, portDatatype, inputPorts.size) } + else { + // Out ports with no connections should still publish to a topic (for other non-generated components + // to subscribe to, for example) + publisherHeaders = publisherHeaders :+ genCppTopicPublisherVarHeader(p, portDatatype, 1) + } } } else { @@ -1523,8 +1579,12 @@ object Generator { if (connectionMap.get(p.path).nonEmpty) { val inputPorts = connectionMap.get(p.path).get publisherHeaders = publisherHeaders :+ genCppTopicPublisherVarHeader(p, portDatatype, inputPorts.size) - putMethodHeaders = putMethodHeaders :+ - genCppPutMsgMethodHeader(p, portDatatype) + putMethodHeaders = putMethodHeaders :+ genCppPutMsgMethodHeader(p, portDatatype) + } + else { + // Out ports with no connections should still publish to a topic + publisherHeaders = publisherHeaders :+ genCppTopicPublisherVarHeader(p, portDatatype, 1) + putMethodHeaders = putMethodHeaders :+ genCppPutMsgMethodHeader(p, portDatatype) } } } @@ -1749,8 +1809,8 @@ object Generator { genCppTopicPublishMethodStrict(p, nodeName, portDatatype, inputPortNames.size) } else { - // Out ports with no connections should still publish to a topic (for other non-generated components - // to subscribe to, for example) + // Out ports with no connections should still publish to a topic + publishers = publishers :+ genCppTopicPublisher(p, portDatatype, getPortNames(IS(p.path.toISZ))) publisherMethods = publisherMethods :+ genCppTopicPublishMethodStrict(p, nodeName, portDatatype, 1) } @@ -1779,6 +1839,12 @@ object Generator { publisherMethods = publisherMethods :+ genCppTopicPublishMethod(p, nodeName, portDatatype, inputPortNames.size) } + else { + // Out ports with no connections should still publish to a topic + publishers = publishers :+ genCppTopicPublisher(p, portDatatype, getPortNames(IS(p.path.toISZ))) + publisherMethods = publisherMethods :+ + genCppTopicPublishMethod(p, nodeName, portDatatype, 1) + } } } } @@ -2092,7 +2158,7 @@ object Generator { var converterHeaders: ISZ[ST] = IS() for (enum <- enumTypes) { - val enumName: String = enum._2.classifier.apply(enum._2.classifier.size - 1) + val enumName: String = ops.StringOps(enum._2.classifier.apply(enum._2.classifier.size - 1)).replaceAllLiterally("_", "") includes = includes :+ st"#include \"${packageName}_interfaces/msg/${enum._1}.hpp\"" @@ -2127,7 +2193,7 @@ object Generator { var converters: ISZ[ST] = IS() for (enum <- enumTypes) { - val enumName: String = enum._2.classifier.apply(enum._2.classifier.size - 1) + val enumName: String = ops.StringOps(enum._2.classifier.apply(enum._2.classifier.size - 1)).replaceAllLiterally("_", "") val enumValues: ISZ[String] = enum._2.asInstanceOf[EnumType].values var cases: ISZ[ST] = IS() @@ -2248,10 +2314,10 @@ object Generator { return files } - def genXmlLaunchPkg(modelName: String, threadComponents: ISZ[AadlThread]): ISZ[(ISZ[String], ST)] = { + def genXmlLaunchPkg(modelName: String, threadComponents: ISZ[AadlThread], systemComponents: ISZ[AadlSystem]): ISZ[(ISZ[String], ST)] = { var files: ISZ[(ISZ[String], ST)] = IS() - files = files :+ genXmlFormatLaunchFile(modelName, threadComponents) + files = files ++ genXmlFormatLaunchFiles(modelName, threadComponents, systemComponents) files = files :+ genLaunchCMakeListsFile(modelName) files = files :+ genLaunchPackageFile(modelName) diff --git a/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Ros2Codegen.scala b/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Ros2Codegen.scala index 4d93d32..7e66a1c 100644 --- a/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Ros2Codegen.scala +++ b/shared/src/main/scala/org/sireum/hamr/codegen/ros2/Ros2Codegen.scala @@ -6,7 +6,7 @@ import org.sireum._ import org.sireum.hamr.codegen.common.CommonUtil import org.sireum.hamr.codegen.common.containers.FileResource import org.sireum.hamr.codegen.common.plugin.Plugin -import org.sireum.hamr.codegen.common.symbols.{AadlComponent, AadlThread, SymbolTable} +import org.sireum.hamr.codegen.common.symbols.{AadlComponent, AadlSystem, AadlThread, SymbolTable} import org.sireum.hamr.codegen.common.types.{AadlType, AadlTypes, ArrayType, BaseType, EnumType, RecordType} import org.sireum.hamr.codegen.common.util.HamrCli.CodegenOption import org.sireum.hamr.codegen.common.util.ResourceUtil @@ -24,6 +24,7 @@ import org.sireum.ops.ISZOps var resources: ISZ[FileResource] = ISZ() var threadComponents: ISZ[AadlThread] = ISZ() + var systemComponents: ISZ[AadlSystem] = ISZ() var connectionMap: Map[ISZ[String], ISZ[ISZ[String]]] = Map.empty var datatypeMap: Map[AadlType, (String, ISZ[String])] = Map.empty @@ -45,7 +46,7 @@ import org.sireum.ops.ISZOps } options.ros2LaunchLanguage.name match { - case "Xml" => files = files ++ Generator.genXmlLaunchPkg(modelName, threadComponents) + case "Xml" => files = files ++ Generator.genXmlLaunchPkg(modelName, threadComponents, systemComponents) case "Python" => files = files ++ Generator.genPyLaunchPkg(modelName, threadComponents) case _ => reporter.error(None(), toolName, s"Unknown code type: ${options.ros2NodesLanguage.name}") } @@ -80,8 +81,12 @@ import org.sireum.ops.ISZOps processConnection(ci, c.component, symbolTable, reporter) } - if (c.isInstanceOf[AadlThread]) { - threadComponents = threadComponents :+ c.asInstanceOf[AadlThread] + c match { + case thread: AadlThread => + threadComponents = threadComponents :+ thread + case system: AadlSystem => + systemComponents = systemComponents :+ system + case _ => } for (sc <- c.subComponents) {