blob: ec64e663bd10094831fc97fe822734f77604eb84 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2018 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Ansgar Radermacher ansgar.radermacher@cea.fr
*
*****************************************************************************/
package org.eclipse.papyrus.robotics.ros2.codegen.message
import org.eclipse.papyrus.MARTE.MARTE_Annexes.VSL.DataTypes.ChoiceType
import org.eclipse.papyrus.infra.tools.file.IPFileSystemAccess
import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil
import org.eclipse.uml2.uml.DataType
import org.eclipse.uml2.uml.Enumeration
import org.eclipse.uml2.uml.NamedElement
import org.eclipse.uml2.uml.PrimitiveType
import org.eclipse.uml2.uml.Property
import org.eclipse.uml2.uml.TemplateBinding
import static extension org.eclipse.papyrus.robotics.codegen.common.utils.PackageTools.pkgName
import static extension org.eclipse.papyrus.robotics.core.utils.InteractionUtils.*
import static extension org.eclipse.papyrus.robotics.ros2.codegen.utils.MessageUtils.*
class CreateMessage {
CreateMsgPackage msgPkgCreator;
/**
* Construct
*/
new(CreateMsgPackage msgPkgCreator) {
this.msgPkgCreator = msgPkgCreator;
}
/**
* Create contents for a data type or an enumeration
*/
def createDtOrEnumMsg(DataType dtOrEnum) {
if (dtOrEnum instanceof Enumeration) {
createEnumMsgs(dtOrEnum as Enumeration)
} else {
createDataTypeMsg(dtOrEnum)
}
}
/**
* Create message contents for a dataType
*/
def createDataTypeMsg(DataType dataType) '''
# Push or Send
«dataType.makeDTExternal»
«IF StereotypeUtil.isApplied(dataType, ChoiceType) && false»
# attributes of choice-type «dataType.qualifiedName» (only first attribute for the moment)
«val attribute = dataType.getAllAttributes.get(0)»
««« TODO: properly handle choice type, just use first attribute in the moment
«attribute.createAttributeMsg»
«ELSE»
# attributes of datatype «dataType.qualifiedName»
«FOR attribute : dataType.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
«ENDIF»
'''
def createServiceMsg(DataType request, DataType response) '''
# query pattern - request
# attributes of request «request.qualifiedName»
«FOR attribute : request.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
---
# attributes of response «response.qualifiedName»
«FOR attribute : response.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
'''
def createActionMsg(DataType goal, DataType response, DataType feedback) '''
# action pattern
# attributes of goal «goal.qualifiedName»
«FOR attribute : goal.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
---
# attributes of result «response.qualifiedName»
«FOR attribute : response.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
---
# attributes of feedback «feedback.qualifiedName»
«FOR attribute : response.getAllAttributes»
«attribute.createAttributeMsg»
«ENDFOR»
'''
/**
* Create an attribute within a message, handling default values and comments
*/
def createAttributeMsg(Property attribute) {
var String typeStr
if (attribute.type instanceof PrimitiveType) {
typeStr = attribute.type.primitiveTypeMap
} else if (attribute.type instanceof Enumeration) {
typeStr = '''
# enum «attribute.type.name»
uint8'''
val type = attribute.type as Enumeration
// recurse, create new message package
msgPkgCreator.createMsgPkg(type);
} else if (attribute.type instanceof DataType) {
val type = attribute.type as DataType
typeStr = String.format("%s/%s", attribute.type.messagePackage.pkgName, attribute.type.name);
msgPkgCreator.createMsgPkg(type);
}
return '''
«typeStr»«attribute.multiplicityStr» «attribute.name»«attribute.defaultValueStr»
'''
}
def getMultiplicityStr(Property attribute) {
if (attribute.upper == -1) {
return "[]"
} else if (attribute.upper != 1) {
return '''[«attribute.upper»]'''
}
}
/**
*
*/
def defaultValueStr(Property attribute) '''
«IF attribute.defaultValue !== null»
«" "»= «attribute.defaultValue.stringValue»
«ENDIF»
'''
/**
*
* generate a message file, unless the message is an already existing system message
* This is the case for messages/services that can be found with an empty AMENT_PREFIX_PATH.
* The user can specify a configurable path that containing entries that should not be
* re-written by code generation.
*/
def void generateFile(IPFileSystemAccess fileAccess, String fileName, String ext, CharSequence content) {
val fileNameWithExt = '''«ext»/«fileName».«ext»'''
fileAccess.generateFile(fileNameWithExt, content.toString)
}
def createEnumMsgs(Enumeration enumeration) '''
# constants to mimic enumeration «enumeration.name»
«var counter = 0»
«FOR enumLiteral : enumeration.ownedLiterals»
uint8 «enumLiteral.name.toUpperCase» = «counter++»
«ENDFOR»
'''
def createMsgForEvent(TemplateBinding tb) '''
# Event
«FOR tps : tb.getParameterSubstitutions»
«val actual = tps.actual»
«(actual as NamedElement).name» «tps.formal.getTPName»
«ENDFOR»
'''
}