diff --git a/code/extensions/build.gradle.kts b/code/extensions/build.gradle.kts new file mode 100644 index 000000000..d96e6f512 --- /dev/null +++ b/code/extensions/build.gradle.kts @@ -0,0 +1,40 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile + +plugins { + mps + kotlin +} + +dependencies { + compileOnly(mpsDistribution()) + compileOnly(project(":code:library")) + compileOnly(project(":code:language")) + + mpsImplementation(project(":code:library", "mps")) + mpsImplementation(project(":code:language", "mps")) + + testImplementation(mpsDistribution()) + testImplementation(project(":code:library")) + testImplementation(project(":code:language")) + testImplementation(project(":code:platform")) +} + +mps { + moduleName.set("org.fbme.platform.lib") +} + +val compileKotlin by tasks.getting(KotlinCompile::class) { + kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=all") +} + +val test by tasks.getting(Test::class) { + dependsOn( + ":code:library:buildDistPlugin", + ":code:platform:buildDistPlugin", + "buildDistPlugin" + ) +} + +val copyLibs by tasks.getting(Copy::class) { + dependsOn(":code:language:jar") +} \ No newline at end of file diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealApi.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealApi.kt new file mode 100644 index 000000000..a5f1d7374 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealApi.kt @@ -0,0 +1,38 @@ +package org.fbme.extensions.adapter + +import org.fbme.lib.iec61499.declarations.SystemDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.jetbrains.mps.openapi.model.SModel + +interface AdapterRevealApi { + /** + * Reveals usages of the provided extended adapter in the provided model. + * Generates new nodes in the same model and deletes all the extended adapters from the model. + * + * @param removeAdapter If true removes provided extendedAdapter after reveal + */ + fun revealAdapter( + extendedAdapter: ExtendedAdapterTypeDeclaration, + model: SModel, + removeAdapter: Boolean = true, + ): RevealDeclarationsResult + + /** + * Reveals inplace all extended adapters that are declared in the model. + * Generates new nodes in the same model and removes all extended adapters from the model. + */ + fun revealModel(model: SModel) + + /** + * Synchronize system resources by revealing all "broken connections" from each application halfway in each resource. + * At the end, a block of connections is added that adapts the adapter for communication using the PUBLISH/SUBSCRIBE. + * If a port already has any connections in the resource it's connections will no be revealed. + * + * @param systemDeclaration Declaration to sync + * @param model Model to generate new nodes into + */ + fun syncApplicationResources( + systemDeclaration: SystemDeclaration, + model: SModel, + ) +} \ No newline at end of file diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealService.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealService.kt new file mode 100644 index 000000000..6e6069e7c --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterRevealService.kt @@ -0,0 +1,215 @@ +package org.fbme.extensions.adapter + +import org.fbme.extensions.utils.IEC61499FactoryUtils +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepository +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.Identifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.DeclarationWithNetwork +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.fbme.lib.iec61499.declarations.SystemDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.fbme.lib.iec61499.declarations.hierarchies.ResourceFunctionBlockHierarchy +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.fbnetwork.EntryKind +import org.fbme.lib.iec61499.fbnetwork.FBNetwork +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase +import org.fbme.lib.st.STFactory +import org.jetbrains.mps.openapi.model.SModel +import org.jetbrains.mps.openapi.model.SNode + +class AdapterRevealService( + private val owner: PlatformRepository, + publishSubscribeProvider: ((name: String) -> FBTypeDeclaration)? = null, +): AdapterRevealApi { + private val extendedAdapterUtils: ExtendedAdapterUtils + private val factoryUtils: IEC61499FactoryUtils + + init { + val stFactory: STFactory = owner.stFactory + val factory: IEC61499Factory = owner.iec61499Factory + extendedAdapterUtils = ExtendedAdapterUtils(factory, stFactory, owner, publishSubscribeProvider) + factoryUtils = IEC61499FactoryUtils(factory) + } + + + override fun revealAdapter( + extendedAdapter: ExtendedAdapterTypeDeclaration, + model: SModel, + removeAdapter: Boolean, + ): RevealDeclarationsResult { + val revealDeclarations = extendedAdapterUtils.createDeclarations(extendedAdapter, model) + val declarationsResults = listOf(revealDeclarations) + val identifiersToRevealResult = + declarationsResults.associateBy { it.extendedAdapter.identifier } + + revealAdapters( + model = model, + identifiersToRevealResult = identifiersToRevealResult, + ) + if (removeAdapter) { + removeExtendedAdapters(declarationsResults, model) + } + return revealDeclarations + } + + private fun removeExtendedAdapters( + declarationsResults: Collection, + currentModel: SModel + ) { + for (revealResult in declarationsResults) { + val node = (revealResult.extendedAdapter as? PlatformElement)?.node + if (node != null) { + currentModel.removeRootNode(node) + } + } + } + + fun revealAdapterWithNetBlocks( + revealResult: RevealDeclarationsResult, + block: FunctionBlockDeclaration, + port: FBPortDescriptor, + count: Int, + model: SModel, + ) = extendedAdapterUtils.revealAdapterWithNetBlocks(revealResult, block, port, count, model) + + override fun revealModel(model: SModel) { + val identifiersToRevealResult = hashMapOf() + val rootNodes = model.rootNodes.toList() + for (node in rootNodes) { + val adapter = owner.adapterOrNull(node) + if (adapter != null) { + identifiersToRevealResult[adapter.identifier] = extendedAdapterUtils.createDeclarations(adapter, model) + } + } + revealAdapters( + model = model, + identifiersToRevealResult = identifiersToRevealResult + ) + removeExtendedAdapters(identifiersToRevealResult.values, model) + } + + private fun revealAdapters( + model: SModel, + identifiersToRevealResult: Map + ) { + val rootNodes = model.rootNodes.toList() + for (node in rootNodes) { + val fbTypeDeclaration = owner.adapterOrNull(node) ?: continue + extendedAdapterUtils.changeBlockPorts(fbTypeDeclaration, identifiersToRevealResult) + } + for (node in rootNodes) { + val networks = getNetworks(node) ?: continue + for (network in networks) { + val sourceIdentifiersToRevealResult = + identifiersToRevealResult.mapKeys { it.value.getFarLeftAdapter().identifier } + extendedAdapterUtils.revealExtendedAdaptersInNetwork( + network = network, + identifiersToRevealResult = sourceIdentifiersToRevealResult, + model = model, + withPublishSubscribe = false, + ) + } + } + } + + private fun getNetworks(node: SNode): List? = + when (val declaration = owner.adapterOrNull(node)) { + is DeclarationWithNetwork -> listOf(declaration.network) + is ExtendedAdapterTypeDeclaration -> + listOfNotNull(declaration.leftNetwork?.network, declaration.rightNetwork?.network) + is SystemDeclaration -> declaration.applications.map { it.network } + + declaration.devices.flatMap { device -> device.resources.map { it.network } } + else -> null + } + + override fun syncApplicationResources( + systemDeclaration: SystemDeclaration, + model: SModel, + ) { + val applicationBlockToMapping: Map = + systemDeclaration.mappings.asSequence() + .mapNotNull { mapping -> + val functionBlock = mapping.applicationFBReference.getTarget()?.functionBlock + val resource = mapping.resourceFBReference.getTarget() + if (functionBlock != null && resource != null) { + functionBlock to resource + } else { + null + } + } + .associate { it } + val revealDeclarationsResults = mutableMapOf() + for (application in systemDeclaration.applications) { + val adapterConnections = application.network.adapterConnections.asSequence() + .filter { ExtendedAdapterUtils.isExtendedAdapterConnection(it) } + .mapNotNull { connection -> (connection.sourceReference.getTarget())?.let { it to connection } } + .groupBy({ it.first }, { it.second }) + for ((plug, connections) in adapterConnections) { + val adapterType = ExtendedAdapterUtils.getPlugExtendedAdapterType(plug.portTarget) ?: continue + val sourceResource = applicationBlockToMapping[plug.functionBlock] ?: continue + val sourceBlockInResource = sourceResource.functionBlock ?: continue + val plugPort = sourceBlockInResource.type.plugPorts.first { it.name == plug.portTarget.name } + val sourceResourceNetwork = sourceResource.resourceHierarchy.resource.network + val needReveal = sourceResourceNetwork.adapterConnections.none { + it.sourceReference.getTarget()?.functionBlock == sourceBlockInResource && + it.sourceReference.getTarget()?.portTarget == plugPort.declaration + } && connections.any { connection -> + val socket = connection.targetReference.getTarget() + sourceResource != applicationBlockToMapping[socket?.functionBlock] + } + if (needReveal) { + val revealDeclarationsResult = revealDeclarationsResults.computeIfAbsent(adapterType.name) { + extendedAdapterUtils.createDeclarations(adapterType, model) + } + extendedAdapterUtils.revealAdapterWithNetBlocks( + revealResult = revealDeclarationsResult, + block = sourceBlockInResource, + port = plugPort, + count = connections.size, + model = model, + ) + } + for (connection in connections) { + val socket = connection.targetReference.getTarget() ?: continue + val targetResource = applicationBlockToMapping[socket.functionBlock] ?: continue + val targetBlockInResource = targetResource.functionBlock ?: continue + val socketPort = targetBlockInResource.type.socketPorts.first { it.name == socket.portTarget.name } + val targetResourceNetwork = targetResource.resourceHierarchy.resource.network + val connectionExists = targetResourceNetwork.adapterConnections.any { + it.targetReference.getTarget()?.functionBlock == targetBlockInResource && + it.targetReference.getTarget()?.portTarget == socketPort.declaration + } + if (!connectionExists) { + if (sourceResource == targetResource) { + targetResourceNetwork.adapterConnections += factoryUtils.createConnection( + source = sourceBlockInResource.getPort(plugPort), + target = targetBlockInResource.getPort(socketPort), + entryKind = EntryKind.ADAPTER, + ) + continue + } + val revealDeclarationsResult = revealDeclarationsResults.computeIfAbsent(adapterType.name) { + extendedAdapterUtils.createDeclarations(adapterType, model) + } + extendedAdapterUtils.revealAdapterWithNetBlocks( + revealResult = revealDeclarationsResult, + block = targetBlockInResource, + port = socketPort, + count = connections.size, + model = model, + ) + } + } + + } + } + } + + fun revealDeclarations( + extendedAdapter: ExtendedAdapterTypeDeclaration, + model: SModel, + ): RevealDeclarationsResult = extendedAdapterUtils.createDeclarations(extendedAdapter, model) +} diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterSwitchGenerator.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterSwitchGenerator.kt new file mode 100644 index 000000000..c477ae6c4 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/AdapterSwitchGenerator.kt @@ -0,0 +1,288 @@ +package org.fbme.extensions.adapter + +import org.fbme.extensions.utils.IEC61499FactoryUtils +import org.fbme.extensions.utils.SModelUtils +import org.fbme.extensions.utils.STFactoryUtils +import org.fbme.ide.iec61499.repository.PlatformRepository +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.ecc.StateAction +import org.fbme.lib.iec61499.ecc.StateDeclaration +import org.fbme.lib.iec61499.fbnetwork.FBNetwork +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclaration +import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase +import org.fbme.lib.st.STFactory +import org.fbme.lib.st.expressions.VariableDeclaration +import org.jetbrains.mps.openapi.model.SModel + +class AdapterSwitchGenerator( + private val factory: IEC61499Factory, + owner: PlatformRepository, + stFactory: STFactory, +) { + private val factoryUtils: IEC61499FactoryUtils = IEC61499FactoryUtils(factory) + private val stFactoryUtils: STFactoryUtils = STFactoryUtils(stFactory) + private val sModelUtils: SModelUtils = SModelUtils(owner) + + fun generateRouter( + name: String, + model: SModel, + source: AdapterTypeDeclaration, + outputsCount: Int, + outputRouterName: String, + target: AdapterTypeDeclaration? = null, + inputRouterName: String? = null, + virtualPackage: String? = null, + ): CompositeFBTypeDeclaration { + val routerDeclaration = factory.createCompositeFBTypeDeclaration( + StringIdentifier("${name}_router") + ) + sModelUtils.addDeclarationToModel(routerDeclaration, model, virtualPackage) + + val socket = factory.createSocketDeclaration(StringIdentifier("socket")) + socket.typeReference.setTarget(source) + routerDeclaration.sockets += socket + + for (i in 0 until outputsCount) { + val plug = factory.createPlugDeclaration(StringIdentifier("plug_$i")) + plug.typeReference.setTarget(target ?: source) + routerDeclaration.plugs += plug + } + addSocketToPlugsSwitch( + adapterName = "${name}_leftSwitch", + model = model, + network = routerDeclaration.network, + source = socket, + targets = routerDeclaration.plugs, + routerName = outputRouterName, + virtualPackage = virtualPackage, + ) + addPlugsToSocketSwitch( + adapterName = "${name}_rightSwitch", + model = model, + network = routerDeclaration.network, + sources = routerDeclaration.plugs, + target = socket, + routerName = inputRouterName, + virtualPackage = virtualPackage, + ) + return routerDeclaration + } + + private fun addSocketToPlugsSwitch( + adapterName: String, + model: SModel, + network: FBNetwork, + source: FunctionBlockDeclarationBase, + targets: List, + routerName: String, + virtualPackage: String? = null, + ): FunctionBlockDeclaration { + val switchFBIdentifier = StringIdentifier(adapterName) + val switchDeclaration = factory.createBasicFBTypeDeclaration(switchFBIdentifier) + sModelUtils.addDeclarationToModel(switchDeclaration, model, virtualPackage) + val switchBlock = factoryUtils.addFunctionalBlock(switchDeclaration, network) + val inputParameters = factoryUtils.copyParametersAndConnect( + destination = switchDeclaration.inputParameters, + destinationBlock = switchBlock, + source = source.type.dataOutputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = source, + network = network, + ).map { it.second } + val routerParameterDeclaration = inputParameters.first { it.name == routerName } + val inputEvents = factoryUtils.copyEventsAndConnect( + destination = switchDeclaration.inputEvents, + destinationBlock = switchBlock, + sources = source.type.eventOutputPorts.map { it.declaration as EventDeclaration }, + sourceBlock = source, + network = network, + keepAssociations = true, + ).onEach { (_, event) -> + for (association in event.associations) { + val name = association.parameterReference.getTarget()?.name + if (name != null) { + association.parameterReference.setTargetName(name) + } + } + }.associateBy { it.second.name } + val startState = factory.createStateDeclaration(StringIdentifier("Start")) + switchDeclaration.ecc.states += startState + for ((i, plug) in targets.withIndex()) { + val parametersAndCopies = factoryUtils.copyParametersAndConnect( + destination = switchDeclaration.outputParameters, + destinationBlock = switchBlock, + source = plug.type.dataInputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = plug, + network = network, + outputToInput = false, + ) + parametersAndCopies.forEach { it.second.name += "_$i" } + factoryUtils.copyEventsAndConnect( + destination = switchDeclaration.outputEvents, + destinationBlock = switchBlock, + sources = plug.type.eventInputPorts.map { it.declaration as EventDeclaration }, + sourceBlock = plug, + network = network, + outputToInput = false, + keepAssociations = true, + ).forEach { (sourceEvent, createdEvent) -> + createdEvent.name += "_$i" + for (association in createdEvent.associations) { + val oldName = association.parameterReference.getTarget()?.name + if (oldName != null) { + association.parameterReference.setTargetName(oldName + "_$i") + } + } + addState( + switchDeclaration = switchDeclaration, + start = startState, + name = createdEvent.name, + inputEventDeclaration = checkNotNull(inputEvents[sourceEvent.name]?.second), + outputEventDeclaration = createdEvent, + assignableToVariableParameters = inputParameters.zip(parametersAndCopies.map { it.second }), + number = i, + outputRouteVariable = routerParameterDeclaration, + inputRouteVariable = null, + ) + } + } + return switchBlock + } + + private fun addPlugsToSocketSwitch( + adapterName: String, + model: SModel, + network: FBNetwork, + sources: List, + target: FunctionBlockDeclarationBase, + routerName: String?, + virtualPackage: String? = null, + ): FunctionBlockDeclaration { + val switchFBIdentifier = StringIdentifier(adapterName) + val switchDeclaration = factory.createBasicFBTypeDeclaration(switchFBIdentifier) + sModelUtils.addDeclarationToModel(switchDeclaration, model, virtualPackage) + val switchBlock = factoryUtils.addFunctionalBlock(switchDeclaration, network) + val outputParameters = factoryUtils.copyParametersAndConnect( + destination = switchDeclaration.outputParameters, + destinationBlock = switchBlock, + source = target.type.dataInputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = target, + network = network, + outputToInput = false, + ).map { it.second } + val outputEvents = factoryUtils.copyEventsAndConnect( + destination = switchDeclaration.outputEvents, + destinationBlock = switchBlock, + sources = target.type.eventInputPorts.map { it.declaration as EventDeclaration }, + sourceBlock = target, + network = network, + outputToInput = false, + keepAssociations = true, + ).onEach { (_, event) -> + for (association in event.associations) { + val name = association.parameterReference.getTarget()?.name + if (name != null) { + association.parameterReference.setTargetName(name) + } + } + }.associateBy { it.second.name } + val routerParameterDeclaration = routerName?.let { router -> + outputParameters.first { it.name == router } + } + val startState = factory.createStateDeclaration(StringIdentifier("Start")) + switchDeclaration.ecc.states += startState + for ((i, plug) in sources.withIndex()) { + val parametersAndCopies = factoryUtils.copyParametersAndConnect( + destination = switchDeclaration.inputParameters, + destinationBlock = switchBlock, + source = plug.type.dataOutputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = plug, + network = network, + ) + parametersAndCopies.forEach { it.second.name += "_$i" } + factoryUtils.copyEventsAndConnect( + destination = switchDeclaration.inputEvents, + destinationBlock = switchBlock, + sources = plug.type.eventOutputPorts.map { it.declaration as EventDeclaration }, + sourceBlock = plug, + network = network, + keepAssociations = true, + ).forEach { (sourceEvent, createdEvent) -> + createdEvent.name += "_$i" + for (association in createdEvent.associations) { + val oldName = association.parameterReference.getTarget()?.name + if (oldName != null) { + association.parameterReference.setTargetName(oldName + "_$i") + } + } + addState( + switchDeclaration = switchDeclaration, + start = startState, + name = createdEvent.name, + inputEventDeclaration = createdEvent, + outputEventDeclaration = checkNotNull(outputEvents[sourceEvent.name]?.second), + assignableToVariableParameters = parametersAndCopies.map { it.second }.zip(outputParameters), + number = i, + outputRouteVariable = null, + inputRouteVariable = routerParameterDeclaration, + ) + } + } + return switchBlock + } + + private fun addState( + switchDeclaration: BasicFBTypeDeclaration, + start: StateDeclaration, + name: String, + inputEventDeclaration: EventDeclaration, + outputEventDeclaration: EventDeclaration, + assignableToVariableParameters: List>, + number: Int, + outputRouteVariable: VariableDeclaration?, + inputRouteVariable: VariableDeclaration?, + ): StateAction { + val state = factory.createStateDeclaration( + StringIdentifier(name + "_state") + ) + switchDeclaration.ecc.states += state + val backTransition = factory.createStateTransition() + switchDeclaration.ecc.transitions += backTransition + backTransition.sourceReference.setTarget(state) + backTransition.targetReference.setTarget(start) + val toNewStateTransition = factory.createStateTransition() + toNewStateTransition.sourceReference.setTarget(start) + toNewStateTransition.targetReference.setTarget(state) + toNewStateTransition.condition.eventReference.setFQName(inputEventDeclaration.name) + if (outputRouteVariable != null) { + toNewStateTransition.condition.setGuardCondition( + stFactoryUtils.intEquality(outputRouteVariable, number) + ) + } + switchDeclaration.ecc.transitions += toNewStateTransition + + val stateAction = factory.createStateAction() + + val algorithmDeclaration = factory.createAlgorithmDeclaration( + StringIdentifier(name + "_algorithm") + ) + val algorithmBody = factory.createAlgorithmBody(AlgorithmLanguage.ST) + for ((assignable, variable) in assignableToVariableParameters) { + algorithmBody.statements += stFactoryUtils.createAssign(variable, stFactoryUtils.createVariable(assignable)) + } + if (inputRouteVariable != null) { + algorithmBody.statements += stFactoryUtils.createAssign( + variable = inputRouteVariable, + assignable = stFactoryUtils.createIntLiteral(number), + ) + } + algorithmDeclaration.body = algorithmBody + stateAction.algorithm.setTarget(algorithmDeclaration) + stateAction.event.setFQName(outputEventDeclaration.name) + + state.actions += stateAction + switchDeclaration.algorithms += algorithmDeclaration + return stateAction + } +} diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/ExtendedAdapterUtils.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/ExtendedAdapterUtils.kt new file mode 100644 index 000000000..c3049b7c1 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/ExtendedAdapterUtils.kt @@ -0,0 +1,915 @@ +package org.fbme.extensions.adapter + +import org.fbme.extensions.utils.FBInterfaceDeclarationUtils +import org.fbme.extensions.utils.IEC61499FactoryUtils +import org.fbme.extensions.utils.SModelUtils +import org.fbme.extensions.utils.STFactoryUtils +import org.fbme.ide.iec61499.repository.PlatformRepository +import org.fbme.lib.common.Declaration +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.fbme.lib.iec61499.descriptors.FBPortDescriptor +import org.fbme.lib.iec61499.fbnetwork.* +import org.fbme.lib.st.STFactory +import org.fbme.lib.st.types.ElementaryType +import org.jetbrains.mps.openapi.model.SModel + +class ExtendedAdapterUtils( + private val factory: IEC61499Factory, + stFactory: STFactory, + owner: PlatformRepository, + private val publishSubscribeProvider: ((name: String) -> FBTypeDeclaration)? = null, +) { + private val sModelUtils: SModelUtils = SModelUtils(owner) + private val fbInterfaceDeclarationUtils = FBInterfaceDeclarationUtils(factory) + private val factoryUtils: IEC61499FactoryUtils = IEC61499FactoryUtils(factory) + private val stFactoryUtils: STFactoryUtils = STFactoryUtils(stFactory) + private val switchGenerator = AdapterSwitchGenerator(factory, owner, stFactory) + private val numberToEventFbTypes: MutableMap = mutableMapOf() + private val eventToNumberFbTypes: MutableMap = mutableMapOf() + private fun getPackageName(name: String) = "generated/$name" + + companion object { + + fun isExtendedAdapterConnection(connection: FBNetworkConnection) = + getSourceExtendedAdapterType(connection) != null && + getTargetSocketAdapterDeclaration(connection) is ExtendedAdapterTypeDeclaration + + fun getSourceExtendedAdapterType(connection: FBNetworkConnection) = + getSourcePlugAdapterDeclaration(connection) as? ExtendedAdapterTypeDeclaration + + fun getPlugExtendedAdapterType(declaration: Declaration?) = + getPlugAdapterDeclaration(declaration) as? ExtendedAdapterTypeDeclaration + + fun getSourcePlugAdapterDeclaration(connection: FBNetworkConnection) = + getPlugAdapterDeclaration(connection.sourceReference.getTarget()?.portTarget) + + fun getTargetSocketAdapterDeclaration(connection: FBNetworkConnection) = + getSocketAdapterDeclaration(connection.targetReference.getTarget()?.portTarget) + + fun getSocketAdapterDeclaration(declaration: Declaration?) = + (declaration as? SocketDeclaration)?.typeReference?.getTarget() + + fun getPlugAdapterDeclaration(declaration: Declaration?) = + (declaration as? PlugDeclaration)?.typeReference?.getTarget() + } + + fun createDeclarations( + extendedAdapter: ExtendedAdapterTypeDeclaration, + model: SModel, + ): RevealDeclarationsResult { + val name = extendedAdapter.name + val routerAdapter = if (extendedAdapter.outputRouter != null) { + val routerName = "RouterAdapter_$name" + findDeclarationOrCreate( + name = routerName, + model = model, + virtualPackage = getPackageName(extendedAdapter.name), + ) { + val adapter = fbInterfaceDeclarationUtils.generateAdapterFromDescriptor( + name = routerName, + fbTypeDescriptor = extendedAdapter.plugTypeDescriptor, + reversed = true, + ) + // create associations with router parameters + for (event in adapter.outputEvents) { + event.associations += factoryUtils.createAssociation(adapter.outputParameters.last()) + } + if (extendedAdapter.inputRouter != null) { + for (event in adapter.inputEvents) { + event.associations += factoryUtils.createAssociation(adapter.inputParameters.last()) + } + } + adapter + } + } else { + null + } + val leftNetwork = extendedAdapter.leftNetwork + val leftAdapterName = "Left_$name" + val leftAdapter = findDeclarationOrCreate( + name = leftAdapterName, + model = model, + virtualPackage = getPackageName(extendedAdapter.name), + ) { + fbInterfaceDeclarationUtils.generateAdapterFromDescriptor( + name = leftAdapterName, + fbTypeDescriptor = if (leftNetwork != null) { + leftNetwork.getCustomNetworkComponents()[1].block.type + } else { + extendedAdapter.plugTypeDescriptor + }, + reversed = false, + ) + } + val middleAdapter = if (leftNetwork == null || + (extendedAdapter.internalFbSocketInterface?.isEmpty() != false && + extendedAdapter.internalNetworksInterface?.isEmpty() != false) + ) { + leftAdapter + } else { + val middleAdapterName = "Middle_$name" + findDeclarationOrCreate( + name = middleAdapterName, + model = model, + virtualPackage = getPackageName(extendedAdapter.name), + ) { + fbInterfaceDeclarationUtils.generateAdapterFromDescriptor( + name = middleAdapterName, + identifier = extendedAdapter.identifier, + fbTypeDescriptor = leftNetwork.getCustomNetworkComponents()[0].block.type, + reversed = true, + ) + } + } + val rightAdapter = if ( + extendedAdapter.rightNetwork == null || + (extendedAdapter.internalFbPlugInterface?.isEmpty() != false && + extendedAdapter.internalNetworksInterface?.isEmpty() != false) + ) { + middleAdapter + } else { + val rightAdapterName = "Right_$name" + findDeclarationOrCreate( + name = rightAdapterName, + model = model, + virtualPackage = getPackageName(extendedAdapter.name), + ) { + fbInterfaceDeclarationUtils.generateAdapterFromDescriptor( + name = rightAdapterName, + fbTypeDescriptor = extendedAdapter.socketTypeDescriptor, + ) + } + } + + val leftBlock = leftNetwork?.let { adapterNetworkDeclaration -> + val leftBlockName = "${extendedAdapter.name}_${adapterNetworkDeclaration.name}" + val existedBlock: CompositeFBTypeDeclaration? = sModelUtils.findOneDeclarationOrNull(leftBlockName, model) + if (existedBlock != null) { + existedBlock + } else { + val compositeFB = createCompositeFB( + name = leftBlockName, + leftAdapter = leftAdapter, + rightAdapter = middleAdapter, + network = adapterNetworkDeclaration.network, + ) + sModelUtils.addDeclarationToModel(compositeFB, model, getPackageName(extendedAdapter.name)) + updateInternalAdapterPorts(compositeFB) + compositeFB + } + } + val rightBlock = extendedAdapter.rightNetwork?.let { adapterNetworkDeclaration -> + val rightBlockName = "${extendedAdapter.name}_${adapterNetworkDeclaration.name}" + val existedBlock: CompositeFBTypeDeclaration? = sModelUtils.findOneDeclarationOrNull(rightBlockName, model) + if (existedBlock != null) { + existedBlock + } else { + val compositeFB = createCompositeFB( + name = rightBlockName, + leftAdapter = middleAdapter, + rightAdapter = rightAdapter, + network = adapterNetworkDeclaration.network, + ) + sModelUtils.addDeclarationToModel(compositeFB, model, getPackageName(extendedAdapter.name)) + updateInternalAdapterPorts(compositeFB) + compositeFB + } + } + + return RevealDeclarationsResult( + extendedAdapter = extendedAdapter, + routerAdapter = routerAdapter, + leftAdapter = leftAdapter, + middleAdapter = middleAdapter, + rightAdapter = rightAdapter, + leftBlockDeclaration = leftBlock, + rightBlockDeclaration = rightBlock, + routers = mutableMapOf(), + ) + } + + private data class ConnectionInfo( + val connection: FBNetworkConnection, + val source: Boolean, + val portPath: PortPath<*>, + ) { + val portName: String get() = portPath.portTarget.name + } + + fun changeBlockPorts( + fbTypeDeclaration: FBTypeDeclaration, + identifiersToRevealResult: Map + ) { + val socketsToChange = fbTypeDeclaration.sockets.filter { socket -> + identifiersToRevealResult[socket.typeReference.getTarget()?.identifier] != null + } + val plugsToChange = fbTypeDeclaration.plugs.filter { plug -> + identifiersToRevealResult[plug.typeReference.getTarget()?.identifier] != null + } + when (fbTypeDeclaration) { + is CompositeFBTypeDeclaration -> { + val network = fbTypeDeclaration.network + val networkConnections = network.eventConnections.asSequence() + .plus(network.dataConnections) + .plus(network.adapterConnections) + .toList() + + val blockToConnections = networkConnections.asSequence() + .flatMap { connection -> + val targetPortPath = connection.targetReference.getTarget() + val target = targetPortPath?.functionBlock + ?.let { it.identifier to ConnectionInfo(connection, false, targetPortPath) } + val sourcePortPath = connection.sourceReference.getTarget() + val source = sourcePortPath?.functionBlock + ?.let { it.identifier to ConnectionInfo(connection, true, sourcePortPath) } + listOfNotNull(target, source) + } + .groupBy({ it.first }, { it.second }) + for (socket in socketsToChange) { + val connectionsToSourcePort = blockToConnections[socket.identifier] ?: continue + val result = identifiersToRevealResult[socket.typeReference.getTarget()?.identifier] ?: continue + changePorts(connectionsToSourcePort, socket) + socket.typeReference.setTarget(result.getFarRightAdapter()) + } + for (plug in plugsToChange) { + val connectionsToTargetPort = blockToConnections[plug.identifier] ?: continue + val result = identifiersToRevealResult[plug.typeReference.getTarget()?.identifier] ?: continue + changePorts(connectionsToTargetPort, plug) + plug.typeReference.setTarget(result.getFarLeftAdapter()) + } + } + + is BasicFBTypeDeclaration -> { + for (socket in socketsToChange) { + val result = identifiersToRevealResult[socket.typeReference.getTarget()?.identifier] ?: continue + socket.typeReference.setTarget(result.getFarRightAdapter()) + } + for (plug in plugsToChange) { + val result = identifiersToRevealResult[plug.typeReference.getTarget()?.identifier] ?: continue + plug.typeReference.setTarget(result.getFarLeftAdapter()) + } + } + + is ServiceInterfaceFBTypeDeclaration -> error("Extended adapters cannot be used in service interface block") + } + } + + private fun changePorts( + connectionInfos: List, + block: FunctionBlockDeclarationBase, + ) { + for (connectionInfo in connectionInfos) { + if (connectionInfo.source) { + val ports = when (connectionInfo.connection.kind) { + EntryKind.EVENT -> block.type.eventOutputPorts + EntryKind.DATA -> block.type.dataOutputPorts + EntryKind.ADAPTER -> block.type.plugPorts + } + connectionInfo.connection.sourceReference.setTarget( + block.getPort(ports.first { it.name == connectionInfo.portName }), + ) + } else { + val ports = when (connectionInfo.connection.kind) { + EntryKind.EVENT -> block.type.eventInputPorts + EntryKind.DATA -> block.type.dataInputPorts + EntryKind.ADAPTER -> block.type.socketPorts + } + connectionInfo.connection.targetReference.setTarget( + block.getPort(ports.first { it.name == connectionInfo.portName }), + ) + } + } + } + + fun revealAdapterWithNetBlocks( + revealResult: RevealDeclarationsResult, + block: FunctionBlockDeclaration, + port: FBPortDescriptor, + count: Int, + model: SModel, + ) = if (port.isInput) { + val network = checkNotNull(block.container) + revealRightPart( + revealResult = revealResult, + leftPort = createRightPublishSubscribeAdapter( + revealResult = revealResult, + network = network, + model = model, + ), + rightPort = block.getPort(port), + network = network, + ) + } else { + val network = checkNotNull(block.container) + val portPaths = revealLeftPart( + revealResult = revealResult, + sourcePort = block.getPort(port), + network = network, + model = model, + connectionsCount = count, + ) + for (connectionSourcePort in portPaths) { + val publishSubscribeAdapter = createLeftPublishSubscribeAdapter( + revealResult = revealResult, + network = network, + model = model, + ) + + network.adapterConnections += factoryUtils.createConnection( + source = connectionSourcePort, + target = publishSubscribeAdapter.getPort( + publishSubscribeAdapter.type.socketPorts.first() + ), + entryKind = EntryKind.ADAPTER, + ) + } + } + + fun revealExtendedAdaptersInNetwork( + network: FBNetwork, + identifiersToRevealResult: Map, + model: SModel, + withPublishSubscribe: Boolean, + ) { + val adapterConnections = network.adapterConnections.asSequence() + .filter { getSourcePlugAdapterDeclaration(it)?.identifier in identifiersToRevealResult } + .mapNotNull { connection -> (connection.sourceReference.getTarget())?.let { it to connection } } + .groupBy({ it.first }, { it.second }) + val connectionsToRemove = network.adapterConnections.asSequence() + .filter { it.sourceReference.getTarget() in adapterConnections } + .toSet() + + for ((sourcePort, connections) in adapterConnections) { + // plugBlock -> router -> leftBlock -> [publish subscribe] -> rightBlock -> socketBlock + val plugAdapterIdentifier = getPlugAdapterDeclaration(sourcePort.portTarget)?.identifier + val revealResult = identifiersToRevealResult[plugAdapterIdentifier] + checkNotNull(revealResult) + if (connections.isEmpty()) { + continue + } + val portsBeforePublishBlocks = revealLeftPart( + revealResult = revealResult, + sourcePort = sourcePort, + network = network, + model = model, + connectionsCount = connections.size, + ) + if (withPublishSubscribe) { + for (connectionSourcePort in portsBeforePublishBlocks) { + val publishSubscribeAdapter = createLeftPublishSubscribeAdapter( + revealResult = revealResult, + network = network, + model = model, + ) + + network.adapterConnections += factoryUtils.createConnection( + source = connectionSourcePort, + target = publishSubscribeAdapter.getPort( + publishSubscribeAdapter.type.socketPorts.first() + ), + entryKind = EntryKind.ADAPTER, + ) + } + } + + val connectionsAndPorts = connections.zip(portsBeforePublishBlocks) + for (i in connectionsAndPorts.indices) { + val (connection, connectionSourcePort) = connectionsAndPorts[i] + revealRightPart( + revealResult = revealResult, + leftPort = if (withPublishSubscribe) { + createRightPublishSubscribeAdapter( + revealResult = revealResult, + network = network, + model = model, + ) + } else { + connectionSourcePort + }, + rightPort = checkNotNull(connection.targetReference.getTarget()), + network = network, + ) + } + } + network.adapterConnections.removeIf { it in connectionsToRemove } + } + + fun revealLeftPart( + revealResult: RevealDeclarationsResult, + sourcePort: PortPath<*>, + network: FBNetwork, + model: SModel, + connectionsCount: Int, + ): List> { + val adapterType = revealResult.extendedAdapter + val outputRouter = adapterType.outputRouter + val routerDeclaration = if (outputRouter == null) { + if (connectionsCount > 1) { + error("Port has more than one connection") + } + null + } else { + revealResult.routers.computeIfAbsent(connectionsCount) { + val name = "${adapterType.name}_$connectionsCount" + sModelUtils.findOneDeclarationOrNull("${name}_router", model) + ?: switchGenerator.generateRouter( + name = name, + model = model, + source = checkNotNull(revealResult.routerAdapter), + target = revealResult.leftAdapter, + outputsCount = connectionsCount, + outputRouterName = outputRouter.name, + inputRouterName = adapterType.inputRouter?.name, + virtualPackage = getPackageName(adapterType.name), + ) + } + } + + val portsBeforePublishBlocks: List> = if (routerDeclaration == null) { + listOf(sourcePort) + } else { + val routerBlock = factoryUtils.addFunctionalBlock(routerDeclaration, network) + network.adapterConnections += factoryUtils.createConnection( + source = sourcePort, + target = routerBlock.getPort(routerBlock.type.socketPorts.first()), + entryKind = EntryKind.ADAPTER, + ) + routerBlock.type.plugPorts.map { routerBlock.getPort(it) } + } + return portsBeforePublishBlocks.map { + connectBlockReturnPlugPort( + blockDeclaration = revealResult.leftBlockDeclaration, + sourcePort = it, + network = network, + name = revealResult.leftBlockDeclaration?.name, + ) + } + } + + private fun createLeftPublishSubscribeAdapter( + revealResult: RevealDeclarationsResult, + network: FBNetwork, + model: SModel, + ): FunctionBlockDeclaration { + val adapterType = revealResult.extendedAdapter + val leftPublishSubscribeAdapter = revealResult.leftPublishSubscribeAdapter ?: run { + val name = "${adapterType.name}_LeftPublishSubscribeAdapter" + val existedDeclaration = sModelUtils.findOneDeclarationOrNull(name, model) + if (existedDeclaration != null) { + existedDeclaration + } else { + val leftCompositeFBType = factory.createCompositeFBTypeDeclaration(StringIdentifier(name)) + val socket = factory.createSocketDeclaration(StringIdentifier("socket")) + socket.typeReference.setTarget(revealResult.middleAdapter) + leftCompositeFBType.sockets += socket + sModelUtils.addDeclarationToModel(leftCompositeFBType, model, getPackageName(adapterType.name)) + createPublishSubscribeAdapter( + compositeFBType = leftCompositeFBType, + declaration = socket, + currentModel = model, + packageName = adapterType.name, + ) + } + } + revealResult.leftPublishSubscribeAdapter = leftPublishSubscribeAdapter + val leftPublishSubscribeAdapterBlock = factoryUtils.addFunctionalBlock( + blockType = leftPublishSubscribeAdapter, + network = network, + ) + addPublishSubscribeBlocks( + source = leftPublishSubscribeAdapterBlock, + network = network, + currentModel = model, + name = "Left_${adapterType.name}", + ) + return leftPublishSubscribeAdapterBlock + } + + private fun revealRightPart( + revealResult: RevealDeclarationsResult, + leftPort: PortPath, + rightPort: PortPath, + network: FBNetwork, + ) { + val portBeforeSocketBlock = connectBlockReturnPlugPort( + blockDeclaration = revealResult.rightBlockDeclaration, + sourcePort = leftPort, + network = network, + name = revealResult.rightBlockDeclaration?.name, + ) + + network.adapterConnections += factoryUtils.createConnection( + source = portBeforeSocketBlock, + target = rightPort, + entryKind = EntryKind.ADAPTER + ) + } + + private fun createRightPublishSubscribeAdapter( + revealResult: RevealDeclarationsResult, + network: FBNetwork, + model: SModel, + ): PortPath { + val adapterType = revealResult.extendedAdapter + val rightPublishSubscribeAdapter = revealResult.rightPublishSubscribeAdapter ?: run { + val name = "${adapterType.name}_RightPublishSubscribeAdapter" + val existedDeclaration = sModelUtils.findOneDeclarationOrNull(name, model) + if (existedDeclaration != null) { + existedDeclaration + } else { + val rightCompositeFBType = factory.createCompositeFBTypeDeclaration(StringIdentifier(name)) + val plug = factory.createPlugDeclaration(StringIdentifier("plug")) + plug.typeReference.setTarget(revealResult.middleAdapter) + rightCompositeFBType.plugs += plug + sModelUtils.addDeclarationToModel(rightCompositeFBType, model, getPackageName(adapterType.name)) + createPublishSubscribeAdapter( + compositeFBType = rightCompositeFBType, + declaration = plug, + currentModel = model, + packageName = adapterType.name + ) + } + } + revealResult.rightPublishSubscribeAdapter = rightPublishSubscribeAdapter + val rightPublishSubscribeAdapterBlock = factoryUtils.addFunctionalBlock( + blockType = rightPublishSubscribeAdapter, + network = network, + ) + addPublishSubscribeBlocks( + source = rightPublishSubscribeAdapterBlock, + network = network, + currentModel = model, + name = "Right_${adapterType.name}", + ) + return PortPath.createPlugPortPath( + functionBlock = rightPublishSubscribeAdapterBlock, + portTarget = rightPublishSubscribeAdapter.plugs.first(), + ) + } + + private fun connectBlockReturnPlugPort( + blockDeclaration: CompositeFBTypeDeclaration?, + sourcePort: PortPath<*>, + network: FBNetwork, + name: String? = null, + ): PortPath { + return if (blockDeclaration == null) { + sourcePort + } else { + val leftBlock = factoryUtils.addFunctionalBlock(blockDeclaration, network, name) + network.adapterConnections += factoryUtils.createConnection( + source = sourcePort, + target = leftBlock.getPort(leftBlock.type.socketPorts.first()), + entryKind = EntryKind.ADAPTER + ) + leftBlock.getPort(leftBlock.type.plugPorts.first()) + } + } + + private fun createPublishSubscribeAdapter( + compositeFBType: CompositeFBTypeDeclaration, + declaration: FunctionBlockDeclarationBase, + currentModel: SModel, + packageName: String, + ): CompositeFBTypeDeclaration { + val typeDescriptor = declaration.type + + val eventToNumberFbType = eventToNumberFbTypes.computeIfAbsent( + typeDescriptor.eventOutputPorts.size + ) { number -> + val name = "EventToNumberAdapter_$number" + findDeclarationOrCreate( + name = name, + model = currentModel, + virtualPackage = getPackageName(packageName), + ) { + createEventToNumberConverter( + name = name, + inputCount = number, + ) + } + } + + val eventToNumberBlock = factoryUtils.addFunctionalBlock(eventToNumberFbType, compositeFBType.network) + + val numberToEventFbType = numberToEventFbTypes.computeIfAbsent( + typeDescriptor.eventInputPorts.size + ) { number -> + val name = "NumberToEventAdapter_$number" + findDeclarationOrCreate( + name = name, + model = currentModel, + virtualPackage = getPackageName(packageName), + ) { + createNumberToEventConverter( + name = "NumberToEventAdapter_$number", + inputCount = number, + ) + } + } + + val numberToEventBlock = factoryUtils.addFunctionalBlock(numberToEventFbType, compositeFBType.network) + + // event way: inputs -> numberToEventBlock -> socket -> eventToNumberBlock -> outputs + // data way: inputs -> numberToEventBlock + // data way: eventToNumberBlock -> outputs + // data way: inputs -> socket -> outputs + factoryUtils.copyEventsAndConnect( + destination = compositeFBType.inputEvents, + destinationBlock = null, + sources = numberToEventFbType.inputEvents, + sourceBlock = numberToEventBlock, + network = compositeFBType.network, + outputToInput = false, + ) + factoryUtils.copyParametersAndConnect( + destination = compositeFBType.inputParameters, + destinationBlock = null, + source = numberToEventFbType.inputParameters, + sourceBlock = numberToEventBlock, + network = compositeFBType.network, + outputToInput = false, + ) + compositeFBType.network.eventConnections += typeDescriptor.eventInputPorts + .zip(numberToEventFbType.outputEvents) + .map { + factoryUtils.createConnection( + entryKind = EntryKind.EVENT, + source = PortPath.createEventPortPath(numberToEventBlock, it.second), + target = declaration.getPort(it.first), + ) + } + compositeFBType.network.eventConnections += typeDescriptor.eventOutputPorts + .zip(eventToNumberFbType.inputEvents) + .map { + factoryUtils.createConnection( + entryKind = EntryKind.EVENT, + source = declaration.getPort(it.first), + target = PortPath.createEventPortPath(eventToNumberBlock, it.second), + ) + } + factoryUtils.copyEventsAndConnect( + destination = compositeFBType.outputEvents, + destinationBlock = null, + sources = eventToNumberFbType.outputEvents, + sourceBlock = eventToNumberBlock, + network = compositeFBType.network + ) + factoryUtils.copyParametersAndConnect( + destination = compositeFBType.outputParameters, + destinationBlock = null, + source = eventToNumberFbType.outputParameters, + sourceBlock = eventToNumberBlock, + network = compositeFBType.network + ) + factoryUtils.copyParametersAndConnect( + destination = compositeFBType.inputParameters, + destinationBlock = null, + source = typeDescriptor.dataInputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = declaration, + network = compositeFBType.network, + outputToInput = false, + ) + factoryUtils.copyParametersAndConnect( + destination = compositeFBType.outputParameters, + destinationBlock = null, + source = typeDescriptor.dataOutputPorts.map { it.declaration as ParameterDeclaration }, + sourceBlock = declaration, + network = compositeFBType.network + ) + for (newInput in compositeFBType.inputEvents) { + newInput.associations += compositeFBType.inputParameters.map { factoryUtils.createAssociation(it) } + } + for (newOutput in compositeFBType.outputEvents) { + newOutput.associations += compositeFBType.outputParameters.map { factoryUtils.createAssociation(it) } + } + return compositeFBType + } + + private fun createEventToNumberConverter( + name: String, + inputCount: Int, + ): BasicFBTypeDeclaration { + val basicFbType = factory.createBasicFBTypeDeclaration(StringIdentifier(name)) + val events = (0 until inputCount).map { factory.createEventDeclaration(StringIdentifier("I_$it")) } + basicFbType.inputEvents += events + val outputEvent = factory.createEventDeclaration(StringIdentifier("REQ")) + basicFbType.outputEvents += outputEvent + val parameterOutput = factory.createParameterDeclaration(StringIdentifier("I_E_number")) + parameterOutput.type = ElementaryType.INT + basicFbType.outputParameters += parameterOutput + outputEvent.associations += factoryUtils.createAssociation(parameterOutput) + val start = factory.createStateDeclaration(StringIdentifier("Start")) + basicFbType.ecc.states += start + for (i in basicFbType.inputEvents.indices) { + val event = basicFbType.inputEvents[i] + val state = factory.createStateDeclaration(StringIdentifier(event.name)) + basicFbType.ecc.states += state + basicFbType.ecc.transitions += factoryUtils.createStateTransition(start, state, event) + basicFbType.ecc.transitions += factoryUtils.createStateTransition(state, start) + + val stateAction = factory.createStateAction() + state.actions += stateAction + stateAction.event.setFQName(outputEvent.name) + val algorithmDeclaration = factory.createAlgorithmDeclaration( + StringIdentifier(state.name + "_algorithm") + ) + val algorithmBody = factory.createAlgorithmBody(AlgorithmLanguage.ST) + algorithmDeclaration.body = algorithmBody + + algorithmBody.statements += stFactoryUtils.createAssign( + variable = parameterOutput, + assignable = stFactoryUtils.createIntLiteral(i), + ) + stateAction.algorithm.setTarget(algorithmDeclaration) + basicFbType.algorithms += algorithmDeclaration + } + return basicFbType + } + + private fun createNumberToEventConverter( + name: String, + inputCount: Int, + ): BasicFBTypeDeclaration { + val basicFbType = factory.createBasicFBTypeDeclaration(StringIdentifier(name)) + val events = (0 until inputCount).map { factory.createEventDeclaration(StringIdentifier("O_$it")) } + basicFbType.outputEvents += events + val inputEvent = factory.createEventDeclaration(StringIdentifier("IND")) + basicFbType.inputEvents += inputEvent + val parameterInput = factory.createParameterDeclaration(StringIdentifier("O_E_number")) + parameterInput.type = ElementaryType.INT + basicFbType.inputParameters += parameterInput + val inputAssociation = factory.createEventAssociation() + inputAssociation.parameterReference.setTarget(parameterInput) + inputEvent.associations += inputAssociation + val start = factory.createStateDeclaration(StringIdentifier("Start")) + basicFbType.ecc.states += start + for (i in basicFbType.outputEvents.indices) { + val event = basicFbType.outputEvents[i] + val state = factory.createStateDeclaration(StringIdentifier(event.name)) + basicFbType.ecc.states += state + basicFbType.ecc.transitions += factoryUtils.createStateTransition( + source = start, + target = state, + eventCondition = inputEvent, + condition = stFactoryUtils.intEquality(parameterInput, i) + ) + basicFbType.ecc.transitions += factoryUtils.createStateTransition(state, start) + val stateAction = factory.createStateAction() + state.actions += stateAction + stateAction.event.setFQName(event.name) + } + return basicFbType + } + + private fun addPublishSubscribeBlocks( + source: FunctionBlockDeclaration, + network: FBNetwork, + currentModel: SModel, + name: String, + ) { + val fbTypeDeclaration = source.typeReference.getTarget() + checkNotNull(fbTypeDeclaration) + val outputEvent = fbTypeDeclaration.outputEvents.first() + val outputParams = fbTypeDeclaration.outputParameters + if (outputParams.size > 10) { + error("Size more than 10") + } + val publishFbType = getFBTypeFrom4diacModel(currentModel, "PUBLISH_${outputParams.size}") + val publishBlock = factoryUtils.addFunctionalBlock(publishFbType, network, name = "Publish_${name}") + network.eventConnections += factoryUtils.createConnection( + source = PortPath.createEventPortPath(source, outputEvent), + target = PortPath.createEventPortPath( + publishBlock, + publishFbType.inputEvents.first { it.name == outputEvent.name } + ), + entryKind = EntryKind.EVENT, + ) + network.dataConnections += fbTypeDeclaration.outputParameters + .zip(publishFbType.inputParameters.filter { it.name.startsWith("SD") }) + .map { (sourceParameter, publishParameter) -> + factoryUtils.createConnection( + source = PortPath.createDataPortPath(source, sourceParameter), + target = PortPath.createDataPortPath(publishBlock, publishParameter), + entryKind = EntryKind.DATA, + ) + } + + val inputEvent = fbTypeDeclaration.inputEvents.first() + val inputParams = fbTypeDeclaration.inputParameters + if (inputParams.size > 10) { + error("Size more than 10") + } + val subscribeFbType = getFBTypeFrom4diacModel(currentModel, "SUBSCRIBE_${inputParams.size}") + val subscribeBlock = factoryUtils.addFunctionalBlock(subscribeFbType, network, name = "Subscribe_${name}") + network.eventConnections += factoryUtils.createConnection( + source = PortPath.createEventPortPath( + subscribeBlock, + subscribeFbType.outputEvents.first { it.name == inputEvent.name }, + ), + target = PortPath.createEventPortPath(source, inputEvent), + entryKind = EntryKind.EVENT, + ) + network.dataConnections += fbTypeDeclaration.inputParameters + .zip(subscribeFbType.outputParameters.filter { it.name.startsWith("RD") }) + .map { (sourceParameter, subscribeParameter) -> + factoryUtils.createConnection( + source = PortPath.createDataPortPath(subscribeBlock, subscribeParameter), + target = PortPath.createDataPortPath(source, sourceParameter), + entryKind = EntryKind.DATA, + ) + } + } + + private fun getFBTypeFrom4diacModel( + currentModel: SModel, + nodeName: String, + ): FBTypeDeclaration = publishSubscribeProvider?.invoke(nodeName) + ?: sModelUtils.getFBTypeFrom4diacModel(currentModel, nodeName) + + private fun createCompositeFB( + name: String, + leftAdapter: AdapterTypeDeclaration, + rightAdapter: AdapterTypeDeclaration, + network: FBNetwork, + ): CompositeFBTypeDeclaration { + val composite = factory.createCompositeFBTypeDeclaration(StringIdentifier(name)) + + val plug = factory.createPlugDeclaration(rightAdapter.identifier) + plug.typeReference.setTarget(rightAdapter) + plug.name = "plug" + composite.plugs += plug + + val socket = factory.createSocketDeclaration(leftAdapter.identifier) + socket.typeReference.setTarget(leftAdapter) + socket.name = "socket" + composite.sockets += socket + + composite.network.functionBlocks += network.functionBlocks.map { it.copy() as FunctionBlockDeclaration } + composite.network.adapterConnections += network.adapterConnections.map { it.copy() as FBNetworkConnection } + composite.network.eventConnections += network.eventConnections.map { it.copy() as FBNetworkConnection } + composite.network.dataConnections += network.dataConnections.map { it.copy() as FBNetworkConnection } + composite.network.endpointCoordinates += network.endpointCoordinates.map { it.copy() as EndpointCoordinate } + return composite + } + + private fun updateInternalAdapterPorts(block: CompositeFBTypeDeclaration) { + val plug = block.plugs.first() + val socket = block.sockets.first() + for (connection in block.network.eventConnections.asSequence() + .plus(block.network.dataConnections) + .plus(block.network.adapterConnections) + .toList()) { + val source = connection.sourceReference.getTarget() + val newSource = getPortForInternalAdapterBlock(source, plug, socket) + if (newSource != null) { + connection.sourceReference.setTarget(newSource) + } + val target = connection.targetReference.getTarget() + val newTarget = getPortForInternalAdapterBlock(target, plug, socket) + if (newTarget != null) { + connection.targetReference.setTarget(newTarget) + } + } + } + + private fun getPortForInternalAdapterBlock( + port: PortPath<*>?, + plug: PlugDeclaration, + socket: SocketDeclaration, + ): PortPath? { + if (port?.functionBlock?.name == "Plug_Connection") { + return plug.ports.first { it.portTarget.name == port.portTarget.name } + } else if (port?.functionBlock?.name == "Socket_Connection") { + return socket.ports.first { it.portTarget.name == port.portTarget.name } + } + return null + } + + /** + * Tries to find exactly one declaration with provided name in provided model, + * returns it if type of declaration matched with expected. + * Otherwise, returns declaration from producer and adds it to the model + * and removes all other nodes with provided name. + * + * This method helps to prevent reference invalidation after second application of the reveal algorithm + */ + private inline fun findDeclarationOrCreate( + name: String, + model: SModel, + virtualPackage: String?, + declarationProvider: () -> T, + ): T { + val existedDeclaration = sModelUtils.findOneDeclarationOrNull(name, model) + if (existedDeclaration != null) { + return existedDeclaration + } + val newDeclaration = declarationProvider() + sModelUtils.addDeclarationToModel(newDeclaration, model, virtualPackage) + return newDeclaration + } +} diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/RevealDeclarationsResult.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/RevealDeclarationsResult.kt new file mode 100644 index 000000000..7fc29d85b --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/adapter/RevealDeclarationsResult.kt @@ -0,0 +1,23 @@ +package org.fbme.extensions.adapter + +import org.fbme.lib.iec61499.declarations.AdapterTypeDeclaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + + +data class RevealDeclarationsResult( + val extendedAdapter: ExtendedAdapterTypeDeclaration, + val routerAdapter: AdapterTypeDeclaration?, + val leftAdapter: AdapterTypeDeclaration, + val middleAdapter: AdapterTypeDeclaration, + val rightAdapter: AdapterTypeDeclaration, + val leftBlockDeclaration: CompositeFBTypeDeclaration?, + val rightBlockDeclaration: CompositeFBTypeDeclaration?, + var leftPublishSubscribeAdapter: CompositeFBTypeDeclaration? = null, + var rightPublishSubscribeAdapter: CompositeFBTypeDeclaration? = null, + val routers: MutableMap = mutableMapOf(), +) { + fun getFarLeftAdapter(): AdapterTypeDeclaration = routerAdapter ?: leftAdapter + + fun getFarRightAdapter(): AdapterTypeDeclaration = rightAdapter +} \ No newline at end of file diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/utils/FBInterfaceDeclarationUtils.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/FBInterfaceDeclarationUtils.kt new file mode 100644 index 000000000..1a1087915 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/FBInterfaceDeclarationUtils.kt @@ -0,0 +1,120 @@ +package org.fbme.extensions.utils + +import org.fbme.lib.common.Identifier +import org.fbme.lib.common.StringIdentifier +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor + +class FBInterfaceDeclarationUtils( + private val factory: IEC61499Factory, +) { + companion object { + fun copyPorts( + target: FBInterfaceDeclaration, + source: FBInterfaceDeclaration, + reversed: Boolean, + ) = copy( + reversed = reversed, + declaration = target, + outputEvents = source.outputEvents, + inputEvents = source.inputEvents, + parameterOutputs = source.outputParameters, + parametersInputs = source.inputParameters, + ) + + fun copyPorts( + declaration: FBInterfaceDeclaration, + fbTypeDescriptor: FBTypeDescriptor, + reversed: Boolean, + ) = copy( + reversed = reversed, + declaration = declaration, + outputEvents = fbTypeDescriptor.eventOutputPorts.map { checkNotNull(it.declaration as EventDeclaration) }, + inputEvents = fbTypeDescriptor.eventInputPorts.map { checkNotNull(it.declaration as EventDeclaration) }, + parameterOutputs = fbTypeDescriptor.dataOutputPorts + .map { checkNotNull(it.declaration as ParameterDeclaration) }, + parametersInputs = fbTypeDescriptor.dataInputPorts + .map { checkNotNull(it.declaration as ParameterDeclaration) }, + ) + + fun copy( + reversed: Boolean, + declaration: FBInterfaceDeclaration, + outputEvents: List, + inputEvents: List, + parameterOutputs: List, + parametersInputs: List, + ) { + if (reversed) { + copy( + reversed = false, + declaration = declaration, + outputEvents = inputEvents, + inputEvents = outputEvents, + parameterOutputs = parametersInputs, + parametersInputs = parameterOutputs, + ) + return + } + val newParametersInputs = parametersInputs.map { it.copy() as ParameterDeclaration } + declaration.inputParameters += newParametersInputs + val newParameterOutputs = parameterOutputs.map { it.copy() as ParameterDeclaration } + declaration.outputParameters += newParameterOutputs + + declaration.inputEvents += inputEvents.map { event -> + (event.copy() as EventDeclaration).also { newEvent -> + newEvent.associations.replaceAll { copyAssociation(it, newParametersInputs) } + } + } + declaration.outputEvents += outputEvents.map { event -> + (event.copy() as EventDeclaration).also { newEvent -> + newEvent.associations.replaceAll { copyAssociation(it, newParameterOutputs) } + } + } + } + + fun copyAssociation( + association: EventAssociation, + newParametersInputs: List + ): EventAssociation { + val newAssociation = association.copy() as EventAssociation + newAssociation.parameterReference.setTarget( + newParametersInputs.first { it.name == association.parameterReference.getTarget()?.name } + ) + return newAssociation + } + } + + fun generateAdapterFromDeclaration( + declaration: FBInterfaceDeclaration, + name: String? = null, + identifier: Identifier? = null, + reversed: Boolean = false, + ): AdapterTypeDeclaration { + val adapterTypeDeclaration = factory.createAdapterTypeDeclaration( + identifier ?: name?.let { StringIdentifier(name) } + ) + if (name != null) { + adapterTypeDeclaration.name = name + } + copyPorts(adapterTypeDeclaration, declaration, reversed) + return adapterTypeDeclaration + } + + fun generateAdapterFromDescriptor( + fbTypeDescriptor: FBTypeDescriptor, + name: String? = null, + identifier: Identifier? = null, + reversed: Boolean = false, + ): AdapterTypeDeclaration { + val adapterTypeDeclaration = factory.createAdapterTypeDeclaration( + identifier ?: name?.let { StringIdentifier(name) } + ) + if (name != null) { + adapterTypeDeclaration.name = name + } + copyPorts(adapterTypeDeclaration, fbTypeDescriptor, reversed) + return adapterTypeDeclaration + } +} \ No newline at end of file diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/utils/IEC61499FactoryUtils.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/IEC61499FactoryUtils.kt new file mode 100644 index 000000000..80d36faa9 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/IEC61499FactoryUtils.kt @@ -0,0 +1,170 @@ +package org.fbme.extensions.utils + +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.IEC61499Factory +import org.fbme.lib.iec61499.declarations.EventAssociation +import org.fbme.lib.iec61499.declarations.EventDeclaration +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.fbme.lib.iec61499.declarations.ParameterDeclaration +import org.fbme.lib.iec61499.ecc.StateDeclaration +import org.fbme.lib.iec61499.ecc.StateTransition +import org.fbme.lib.iec61499.fbnetwork.* +import org.fbme.lib.st.expressions.Expression + +class IEC61499FactoryUtils( + private val factory: IEC61499Factory, +) { + fun createStateTransition( + source: StateDeclaration, + target: StateDeclaration, + eventCondition: EventDeclaration? = null, + condition: Expression? = null, + ): StateTransition { + val transition = factory.createStateTransition() + transition.sourceReference.setTarget(source) + transition.targetReference.setTarget(target) + if (eventCondition != null) { + transition.condition.eventReference.setFQName(eventCondition.name) + } + if (condition != null) { + transition.condition.setGuardCondition(condition) + } + return transition + } + + fun createNetworkConnection( + kind: EntryKind, + source: FunctionBlockDeclarationBase?, + sourcePortTarget: Declaration, + target: FunctionBlockDeclarationBase?, + targetPortTarget: Declaration, + ): FBNetworkConnection = createConnection( + source = PortPath.createPortPath(source, kind, sourcePortTarget), + target = PortPath.createPortPath(target, kind, targetPortTarget), + entryKind = kind, + ) + + fun createConnection( + source: PortPath<*>, + target: PortPath<*>, + entryKind: EntryKind, + ): FBNetworkConnection { + val connection = factory.createFBNetworkConnection(entryKind) + connection.sourceReference.setTarget(source) + connection.targetReference.setTarget(target) + return connection + } + + fun createAssociation( + declaration: ParameterDeclaration, + ): EventAssociation { + val eventAssociation = factory.createEventAssociation() + eventAssociation.parameterReference.setTarget(declaration) + return eventAssociation + } + + fun addFunctionalBlock( + blockType: FBTypeDeclaration, + network: FBNetwork, + name: String? = null, + ): FunctionBlockDeclaration { + val block = factory.createFunctionBlockDeclaration(blockType.identifier) + block.name = getUnusedName( + name ?: blockType.name, + network.functionBlocks.asSequence().map { it.name }.toSet() + ) + block.typeReference.setTarget(blockType) + network.functionBlocks += block + return block + } + + private fun getUnusedName(name: String, usedNames: Set): String = if (name in usedNames) { + getUnusedName(name, usedNames, 2) + } else { + name + } + + private fun getUnusedName(name: String, usedNames: Set, id: Int): String { + val nextName = "${name}_$id" + return if (nextName in usedNames) { + getUnusedName(name, usedNames, id + 1) + } else { + nextName + } + } + + fun copyEventsAndConnect( + destination: MutableList, + destinationBlock: FunctionBlockDeclarationBase?, + sources: List, + sourceBlock: FunctionBlockDeclarationBase?, + network: FBNetwork, + outputToInput: Boolean = true, + keepAssociations: Boolean = false, + ): List> { + val eventsAndCopies = sources.map { source -> + val copy = source.copy() as EventDeclaration + if (!keepAssociations) { + copy.associations.clear() + } + source to copy + } + destination += eventsAndCopies.map { it.second } + + network.eventConnections += eventsAndCopies.map { + if (outputToInput) { + createNetworkConnection( + kind = EntryKind.EVENT, + source = sourceBlock, + sourcePortTarget = it.first, + target = destinationBlock, + targetPortTarget = it.second, + ) + } else { + createNetworkConnection( + kind = EntryKind.EVENT, + source = destinationBlock, + sourcePortTarget = it.second, + target = sourceBlock, + targetPortTarget = it.first, + ) + } + } + return eventsAndCopies + } + + fun copyParametersAndConnect( + destination: MutableList, + destinationBlock: FunctionBlockDeclarationBase?, + source: List, + sourceBlock: FunctionBlockDeclarationBase?, + network: FBNetwork, + outputToInput: Boolean = true, + ): List> { + val inputsAndCopies = source.map { + it to it.copy() as ParameterDeclaration + } + destination += inputsAndCopies.map { it.second } + + network.dataConnections += inputsAndCopies.map { + if (outputToInput) { + createNetworkConnection( + kind = EntryKind.DATA, + source = sourceBlock, + sourcePortTarget = it.first, + target = destinationBlock, + targetPortTarget = it.second, + ) + } else { + createNetworkConnection( + kind = EntryKind.DATA, + source = destinationBlock, + sourcePortTarget = it.second, + target = sourceBlock, + targetPortTarget = it.first, + ) + } + } + return inputsAndCopies + } +} \ No newline at end of file diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/utils/SModelUtils.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/SModelUtils.kt new file mode 100644 index 000000000..218f934d4 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/SModelUtils.kt @@ -0,0 +1,67 @@ +package org.fbme.extensions.utils + +import jetbrains.mps.smodel.ModelImports +import jetbrains.mps.smodel.SNodeUtil +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.iec61499.repository.PlatformRepository +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.jetbrains.mps.openapi.model.SModel + +class SModelUtils( + private val owner: PlatformRepository, +) { + fun getFBTypeFrom4diacModel( + currentModel: SModel, + nodeName: String, + ): FBTypeDeclaration = owner.adapter( + ModelImports(currentModel).importedModels + .first { it.modelName == MODEL_4DIAC_NAME } + .resolve(owner.mpsRepository) + .rootNodes + .first { it.name == nodeName } + ) + + inline fun findOneDeclarationOrNull( + name: String, + model: SModel, + ): T? = findDeclarations(setOf(name), model).singleOrNull() as? T + + fun findDeclarations( + names: Collection, + model: SModel, + ): List = model.rootNodes.asSequence() + .mapNotNull { + if (it.name !in names) { + null + } else { + owner.adapter(it) + } + } + .toList() + + fun addDeclarationToModel(declaration: Declaration?, model: SModel, virtualPackage: String? = null) = + addDeclarationsToModel(declaration, model = model, virtualPackage = virtualPackage) + + fun addDeclarationsToModel( + vararg declarations: Declaration?, + model: SModel, + virtualPackage: String? = null, + ) { + val distinctDeclarations = declarations.filterNotNull().associateBy { it.name } + val existedNodes = model.rootNodes.filter { it.name in distinctDeclarations } + for (node in existedNodes) { + node.delete() + } + + for (declaration in distinctDeclarations.values) { + val node = (declaration as PlatformElement).node + if (!virtualPackage.isNullOrEmpty()) { + node.setProperty(SNodeUtil.property_BaseConcept_virtualPackage, virtualPackage) + } + model.addRootNode(node) + } + } +} + +private const val MODEL_4DIAC_NAME = "iec61499.4diac.stdlib" diff --git a/code/extensions/src/main/kotlin/org/fbme/extensions/utils/STFactoryUtils.kt b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/STFactoryUtils.kt new file mode 100644 index 000000000..6b1a1a220 --- /dev/null +++ b/code/extensions/src/main/kotlin/org/fbme/extensions/utils/STFactoryUtils.kt @@ -0,0 +1,38 @@ +package org.fbme.extensions.utils + +import org.fbme.lib.st.STFactory +import org.fbme.lib.st.expressions.* +import org.fbme.lib.st.statements.AssignmentStatement + +class STFactoryUtils( + private val stFactory: STFactory, +) { + fun intEquality(variable: VariableDeclaration, number: Int): BinaryExpression { + val equality = stFactory.createBinaryExpression(BinaryOperation.EQ) + equality.leftExpression = createVariable(variable) + equality.rightExpression = createIntLiteral(number) + return equality + } + + fun createIntLiteral(number: Int): Literal { + val numberLiteral = stFactory.createLiteral(LiteralKind.DEC_INT) as Literal + numberLiteral.value = number + return numberLiteral + } + + fun createAssign( + variable: VariableDeclaration, + assignable: Expression, + ): AssignmentStatement { + val assignment = stFactory.createAssignmentStatement() + assignment.variable = createVariable(variable) + assignment.expression = assignable + return assignment + } + + fun createVariable(variable: VariableDeclaration): VariableReference { + val variableReference = stFactory.createVariableReference() + variableReference.reference.setTarget(variable) + return variableReference + } +} \ No newline at end of file diff --git a/code/extensions/src/test/kotlin/org/fbme/ide/extensions/utils/AdapterRevealServiceTest.kt b/code/extensions/src/test/kotlin/org/fbme/ide/extensions/utils/AdapterRevealServiceTest.kt new file mode 100644 index 000000000..d9674deeb --- /dev/null +++ b/code/extensions/src/test/kotlin/org/fbme/ide/extensions/utils/AdapterRevealServiceTest.kt @@ -0,0 +1,179 @@ +package org.fbme.ide.extensions.utils + +import jetbrains.mps.smodel.tempmodel.TempModuleOptions +import jetbrains.mps.smodel.tempmodel.TemporaryModels +import org.fbme.extensions.adapter.AdapterRevealService +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.platform.testing.PlatformTestBase +import org.fbme.lib.common.Declaration +import org.fbme.lib.iec61499.declarations.CompositeFBTypeDeclaration +import org.fbme.lib.iec61499.declarations.FBTypeDeclaration +import org.fbme.lib.iec61499.stringify.RootDeclarationPrinter +import org.jdom.Document +import org.jdom.output.Format +import org.jdom.output.XMLOutputter +import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.mps.openapi.model.SModel +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class AdapterRevealServiceTest : PlatformTestBase() { + private val adapterRevealService = AdapterRevealService(repository, ::getPublishSubscribeBlock) + private val publishSubscribeMap: Map = mapOf( + "PUBLISH_5" to rootConverterByPath("/source/publishSubscribes/PUBLISH_5.fbt").convertFBType(), + "SUBSCRIBE_5" to rootConverterByPath("/source/publishSubscribes/SUBSCRIBE_5.fbt").convertFBType() + ) + + private fun getPublishSubscribeBlock(name: String): FBTypeDeclaration { + return checkNotNull(publishSubscribeMap[name]) + } + + @Test + fun testRevealDeclarations() { + val sourcePath = "/source/testRevealDeclarations" + val resultPath = "/results/testRevealDeclarations" + val extendedAdapterType = rootConverterByPath("$sourcePath/EA.eadp").convertExtendedAdapterType() + val leftBlock = createDocumentByPath("$resultPath/EA_network1.fbt") + val rightBlock = createDocumentByPath("$resultPath/EA_network2.fbt") + val leftAdapter = createDocumentByPath("$resultPath/Left_EA.adp") + val middleAdapter = createDocumentByPath("$resultPath/Middle_EA.adp") + val rightAdapter = createDocumentByPath("$resultPath/Right_EA.adp") + project.repository.modelAccess.runWriteAction { + val model = TemporaryModels.getInstance().create(false, false, "tmp", TempModuleOptions.forDefaultModule()) + model.addRootNode((extendedAdapterType as PlatformElement).node) + val revealDeclarations = adapterRevealService.revealDeclarations(extendedAdapterType, model) + + assertEqualStrings(leftAdapter, revealDeclarations.leftAdapter.toDocument()) + assertEqualStrings(middleAdapter, revealDeclarations.middleAdapter.toDocument()) + assertEqualStrings(rightAdapter, revealDeclarations.rightAdapter.toDocument()) + assertEqualStrings(leftBlock, assertNotNull(revealDeclarations.leftBlockDeclaration).toDocument()) + assertEqualStrings(rightBlock, assertNotNull(revealDeclarations.rightBlockDeclaration).toDocument()) + } + } + + @Test + fun testRevealAdapter() { + val sourcePath = "/source/testRevealAdapter" + val resultPath = "/results/testRevealAdapter" + val extendedAdapterType = rootConverterByPath("$sourcePath/EA.eadp").convertExtendedAdapterType() + val example = rootConverterByPath("$sourcePath/CompositeBlock.fbt").convertFBType() + val baseBlock = rootConverterByPath("$sourcePath/BaseBlock.fbt").convertFBType() + val leftBlock = createDocumentByPath("$resultPath/EA_network1.fbt") + val rightBlock = createDocumentByPath("$resultPath/EA_network2.fbt") + val leftAdapter = createDocumentByPath("$resultPath/Left_EA.adp") + val middleAdapter = createDocumentByPath("$resultPath/Middle_EA.adp") + val rightAdapter = createDocumentByPath("$resultPath/Right_EA.adp") + val routerAdapter = createDocumentByPath("$resultPath/RouterAdapter_EA.adp") + + project.repository.modelAccess.runWriteAction { + val model = TemporaryModels.getInstance().create(false, false, "tmp", TempModuleOptions.forDefaultModule()) + model.addRootNode((baseBlock as PlatformElement).node) + model.addRootNode((extendedAdapterType as PlatformElement).node) + model.addRootNode((example as PlatformElement).node) + + val revealDeclarations = adapterRevealService.revealAdapter(extendedAdapterType, model) + + assertEqualStrings(leftAdapter, revealDeclarations.leftAdapter.toDocument()) + assertEqualStrings(middleAdapter, revealDeclarations.middleAdapter.toDocument()) + assertEqualStrings(rightAdapter, revealDeclarations.rightAdapter.toDocument()) + assertEqualStrings(leftBlock, assertNotNull(revealDeclarations.leftBlockDeclaration).toDocument()) + assertEqualStrings(rightBlock, assertNotNull(revealDeclarations.rightBlockDeclaration).toDocument()) + assertEqualStrings(routerAdapter, assertNotNull(revealDeclarations.routerAdapter?.toDocument())) + checkNode(model, "$resultPath/CompositeBlock.fbt", "CompositeBlock") + checkNode(model, "$resultPath/EA_2_leftSwitch.fbt", "EA_2_leftSwitch") + checkNode(model, "$resultPath/EA_2_rightSwitch.fbt", "EA_2_rightSwitch") + checkNode(model, "$resultPath/EA_2_router.fbt", "EA_2_router") + } + } + + @Test + fun testRevealAdapterWithNetLeft() { + val sourcePath = "/source/testRevealAdapter" + val resultPath = "/results/testRevealAdapter" + val networkPath = "/results/resourceNetworkBlocks" + val extendedAdapterType = rootConverterByPath("$sourcePath/EA.eadp").convertExtendedAdapterType() + val composite = rootConverterByPath("$sourcePath/CompositeBlockWithoutConnections.fbt").convertFBType() + val baseBlock = rootConverterByPath("$sourcePath/BaseBlock.fbt").convertFBType() + val routerAdapter = createDocumentByPath("$resultPath/RouterAdapter_EA.adp") + + project.repository.modelAccess.runWriteAction { + val model = TemporaryModels.getInstance().create(false, false, "tmp", TempModuleOptions.forDefaultModule()) + model.addRootNode((baseBlock as PlatformElement).node) + model.addRootNode((extendedAdapterType as PlatformElement).node) + model.addRootNode((composite as PlatformElement).node) + model.addRootNode((publishSubscribeMap["PUBLISH_5"] as PlatformElement).node) + model.addRootNode((publishSubscribeMap["SUBSCRIBE_5"] as PlatformElement).node) + val revealDeclarations = adapterRevealService.revealDeclarations(extendedAdapterType, model) + val functionBlockDeclaration = + composite.cast().network.functionBlocks.first { it.name == "BaseBlock1" } + adapterRevealService.revealAdapterWithNetBlocks( + revealResult = revealDeclarations, + block = functionBlockDeclaration, + port = functionBlockDeclaration.type.plugPorts[0], + count = 2, + model = model, + ) + + assertEqualStrings(routerAdapter, assertNotNull(revealDeclarations.routerAdapter?.toDocument())) + checkNode(model, "$networkPath/left/CompositeBlockWithoutConnections.fbt", "CompositeBlockWithoutConnections") + checkNode(model, "$networkPath/left/EA_LeftPublishSubscribeAdapter.fbt", "EA_LeftPublishSubscribeAdapter") + checkNode(model, "$networkPath/EventToNumberAdapter_4.fbt", "EventToNumberAdapter_4") + checkNode(model, "$networkPath/NumberToEventAdapter_4.fbt", "NumberToEventAdapter_4") + } + } + + @Test + fun testRevealAdapterWithNetRight() { + val sourcePath = "/source/testRevealAdapter" + val resultPath = "/results/testRevealAdapter" + val networkPath = "/results/resourceNetworkBlocks" + val extendedAdapterType = rootConverterByPath("$sourcePath/EA.eadp").convertExtendedAdapterType() + val composite = rootConverterByPath("$sourcePath/CompositeBlockWithoutConnections.fbt").convertFBType() + val baseBlock = rootConverterByPath("$sourcePath/BaseBlock.fbt").convertFBType() + val routerAdapter = createDocumentByPath("$resultPath/RouterAdapter_EA.adp") + + project.repository.modelAccess.runWriteAction { + val model = TemporaryModels.getInstance().create(false, false, "tmp", TempModuleOptions.forDefaultModule()) + model.addRootNode((baseBlock as PlatformElement).node) + model.addRootNode((extendedAdapterType as PlatformElement).node) + model.addRootNode((composite as PlatformElement).node) + model.addRootNode((publishSubscribeMap["PUBLISH_5"] as PlatformElement).node) + model.addRootNode((publishSubscribeMap["SUBSCRIBE_5"] as PlatformElement).node) + val revealDeclarations = adapterRevealService.revealDeclarations(extendedAdapterType, model) + val functionBlockDeclaration = + composite.cast().network.functionBlocks.first { it.name == "BaseBlock1" } + adapterRevealService.revealAdapterWithNetBlocks( + revealResult = revealDeclarations, + block = functionBlockDeclaration, + port = functionBlockDeclaration.type.socketPorts[0], + count = 2, + model = model, + ) + + assertEqualStrings(routerAdapter, assertNotNull(revealDeclarations.routerAdapter?.toDocument())) + checkNode(model, "$networkPath/right/CompositeBlockWithoutConnections.fbt", "CompositeBlockWithoutConnections") + checkNode(model, "$networkPath/right/EA_RightPublishSubscribeAdapter.fbt", "EA_RightPublishSubscribeAdapter") + checkNode(model, "$networkPath/EventToNumberAdapter_4.fbt", "EventToNumberAdapter_4") + checkNode(model, "$networkPath/NumberToEventAdapter_4.fbt", "NumberToEventAdapter_4") + } + } + + private fun checkNode(model: SModel, path: String, nodeName: String) { + val example = createDocumentByPath(path) + val nodes = model.rootNodes.toList() + assertEqualStrings( + example, + assertNotNull(repository.adapterOrNull( + nodes.first { it.name == nodeName } + )).toDocument() + ) + } +} + +private fun assertEqualStrings(expected: Document, actual: Document) = + assertEquals(toString(expected), toString(actual)) + +private fun toString(document: Document): String = XMLOutputter(Format.getPrettyFormat()).outputString(document) + +private fun Declaration.toDocument(): Document = RootDeclarationPrinter(this).print() diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/EventToNumberAdapter_4.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/EventToNumberAdapter_4.fbt new file mode 100644 index 000000000..2200bea61 --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/EventToNumberAdapter_4.fbt @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/NumberToEventAdapter_4.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/NumberToEventAdapter_4.fbt new file mode 100644 index 000000000..190a74e30 --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/NumberToEventAdapter_4.fbt @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/CompositeBlockWithoutConnections.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/CompositeBlockWithoutConnections.fbt new file mode 100644 index 000000000..2fbe36ff8 --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/CompositeBlockWithoutConnections.fbt @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/EA_LeftPublishSubscribeAdapter.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/EA_LeftPublishSubscribeAdapter.fbt new file mode 100644 index 000000000..2402a4330 --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/left/EA_LeftPublishSubscribeAdapter.fbt @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/CompositeBlockWithoutConnections.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/CompositeBlockWithoutConnections.fbt new file mode 100644 index 000000000..b21599bdc --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/CompositeBlockWithoutConnections.fbt @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/EA_RightPublishSubscribeAdapter.fbt b/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/EA_RightPublishSubscribeAdapter.fbt new file mode 100644 index 000000000..5297190c6 --- /dev/null +++ b/code/extensions/src/test/resources/results/resourceNetworkBlocks/right/EA_RightPublishSubscribeAdapter.fbt @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/CompositeBlock.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/CompositeBlock.fbt new file mode 100644 index 000000000..9bcdbe878 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/CompositeBlock.fbt @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_leftSwitch.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_leftSwitch.fbt new file mode 100644 index 000000000..22c469198 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_leftSwitch.fbt @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_rightSwitch.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_rightSwitch.fbt new file mode 100644 index 000000000..201d6bce9 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_rightSwitch.fbt @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_router.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_router.fbt new file mode 100644 index 000000000..887d26287 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/EA_2_router.fbt @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/EA_network1.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/EA_network1.fbt new file mode 100644 index 000000000..89f5ca737 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/EA_network1.fbt @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/EA_network2.fbt b/code/extensions/src/test/resources/results/testRevealAdapter/EA_network2.fbt new file mode 100644 index 000000000..813bce2cd --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/EA_network2.fbt @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/Left_EA.adp b/code/extensions/src/test/resources/results/testRevealAdapter/Left_EA.adp new file mode 100644 index 000000000..58a51047e --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/Left_EA.adp @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/Middle_EA.adp b/code/extensions/src/test/resources/results/testRevealAdapter/Middle_EA.adp new file mode 100644 index 000000000..3dacb3e9b --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/Middle_EA.adp @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/Right_EA.adp b/code/extensions/src/test/resources/results/testRevealAdapter/Right_EA.adp new file mode 100644 index 000000000..23e9bc973 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/Right_EA.adp @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealAdapter/RouterAdapter_EA.adp b/code/extensions/src/test/resources/results/testRevealAdapter/RouterAdapter_EA.adp new file mode 100644 index 000000000..f70f2f938 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealAdapter/RouterAdapter_EA.adp @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network1.fbt b/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network1.fbt new file mode 100644 index 000000000..ecd8f8460 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network1.fbt @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network2.fbt b/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network2.fbt new file mode 100644 index 000000000..b3fca0b97 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealDeclarations/EA_network2.fbt @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealDeclarations/Left_EA.adp b/code/extensions/src/test/resources/results/testRevealDeclarations/Left_EA.adp new file mode 100644 index 000000000..de082465d --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealDeclarations/Left_EA.adp @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealDeclarations/Middle_EA.adp b/code/extensions/src/test/resources/results/testRevealDeclarations/Middle_EA.adp new file mode 100644 index 000000000..848389ead --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealDeclarations/Middle_EA.adp @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/results/testRevealDeclarations/Right_EA.adp b/code/extensions/src/test/resources/results/testRevealDeclarations/Right_EA.adp new file mode 100644 index 000000000..e6acc4f19 --- /dev/null +++ b/code/extensions/src/test/resources/results/testRevealDeclarations/Right_EA.adp @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/publishSubscribes/PUBLISH_5.fbt b/code/extensions/src/test/resources/source/publishSubscribes/PUBLISH_5.fbt new file mode 100644 index 000000000..6cc72c38b --- /dev/null +++ b/code/extensions/src/test/resources/source/publishSubscribes/PUBLISH_5.fbt @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/publishSubscribes/SUBSCRIBE_5.fbt b/code/extensions/src/test/resources/source/publishSubscribes/SUBSCRIBE_5.fbt new file mode 100644 index 000000000..fb0c0dead --- /dev/null +++ b/code/extensions/src/test/resources/source/publishSubscribes/SUBSCRIBE_5.fbt @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/testRevealAdapter/BaseBlock.fbt b/code/extensions/src/test/resources/source/testRevealAdapter/BaseBlock.fbt new file mode 100644 index 000000000..686dada82 --- /dev/null +++ b/code/extensions/src/test/resources/source/testRevealAdapter/BaseBlock.fbt @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlock.fbt b/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlock.fbt new file mode 100644 index 000000000..1adf2e90f --- /dev/null +++ b/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlock.fbt @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlockWithoutConnections.fbt b/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlockWithoutConnections.fbt new file mode 100644 index 000000000..9d3dd18ff --- /dev/null +++ b/code/extensions/src/test/resources/source/testRevealAdapter/CompositeBlockWithoutConnections.fbt @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/testRevealAdapter/EA.eadp b/code/extensions/src/test/resources/source/testRevealAdapter/EA.eadp new file mode 100644 index 000000000..f86a265b3 --- /dev/null +++ b/code/extensions/src/test/resources/source/testRevealAdapter/EA.eadp @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/extensions/src/test/resources/source/testRevealDeclarations/EA.eadp b/code/extensions/src/test/resources/source/testRevealDeclarations/EA.eadp new file mode 100644 index 000000000..422fb0afc --- /dev/null +++ b/code/extensions/src/test/resources/source/testRevealDeclarations/EA.eadp @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps index e5cb9e719..697067d12 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.behavior.mps @@ -116,6 +116,7 @@ + @@ -236,8 +237,10 @@ + + @@ -961,11 +964,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -989,6 +1063,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1012,6 +1133,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1035,6 +1260,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1057,11 +1386,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1085,6 +1485,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1108,6 +1555,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1131,6 +1625,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4599,5 +5140,1740 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps index e652db39a..27c791e63 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.editor.mps @@ -4381,5 +4381,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps index 118e9d192..d926864cf 100644 --- a/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps +++ b/code/language/languages/org.fbme.ide.iec61499.lang/models/org.fbme.ide.iec61499.lang.structure.mps @@ -539,27 +539,9 @@ - - - - - - - - - - - - - - - - - - @@ -1575,5 +1557,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps index c407d7d91..9b4187a55 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.fbnetwork.mps @@ -58,6 +58,7 @@ + @@ -215,6 +216,7 @@ + @@ -234,6 +236,7 @@ + @@ -4423,7 +4426,15 @@ - + + + + + + + + + @@ -4449,9 +4460,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -4471,7 +4539,7 @@ - + @@ -4514,7 +4582,7 @@ - + @@ -4557,7 +4625,7 @@ - + @@ -4600,7 +4668,7 @@ - + @@ -4623,6 +4691,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4648,7 +4741,7 @@ - + @@ -4701,7 +4794,7 @@ - + @@ -4764,7 +4857,7 @@ - + @@ -4820,10 +4913,11 @@ + - + @@ -4856,7 +4950,6 @@ - @@ -4882,7 +4975,7 @@ - + @@ -4938,10 +5031,11 @@ + - + @@ -4974,7 +5068,6 @@ - @@ -4990,7 +5083,7 @@ - + @@ -5041,7 +5134,7 @@ - + @@ -5064,6 +5157,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5902,5 +6343,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps index 5a040de71..1bf375d8c 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.adapter.interfacepart.mps @@ -27,6 +27,7 @@ + @@ -129,6 +130,9 @@ + + + @@ -237,6 +241,7 @@ + @@ -966,11 +971,15 @@ + + + + - - + + @@ -993,8 +1002,8 @@ - - + + @@ -1004,6 +1013,12 @@ + + + + + + @@ -7660,5 +7675,1275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps index e64069bfc..9684afd45 100644 --- a/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps +++ b/code/language/solutions/org.fbme.ide.iec61499.adapter/models/org.fbme.ide.iec61499.repository.mps @@ -29,6 +29,7 @@ + @@ -93,6 +94,9 @@ + + + @@ -307,6 +311,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -445,6 +622,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4268,6 +4491,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4300,6 +4587,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt index 5cf2d46dc..12b58a4e7 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/IEC61499Factory.kt @@ -2,6 +2,8 @@ package org.fbme.lib.iec61499 import org.fbme.lib.common.Identifier import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration import org.fbme.lib.iec61499.ecc.StateAction import org.fbme.lib.iec61499.ecc.StateDeclaration import org.fbme.lib.iec61499.ecc.StateTransition @@ -13,11 +15,14 @@ import org.fbme.lib.iec61499.fbnetwork.subapp.SubapplicationDeclaration interface IEC61499Factory { fun createAdapterTypeDeclaration(identifier: Identifier?): AdapterTypeDeclaration + fun createExtendedAdapterTypeDeclaration(identifier: Identifier?): ExtendedAdapterTypeDeclaration + fun createAdapterNetworkDeclaration(identifier: Identifier?): AdapterNetworkDeclaration fun createAlgorithmDeclaration(identifier: Identifier?): AlgorithmDeclaration fun createAlgorithmBody(language: AlgorithmLanguage): BodyT fun createApplicationDeclaration(identifier: Identifier?): ApplicationDeclaration fun createBasicFBTypeDeclaration(identifier: Identifier?): BasicFBTypeDeclaration fun createCompositeFBTypeDeclaration(identifier: Identifier?): CompositeFBTypeDeclaration + fun createDeclarationWithInterfaceSection(identifier: Identifier?): DeclarationWithInterfaceSection fun createDeviceDeclaration(identifier: Identifier?): DeviceDeclaration fun createDeviceTypeDeclaration(identifier: Identifier?): DeviceTypeDeclaration fun createParameterAssignment(): ParameterAssignment diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterTypeDeclaration.kt index 13e7cc6ee..4b3f6dab6 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterTypeDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/AdapterTypeDeclaration.kt @@ -1,14 +1,13 @@ package org.fbme.lib.iec61499.declarations -import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor import org.fbme.lib.iec61499.descriptors.PlugType import org.fbme.lib.iec61499.descriptors.SocketType -interface AdapterTypeDeclaration : FBInterfaceDeclaration, Declaration, RootElement { +interface AdapterTypeDeclaration : FBInterfaceDeclaration, RootElement { val plugTypeDescriptor: FBTypeDescriptor get() = PlugType(this) val socketTypeDescriptor: FBTypeDescriptor get() = SocketType(this) -} +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DeclarationWithInterfaceSection.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DeclarationWithInterfaceSection.kt new file mode 100644 index 000000000..94db76dda --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/DeclarationWithInterfaceSection.kt @@ -0,0 +1,3 @@ +package org.fbme.lib.iec61499.declarations + +interface DeclarationWithInterfaceSection : FBInterfaceDeclaration \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/FBInterfaceDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/FBInterfaceDeclaration.kt index 14be726c8..560a7ea42 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/FBInterfaceDeclaration.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/FBInterfaceDeclaration.kt @@ -2,6 +2,7 @@ package org.fbme.lib.iec61499.declarations import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor +import org.fbme.lib.iec61499.descriptors.SocketType interface FBInterfaceDeclaration : Declaration { val inputEvents: MutableList @@ -17,8 +18,23 @@ interface FBInterfaceDeclaration : Declaration { return this.typeDescriptor } if (this is AdapterTypeDeclaration) { - return this.socketTypeDescriptor + return SocketType(this) } throw IllegalArgumentException("Unknown declaration with FB interface: " + this.javaClass.name) } + + fun isEmpty(): Boolean = inputEvents.isEmpty() && + outputEvents.isEmpty() && + inputParameters.isEmpty() && + outputParameters.isEmpty() + + fun copyEvents(declaration: FBInterfaceDeclaration) { + inputEvents += declaration.inputEvents.map { it.copy() as EventDeclaration } + outputEvents += declaration.outputEvents.map { it.copy() as EventDeclaration } + } + + fun copyParameters(declaration: FBInterfaceDeclaration) { + inputParameters += declaration.inputParameters.map { it.copy() as ParameterDeclaration } + outputParameters += declaration.outputParameters.map { it.copy() as ParameterDeclaration } + } } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/AdapterNetworkDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/AdapterNetworkDeclaration.kt new file mode 100644 index 000000000..0f26f5732 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/AdapterNetworkDeclaration.kt @@ -0,0 +1,37 @@ +package org.fbme.lib.iec61499.declarations.extention + +import org.fbme.lib.iec61499.declarations.DeclarationWithNetwork +import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor +import org.fbme.lib.iec61499.descriptors.InternalPlugType +import org.fbme.lib.iec61499.descriptors.InternalSocketType +import org.fbme.lib.iec61499.fbnetwork.CustomNetworkComponentProvider + +interface AdapterNetworkDeclaration : CustomNetworkComponentProvider, DeclarationWithNetwork { + override val container: ExtendedAdapterTypeDeclaration + + val internalFbPlugDescriptor: FBTypeDescriptor + get() = InternalPlugType(container, this) + + val internalFbSocketDescriptor: FBTypeDescriptor + get() = InternalSocketType(container, this) + + fun networkType(): NetworkType = + if (container.leftNetwork == null || container.rightNetwork == null) { + NetworkType.SINGLE + } else if (container.rightNetwork == this) { + NetworkType.RIGHT + } else if (container.leftNetwork == this) { + NetworkType.LEFT + } else { + error("Container doesn't contain this network") + } + + enum class NetworkType( + val extendSocket: Boolean, + val extendPlug: Boolean, + ) { + LEFT(true, false), + RIGHT(false, true), + SINGLE(true, true), + } +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/ExtendedAdapterTypeDeclaration.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/ExtendedAdapterTypeDeclaration.kt new file mode 100644 index 000000000..a5856f7c9 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/declarations/extention/ExtendedAdapterTypeDeclaration.kt @@ -0,0 +1,26 @@ +package org.fbme.lib.iec61499.declarations.extention + +import org.fbme.lib.iec61499.declarations.AdapterTypeDeclaration +import org.fbme.lib.iec61499.declarations.DeclarationWithInterfaceSection +import org.fbme.lib.iec61499.declarations.ParameterDeclaration +import org.fbme.lib.iec61499.descriptors.ExtendedPlugType +import org.fbme.lib.iec61499.descriptors.ExtendedSocketType +import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor + +interface ExtendedAdapterTypeDeclaration : AdapterTypeDeclaration { + var leftNetwork: AdapterNetworkDeclaration? + var rightNetwork: AdapterNetworkDeclaration? + + override val plugTypeDescriptor: FBTypeDescriptor + get() = ExtendedPlugType(this) + + override val socketTypeDescriptor: FBTypeDescriptor + get() = ExtendedSocketType(this) + + var inputRouter: ParameterDeclaration? + var outputRouter: ParameterDeclaration? + + var internalFbSocketInterface: DeclarationWithInterfaceSection? + var internalFbPlugInterface: DeclarationWithInterfaceSection? + var internalNetworksInterface: DeclarationWithInterfaceSection? +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedPlugType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedPlugType.kt new file mode 100644 index 000000000..842014e42 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedPlugType.kt @@ -0,0 +1,42 @@ +package org.fbme.lib.iec61499.descriptors + +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class ExtendedPlugType(override val myDeclaration: ExtendedAdapterTypeDeclaration) : PlugType(myDeclaration) { + override val eventInputPorts: List + get() = myDeclaration.outputEvents.asSequence() + .plus(myDeclaration.internalFbSocketInterface?.outputEvents?.asSequence() ?: sequenceOf()) + .toEventPortDescriptors(isInput = true) + .toList() + override val eventOutputPorts: List + get() = myDeclaration.inputEvents.asSequence() + .plus(myDeclaration.internalFbSocketInterface?.inputEvents?.asSequence() ?: sequenceOf()) + .toEventPortDescriptors(isInput = false) + .toList() + override val dataInputPorts: List + get() = myDeclaration.outputParameters.asSequence() + .plus(myDeclaration.internalFbSocketInterface?.outputParameters?.asSequence() ?: sequenceOf()) + .run { myDeclaration.outputRouter?.let { plus(it) } ?: this } + .toParametersPortDescriptors(isInput = true) + .toList() + override val dataOutputPorts: List + get() = myDeclaration.inputParameters.asSequence() + .plus(myDeclaration.internalFbSocketInterface?.inputParameters?.asSequence() ?: sequenceOf()) + .run { myDeclaration.inputRouter?.let { plus(it) } ?: this } + .toParametersPortDescriptors(isInput = false) + .toList() + + override fun getAssociatedVariablesForInputEvent(eventNumber: Int): List { + if (myDeclaration.inputRouter != null) { + return super.getAssociatedVariablesForInputEvent(eventNumber) + dataOutputPorts.size + } + return super.getAssociatedVariablesForInputEvent(eventNumber) + } + + override fun getAssociatedVariablesForOutputEvent(eventNumber: Int): List { + if (myDeclaration.outputRouter != null) { + return super.getAssociatedVariablesForInputEvent(eventNumber) + dataInputPorts.size + } + return super.getAssociatedVariablesForOutputEvent(eventNumber) + } +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedSocketType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedSocketType.kt new file mode 100644 index 000000000..6f86121b3 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/ExtendedSocketType.kt @@ -0,0 +1,26 @@ +package org.fbme.lib.iec61499.descriptors + +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class ExtendedSocketType(override val myDeclaration: ExtendedAdapterTypeDeclaration) : SocketType(myDeclaration) { + override val eventInputPorts: List + get() = myDeclaration.inputEvents.asSequence() + .plus(myDeclaration.internalFbPlugInterface?.outputEvents?.asSequence() ?: sequenceOf()) + .toEventPortDescriptors(isInput = true) + .toList() + override val eventOutputPorts: List + get() = myDeclaration.outputEvents.asSequence() + .plus(myDeclaration.internalFbPlugInterface?.inputEvents?.asSequence() ?: sequenceOf()) + .toEventPortDescriptors(isInput = false) + .toList() + override val dataInputPorts: List + get() = myDeclaration.inputParameters.asSequence() + .plus(myDeclaration.internalFbPlugInterface?.outputParameters?.asSequence() ?: sequenceOf()) + .toParametersPortDescriptors(isInput = true) + .toList() + override val dataOutputPorts: List + get() = myDeclaration.outputParameters.asSequence() + .plus(myDeclaration.internalFbPlugInterface?.inputParameters?.asSequence() ?: sequenceOf()) + .toParametersPortDescriptors(isInput = false) + .toList() +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/FBTypeDescriptorUtils.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/FBTypeDescriptorUtils.kt index b18a481af..8b8a7df26 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/FBTypeDescriptorUtils.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/FBTypeDescriptorUtils.kt @@ -1,7 +1,9 @@ package org.fbme.lib.iec61499.descriptors +import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.declarations.FBInterfaceDeclaration import org.fbme.lib.iec61499.declarations.FBInterfaceDeclarationWithAdapters +import org.fbme.lib.iec61499.declarations.ParameterDeclaration import org.fbme.lib.iec61499.fbnetwork.EntryKind internal object FBTypeDescriptorUtils { @@ -93,3 +95,26 @@ internal object FBTypeDescriptorUtils { return list } } + +internal fun Sequence.toEventPortDescriptors(isInput: Boolean) = mapIndexed { index, event -> + FBPortDescriptor( + name = event.name, + connectionKind = EntryKind.EVENT, + position = index, + isInput = isInput, + isValid = true, + declaration = event, + ) +} + +internal fun Sequence.toParametersPortDescriptors(isInput: Boolean) = + mapIndexed { index, event -> + FBPortDescriptor( + name = event.name, + connectionKind = EntryKind.DATA, + position = index, + isInput = isInput, + isValid = true, + declaration = event, + ) + } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalPlugType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalPlugType.kt new file mode 100644 index 000000000..1248f916e --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalPlugType.kt @@ -0,0 +1,57 @@ +package org.fbme.lib.iec61499.descriptors + +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class InternalPlugType( + override val myDeclaration: ExtendedAdapterTypeDeclaration, + private val networkDeclaration: AdapterNetworkDeclaration, +) : PlugType(myDeclaration) { + override val eventInputPorts: List + get() = myDeclaration.outputEvents.asSequence() + .plus( + if (extendPlug()) { + myDeclaration.internalFbPlugInterface?.inputEvents + } else { + myDeclaration.internalNetworksInterface?.inputEvents + }?.asSequence() ?: sequenceOf() + ) + .toEventPortDescriptors(isInput = true) + .toList() + + override val eventOutputPorts: List + get() = myDeclaration.inputEvents.asSequence() + .plus( + if (extendPlug()) { + myDeclaration.internalFbPlugInterface?.outputEvents + } else { + myDeclaration.internalNetworksInterface?.outputEvents + }?.asSequence() ?: sequenceOf() + ) + .toEventPortDescriptors(isInput = false) + .toList() + override val dataInputPorts: List + get() = myDeclaration.outputParameters.asSequence() + .plus( + if (extendPlug()) { + myDeclaration.internalFbPlugInterface?.inputParameters + } else { + myDeclaration.internalNetworksInterface?.inputParameters + }?.asSequence() ?: sequenceOf() + ) + .toParametersPortDescriptors(isInput = true) + .toList() + override val dataOutputPorts: List + get() = myDeclaration.inputParameters.asSequence() + .plus( + if (extendPlug()) { + myDeclaration.internalFbPlugInterface?.outputParameters + } else { + myDeclaration.internalNetworksInterface?.outputParameters + }?.asSequence() ?: sequenceOf() + ) + .toParametersPortDescriptors(isInput = false) + .toList() + + private fun extendPlug() = networkDeclaration.networkType().extendPlug +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalSocketType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalSocketType.kt new file mode 100644 index 000000000..58d53236f --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/InternalSocketType.kt @@ -0,0 +1,56 @@ +package org.fbme.lib.iec61499.descriptors + +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class InternalSocketType( + override val myDeclaration: ExtendedAdapterTypeDeclaration, + private val networkDeclaration: AdapterNetworkDeclaration, +) : SocketType(myDeclaration) { + override val eventInputPorts: List + get() = myDeclaration.inputEvents.asSequence() + .plus( + if (extendSocket()) { + myDeclaration.internalFbSocketInterface?.inputEvents + } else { + myDeclaration.internalNetworksInterface?.outputEvents + }?.asSequence() ?: sequenceOf() + ) + .toEventPortDescriptors(isInput = true) + .toList() + override val eventOutputPorts: List + get() = myDeclaration.outputEvents.asSequence() + .plus( + if (extendSocket()) { + myDeclaration.internalFbSocketInterface?.outputEvents + } else { + myDeclaration.internalNetworksInterface?.inputEvents + }?.asSequence() ?: sequenceOf() + ) + .toEventPortDescriptors(isInput = false) + .toList() + override val dataInputPorts: List + get() = myDeclaration.inputParameters.asSequence() + .plus( + if (extendSocket()) { + myDeclaration.internalFbSocketInterface?.inputParameters + } else { + myDeclaration.internalNetworksInterface?.outputParameters + }?.asSequence() ?: sequenceOf() + ) + .toParametersPortDescriptors(isInput = true) + .toList() + override val dataOutputPorts: List + get() = myDeclaration.outputParameters.asSequence() + .plus( + if (extendSocket()) { + myDeclaration.internalFbSocketInterface?.outputParameters + } else { + myDeclaration.internalNetworksInterface?.inputParameters + }?.asSequence() ?: sequenceOf() + ) + .toParametersPortDescriptors(isInput = false) + .toList() + + private fun extendSocket() = networkDeclaration.networkType().extendSocket +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/PlugType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/PlugType.kt index 5a22afb0a..1ebe97ca6 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/PlugType.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/PlugType.kt @@ -3,7 +3,7 @@ package org.fbme.lib.iec61499.descriptors import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.AdapterTypeDeclaration -class PlugType(private val myDeclaration: AdapterTypeDeclaration) : FBTypeDescriptor { +open class PlugType(protected open val myDeclaration: AdapterTypeDeclaration) : FBTypeDescriptor { override val typeName: String get() = myDeclaration.name override val declaration: Declaration diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/SocketType.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/SocketType.kt index c74bb4f87..50e2ecaa1 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/SocketType.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/descriptors/SocketType.kt @@ -3,7 +3,7 @@ package org.fbme.lib.iec61499.descriptors import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.AdapterTypeDeclaration -class SocketType(private val myDeclaration: AdapterTypeDeclaration) : FBTypeDescriptor { +open class SocketType(protected open val myDeclaration: AdapterTypeDeclaration) : FBTypeDescriptor { override val declaration: Declaration get() = myDeclaration override val typeName: String diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt index 77e29eadd..6d9f4ab43 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/fbnetwork/FBNetwork.kt @@ -2,10 +2,15 @@ package org.fbme.lib.iec61499.fbnetwork import org.fbme.lib.common.Declaration import org.fbme.lib.common.Element -import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.DeclarationWithNetwork +import org.fbme.lib.iec61499.declarations.EventDeclaration +import org.fbme.lib.iec61499.declarations.ParameterDeclaration import java.util.* interface FBNetwork : Element { + /*readonly*/ + val customNetworkComponents: List + /*readonly*/ val contextComponents: List @@ -54,3 +59,13 @@ interface FBNetwork : Element { } } } + +interface CustomNetworkComponentProvider { + fun getCustomNetworkComponents(): List +} + +data class CustomNetworkComponent( + val block: FunctionBlockDeclarationBase, + val associatedElement: Element, + val editable: Boolean = false, +) \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/instances/NetworkInstance.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/instances/NetworkInstance.kt index c780d4904..2ffd9d019 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/instances/NetworkInstance.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/instances/NetworkInstance.kt @@ -2,6 +2,7 @@ package org.fbme.lib.iec61499.instances import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration import org.fbme.lib.iec61499.fbnetwork.FBNetwork import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase @@ -61,6 +62,12 @@ interface NetworkInstance : Instance { return RegularNetworkInstance(parent, networkDeclaration, device) } + @JvmStatic + fun createForAdapterNetwork(adapterNetworkDeclaration: AdapterNetworkDeclaration, parent: Instance?): NetworkInstance { + val networkDeclaration = adapterNetworkDeclaration.network + return RegularNetworkInstance(parent, networkDeclaration, adapterNetworkDeclaration) + } + @JvmStatic @JvmOverloads fun createForDeclaration(declaration: Declaration, parent: Instance? = null): NetworkInstance { @@ -76,6 +83,7 @@ interface NetworkInstance : Instance { is ApplicationDeclaration -> createForApplication(decl, parent) is ResourceDeclaration -> createForResource(decl, parent) is DeviceDeclaration -> createForImplicitResourceOfDevice(decl, parent) + is AdapterNetworkDeclaration -> createForAdapterNetwork(decl, parent) else -> throw IllegalArgumentException("Unknown kind of declaration: " + decl!!.javaClass) } } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/AdapterTypeConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/AdapterTypeConverter.kt index 5de0d80a4..70023c835 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/AdapterTypeConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/AdapterTypeConverter.kt @@ -3,7 +3,7 @@ package org.fbme.lib.iec61499.parser import org.fbme.lib.common.Identifier import org.fbme.lib.iec61499.declarations.AdapterTypeDeclaration -class AdapterTypeConverter(arguments: ConverterArguments) : +open class AdapterTypeConverter(arguments: ConverterArguments) : DeclarationConverterBase(arguments) { override fun extractDeclarationBody(identifier: Identifier?): AdapterTypeDeclaration { val declaration = factory.createAdapterTypeDeclaration(identifier) diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/ExtendedAdapterTypeConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/ExtendedAdapterTypeConverter.kt new file mode 100644 index 000000000..10444a089 --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/ExtendedAdapterTypeConverter.kt @@ -0,0 +1,66 @@ +package org.fbme.lib.iec61499.parser + +import org.fbme.lib.common.Identifier +import org.fbme.lib.iec61499.declarations.DeclarationWithInterfaceSection +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.jdom.Element + +class ExtendedAdapterTypeConverter(arguments: ConverterArguments) + : DeclarationConverterBase(arguments) { + override fun extractDeclarationBody(identifier: Identifier?): ExtendedAdapterTypeDeclaration { + val declaration = factory.createExtendedAdapterTypeDeclaration(identifier) + FBInterfaceConverter(this, declaration).extractInterface() + val element = checkNotNull(element) + declaration.leftNetwork = extractNetwork(element.getChild("leftNetwork")) + declaration.rightNetwork = extractNetwork(element.getChild("rightNetwork")) + extractRouters(element, declaration) + extractInternalInterfaces(element, declaration) + return declaration + } + + private fun extractNetwork(element: Element?): AdapterNetworkDeclaration? { + if (element == null) { + return null + } + val identifier = identifierLocus.onDeclarationEntered(element) + try { + val network = factory.createAdapterNetworkDeclaration(identifier) + FBNetworkConverter(with(element.getChild("FBNetwork")), network.network).extractNetwork() + network.name = element.getAttributeValue("Name") + return network + } finally { + identifierLocus.onDeclarationLeaved() + } + } + private fun extractInternalInterfaces(element: Element, declaration: ExtendedAdapterTypeDeclaration) { + declaration.internalFbSocketInterface = + extractDeclarationWithInterfaceSection(element.getChild("internalFbSocketInterface")) + declaration.internalFbPlugInterface = + extractDeclarationWithInterfaceSection(element.getChild("internalFbPlugInterface")) + declaration.internalNetworksInterface = + extractDeclarationWithInterfaceSection(element.getChild("internalNetworksInterface")) + } + + private fun extractRouters(element: Element, declaration: ExtendedAdapterTypeDeclaration) { + declaration.inputRouter = extractParameter(element, "inputRouter") + declaration.outputRouter = extractParameter(element, "outputRouter") + } + + private fun extractParameter(element: Element, fieldName: String) = element.getChild(fieldName)?.let { + ParameterDeclarationConverter(with(it.getChildren("VarDeclaration").first())).extract() + } + + private fun extractDeclarationWithInterfaceSection( + element: Element?, + ): DeclarationWithInterfaceSection? = element?.let { + val identifier = identifierLocus.onDeclarationEntered(it) + try { + val interfaceSection = factory.createDeclarationWithInterfaceSection(identifier) + FBInterfaceConverter(this.with(it), interfaceSection).extractInterface() + interfaceSection + } finally { + identifierLocus.onDeclarationLeaved() + } + } +} \ No newline at end of file diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt index d6d5e1139..f9ebd3090 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/parser/RootConverter.kt @@ -1,6 +1,7 @@ package org.fbme.lib.iec61499.parser import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration import org.jdom.Document class RootConverter( @@ -24,6 +25,10 @@ class RootConverter( return AdapterTypeConverter(arguments()).extract() } + fun convertExtendedAdapterType(): ExtendedAdapterTypeDeclaration { + return ExtendedAdapterTypeConverter(arguments()).extract() + } + fun convertSubapplicationType(): SubapplicationTypeDeclaration { return SubappTypeConverter(arguments()).extract() } diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/ExtendedAdapterTypePrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/ExtendedAdapterTypePrinter.kt new file mode 100644 index 000000000..0904c9d4e --- /dev/null +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/ExtendedAdapterTypePrinter.kt @@ -0,0 +1,58 @@ +package org.fbme.lib.iec61499.stringify + +import org.fbme.lib.iec61499.declarations.DeclarationWithInterfaceSection +import org.fbme.lib.iec61499.declarations.ParameterDeclaration +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.jdom.Element + +class ExtendedAdapterTypePrinter(declaration: ExtendedAdapterTypeDeclaration) : + DeclarationPrinterBase(declaration, "ExtendedAdapterType") { + override fun printDeclarationBody(element: Element) { + element.addContent(FBInterfacePrinter(this.element, false).print()) + printNetwork(element, "leftNetwork", this.element.leftNetwork) + printNetwork(element, "rightNetwork", this.element.rightNetwork) + printParameter(element, "inputRouter", this.element.inputRouter) + printParameter(element, "outputRouter", this.element.outputRouter) + printInternalInterfaces(element, this.element) + } + + private fun printNetwork(element: Element, name: String, network: AdapterNetworkDeclaration?) { + if (network == null) { + return + } + element.addContent( + Element(name).addContent(FBNetworkPrinter(network.network).print()) + .setAttribute("Name", network.name) + ) + } + + private fun printInternalInterfaces(element: Element, declaration: ExtendedAdapterTypeDeclaration) { + addNullableContent( + element, + printDeclarationWithInterface(declaration.internalFbSocketInterface, "internalFbSocketInterface"), + ) + addNullableContent( + element, + printDeclarationWithInterface(declaration.internalFbPlugInterface, "internalFbPlugInterface"), + ) + addNullableContent( + element, + printDeclarationWithInterface(declaration.internalNetworksInterface, "internalNetworksInterface"), + ) + } + + private fun printDeclarationWithInterface( + fbInterface: DeclarationWithInterfaceSection?, + name: String, + ) = fbInterface?.let { + val child = Element(name) + child.addContent(FBInterfacePrinter(fbInterface, false).print()) + .setAttribute("Name", name) + } + + private fun printParameter(root: Element, parameterElementName: String, declaration: ParameterDeclaration?) { + val createdElement = ParameterDeclarationPrinter.printAll(parameterElementName, listOfNotNull(declaration)) + addNullableContent(root, createdElement) + } +} diff --git a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt index 948987ec4..6e5eb4223 100644 --- a/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt +++ b/code/library/src/main/kotlin/org/fbme/lib/iec61499/stringify/RootDeclarationPrinter.kt @@ -2,6 +2,7 @@ package org.fbme.lib.iec61499.stringify import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration import org.jdom.DocType import org.jdom.Document import org.jdom.Element @@ -9,6 +10,7 @@ import org.jdom.Element class RootDeclarationPrinter(private val myDeclaration: Declaration) { fun print(): Document { val rootElement: Element = when (myDeclaration) { + is ExtendedAdapterTypeDeclaration -> ExtendedAdapterTypePrinter(myDeclaration).print() is AdapterTypeDeclaration -> AdapterTypePrinter(myDeclaration).print() is BasicFBTypeDeclaration -> BasicFBTypePrinter(myDeclaration).print() is CompositeFBTypeDeclaration -> CompositeFBTypePrinter(myDeclaration).print() diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt index 02e5e0ebc..3bd71abf5 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/persistence/Iec61499ModelFactory.kt @@ -27,6 +27,7 @@ import org.fbme.ide.platform.converter.PlatformConverter.create import org.fbme.lib.common.Declaration import org.fbme.lib.common.RootElement import org.fbme.lib.iec61499.declarations.* +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration import org.fbme.lib.iec61499.stringify.RootDeclarationPrinter import org.jdom.Document import org.jetbrains.mps.openapi.model.SModel @@ -48,6 +49,7 @@ import java.util.stream.Collectors class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { private fun supportedFileExtension(fileExt: String): Boolean { return fileExt == FBT_FILE_EXT + || fileExt == EXT_ADP_FILE_EXT || fileExt == ADP_FILE_EXT || fileExt == SUB_FILE_EXT || fileExt == RES_FILE_EXT @@ -306,6 +308,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { const val FBT_FILE_EXT = "fbt" const val ADP_FILE_EXT = "adp" + const val EXT_ADP_FILE_EXT = "eadp" const val SUB_FILE_EXT = "app" const val RES_FILE_EXT = "res" const val DEV_FILE_EXT = "dev" @@ -338,6 +341,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { val converter = create(owner, reference, doc) return when (fileExtension) { FBT_FILE_EXT -> (converter.convertFBType() as PlatformElement).node + EXT_ADP_FILE_EXT -> (converter.convertExtendedAdapterType() as PlatformElement).node ADP_FILE_EXT -> (converter.convertAdapterType() as PlatformElement).node SUB_FILE_EXT -> (converter.convertSubapplicationType() as PlatformElement).node RES_FILE_EXT -> (converter.convertResourceType() as PlatformElement).node @@ -352,6 +356,7 @@ class Iec61499ModelFactory : ModelFactory, DataLocationAwareModelFactory { val element = owner.getAdapter(node, RootElement::class.java) return when (element) { is FBTypeDeclaration -> FBT_FILE_EXT + is ExtendedAdapterTypeDeclaration -> EXT_ADP_FILE_EXT is AdapterTypeDeclaration -> ADP_FILE_EXT is SubapplicationTypeDeclaration -> SUB_FILE_EXT is ResourceTypeDeclaration -> RES_FILE_EXT diff --git a/code/platform/src/main/kotlin/org/fbme/ide/platform/testing/PlatformTestBase.kt b/code/platform/src/main/kotlin/org/fbme/ide/platform/testing/PlatformTestBase.kt index c72827685..c4e74a838 100644 --- a/code/platform/src/main/kotlin/org/fbme/ide/platform/testing/PlatformTestBase.kt +++ b/code/platform/src/main/kotlin/org/fbme/ide/platform/testing/PlatformTestBase.kt @@ -17,6 +17,7 @@ import org.fbme.lib.iec61499.IEC61499Factory import org.fbme.lib.iec61499.parser.IdentifierLocus import org.fbme.lib.iec61499.parser.RootConverter import org.fbme.lib.st.STFactory +import org.jdom.Document import org.jdom.Element import org.jdom.JDOMException import org.jetbrains.mps.openapi.model.SModel @@ -44,6 +45,9 @@ abstract class PlatformTestBase { fun rootConverterByPath(input: String, config: PlatformConverter.DefaultConfigurationFactory) = createConverter(requireNotNull(this::class.java.getResourceAsStream(input)), config) + fun createDocumentByPath(input: String): Document = + JDOMUtil.loadDocument(requireNotNull(this::class.java.getResourceAsStream(input))) + private fun createConverter(stream: InputStream): RootConverter { return createConverter(stream, null) } diff --git a/code/platform/src/test/kotlin/org/fbme/ide/platform/adapters/IEC61499FactoryTest.kt b/code/platform/src/test/kotlin/org/fbme/ide/platform/adapters/IEC61499FactoryTest.kt index 45805a3fd..3dfca06e2 100644 --- a/code/platform/src/test/kotlin/org/fbme/ide/platform/adapters/IEC61499FactoryTest.kt +++ b/code/platform/src/test/kotlin/org/fbme/ide/platform/adapters/IEC61499FactoryTest.kt @@ -16,6 +16,14 @@ class IEC61499FactoryTest : PlatformTestBase() { Assert.assertEquals("TestAdapterTypeDeclaration", element.name) } + @Test + fun createExtendedAdapterTypeDeclaration() { + val identifier = StringIdentifier("TestExtendedAdapterTypeDeclaration") + val element = factory.createExtendedAdapterTypeDeclaration(identifier) + Assert.assertNotNull(element) + Assert.assertEquals("TestExtendedAdapterTypeDeclaration", element.name) + } + @Test fun createAlgorithmDeclaration() { val identifier = StringIdentifier("TestAlgorithmDeclaration") diff --git a/code/richediting/build.gradle.kts b/code/richediting/build.gradle.kts index 38f9d91e8..4403a2565 100644 --- a/code/richediting/build.gradle.kts +++ b/code/richediting/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { compileOnly(project(":code:language")) compileOnly(project(":code:platform")) + implementation(project(":code:extensions")) implementation("org.eclipse.elk:org.eclipse.elk.alg.layered:0.7.1") implementation("org.eclipse.elk:org.eclipse.elk.core:0.7.1") implementation("org.eclipse.elk:org.eclipse.elk.graph:0.7.1") diff --git a/code/richediting/languages/org.fbme.ide.richediting.lang/models/org.fbme.ide.richediting.lang.editor.mps b/code/richediting/languages/org.fbme.ide.richediting.lang/models/org.fbme.ide.richediting.lang.editor.mps index a9894c0b9..12556403f 100644 --- a/code/richediting/languages/org.fbme.ide.richediting.lang/models/org.fbme.ide.richediting.lang.editor.mps +++ b/code/richediting/languages/org.fbme.ide.richediting.lang/models/org.fbme.ide.richediting.lang.editor.mps @@ -2070,7 +2070,6 @@ - @@ -2078,97 +2077,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + @@ -3173,5 +3086,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps b/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps index f9cc459f5..759653d8e 100644 --- a/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps +++ b/code/richediting/solutions/org.fbme.ide.richediting/models/org.fbme.ide.richediting.plugin.mps @@ -48,8 +48,8 @@ + - diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealAllExtendedAdaptersAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealAllExtendedAdaptersAction.kt new file mode 100644 index 000000000..9fb2f1e29 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealAllExtendedAdaptersAction.kt @@ -0,0 +1,52 @@ +package org.fbme.ide.richediting.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAware +import jetbrains.mps.extapi.persistence.ModelFactoryService +import jetbrains.mps.ide.actions.MPSCommonDataKeys +import jetbrains.mps.ide.dialogs.project.creation.ModelCreateHelper +import jetbrains.mps.model.ModelDeleteHelper +import jetbrains.mps.project.AbstractModule +import jetbrains.mps.project.MPSProject +import org.fbme.extensions.adapter.AdapterRevealService +import org.jetbrains.mps.openapi.model.EditableSModel +import org.jetbrains.mps.openapi.model.SModel +import org.jetbrains.mps.openapi.model.SModelName + +class RevealAllExtendedAdaptersAction : AnAction(), DumbAware { + override fun update(event: AnActionEvent) = event.executeReadAction { + val model = event.getData(MPSCommonDataKeys.CONTEXT_MODEL) + event.presentation.isEnabledAndVisible = model != null + } + + override fun actionPerformed(event: AnActionEvent) = event.executeWriteActionInEditor { + val model = event.getRequiredData(MPSCommonDataKeys.CONTEXT_MODEL) + val project = event.getRequiredData(MPSCommonDataKeys.MPS_PROJECT) + val adapterRevealService = AdapterRevealService(owner = event.repository) + val modelCopy = copyModel(model, project, "${model.name}_extensions_revealed") + adapterRevealService.revealModel(modelCopy) + } +} + +internal fun copyModel( + source: SModel, + project: MPSProject, + newName: String, +): EditableSModel { + val newSModelName = SModelName(newName) + val existedModule = source.module.models.firstOrNull { it.name == newSModelName } + if (existedModule != null) { + ModelDeleteHelper(existedModule).delete() + } + val modelCopy = ModelCreateHelper( + project, + source.module as AbstractModule, + newSModelName, + source.modelRoot, + project.getComponent(ModelFactoryService::class.java).factoryTypes.first(), + ) + .setClone(source, false) + .createModel() + return modelCopy +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealExtendedAdapterAction.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealExtendedAdapterAction.kt new file mode 100644 index 000000000..a7ddd817a --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/RevealExtendedAdapterAction.kt @@ -0,0 +1,36 @@ +package org.fbme.ide.richediting.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAware +import jetbrains.mps.ide.actions.MPSCommonDataKeys +import jetbrains.mps.project.MPSProject +import org.fbme.extensions.adapter.AdapterRevealService +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class RevealExtendedAdapterAction : AnAction(), DumbAware { + override fun update(event: AnActionEvent) = event.executeReadAction { + val repository = event.repository + val node = event.getData(MPSCommonDataKeys.NODE) + val adapterTypeDeclaration = node?.let { + repository.adapterOrNull(node) + } + event.presentation.isEnabledAndVisible = adapterTypeDeclaration != null + } + + override fun actionPerformed(event: AnActionEvent) = event.executeWriteActionInEditor { + val repository = event.repository + val node = event.getData(MPSCommonDataKeys.NODE) + val model = event.getRequiredData(MPSCommonDataKeys.CONTEXT_MODEL) + val project: MPSProject = event.getRequiredData(MPSCommonDataKeys.MPS_PROJECT) + + val extendedAdapter = node?.let { + repository.adapterOrNull(node) + } ?: return@executeWriteActionInEditor + val adapterRevealService = AdapterRevealService(owner = repository) + val modelCopy = copyModel(model, project, "${model.name}_extensions_revealed") + val nodeCopy = modelCopy.rootNodes.first { it.name == extendedAdapter.name } + val extendedAdapterCopy = repository.adapter(nodeCopy) + adapterRevealService.revealAdapter(extendedAdapterCopy, modelCopy) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/SyncSystemResources.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/SyncSystemResources.kt new file mode 100644 index 000000000..2c3f49966 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/actions/SyncSystemResources.kt @@ -0,0 +1,25 @@ +package org.fbme.ide.richediting.actions + +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAware +import jetbrains.mps.ide.actions.MPSCommonDataKeys +import org.fbme.extensions.adapter.AdapterRevealApi +import org.fbme.extensions.adapter.AdapterRevealService +import org.fbme.lib.iec61499.declarations.SystemDeclaration + +class SyncSystemResources : AnAction(), DumbAware { + override fun update(event: AnActionEvent) = event.executeReadAction { + val systemDeclaration = event.element() + event.presentation.isEnabledAndVisible = systemDeclaration != null + } + + override fun actionPerformed(event: AnActionEvent) = event.executeWriteActionInEditor { + val model = event.getRequiredData(MPSCommonDataKeys.CONTEXT_MODEL) + + val systemDeclaration = event.element() + ?: return@executeWriteActionInEditor + val adapterRevealApi: AdapterRevealApi = AdapterRevealService(owner = event.repository) + adapterRevealApi.syncApplicationResources(systemDeclaration, model) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCEditors.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCEditors.kt index cbc5332bb..e375105ba 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCEditors.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/ecc/ECCEditors.kt @@ -13,9 +13,6 @@ import org.fbme.ide.richediting.editor.RichEditorStyleAttributes import org.fbme.ide.richediting.inspections.ECCInspectionsFacility import org.fbme.lib.common.Declaration import org.fbme.lib.iec61499.IEC61499Factory -import org.fbme.lib.iec61499.declarations.AlgorithmDeclaration -import org.fbme.lib.iec61499.declarations.BasicFBTypeDeclaration -import org.fbme.lib.iec61499.declarations.EventDeclaration import org.fbme.lib.iec61499.ecc.ECC import org.fbme.lib.iec61499.ecc.StateAction import org.fbme.lib.iec61499.ecc.StateDeclaration @@ -154,7 +151,8 @@ object ECCEditors { return object : ConnectionControllerFactory { override fun create( context: EditorContext, - view: StateTransition + view: StateTransition, + sourceConnectionNumber: Int? ): ConnectionController { val transitionNode = (view as PlatformElement).node val cell = createTransitionCell(context, transitionNode) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt index 27fe94e7c..0b1aea85c 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBConnectionController.kt @@ -8,6 +8,7 @@ import jetbrains.mps.nodeEditor.cells.EditorCell_Collection import jetbrains.mps.openapi.editor.EditorContext import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory import org.fbme.ide.richediting.adapters.fbnetwork.fb.DiagramColors +import org.fbme.extensions.adapter.ExtendedAdapterUtils import org.fbme.ide.richediting.viewmodel.NetworkConnectionView import org.fbme.lib.iec61499.fbnetwork.ConnectionPath import org.fbme.lib.iec61499.fbnetwork.EntryKind @@ -24,8 +25,12 @@ import kotlin.math.abs import kotlin.math.max import kotlin.math.min -class FBConnectionController(context: EditorContext, view: NetworkConnectionView) : - ConnectionController { +class FBConnectionController( + context: EditorContext, + view: NetworkConnectionView, + private val sourceConnectionNumber: Int?, +) : ConnectionController { + private val isExtendedAdapter: Boolean private val kind: EntryKind private val isEditable: Boolean private val fakeCell: EditorCell_Collection @@ -47,13 +52,26 @@ class FBConnectionController(context: EditorContext, view: NetworkConnectionView g.color = highlightColor painter.paint(g, false) } - g.color = DiagramColors.getColorFor(kind, isEditable) + g.color = if (isExtendedAdapter) { + DiagramColors.EXTENDED_ADAPTER + } else { + DiagramColors.getColorFor(kind, isEditable) + } if (selected) { FBConnectionPathPainter.setupSelectedPathPaint(g, scale(1).toFloat()) } else { FBConnectionPathPainter.setupRegularPathPaint(g, scale(1).toFloat()) } painter.paint(g, selected) + val printConnectionNumber = when (kind) { + EntryKind.EVENT, EntryKind.DATA -> false + EntryKind.ADAPTER -> true + } + if (sourceConnectionNumber != null && printConnectionNumber) { + val point = path.targetPosition + g.color = g.color.brighter() + g.drawString(sourceConnectionNumber.toString(), point.x - 10, point.y) + } } override fun paintTrace(path: FBConnectionPath, graphics: Graphics) { @@ -458,6 +476,7 @@ class FBConnectionController(context: EditorContext, view: NetworkConnectionView kind = view.kind isEditable = view.isEditable val associatedNode = view.associatedNode + isExtendedAdapter = view.connection?.let { ExtendedAdapterUtils.isExtendedAdapterConnection(it) } ?: false fakeCell = FakeCells.createCollection(context, associatedNode) val connectionPaths: Iterator = SNodeOperations.ofConcept(SNodeOperations.getChildren(associatedNode), CONCEPTS.`ConnectionPath$IA`) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt index f1c24488d..12de05a91 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/FBNetworkEditors.kt @@ -39,11 +39,13 @@ object FBNetworkEditors { object : ConnectionControllerFactory { override fun create( context: EditorContext, - view: NetworkConnectionView + view: NetworkConnectionView, + sourceConnectionNumber: Int?, ): ConnectionController { return FBConnectionController( context, - view + view, + sourceConnectionNumber, ) } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/DiagramColors.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/DiagramColors.kt index 834e16790..7c3270a00 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/DiagramColors.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/adapters/fbnetwork/fb/DiagramColors.kt @@ -20,6 +20,9 @@ object DiagramColors { @JvmField val ADAPTER = Color(0xEE8822) + @JvmField + val EXTENDED_ADAPTER: Color = Color.RED + @JvmField val EVENT_RO = Color(0x88AACC) diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichAdapterNetworkProjectionController.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichAdapterNetworkProjectionController.kt new file mode 100644 index 000000000..725fb4092 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/RichAdapterNetworkProjectionController.kt @@ -0,0 +1,57 @@ +package org.fbme.ide.richediting.editor + +import jetbrains.mps.project.Project +import org.fbme.ide.iec61499.fbnetwork.MPSNetworkInstanceReference +import org.fbme.ide.iec61499.repository.PlatformRepository +import org.fbme.ide.iec61499.repository.PlatformRepositoryProvider +import org.fbme.ide.platform.editor.EditorProjection +import org.fbme.ide.platform.editor.EditorProjectionController +import org.fbme.lib.iec61499.declarations.extention.AdapterNetworkDeclaration +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration +import org.fbme.lib.iec61499.instances.NetworkInstance +import org.jdom.Element +import org.jetbrains.mps.openapi.model.SNode + +class RichAdapterNetworkProjectionController( + private val node: SNode, + private val project: Project, + left: Boolean, + override val id: String, +) : EditorProjectionController { + private val repository: PlatformRepository = PlatformRepositoryProvider.getInstance(project) + private val adapterType: ExtendedAdapterTypeDeclaration = repository.adapter(node) + private val networkDeclaration: AdapterNetworkDeclaration? = + if (left) adapterType.leftNetwork else adapterType.rightNetwork + + override val priority: Int get() = 1 + + override fun createProjection(name: String): EditorProjection { + return if (name == id) { + createProjectionInternal(name) + } else { + throw IllegalArgumentException("Unsupported projection") + } + } + + override fun restoreProjection(name: String, e: Element): EditorProjection { + if (name == id) { + val ref = e.getAttributeValue(NetworkInstanceEditorProjection.PERSISTENCE_KEY) + val declaration = networkDeclaration + val instance = when { + ref != null -> MPSNetworkInstanceReference.deserialize(ref).resolve(repository) + declaration != null -> NetworkInstance.createForDeclaration(declaration) + else -> error("Declaration is null") + } + return NetworkInstanceEditorProjection(node, this, name, instance!!, project) + } else { + throw IllegalArgumentException("Unsupported projection") + } + } + + private fun createProjectionInternal(name: String): NetworkInstanceEditorProjection { + val instance = NetworkInstance.createForDeclaration( + networkDeclaration ?: error("Declaration is null") + ) + return NetworkInstanceEditorProjection(node, this, name, instance, project) + } +} diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterLeftNetworkControllerProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterLeftNetworkControllerProvider.kt new file mode 100644 index 000000000..8df66a2f1 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterLeftNetworkControllerProvider.kt @@ -0,0 +1,23 @@ +package org.fbme.ide.richediting.editor.providers + +import jetbrains.mps.project.Project +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.platform.editor.EditorProjectionController +import org.fbme.ide.platform.editor.EditorProjectionControllerProvider +import org.fbme.ide.richediting.editor.RichAdapterNetworkProjectionController +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class AdapterLeftNetworkControllerProvider: EditorProjectionControllerProvider("Left Network") { + override fun isApplicable(element: PlatformElement): Boolean { + return (element as? ExtendedAdapterTypeDeclaration)?.leftNetwork != null + } + + override fun create(element: PlatformElement, project: Project): EditorProjectionController { + return RichAdapterNetworkProjectionController( + element.node, + project, + left = true, + id = "Left Network", + ) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterRightNetworkControllerProvider.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterRightNetworkControllerProvider.kt new file mode 100644 index 000000000..82dafc335 --- /dev/null +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/editor/providers/AdapterRightNetworkControllerProvider.kt @@ -0,0 +1,23 @@ +package org.fbme.ide.richediting.editor.providers + +import jetbrains.mps.project.Project +import org.fbme.ide.iec61499.repository.PlatformElement +import org.fbme.ide.platform.editor.EditorProjectionController +import org.fbme.ide.platform.editor.EditorProjectionControllerProvider +import org.fbme.ide.richediting.editor.RichAdapterNetworkProjectionController +import org.fbme.lib.iec61499.declarations.extention.ExtendedAdapterTypeDeclaration + +class AdapterRightNetworkControllerProvider: EditorProjectionControllerProvider("Left Network") { + override fun isApplicable(element: PlatformElement): Boolean { + return (element as? ExtendedAdapterTypeDeclaration)?.rightNetwork != null + } + + override fun create(element: PlatformElement, project: Project): EditorProjectionController { + return RichAdapterNetworkProjectionController( + element.node, + project, + left = false, + id = "Right Network", + ) + } +} \ No newline at end of file diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt index 1c6b08c02..34f4a570c 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/FunctionBlockView.kt @@ -5,10 +5,12 @@ import org.fbme.lib.iec61499.descriptors.FBTypeDescriptor import org.fbme.lib.iec61499.fbnetwork.FunctionBlockDeclarationBase import org.jetbrains.mps.openapi.model.SNode -class FunctionBlockView(val component: FunctionBlockDeclarationBase, isEditable: Boolean) : NetworkComponentView { +class FunctionBlockView( + val component: FunctionBlockDeclarationBase, + override val isEditable: Boolean, val associatedNode: SNode = (component as PlatformElement).node +) : NetworkComponentView { private val myTypeDescriptor: TypeDescriptorAdapter - override val isEditable: Boolean val type: FBTypeDescriptor get() = myTypeDescriptor @@ -31,6 +33,5 @@ class FunctionBlockView(val component: FunctionBlockDeclarationBase, isEditable: init { myTypeDescriptor = TypeDescriptorAdapter(component.type) - this.isEditable = isEditable } } diff --git a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt index ce3af9c34..297ab5393 100644 --- a/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt +++ b/code/richediting/src/main/kotlin/org/fbme/ide/richediting/viewmodel/NetworkView.kt @@ -1,5 +1,6 @@ package org.fbme.ide.richediting.viewmodel +import org.fbme.ide.iec61499.repository.PlatformElement import org.fbme.lib.common.Declaration import org.fbme.lib.common.Element import org.fbme.lib.iec61499.IEC61499Factory @@ -16,7 +17,7 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: private val myAuxComponents: MutableMap> = HashMap() private val myComponentToPorts: MutableMap> = HashMap() private val myPorts: MutableMap = HashMap() - private val myConnectionSources: MutableMap = HashMap() + private val myConnectionSources: MutableMap = LinkedHashMap() private val myConnectionDestinations: MutableMap = HashMap() private val myElementModelMap: MutableMap = HashMap() private val myPortModelMap: MutableMap?, NetworkPortView> = HashMap() @@ -44,6 +45,16 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: } private fun initFBs(network: FBNetwork, editable: Boolean) { + for (component in network.customNetworkComponents) { + addFunctionBlock( + functionBlock = component.block, + view = FunctionBlockView( + component = component.block, + isEditable = component.editable, + associatedNode = (component.associatedElement as PlatformElement).node + ) + ) + } for (functionBlock in network.functionBlocks) { addFunctionBlock(functionBlock, editable) } @@ -140,8 +151,15 @@ class NetworkView(private val myFactory: IEC61499Factory, private val myNetwork: myComponentToPorts[view] = setOf(view) } - private fun addFunctionBlock(functionBlock: FunctionBlockDeclarationBase, editable: Boolean) { - val view = FunctionBlockView(functionBlock, editable) + private fun addFunctionBlock( + functionBlock: FunctionBlockDeclarationBase, + editable: Boolean + ) = addFunctionBlock(functionBlock, FunctionBlockView(functionBlock, editable)) + + private fun addFunctionBlock( + functionBlock: FunctionBlockDeclarationBase, + view: FunctionBlockView, + ) { myElementModelMap[functionBlock] = view myMainComponents.add(view) val type = functionBlock.type diff --git a/code/richediting/src/main/resources/META-INF/plugin.xml b/code/richediting/src/main/resources/META-INF/plugin.xml index 561b0538d..3b8dfad91 100644 --- a/code/richediting/src/main/resources/META-INF/plugin.xml +++ b/code/richediting/src/main/resources/META-INF/plugin.xml @@ -59,11 +59,24 @@ + + + + + { - fun create(context: EditorContext, view: ViewT): ConnectionController + fun create(context: EditorContext, view: ViewT, sourceConnectionNumber: Int?): ConnectionController } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt index 057c0c25e..6b06e3ee3 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionEntry.kt @@ -5,10 +5,15 @@ import java.awt.Rectangle internal class ConnectionEntry( private val connectionsFacility: ConnectionsFacility, - val connection: ConnT + val connection: ConnT, + sourceConnectionNumber: Int?, ) { val controller: ConnectionController = - connectionsFacility.controllerFactory.create(connectionsFacility.scene.editorContext, connection) + connectionsFacility.controllerFactory.create( + context = connectionsFacility.scene.editorContext, + view = connection, + sourceConnectionNumber = sourceConnectionNumber, + ) private val pathProvider: (Point, Point) -> PathT = connectionsFacility.connectionSynchronizer.getPath(connection) var modelPath: PathT var transformedPath: PathT? = null diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt index 02bf1050c..92611650d 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/ConnectionsFacility.kt @@ -59,9 +59,16 @@ class ConnectionsFacility( } private fun init() { - val viewConnections = diagramController.connections - for (connection in viewConnections) { - connections[connection] = ConnectionEntry(this@ConnectionsFacility, connection) + val sourcesConnectionsCount = diagramController.connections.groupBy { connection -> + diagramController.getSource(connection) + } + sourcesConnectionsCount.forEach { (_, controllerConnections) -> + val hasMultipleConnections = controllerConnections.size > 1 + for (i in controllerConnections.indices) { + val number = if (hasMultipleConnections) i else null + val connection = controllerConnections[i] + connections[connection] = ConnectionEntry(this@ConnectionsFacility, connection, number) + } } } diff --git a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt index 0b25ab078..8883cafe0 100644 --- a/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt +++ b/code/scenes/src/main/kotlin/org/fbme/scenes/controllers/diagram/DiagramFacility.kt @@ -9,7 +9,7 @@ class DiagramFacility( private val componentSettings: DiagramComponentSettingProvider ) { private val components: MutableSet = HashSet() - private val edges: MutableSet = HashSet() + private val edges: MutableSet = LinkedHashSet() private val componentToPorts: MutableMap> = HashMap() private val portToComponent: MutableMap = HashMap() private val connectionToSource: MutableMap = HashMap() diff --git a/docs/images/extended-adapter/ea-usage.png b/docs/images/extended-adapter/ea-usage.png new file mode 100644 index 000000000..84403deeb Binary files /dev/null and b/docs/images/extended-adapter/ea-usage.png differ diff --git a/docs/images/extended-adapter/internal-networks-interfaces.png b/docs/images/extended-adapter/internal-networks-interfaces.png new file mode 100644 index 000000000..74dcc307c Binary files /dev/null and b/docs/images/extended-adapter/internal-networks-interfaces.png differ diff --git a/docs/images/extended-adapter/plug-example.png b/docs/images/extended-adapter/plug-example.png new file mode 100644 index 000000000..60763e508 Binary files /dev/null and b/docs/images/extended-adapter/plug-example.png differ diff --git a/docs/images/extended-adapter/router-fields.png b/docs/images/extended-adapter/router-fields.png new file mode 100644 index 000000000..070b41ad4 Binary files /dev/null and b/docs/images/extended-adapter/router-fields.png differ diff --git a/docs/pages/extended-adapter.md b/docs/pages/extended-adapter.md new file mode 100644 index 000000000..d21fb0c54 --- /dev/null +++ b/docs/pages/extended-adapter.md @@ -0,0 +1,47 @@ + +# Extended adapter + +Adapter extension allows to implement dynamic connections between components and +add additional internal logic(internal fb networks) to the adapter declaration. + +A new extended adapter type can be created like other elements, +and added to the socket and plug sections for other blocks, such as a common adapter. + +You can convert a model that uses extended adapters to standard elements by selecting the +"Convert Extended Adapters to Standard Elements" option from the context menu. +As a result a copy of the current model will be created with suffix name "_extensions_revealed". +Networks that use extended adapters will be modified, and new models on the connection path will be added. +The new generated models will be stored in a directory with the prefix "generated". + +Also, in the system module you can select the "Synchronize System Resources" action, which will reveal +all broken connections of the extended adapter type halfway in the resources and add publish/subscribe blocks. +If a broken connection has any connections in the resource it will not be modified. + +## Dynamic adapter + +Dynamic connection allows you to connect a plug with multiple sockets and choose at runtime which socket will receive message. +Sockets in dynamic connections are numbered. + +ea usage example + +To use dynamic adapter connections, data parameter "Input router" should be added with type INT in the adapter declaration. +Additionally, a parameter "Output router" should be defined to receive the number of socket that sent a message to plug. + +routers fields + +These parameters appear in the plug and can be used in a similar way to other parameters. + +plug example + +## Adapter with internal networks + +There are two fields that can be used to create an internal network in the adapter. +Left network executes on the plug side, right network on the socket side. +Both the left and right networks have editors with two specific blocks: +"Socket_Connection"(can be considered as a socket for an internal composite block, that will be added in every connection usage) +and "Plug_Connection". +These blocks are symmetrical at first, you can add additional parameters("Setting Interfaces") to the adapter declaration. +This allows you to pass certain parameters to the internal algorithm, but not to the other end of the connection. +The next image demonstrates which part of the connection each setting interface affects. + +Setting Interfaces \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 14f191ebb..145855487 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ rootProject.name = "FBME" include( "code:4diac-integration", "code:enas", + "code:extensions", "code:language", "code:library", "code:nxt-integration",