| /***************************************************************************** |
| * 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» |
| ''' |
| } |