| /** |
| * ******************************************************************************* |
| * Copyright (c) 2019 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| * ******************************************************************************* |
| */ |
| |
| package templates.m2m.constraints |
| |
| import com.google.inject.Inject |
| import com.google.inject.Singleton |
| import com.inchron.realtime.root.model.DataFlow |
| import com.inchron.realtime.root.model.DataFlowEdge |
| import org.eclipse.app4mc.amalthea.model.AbstractEventChain |
| import org.eclipse.app4mc.amalthea.model.ChannelAccess |
| import org.eclipse.app4mc.amalthea.model.ChannelEvent |
| import org.eclipse.app4mc.amalthea.model.EventChain |
| import org.eclipse.app4mc.amalthea.model.EventChainContainer |
| import org.eclipse.app4mc.amalthea.model.EventChainItem |
| import org.eclipse.app4mc.amalthea.model.EventChainReference |
| import org.eclipse.app4mc.amalthea.model.Process |
| import templates.AbstractAmaltheaInchronTransformer |
| import templates.m2m.sw.runnableItem.ChannelAccessTransformer |
| import templates.m2m.utils.DataFlowUtils |
| |
| @Singleton |
| class EventChainTransformer extends AbstractAmaltheaInchronTransformer { |
| |
| @Inject EventChainReferenceTransformer eventChainReferenceTransformer |
| @Inject ChannelAccessTransformer channelAccessTransformer |
| |
| def create inchronModelFactory.createDataFlow createDataFlow(EventChain amltEventChain) { |
| |
| //check if amalthea structure is feasible to be transformed to data flow |
| //list of checks: |
| // - no circular dependencies within nested event chain references |
| // - channel event specifies: runnable, channel, access type (send or receive) |
| // - stimulus and response are of type channel event |
| // - stimulus and responsecan be traced to ONE specific channel access runnable item |
| // - rules above also apply to nested and referenced event chains |
| // Note: strands are not supported and will be neglected |
| if (DataFlowUtils.isDataFlow(amltEventChain)){ |
| it.name = amltEventChain.name |
| extendDataFlow(it, amltEventChain) |
| getInchronRoot.eventChains.add(it) |
| } else { |
| //do event sequence sequence |
| getLogger.error("Event chain " + amltEventChain.name + " cannot be converted, as it is not a feasible data flow") |
| } |
| } |
| |
| def void extendDataFlow(DataFlow dataFlow, AbstractEventChain amltAbstractEventChain) { |
| if (!amltAbstractEventChain.segments.isEmpty) { |
| //event chain is hierarchical --> step down |
| amltAbstractEventChain.segments.forEach[EventChainItem amltEventChainItem | { //item may be a container or a reference |
| if (amltEventChainItem instanceof EventChainContainer){ |
| //recursively process contained (sub)event chain |
| extendDataFlow(dataFlow, (amltEventChainItem as EventChainContainer).eventChain) |
| } else if (amltEventChainItem instanceof EventChainReference) { |
| //create [cs]DataFlowReference from [amlt]EventChainReference |
| |
| dataFlow.references.add(eventChainReferenceTransformer.createDataFlowReference( |
| (amltEventChainItem as EventChainReference), amltAbstractEventChain)) |
| } |
| }] |
| } |
| else { |
| //create new edge |
| val DataFlowEdge dataFlowEdge = inchronModelFactory.createDataFlowEdge |
| |
| //set stimulus and receiver according to channel events |
| val Process stimulusTask = (amltAbstractEventChain.stimulus as ChannelEvent).process |
| val ChannelAccess stimulus = DataFlowUtils.findChannelAccess(amltAbstractEventChain.stimulus as ChannelEvent) |
| if (stimulus !== null){ |
| dataFlowEdge.stimulus = channelAccessTransformer.createVariableAccess(stimulusTask, stimulus) |
| } else { |
| dataFlowEdge.stimulus = null; |
| } |
| |
| val Process responseTask = (amltAbstractEventChain.response as ChannelEvent).process |
| val ChannelAccess response = DataFlowUtils.findChannelAccess(amltAbstractEventChain.response as ChannelEvent) |
| if (response !== null){ |
| dataFlowEdge.response = channelAccessTransformer.createVariableAccess(responseTask, response) |
| } else { |
| dataFlowEdge.response = null; |
| } |
| |
| //add new edge dataflow |
| dataFlow.edges.add(dataFlowEdge) |
| } |
| } |
| |
| } |