| /* |
| * Copyright (c) 2022 CEA LIST. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Florian Pauker (TU Wien) pauker@ift.at |
| * Thomas Fruhwirth (TU Wien) thomas.fruehwirth@tuwien.ac.at |
| * Saadia Dhouib (CEA LIST) saadia.dhouib@cea.fr |
| * Fadwa Tmar (CEA LIST) fadwa.tmar@cea.fr |
| *******************************************************************************/ |
| |
| /* |
| * This file specifies a QVTo transformation. |
| */ |
| import Common.Helpers; |
| import ClassDiagram.Classes; |
| import ClassDiagram.Enumerations; |
| import StateMachineDiagram.StateMachines; |
| import Uml2Opcua; |
| |
| //modeltype UA uses 'http://unifiedautomation.com/Configuration/NodeSet.xsd'; |
| |
| modeltype UML uses 'http://www.eclipse.org/uml2/5.0.0/UML'; |
| modeltype SYSML uses 'http://www.eclipse.org/papyrus/sysml/1.6/SysML'; |
| modeltype BLOCKS uses 'http://www.eclipse.org/papyrus/sysml/1.6/SysML/Blocks'; |
| modeltype OPCUA uses set('http://opcfoundation.org/UA/2011/03/UANodeSet.xsd'); |
| modeltype TYPES uses types('http://opcfoundation.org/UA/2008/02/Types.xsd'); |
| modeltype ecore uses 'http://www.eclipse.org/emf/2002/Ecore'; |
| modeltype NodeIdsCsv uses NodeIdsCsv('http://org.eclipse.papyrus.opcua.uml2opcua.nodeIdsCsv.ecore'); |
| |
| |
| modeltype OPCUA_Robotics_Profile uses 'http://Papyrus/OPCUARoboticsProfile'; |
| |
| |
| |
| |
| modeltype OPCUA_Robotics uses opcuarobotics('http://opcfoundation.org/UA/Robotics/'); |
| /* |
| * UML to OPC UA Model Transformation using QVTo |
| * @param umlInputModel The UML input model. |
| * @param opcuaOutputModel The OPC UA output model that will be generated from the umlInputModel by means of model transformation. |
| */ |
| //transformation UMLtoOPCUA(in umlInputModel : UML, out opcuaOutputModel : OPCUA, out nodeIdsCsvOutputModel : NodeIdsCsv, in sysml : SYSML, in robotics:OPCUA_Robotics_Profile, in diProfile:OPCUA_DI_Profile, in uaProfile : OPCUA_Profile ); |
| transformation ElementtoOPCUA(in umlElementInputModel : UML, in roboticsProfile:UML, out opcuaOutputModel : OPCUA, out nodeIdsCsvOutputModel : NodeIdsCsv); |
| |
| |
| |
| property roboticsProfileProfile : UML::Profile = roboticsProfile.rootObjects()![UML::Profile]; |
| //property testMotionDeviceSystemTypeStereotype : UML::Stereotype =roboticsProfileProfile.ownedStereotype![name = "MotionDeviceSystemType"]; |
| |
| /* |
| * The main entry point of the transformation. |
| */ |
| main() { |
| log("Starting UML 2 OPC UA transformation using QVTo"); |
| |
| // initilize internal datastructures |
| addNamespace(0, OPCUA_NAMESPACE_URI); // this Namespace Uri always needs to be added |
| // Namespace Uri DI and Robotics are added only if the robotics profile is applied |
| if(roboticsProfileProfile!=null) { |
| addNamespace(1, OPCUA_DI_NAMESPACE_URI); |
| addNamespace(2, OPCUA_ROBOTICS_NAMESPACE_URI); |
| } ; |
| // the transformation supports the use of NodeId aliases, i.e. using human-readable names instead of NodeIds |
| // these aliases can either be read from a NodeId CSV file, or aliases internally defined in Helpers.qvto |
| if(CFG_USE_BLACKBOX) { |
| loadExternalNodeIds(OPCUA_NAMESPACE_URI, "/NodeIds/NS0/NodeIds.csv"); |
| } else { |
| loadInternalNodeIds(); |
| }; |
| |
| // create a OPCUA::DocumentRoot as the top-level element of the OPC UA model |
| var documentRoot := object OPCUA::DocumentRoot{}; |
| |
| // map the sleceted UML::Element to OPCUA::NodeSetType elements and collect them in a set |
| // do same if the selected element is an UML::Model inputModel contains multiple UML::Model elements |
| var x := documentRoot.xMLNSPrefixMap; |
| if (umlElementInputModel.rootObjects()![UML::Model]<>null){ |
| documentRoot.uANodeSet += umlElementInputModel.rootObjects()![UML::Model]->map model2OPCUANodeSetType(); |
| }endif; |
| if (umlElementInputModel.rootObjects()![UML::Element]<>null){ |
| documentRoot.uANodeSet += umlElementInputModel.rootObjects()![UML::Element]->map element2OPCUANodeSetType(); |
| }endif; |
| } |
| |
| /* |
| * Transformation rule mapping a UML::Model element to an OPCUA::UANodeSetType element |
| */ |
| mapping UML::Element::element2OPCUANodeSetType() : OPCUA::UANodeSetType { |
| //add UaModeler Extention |
| //var uaModelerExtension :=object OPCUA::ExtensionType{}; |
| //extensions:=object ListOfExtensions{extension+=uaModelerExtension}; |
| |
| |
| |
| self->selectByType(UML::Package).package2Namespace(result); |
| self->selectByType(UML::Model).package2Namespace(result); |
| // map UML::Classes with stéréotypes : if there is a stereotype that's mean that |
| //the type is allaready defined in on of the extentions of OPC UA (exple DI or Robitcs) |
| |
| uAObject += self->selectByType(UML::Class)->select(c|c.getAppliedStereotypes()->exists(s|s.name='MotionDeviceSystemType'))-> map class2MotionDeviceSystemObject(result); |
| // map UML::Classes without stéréotypes |
| // map UML::Classes to OPCUA::UAObjectTypes that are not included in any namspeace |
| // TODO the condition here is to verify if there is no applied stereotypes comming from robotics or another profile |
| uAObjectType += self->selectByType(UML::Class)->select(c|c.getAppliedStereotypes()->size()=1 and c.getAppliedStereotypes()->exists(s|s.name='Block'))->map class2OPCUAObjectType(result); |
| |
| // map UML::InstanceSpecification to OPCUA::UAObject that are not included in any namspeace |
| uAObject += self->selectByType(UML::InstanceSpecification)->map instanceSpecification2OPCUAObject(result); |
| |
| // map UML::StateMachines to OPCUA::UAObjectTypes that are not included in any namspeace |
| uAObjectType += self->selectByType(UML::StateMachine)->map statemachine2FiniteStateMachineType(result); |
| |
| //map UML::Enumerations to OPCUA::UADataType |
| uADataType+=self->selectByType(UML::Enumeration)->map enumeration2OPCUADataType(result); |
| // although UML::Associations are top-level elements in a model, UML::Association to OPCUA::Reference transformation is handled as part of the class transformation |
| |
| // create a OPCUA::UriTable and link it to the DocumentRoot |
| namespaceUris := object OPCUA::UriTable{}; |
| fillUriTable(namespaceUris); |
| |
| |
| //TODO add model element of type ModelTableEntry for each profile |
| //models |
| if(roboticsProfileProfile!=null) { |
| //Add the model table entry and the required model entry Di and Robotics |
| var newModel :=object OPCUA ::ModelTableEntry{}; |
| fillModelTableEntry(newModel,self.getUri()); |
| //TODO add URI for each applied profile |
| models :=object OPCUA::ModelTable{model+=newModel}; |
| } ; |
| |
| // create an OPCUA::Alias table |
| if(CFG_ENABLE_ALIAS_TABLE) { |
| aliases := object OPCUA::AliasTable{}; |
| fillAliasTable(aliases); |
| }; |
| |
| // create NodeIdCsv |
| var nodeIdsCsvFile := object NodeIdsCsv::NodeIdsCsvFile{}; |
| result.createNodeIdsCsv(nodeIdsCsvFile); |
| } |
| |
| |
| |