| /***************************************************************************** |
| * Copyright (c) 2020 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.cpp.component |
| |
| import java.util.ArrayList |
| import org.eclipse.core.resources.IProject |
| import org.eclipse.papyrus.designer.languages.common.profile.Codegen.TemplateBinding |
| import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Include |
| import org.eclipse.papyrus.designer.transformation.base.utils.TransformationException |
| import org.eclipse.papyrus.designer.transformation.core.transformations.ExecuteTransformationChain |
| import org.eclipse.papyrus.designer.transformation.core.transformations.TransformationContext |
| import org.eclipse.papyrus.designer.languages.common.base.file.IPFileSystemAccess |
| import org.eclipse.papyrus.robotics.codegen.common.utils.ApplyProfiles |
| import org.eclipse.papyrus.robotics.core.utils.PortUtils |
| import org.eclipse.papyrus.robotics.profile.robotics.components.ComponentDefinition |
| import org.eclipse.papyrus.robotics.profile.robotics.functions.Function |
| import org.eclipse.papyrus.robotics.ros2.codegen.common.component.AbstractCompTransformations |
| import org.eclipse.papyrus.robotics.ros2.codegen.common.message.CreateMsgPackage |
| import org.eclipse.papyrus.robotics.ros2.codegen.cpp.utils.ProjectTools |
| import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil |
| import org.eclipse.uml2.uml.Class |
| import org.eclipse.uml2.uml.OpaqueBehavior |
| import org.eclipse.uml2.uml.Property |
| import org.eclipse.uml2.uml.util.UMLUtil |
| |
| import static org.eclipse.papyrus.robotics.ros2.codegen.cpp.utils.RosCppTypes.* |
| |
| import static extension org.eclipse.papyrus.designer.uml.tools.utils.ElementUtils.varName |
| import static extension org.eclipse.papyrus.robotics.codegen.common.utils.ActivityUtils.* |
| import static extension org.eclipse.papyrus.robotics.codegen.common.utils.ComponentUtils.isRegistered |
| import static extension org.eclipse.papyrus.robotics.core.utils.InteractionUtils.* |
| import static extension org.eclipse.papyrus.robotics.core.utils.ParameterUtils.getAllParameters |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.common.component.ComponentTransformationUtils.* |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.common.utils.MessageUtils.* |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.common.utils.RosHelpers.* |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.Constructor.createConstructor |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.CreateMain.createMain |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.CreateMain.registerComponent |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.ParameterTransformations.declareParameters |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.ParameterTransformations.initParameters |
| import static extension org.eclipse.papyrus.robotics.ros2.codegen.cpp.component.ParameterTransformations.moveParameters |
| |
| class ComponentTransformations extends AbstractCompTransformations { |
| |
| new(IPFileSystemAccess fileAccess, IProject genProject) { |
| super(fileAccess, genProject) |
| } |
| |
| def static createPubsSubsAttrs(Class component) { |
| for (port : PortUtils.getAllPorts(component)) { |
| val cp = port.communicationPattern |
| if (cp.isPush || cp.isPubSub) { |
| var Property attribute |
| if (port.provideds.size() > 0) { |
| val rosPublisher = getType(port, "ros2Library::rclcpp_lifecycle::LifecyclePublisher") |
| attribute = component.createOwnedAttribute('''«port.varName»_pub_''', rosPublisher) |
| } else if (port.requireds.size() > 0) { |
| val rosSubscriber = getType(port, "ros2Library::rclcpp::Subscription") |
| attribute = component.createOwnedAttribute('''«port.varName»_sub_''', rosSubscriber) |
| } |
| ApplyProfiles.applyCommonProfile(attribute) |
| val template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| template.actuals.add(port.commObject) |
| attribute.useSharedPtr |
| } |
| } |
| } |
| |
| def static createSendAttrs(Class component) { |
| for (port : PortUtils.getAllPorts(component)) { |
| if (port.communicationPattern.isSend) { |
| var Property attribute |
| if (port.provideds.size() > 0) { |
| val rosSubscriber = getType(port, "ros2Library::rclcpp::Subscription") |
| attribute = component.createOwnedAttribute('''«port.varName»_recv_''', rosSubscriber) |
| } else if (port.requireds.size() > 0) { |
| val rosPublisher = getType(port, "ros2Library::rclcpp_lifecycle::LifecyclePublisher") |
| attribute = component.createOwnedAttribute('''«port.varName»_send_''', rosPublisher) |
| } |
| ApplyProfiles.applyCommonProfile(attribute) |
| val template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| template.actuals.add(port.commObject) |
| attribute.useSharedPtr |
| } |
| } |
| } |
| |
| def static createServiceAttrs(Class component) { |
| for (port : PortUtils.getAllPorts(component)) { |
| if (port.communicationPattern.isQuery) { |
| var Property attribute |
| if (port.provideds.size() > 0) { |
| val rosService = getType(port, "ros2Library::rclcpp::Service"); |
| attribute = component.createOwnedAttribute('''«port.varName»_srv_''', rosService); |
| } else if (port.requireds.size() > 0) { |
| val rosClient = getType(port, "ros2Library::rclcpp::Client"); |
| attribute = component.createOwnedAttribute('''«port.varName»_client_''', rosClient); |
| } |
| var template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| if (template === null) { |
| ApplyProfiles.applyCommonProfile(attribute) |
| template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| } |
| template.actuals.add(port.serviceType) |
| attribute.useSharedPtr |
| } |
| } |
| } |
| |
| /** |
| * Add action attributes |
| */ |
| def static createActionAttrs(Class component) { |
| for (port : PortUtils.getAllPorts(component)) { |
| if (port.communicationPattern.isAction) { |
| var Property attribute |
| if (port.provideds.size() > 0) { |
| val rosService = getType(port, "ros2Library::rclcpp_action::Server"); |
| attribute = component.createOwnedAttribute('''«port.varName»_actsrv_''', rosService); |
| } else if (port.requireds.size() > 0) { |
| val rosClient = getType(port, "ros2Library::rclcpp_action::Client"); |
| attribute = component.createOwnedAttribute('''«port.varName»_actcli_''', rosClient); |
| } |
| var template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| if (template === null) { |
| ApplyProfiles.applyCommonProfile(attribute) |
| template = StereotypeUtil.applyApp(attribute, TemplateBinding) |
| } |
| template.actuals.add(port.serviceType) |
| attribute.useSharedPtr |
| } |
| } |
| } |
| |
| /** |
| * Remove functions that are not referenced by activities (this can happen after |
| * deletion of a function from an activity) |
| */ |
| def static removeUnrefFunctions(Class component) { |
| val cd = UMLUtil.getStereotypeApplication(component, ComponentDefinition) |
| val fctList = new ArrayList<Function>(); |
| |
| for (activity : cd.activities) { |
| fctList.addAll(activity.functions) |
| } |
| for (pe : component.nearestPackage.packagedElements.clone) { |
| if (pe instanceof OpaqueBehavior) { |
| val fct = UMLUtil.getStereotypeApplication(pe, Function) |
| if (fct !== null && !fctList.contains(fct)) { |
| pe.destroy(); |
| } |
| } |
| } |
| } |
| |
| override componentTrafo(Class component, CreateMsgPackage msgPkgCreator) { |
| msgPkgCreator.createMessagesOrServices(component) |
| |
| if (genProject === null) { |
| throw new TransformationException(ExecuteTransformationChain.USER_CANCEL); |
| } |
| component.liftFunctions |
| component.createConstructor |
| var include = StereotypeUtil.applyApp(component, Include); |
| |
| // TODO: do via external type add rclcpp via external type? |
| include.header = include.header + "#include <rclcpp/rclcpp.hpp>\n" |
| if (component.hasActions) { |
| include.header = include.header + "#include <rclcpp_action/rclcpp_action.hpp>\n" |
| } |
| if (component.isRegistered) { |
| include.body = include.body + component.registerComponent; |
| } |
| |
| component.createMain; |
| |
| if (component.hasExternalCode) { |
| new Ros2CodeSkeleton().createSkeleton(component); |
| } |
| // val stdString = getType(node, "ros2Library::std_msgs::String"); |
| // node.createDependency(stdString) |
| component.removeActivities |
| component.createPubsSubsAttrs |
| component.createSendAttrs |
| component.createServiceAttrs |
| component.createActionAttrs |
| |
| if (component.allParameters.size > 0) { |
| component.declareParameters |
| component.initParameters |
| } |
| // move parameter needs to be called even if there are not parameters |
| // as it also removes the nested class holding parameters |
| component.moveParameters |
| } |
| |
| override componentCodegen(Class component, CreateMsgPackage msgPkgCreator) { |
| val codeGen = new RoboticsCppCreator(genProject, fileAccess, "src-skel/", "src/"); |
| |
| component.removeTemplateSig |
| component.removePorts |
| component.removeUnrefFunctions; |
| TransformationContext.current.project = genProject |
| // RoboticsTContext.current.getProjet |
| ProjectTools.genCode(codeGen, component) |
| } |
| } |