blob: 7fe23891780a79fb07e2b4e06c1af2297e24830e [file] [log] [blame]
/*******************************************************************************
* 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("\"", "\\\"");
}
}