Skip to content

Commit a482a24

Browse files
committed
Added Virtual Methods
1 parent 16b2666 commit a482a24

File tree

6 files changed

+151
-30
lines changed

6 files changed

+151
-30
lines changed

.DS_Store

0 Bytes
Binary file not shown.

jvm/.DS_Store

0 Bytes
Binary file not shown.

jvm/src/.DS_Store

0 Bytes
Binary file not shown.

jvm/src/test

Submodule test updated from 301c7f4 to 6e9520f

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

Lines changed: 149 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package org.sireum.hamr.codegen.ros2
44

55
import org.sireum._
66
import org.sireum.hamr.codegen.common.containers.Marker
7-
import org.sireum.hamr.codegen.common.symbols.{AadlDataPort, AadlEventDataPort, AadlPort, AadlSystem, AadlThread, Dispatch_Protocol}
7+
import org.sireum.hamr.codegen.common.symbols.{AadlComponent, AadlDataPort, AadlEventDataPort, AadlPort, AadlProcess, AadlSystem, AadlThread, Dispatch_Protocol}
88
import org.sireum.hamr.codegen.common.types.{AadlType, EnumType}
99
import org.sireum.hamr.ir.Direction
1010
import org.sireum.message.Reporter
@@ -505,24 +505,73 @@ object GeneratorPy {
505505
// package="tc_cpp_pkg",
506506
// executable="tc_exe"
507507
// )
508-
def genPyFormatLaunchNodeDecl(launch_node_decl_nameT: String,
509-
top_level_package_nameT: String,
510-
component: AadlThread): ST = {
511-
val node_executable_file_nameT = genExecutableFileName(genNodeName(component))
508+
def genPyFormatLaunchNodeDecl(top_level_package_nameT: String,
509+
thread: AadlThread): ST = {
510+
val node_executable_file_nameT = genExecutableFileName(genNodeName(thread))
511+
val launch_node_decl_nameT = genPyFormatLaunchNodeDeclName(genNodeName(thread))
512512
val s =
513513
st"""${launch_node_decl_nameT} = Node(
514514
| package = "${top_level_package_nameT}",
515515
| executable = "${node_executable_file_nameT}"
516-
| )
516+
|)
517517
"""
518518
return s
519519
}
520520

521+
// Generate system launch code (including a system launch file)
522+
// Example:
523+
// <include file="$(find-pkg-share gazebo_ros)/launch/gazebo.launch.py"/>
524+
def genPyFormatLaunchSystemDecl(top_level_package_nameT: String,
525+
system: AadlSystem): ST = {
526+
val launch_node_decl_nameT = genPyFormatLaunchNodeDeclName(system.identifier)
527+
val launchFileName: String = genPyLaunchFileName(system.identifier)
528+
val s =
529+
st"""${launch_node_decl_nameT} = IncludeLaunchDescription(
530+
| PythonLaunchDescriptionSource(
531+
| os.path.join(get_package_share_directory('${top_level_package_nameT}_bringup'),
532+
| 'launch/${launchFileName}')
533+
| )
534+
|)
535+
"""
536+
return s
537+
}
538+
539+
def genPyFormatLaunchDecls(component: AadlComponent, packageName: String): ISZ[ST] = {
540+
var launch_decls: ISZ[ST] = IS()
541+
542+
for (comp <- component.subComponents) {
543+
comp match {
544+
case thread: AadlThread =>
545+
launch_decls = launch_decls :+ genPyFormatLaunchNodeDecl(packageName, thread)
546+
case system: AadlSystem =>
547+
launch_decls = launch_decls :+ genPyFormatLaunchSystemDecl(packageName, system)
548+
case process: AadlProcess =>
549+
launch_decls = launch_decls ++ genPyFormatLaunchDecls(process, packageName)
550+
case _ =>
551+
}
552+
}
553+
554+
return launch_decls
555+
}
556+
521557
// Example:
522558
// ld.add_action(tc_node)
523-
def genPyFormatLaunchAddAction(launch_node_decl_nameT: String): ST = {
524-
val s = st"""ld.add_action(${launch_node_decl_nameT})"""
525-
return s
559+
def genPyFormatLaunchAddAction(component: AadlComponent): ISZ[ST] = {
560+
var ld_entries: ISZ[ST] = IS()
561+
562+
for(comp <- component.subComponents) {
563+
comp match {
564+
case thread: AadlThread =>
565+
ld_entries = ld_entries :+ st"""ld.add_action(${genPyFormatLaunchNodeDeclName(genNodeName(thread))})"""
566+
case system: AadlSystem =>
567+
ld_entries = ld_entries :+ st"""ld.add_action(${genPyFormatLaunchNodeDeclName(system.identifier)})"""
568+
case process: AadlProcess =>
569+
ld_entries = ld_entries ++ genPyFormatLaunchAddAction(process)
570+
case _ =>
571+
}
572+
}
573+
574+
return ld_entries
526575
}
527576

528577
// For example, see https://github.com/santoslab/ros-examples/blob/main/tempControl_ws/src/tc_bringup/launch/tc.launch.py
@@ -534,15 +583,20 @@ object GeneratorPy {
534583
var launchFiles: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
535584

536585
for (system <- systemComponents) {
537-
val fileName = genPyFormatLaunchNodeDeclName(system.identifier)
586+
val fileName = genPyLaunchFileName(system.identifier)
538587

539-
val node_decls: ISZ[ST] = IS()
540-
val ld_entries: ISZ[ST] = IS()
588+
val node_decls: ISZ[ST] = genPyFormatLaunchDecls(system, top_level_package_nameT)
589+
val ld_entries: ISZ[ST] = genPyFormatLaunchAddAction(system)
541590

542591
val launchFileBody =
543592
st"""from launch import LaunchDescription
544593
|from launch_ros.actions import Node
545594
|
595+
|import os
596+
|from ament_index_python.packages import get_package_share_directory
597+
|from launch.actions import IncludeLaunchDescription
598+
|from launch.launch_description_sources import PythonLaunchDescriptionSource
599+
|
546600
|def generate_launch_description():
547601
| ld = LaunchDescription()
548602
|
@@ -772,6 +826,25 @@ object GeneratorPy {
772826
return subscriptionMessageHeader
773827
}
774828

829+
def genPySubscriptionHandlerVirtualStrict(inPort: AadlPort, portType: String): ST = {
830+
val handlerName = inPort.identifier
831+
832+
var handlerCode: ST = st""
833+
if (isEventPort(portType)) {
834+
handlerCode =
835+
st"""def handle_${handlerName}(self):
836+
| raise NotImplementedError("Subclasses must implement this method")
837+
|"""
838+
} else {
839+
handlerCode =
840+
st"""def handle_${handlerName}(self, msg):
841+
| raise NotImplementedError("Subclasses must implement this method")
842+
|"""
843+
}
844+
845+
return handlerCode
846+
}
847+
775848
def genPySubscriptionHandlerBaseSporadic(inPort: AadlPort, portType: String): ST = {
776849
val handlerName = inPort.identifier
777850

@@ -905,7 +978,7 @@ object GeneratorPy {
905978
handler = st"self.event_handle_${handlerName}"
906979
}
907980
else {
908-
handler = st"handle_${handlerName}"
981+
handler = st"self.handle_${handlerName}"
909982
}
910983

911984
if (outPortNames.size == 1) {
@@ -986,6 +1059,25 @@ object GeneratorPy {
9861059
return subscriptionMessageVar
9871060
}
9881061

1062+
def genPySubscriptionHandlerVirtual(inPort: AadlPort, portType: String): ST = {
1063+
val handlerName = inPort.identifier
1064+
1065+
var handlerCode: ST = st""
1066+
if (isEventPort(portType)) {
1067+
handlerCode =
1068+
st"""def handle_${handlerName}(self):
1069+
| raise NotImplementedError("Subclasses must implement this method")
1070+
|"""
1071+
} else {
1072+
handlerCode =
1073+
st"""def handle_${handlerName}(self, msg):
1074+
| raise NotImplementedError("Subclasses must implement this method")
1075+
|"""
1076+
}
1077+
1078+
return handlerCode
1079+
}
1080+
9891081
def genPyInfrastructureOutQueue(inPort: AadlPort): ST = {
9901082
val portName = inPort.identifier
9911083

@@ -1217,7 +1309,7 @@ object GeneratorPy {
12171309
var inPortNames: ISZ[String] = IS()
12181310
var strictPutMsgMethods: ISZ[ST] = IS()
12191311
var strictSubscriptionMessageAcceptorMethods: ISZ[ST] = IS()
1220-
var strictSubscriptionHandlerBaseMethods: ISZ[ST] = IS()
1312+
var subscriptionHandlerMethods: ISZ[ST] = IS()
12211313
var msgTypes: ISZ[String] = IS()
12221314

12231315
var inMsgVars: ISZ[ST] = IS()
@@ -1259,7 +1351,9 @@ object GeneratorPy {
12591351
subscriptionMessageGetters = subscriptionMessageGetters :+ genPyGetApplicationInValue(p, portDatatype)
12601352
}
12611353
else {
1262-
strictSubscriptionHandlerBaseMethods = strictSubscriptionHandlerBaseMethods :+
1354+
subscriptionHandlerMethods = subscriptionHandlerMethods :+
1355+
genPySubscriptionHandlerVirtualStrict(p, portDatatype)
1356+
subscriptionHandlerMethods = subscriptionHandlerMethods :+
12631357
genPySubscriptionHandlerBaseSporadic(p, portDatatype)
12641358
}
12651359
hasInPorts = T
@@ -1317,6 +1411,9 @@ object GeneratorPy {
13171411
genPySubscriptionHandlerPeriodic(p, portDatatype)
13181412
subscriptionMessageGetters = subscriptionMessageGetters :+ genPyGetSubscriptionMessage(p, nodeName)
13191413
inMsgVars = inMsgVars :+ genPySubscriptionMessageVar(p)
1414+
} else {
1415+
subscriptionHandlerMethods = subscriptionHandlerMethods :+
1416+
genPySubscriptionHandlerVirtual(p, portDatatype)
13201417
}
13211418
hasInPorts = T
13221419
}
@@ -1359,7 +1456,7 @@ object GeneratorPy {
13591456
if (!strictAADLMode && subscribers.size > 0) {
13601457
stdIncludes =
13611458
st"""${stdIncludes}
1362-
|from ${packageName}.user_code.consumer_consumer_src import *"""
1459+
|from ${packageName}.user_code.${genNodeName(component)}_src import *"""
13631460
}
13641461

13651462
var fileBody =
@@ -1451,9 +1548,9 @@ object GeneratorPy {
14511548
if (subscriberMethods.size > 0 || publisherMethods.size > 0 || (strictAADLMode && subscribers.size > 0)) {
14521549
fileBody =
14531550
st"""${fileBody}
1454-
|#=================================================
1455-
|# C o m m u n i c a t i o n
1456-
|#=================================================
1551+
| #=================================================
1552+
| # C o m m u n i c a t i o n
1553+
| #=================================================
14571554
"""
14581555

14591556
if (strictSubscriptionMessageAcceptorMethods.size > 0) {
@@ -1474,12 +1571,6 @@ object GeneratorPy {
14741571
| ${(subscriptionMessageGetters, "\n")}"""
14751572
}
14761573

1477-
if (strictSubscriptionHandlerBaseMethods.size > 0) {
1478-
fileBody =
1479-
st"""${fileBody}
1480-
| ${(strictSubscriptionHandlerBaseMethods, "\n")}"""
1481-
}
1482-
14831574
if (publisherMethods.size > 0) {
14841575
fileBody =
14851576
st"""${fileBody}
@@ -1488,6 +1579,16 @@ object GeneratorPy {
14881579
}
14891580
}
14901581

1582+
if (subscriptionHandlerMethods.size > 0) {
1583+
fileBody =
1584+
st"""${fileBody}
1585+
| #=================================================
1586+
| # C o m p u t e E n t r y P o i n t
1587+
| #=================================================
1588+
| ${(subscriptionHandlerMethods, "\n")}
1589+
|"""
1590+
}
1591+
14911592
if (strictAADLMode) {
14921593
if (!isSporadic(component)) {
14931594
fileBody =
@@ -1510,6 +1611,12 @@ object GeneratorPy {
15101611
return (filePath, fileBody, T, IS())
15111612
}
15121613

1614+
def genPySubscriptionHandlerAdder(inPort: AadlPort): ST = {
1615+
val handlerName = inPort.identifier
1616+
val subscriptionAdder: ST = st"node.handle_${handlerName} = handle_${handlerName}"
1617+
return subscriptionAdder
1618+
}
1619+
15131620
def genPySubscriptionHandlerSporadicStrict(inPort: AadlPort, portType: String): ST = {
15141621
val handlerName = inPort.identifier
15151622

@@ -1565,23 +1672,29 @@ object GeneratorPy {
15651672
val endMarker: String = "# Additions within these tags will be preserved when re-running Codegen"
15661673

15671674
var subscriptionHandlers: ISZ[ST] = IS()
1675+
var subscriptionAdders: ISZ[ST] = IS()
15681676
if (isSporadic(component)) {
15691677
for (p <- component.getPorts()) {
15701678
val portDatatype: String = genPortDatatype(p, packageName, datatypeMap, reporter)
15711679
if (p.direction == Direction.In && !p.isInstanceOf[AadlDataPort]) {
15721680
if (strictAADLMode) {
15731681
subscriptionHandlers = subscriptionHandlers :+
15741682
genPySubscriptionHandlerSporadicStrict(p, portDatatype)
1683+
subscriptionAdders = subscriptionAdders :+
1684+
genPySubscriptionHandlerAdder(p)
15751685
}
15761686
else {
15771687
subscriptionHandlers = subscriptionHandlers :+
15781688
genPySubscriptionHandlerSporadic(p, portDatatype)
1689+
subscriptionAdders = subscriptionAdders :+
1690+
genPySubscriptionHandlerAdder(p)
15791691
}
15801692
}
15811693
}
15821694
}
15831695
else {
15841696
subscriptionHandlers = subscriptionHandlers :+ genPyTimeTriggeredMethod()
1697+
subscriptionAdders = subscriptionAdders :+ st"node.timeTriggered = timeTriggered"
15851698
}
15861699

15871700
var includeFiles: ST =
@@ -1609,6 +1722,7 @@ object GeneratorPy {
16091722
| node.get_logger().info("Initialize Entry Point invoked")
16101723
|
16111724
| # Initialize the node
1725+
| ${(subscriptionAdders, "\n")}
16121726
|
16131727
|#=================================================
16141728
|# C o m p u t e E n t r y P o i n t
@@ -1735,9 +1849,16 @@ object GeneratorPy {
17351849

17361850
def genPyEnumConverterFile(packageName: String, enumTypes: ISZ[(String, AadlType)],
17371851
strictAADLMode: B): (ISZ[String], ST, B, ISZ[Marker]) = {
1852+
var includes: ISZ[ST] = IS()
1853+
1854+
for (enum <- enumTypes) {
1855+
val enumName: String = ops.StringOps(enum._2.classifier.apply(enum._2.classifier.size - 1)).replaceAllLiterally("_", "")
1856+
includes = includes :+ st"from ${packageName}_interfaces.msg import ${enumName}"
1857+
}
1858+
17381859
val fileBody =
17391860
st"""#!/usr/bin/env python3
1740-
|from datatypes_system_py_pkg_interfaces.msg import MyEnum
1861+
|${(includes, "\n")}
17411862
|
17421863
|#========================================================
17431864
|# Re-running Codegen will overwrite changes to this file
@@ -1807,11 +1928,11 @@ object GeneratorPy {
18071928
return files
18081929
}
18091930

1810-
def genPyLaunchPkg(modelName: String, threadComponents: ISZ[AadlThread]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
1931+
def genPyLaunchPkg(modelName: String, threadComponents: ISZ[AadlThread], systemComponents: ISZ[AadlSystem]): ISZ[(ISZ[String], ST, B, ISZ[Marker])] = {
18111932
var files: ISZ[(ISZ[String], ST, B, ISZ[Marker])] = IS()
18121933
files = files :+ genLaunchCMakeListsFile(modelName)
18131934
files = files :+ genLaunchPackageFile(modelName)
1814-
files = files :+ genPyFormatLaunchFile(modelName, threadComponents)
1935+
files = files ++ genPyFormatLaunchFile(modelName, threadComponents, systemComponents)
18151936

18161937
return files
18171938
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import org.sireum.ops.ISZOps
5050

5151
options.ros2LaunchLanguage.name match {
5252
case "Xml" => files = files ++ Generator.genXmlLaunchPkg(modelName, threadComponents, systemComponents)
53-
case "Python" => files = files ++ GeneratorPy.genPyLaunchPkg(modelName, threadComponents)
53+
case "Python" => files = files ++ GeneratorPy.genPyLaunchPkg(modelName, threadComponents, systemComponents)
5454
case _ => reporter.error(None(), toolName, s"Unknown code type: ${options.ros2NodesLanguage.name}")
5555
}
5656

0 commit comments

Comments
 (0)