| /******************************************************************************* |
| * Copyright (c) 2019 fortiss GmbH |
| * 2020 Johannes Kepler University Linz |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Martin Jobst - initial API and implementation and/or initial documentation |
| * Alois Zoitl - fixed adapter and fb number generation in connection lists |
| *******************************************************************************/ |
| package org.eclipse.fordiac.ide.export.forte_ng.composite |
| |
| import java.nio.file.Path |
| import java.util.ArrayList |
| import java.util.HashSet |
| import org.eclipse.emf.common.util.EList |
| import org.eclipse.fordiac.ide.export.forte_ng.ForteFBTemplate |
| import org.eclipse.fordiac.ide.model.libraryElement.AdapterFB |
| import org.eclipse.fordiac.ide.model.libraryElement.AdapterFBType |
| import org.eclipse.fordiac.ide.model.libraryElement.CompositeFBType |
| import org.eclipse.fordiac.ide.model.libraryElement.Connection |
| import org.eclipse.fordiac.ide.model.libraryElement.DataConnection |
| import org.eclipse.fordiac.ide.model.libraryElement.EventConnection |
| import org.eclipse.fordiac.ide.model.libraryElement.FBNetworkElement |
| import org.eclipse.fordiac.ide.model.libraryElement.IInterfaceElement |
| import org.eclipse.fordiac.ide.model.libraryElement.VarDeclaration |
| import org.eclipse.xtend.lib.annotations.Accessors |
| |
| class CompositeFBImplTemplate extends ForteFBTemplate { |
| |
| @Accessors(PROTECTED_GETTER) CompositeFBType type |
| |
| var fbs = new ArrayList<FBNetworkElement> |
| var numCompFBParams = 0; |
| var eConnNumber = 0 |
| var fannedOutEventConns = 0 |
| var dataConnNumber = 0 |
| var fannedOutDataConns = 0 |
| |
| new(CompositeFBType type, String name, Path prefix) { |
| super(name, prefix) |
| this.type = type |
| fbs.addAll(type.FBNetwork.networkElements.filter[!(it.type instanceof AdapterFBType)]) |
| } |
| |
| override generate() ''' |
| «generateHeader» |
| |
| «generateImplIncludes» |
| |
| «generateFBDefinition» |
| |
| «generateFBInterfaceDefinition» |
| |
| «generateFBInterfaceSpecDefinition» |
| |
| «generateFBNetwork» |
| |
| ''' |
| |
| def protected generateFBNetwork() ''' |
| «IF type.FBNetwork.networkElements.exists[!(it.type instanceof AdapterFBType)]» |
| const SCFB_FBInstanceData «FBClassName»::scm_astInternalFBs[] = { |
| «FOR elem : fbs SEPARATOR ",\n"»{«elem.name.FORTEString», «elem.type.name.FORTEString»}«ENDFOR» |
| }; |
| «ENDIF» |
| |
| «type.FBNetwork.networkElements.exportFBParams» |
| |
| «IF !type.FBNetwork.eventConnections.empty» |
| «type.FBNetwork.eventConnections.exportEventConns» |
| |
| «ENDIF» |
| «IF !type.FBNetwork.dataConnections.empty» |
| «type.FBNetwork.dataConnections.exportDataConns» |
| |
| «ENDIF» |
| «generateFBNDataStruct()» |
| ''' |
| |
| protected def generateFBNDataStruct() |
| ''' |
| const SCFB_FBNData «FBClassName»::scm_stFBNData = { |
| «fbs.size», «IF !fbs.isEmpty»scm_astInternalFBs«ELSE»nullptr«ENDIF», |
| «eConnNumber», «IF 0 != eConnNumber»scm_astEventConnections«ELSE»nullptr«ENDIF», |
| «fannedOutEventConns», «IF 0 != fannedOutEventConns»scm_astFannedOutEventConnections«ELSE»nullptr«ENDIF», |
| «dataConnNumber», «IF 0 != dataConnNumber»scm_astDataConnections«ELSE»nullptr«ENDIF», |
| «fannedOutDataConns», «IF 0 != fannedOutDataConns»scm_astFannedOutDataConnections«ELSE»nullptr«ENDIF», |
| «numCompFBParams», «IF 0 != numCompFBParams»scm_astParamters«ELSE»nullptr«ENDIF» |
| }; |
| |
| ''' |
| |
| |
| def protected generateConnectionPortID(IInterfaceElement iface, FBNetworkElement elem) { |
| return if(type.FBNetwork.networkElements.contains(elem)) |
| '''GENERATE_CONNECTION_PORT_ID_2_ARG(«elem.name.FORTEString», «iface.name.FORTEString»), «elem.fbId»''' |
| else |
| '''GENERATE_CONNECTION_PORT_ID_1_ARG(«iface.name.FORTEString»), -1''' |
| } |
| |
| def protected dispatch fbId(FBNetworkElement elem) |
| '''«fbs.indexOf(elem)»''' |
| |
| def protected dispatch fbId(AdapterFB elem) |
| '''CCompositeFB::scm_nAdapterMarker | «IF elem.isPlug»«getPlugIndex(elem)»«ELSE»«type.interfaceList.sockets.indexOf(elem.adapterDecl)»«ENDIF»''' |
| |
| def protected getPlugIndex(AdapterFB elem) { |
| type.interfaceList.sockets.size + type.interfaceList.plugs.indexOf(elem.adapterDecl) |
| } |
| |
| def protected exportEventConns(EList<EventConnection> eConns) { |
| var retVal = new StringBuilder() |
| var conSet = new HashSet() |
| var fannedOutConns = new StringBuilder() |
| |
| retVal.append("const SCFB_FBConnectionData " + FBClassName + "::scm_astEventConnections[] = {\n") |
| |
| for (Connection eConn : eConns) { |
| if (!conSet.contains(eConn)) { |
| conSet.add(eConn) |
| |
| retVal.append(eConn.getConnListEntry) |
| |
| if (eConn.source.getOutputConnections.size > 1) { |
| // we have fan out |
| for (Connection fannedConn : eConn.source.getOutputConnections().filter[!(it == eConn)]) { |
| conSet.add(fannedConn) |
| fannedOutConns.append(fannedConn.genFannedOutConnString(eConnNumber)) |
| fannedOutEventConns++ |
| } |
| } |
| eConnNumber++; |
| } |
| } |
| |
| retVal.append("};\n") |
| |
| retVal.append("\nconst SCFB_FBFannedOutConnectionData " + FBClassName + "::scm_astFannedOutEventConnections[] = {\n") |
| if (0 != fannedOutEventConns) { |
| retVal.append(fannedOutConns) |
| } |
| retVal.append("};\n"); //$NON-NLS-1$ |
| } |
| |
| def protected exportDataConns(EList<DataConnection> dataConns) { |
| var retVal = new StringBuilder() |
| var conSet = new HashSet() |
| var fannedOutConns = new StringBuilder() |
| |
| retVal.append("const SCFB_FBConnectionData " + FBClassName + "::scm_astDataConnections[] = {\n") |
| |
| for (DataConnection dConn : dataConns) { |
| if (!conSet.contains(dConn)) { |
| val primConn = getPrimaryDataConn(dConn) |
| conSet.add(primConn); |
| |
| retVal.append(primConn.getConnListEntry) |
| |
| if (primConn.source.getOutputConnections.size > 1 ){ |
| // we have fan out |
| for (Connection fannedConn : primConn.source.getOutputConnections().filter[!(it == primConn)]) { |
| conSet.add(fannedConn) |
| if (fannedConn.hasCFBInterfaceDestination && primConn.hasCFBInterfaceDestination){ |
| fannedOutConns.append("#error a fanout to several composite FB's outputs is currently not supported: "); //$NON-NLS-1$ |
| errors.add(" - " + name + " FORTE does currently not allow that a data a composite's data connection may be connected to several data outputs of the composite FB."); //$NON-NLS-1$ |
| } |
| fannedOutConns.append(fannedConn.genFannedOutConnString(dataConnNumber)) |
| fannedOutDataConns++ |
| } |
| } |
| dataConnNumber++; |
| } |
| } |
| |
| retVal.append("};\n") |
| |
| retVal.append("\nconst SCFB_FBFannedOutConnectionData " + FBClassName + "::scm_astFannedOutDataConnections[] = {\n") |
| if (0 != fannedOutDataConns) { |
| retVal.append(fannedOutConns) |
| } |
| retVal.append("};\n"); //$NON-NLS-1$ |
| } |
| |
| def protected getConnListEntry(Connection con) |
| ''' {«con.source.generateConnectionPortID(con.sourceElement)», «con.destination.generateConnectionPortID(con.destinationElement)»}, |
| ''' |
| |
| def protected genFannedOutConnString(Connection con, int connNum) { |
| ''' {«connNum», «con.destination.generateConnectionPortID(con.destinationElement)»}, |
| ''' |
| } |
| |
| def private getPrimaryDataConn(DataConnection dataConn) { |
| //if from the source one connection is target to the interface of the CFB we have to take this first |
| for (Connection dc : dataConn.getSource().getOutputConnections()) { |
| if (dc.hasCFBInterfaceDestination) { |
| return dc |
| } |
| } |
| return dataConn |
| } |
| |
| def private hasCFBInterfaceDestination(Connection conn){ |
| conn?.getDestination()?.eContainer()?.eContainer() instanceof CompositeFBType |
| } |
| |
| def protected exportFBParams(EList<FBNetworkElement> fbs) { |
| var retVal = new StringBuilder() |
| |
| for (FBNetworkElement fb : fbs) { |
| for (VarDeclaration v : fb.getInterface.getInputVars.filter[it.value !== null && !it.value.value.isEmpty]) { |
| retVal.append(''' {«fb.fbId», g_nStringId«v.name», "«getParamValue(v)»"}, |
| ''') |
| numCompFBParams++ |
| } |
| } |
| |
| ''' |
| const SCFB_FBParameter «FBClassName»::scm_astParamters[] = { |
| «IF 0 != numCompFBParams»«retVal.toString»«ENDIF» |
| };''' |
| } |
| |
| def private getParamValue(VarDeclaration v) { |
| v.value.value.replace("\"", "\\\""); |
| } |
| |
| } |