Search in sources :

Example 1 with LfFactory

use of org.lflang.lf.LfFactory in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkSenderReaction.

/**
 * Add a network sender reaction for a given input port 'source' to
 * source's parent reactor. This reaction will react to the 'source'
 * and then send a message on the network destined for the destinationFederate.
 *
 * @note Used in federated execution
 *
 * @param source The source port instance.
 * @param destination The destination port instance.
 * @param connection The network connection.
 * @param sourceFederate The source federate.
 * @param leftBankIndex The left bank index or -1 if the left reactor is not in a bank.
 * @param leftChannelIndex The left channel index or -1 if the left port is not a multiport.
 * @param destinationFederate The destination federate.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param coordination One of CoordinationType.DECENTRALIZED or CoordinationType.CENTRALIZED.
 * @param serializer The serializer used on the connection
 */
private static void addNetworkSenderReaction(PortInstance source, PortInstance destination, Connection connection, FederateInstance sourceFederate, int leftBankIndex, int leftChannelIndex, FederateInstance destinationFederate, GeneratorBase generator, CoordinationType coordination, SupportedSerializers serializer) {
    LfFactory factory = LfFactory.eINSTANCE;
    // Assume all the types are the same, so just use the first on the right.
    Type type = EcoreUtil.copy(source.getDefinition().getType());
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    Reactor parent = (Reactor) connection.eContainer();
    Reaction networkSenderReaction = factory.createReaction();
    // These reactions do not require any dependency relationship
    // to other reactions in the container.
    generator.makeUnordered(networkSenderReaction);
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(networkSenderReaction, leftBankIndex);
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        sourceFederate.outboundP2PConnections.add(destinationFederate);
    } else {
        // to make P2P connections
        if (coordination == CoordinationType.DECENTRALIZED) {
            sourceFederate.outboundP2PConnections.add(destinationFederate);
        }
    }
    // Record this action in the right federate.
    // The ID of the receiving port (rightPort) is the position
    // of the action in this list.
    int receivingPortID = destinationFederate.networkMessageActions.size();
    // Establish references to the involved ports.
    sourceRef.setContainer(source.getParent().getDefinition());
    sourceRef.setVariable(source.getDefinition());
    destRef.setContainer(destination.getParent().getDefinition());
    destRef.setVariable(destination.getDefinition());
    // Configure the sending reaction.
    networkSenderReaction.getTriggers().add(sourceRef);
    networkSenderReaction.setCode(factory.createCode());
    networkSenderReaction.getCode().setBody(generator.generateNetworkSenderBody(sourceRef, destRef, receivingPortID, sourceFederate, leftBankIndex, leftChannelIndex, destinationFederate, InferredType.fromAST(type), connection.isPhysical(), connection.getDelay(), serializer));
    // Add the sending reaction to the parent.
    parent.getReactions().add(networkSenderReaction);
    // Add the network sender reaction to the federate instance's list
    // of network reactions
    sourceFederate.networkReactions.add(networkSenderReaction);
}
Also used : VarRef(org.lflang.lf.VarRef) InferredType(org.lflang.InferredType) Type(org.lflang.lf.Type) CoordinationType(org.lflang.TargetProperty.CoordinationType) LfFactory(org.lflang.lf.LfFactory) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction)

Example 2 with LfFactory

use of org.lflang.lf.LfFactory in project lingua-franca by lf-lang.

the class FedASTUtils method createNetworkAction.

/**
 * Create a "network action" in the reactor that contains the given
 * connection and return it.
 *
 * The purpose of this action is to serve as a trigger for a "network
 * input reaction" that is responsible for relaying messages to the
 * port that is on the receiving side of the given connection. The
 * connection is assumed to be between two reactors that reside in
 * distinct federates. Hence, the container of the connection is
 * assumed to be top-level.
 *
 * @param connection A connection between to federates.
 * @param serializer The serializer used on the connection.
 * @param type The type of the source port (indicating the type of
 *  data to be received).
 * @param networkBufferType The type of the buffer used for network
 *  communication in the target (e.g., uint8_t* in C).
 * @return The newly created action.
 */
private static Action createNetworkAction(Connection connection, SupportedSerializers serializer, Type type, String networkBufferType) {
    Reactor top = (Reactor) connection.eContainer();
    LfFactory factory = LfFactory.eINSTANCE;
    Action action = factory.createAction();
    // Name the newly created action; set its delay and type.
    action.setName(ASTUtils.getUniqueIdentifier(top, "networkMessage"));
    if (serializer == SupportedSerializers.NATIVE) {
        action.setType(type);
    } else {
        Type action_type = factory.createType();
        action_type.setId(networkBufferType);
        action.setType(action_type);
    }
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        action.setOrigin(ActionOrigin.PHYSICAL);
        // the minDelay.
        if (connection.getDelay() != null) {
            action.setMinDelay(factory.createValue());
            action.getMinDelay().setTime(connection.getDelay().getTime());
        }
    } else {
        action.setOrigin(ActionOrigin.LOGICAL);
    }
    return action;
}
Also used : Action(org.lflang.lf.Action) InferredType(org.lflang.InferredType) Type(org.lflang.lf.Type) CoordinationType(org.lflang.TargetProperty.CoordinationType) Reactor(org.lflang.lf.Reactor) LfFactory(org.lflang.lf.LfFactory)

Example 3 with LfFactory

use of org.lflang.lf.LfFactory in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkOutputControlReaction.

/**
 * Add a network control reaction for a given output port 'source' to
 * source's parent reactor. This reaction will send a port absent
 * message if the status of the output port is absent.
 *
 * @note Used in federated execution
 *
 * @param source The output port of the source federate
 * @param instance The federate instance is used to keep track of all
 *  network reactions and some relevant triggers
 * @param receivingPortID The ID of the receiving port
 * @param channelIndex The channel index of the sending port, if it is a multiport.
 * @param bankIndex The bank index of the sending federate, if it is a bank.
 * @param receivingFedID The ID of destination federate.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param delay The delay value imposed on the connection using after
 */
private static void addNetworkOutputControlReaction(PortInstance source, FederateInstance instance, int receivingPortID, int bankIndex, int channelIndex, int receivingFedID, GeneratorBase generator, Delay delay) {
    LfFactory factory = LfFactory.eINSTANCE;
    Reaction reaction = factory.createReaction();
    // Top-level reactor.
    Reactor top = source.getParent().getParent().reactorDefinition;
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(reaction, bankIndex);
    // Add the output from the contained reactor as a source to
    // the reaction to preserve precedence order.
    VarRef newPortRef = factory.createVarRef();
    newPortRef.setContainer(source.getParent().getDefinition());
    newPortRef.setVariable(source.getDefinition());
    reaction.getSources().add(newPortRef);
    // Check whether the action already has been created.
    if (instance.networkOutputControlReactionsTrigger == null) {
        // The port has not been created.
        String triggerName = "outputControlReactionTrigger";
        // Find the trigger definition in the reactor definition, which could have been
        // generated for another federate instance if there are multiple instances
        // of the same reactor that are each distinct federates.
        Optional<Action> optTriggerInput = top.getActions().stream().filter(I -> I.getName().equals(triggerName)).findFirst();
        if (optTriggerInput.isEmpty()) {
            // If no trigger with the name "outputControlReactionTrigger" is
            // already added to the reactor definition, we need to create it
            // for the first time. The trigger is a logical action.
            Action newTriggerForControlReactionVariable = factory.createAction();
            newTriggerForControlReactionVariable.setName(triggerName);
            newTriggerForControlReactionVariable.setOrigin(ActionOrigin.LOGICAL);
            top.getActions().add(newTriggerForControlReactionVariable);
            // Now that the variable is created, store it in the federate instance
            instance.networkOutputControlReactionsTrigger = newTriggerForControlReactionVariable;
        } else {
            // If the "outputControlReactionTrigger" trigger is already
            // there, we can re-use it for this new reaction since a single trigger
            // will trigger
            // all network output control reactions.
            instance.networkOutputControlReactionsTrigger = optTriggerInput.get();
        }
    }
    // Add the trigger for all output control reactions to the list of triggers
    VarRef triggerRef = factory.createVarRef();
    triggerRef.setVariable(instance.networkOutputControlReactionsTrigger);
    reaction.getTriggers().add(triggerRef);
    // Generate the code
    reaction.setCode(factory.createCode());
    reaction.getCode().setBody(generator.generateNetworkOutputControlReactionBody(newPortRef, receivingPortID, receivingFedID, bankIndex, channelIndex, delay));
    // Make the reaction unordered w.r.t. other reactions in the top level.
    generator.makeUnordered(reaction);
    // Insert the newly generated reaction after the generated sender and
    // receiver top-level reactions.
    top.getReactions().add(reaction);
    // Add the network output control reaction to the federate instance's list
    // of network reactions
    instance.networkReactions.add(reaction);
}
Also used : VarRef(org.lflang.lf.VarRef) Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) Instantiation(org.lflang.lf.Instantiation) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Connection(org.lflang.lf.Connection) Type(org.lflang.lf.Type) GeneratorBase(org.lflang.generator.GeneratorBase) CoordinationType(org.lflang.TargetProperty.CoordinationType) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) PortInstance(org.lflang.generator.PortInstance) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) Optional(java.util.Optional) VarRef(org.lflang.lf.VarRef) Collections(java.util.Collections) ASTUtils(org.lflang.ASTUtils) Action(org.lflang.lf.Action) LfFactory(org.lflang.lf.LfFactory) Reaction(org.lflang.lf.Reaction) Reactor(org.lflang.lf.Reactor)

Example 4 with LfFactory

use of org.lflang.lf.LfFactory in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkInputControlReaction.

/**
 * Add a network control reaction for a given input port 'destination' to
 * destination's parent reactor. This reaction will block for
 * any valid logical time until it is known whether the trigger for the
 * action corresponding to the given port is present or absent.
 *
 * @note Used in federated execution
 *
 * @param source The output port of the source federate reactor.
 *  Added as a trigger to the network control reaction to preserve the
 *  overall dependency structure of the program across federates.
 * @param destination The input port of the destination federate reactor.
 * @param recevingPortID The ID of the receiving port
 * @param bankIndex The bank index of the receiving federate, or -1 if not in a bank.
 * @param instance The federate instance is used to keep track of all
 *  network input ports globally
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 */
private static void addNetworkInputControlReaction(PortInstance source, PortInstance destination, int recevingPortID, int bankIndex, FederateInstance instance, GeneratorBase generator) {
    LfFactory factory = LfFactory.eINSTANCE;
    Reaction reaction = factory.createReaction();
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(reaction, bankIndex);
    // Create a new action that will be used to trigger the
    // input control reactions.
    Action newTriggerForControlReactionInput = factory.createAction();
    newTriggerForControlReactionInput.setOrigin(ActionOrigin.LOGICAL);
    // Set the container and variable according to the network port
    destRef.setContainer(destination.getParent().getDefinition());
    destRef.setVariable(destination.getDefinition());
    sourceRef.setContainer(source.getParent().getDefinition());
    sourceRef.setVariable(source.getDefinition());
    Reactor top = destination.getParent().getParent().reactorDefinition;
    newTriggerForControlReactionInput.setName(ASTUtils.getUniqueIdentifier(top, "inputControlReactionTrigger"));
    // Add the newly created Action to the action list of the federated reactor.
    top.getActions().add(newTriggerForControlReactionInput);
    // Create the trigger for the reaction
    VarRef newTriggerForControlReaction = factory.createVarRef();
    newTriggerForControlReaction.setVariable(newTriggerForControlReactionInput);
    // Add the appropriate triggers to the list of triggers of the reaction
    reaction.getTriggers().add(newTriggerForControlReaction);
    // Add the original output port of the source federate
    // as a trigger to keep the overall dependency structure.
    // This is useful when assigning levels.
    reaction.getTriggers().add(sourceRef);
    // Add this trigger to the list of disconnected network reaction triggers
    instance.remoteNetworkReactionTriggers.add(sourceRef);
    // Add the destination port as an effect of the reaction
    reaction.getEffects().add(destRef);
    // Generate code for the network input control reaction
    reaction.setCode(factory.createCode());
    TimeValue maxSTP = findMaxSTP(destination.getDefinition(), instance, generator, destination.getParent().reactorDefinition);
    reaction.getCode().setBody(generator.generateNetworkInputControlReactionBody(recevingPortID, maxSTP));
    generator.makeUnordered(reaction);
    // Insert the reaction
    top.getReactions().add(reaction);
    // Add the trigger for this reaction to the list of triggers, used to actually
    // trigger the reaction at the beginning of each logical time.
    instance.networkInputControlReactionsTriggers.add(newTriggerForControlReactionInput);
    // Add the network input control reaction to the federate instance's list
    // of network reactions
    instance.networkReactions.add(reaction);
}
Also used : VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) LfFactory(org.lflang.lf.LfFactory) Reaction(org.lflang.lf.Reaction) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 5 with LfFactory

use of org.lflang.lf.LfFactory in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkReceiverReaction.

/**
 * Add a network receiver reaction for a given input port 'destination' to
 * destination's parent reactor. This reaction will react to a generated
 * 'networkAction' (triggered asynchronously, e.g., by federate.c). This
 * 'networkAction' will contain the actual message that is sent by the sender
 * in 'action->value'. This value is forwarded to 'destination' in the network
 * receiver reaction.
 *
 * @note: Used in federated execution
 *
 * @param networkAction The network action (also, @see createNetworkAction)
 * @param source The source port instance.
 * @param destination The destination port instance.
 * @param connection The network connection.
 * @param sourceFederate The source federate.
 * @param destinationFederate The destination federate.
 * @param rightBankIndex The right bank index or -1 if the right reactor is not in a bank.
 * @param rightChannelIndex The right channel index or -1 if the right port is not a multiport.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param coordination One of CoordinationType.DECENTRALIZED or CoordinationType.CENTRALIZED.
 * @param serializer The serializer used on the connection
 */
private static void addNetworkReceiverReaction(Action networkAction, PortInstance source, PortInstance destination, Connection connection, FederateInstance sourceFederate, FederateInstance destinationFederate, int rightBankIndex, int rightChannelIndex, GeneratorBase generator, CoordinationType coordination, SupportedSerializers serializer) {
    LfFactory factory = LfFactory.eINSTANCE;
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    Reactor parent = (Reactor) connection.eContainer();
    Reaction networkReceiverReaction = factory.createReaction();
    // These reactions do not require any dependency relationship
    // to other reactions in the container.
    generator.makeUnordered(networkReceiverReaction);
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(networkReceiverReaction, rightBankIndex);
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        destinationFederate.inboundP2PConnections.add(sourceFederate);
    } else {
        // to make P2P connections
        if (coordination == CoordinationType.DECENTRALIZED) {
            destinationFederate.inboundP2PConnections.add(sourceFederate);
        }
    }
    // Record this action in the right federate.
    // The ID of the receiving port (rightPort) is the position
    // of the action in this list.
    int receivingPortID = destinationFederate.networkMessageActions.size();
    // Establish references to the involved ports.
    sourceRef.setContainer(source.getParent().getDefinition());
    sourceRef.setVariable(source.getDefinition());
    destRef.setContainer(destination.getParent().getDefinition());
    destRef.setVariable(destination.getDefinition());
    if (!connection.isPhysical()) {
        // If the connection is not physical,
        // add the original output port of the source federate
        // as a trigger to keep the overall dependency structure.
        // This is useful when assigning levels.
        VarRef senderOutputPort = factory.createVarRef();
        senderOutputPort.setContainer(source.getParent().getDefinition());
        senderOutputPort.setVariable(source.getDefinition());
        networkReceiverReaction.getTriggers().add(senderOutputPort);
        // Add this trigger to the list of disconnected network reaction triggers
        destinationFederate.remoteNetworkReactionTriggers.add(senderOutputPort);
    }
    // Add the input port at the receiver federate reactor as an effect
    networkReceiverReaction.getEffects().add(destRef);
    VarRef triggerRef = factory.createVarRef();
    // Establish references to the action.
    triggerRef.setVariable(networkAction);
    // Add the action as a trigger to the receiver reaction
    networkReceiverReaction.getTriggers().add(triggerRef);
    // Generate code for the network receiver reaction
    networkReceiverReaction.setCode(factory.createCode());
    networkReceiverReaction.getCode().setBody(generator.generateNetworkReceiverBody(networkAction, sourceRef, destRef, receivingPortID, sourceFederate, destinationFederate, rightBankIndex, rightChannelIndex, ASTUtils.getInferredType(networkAction), connection.isPhysical(), serializer));
    // Add the receiver reaction to the parent
    parent.getReactions().add(networkReceiverReaction);
    // Add the network receiver reaction to the federate instance's list
    // of network reactions
    destinationFederate.networkReactions.add(networkReceiverReaction);
}
Also used : VarRef(org.lflang.lf.VarRef) LfFactory(org.lflang.lf.LfFactory) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction)

Aggregations

LfFactory (org.lflang.lf.LfFactory)5 Reactor (org.lflang.lf.Reactor)5 Reaction (org.lflang.lf.Reaction)4 VarRef (org.lflang.lf.VarRef)4 InferredType (org.lflang.InferredType)3 CoordinationType (org.lflang.TargetProperty.CoordinationType)3 Action (org.lflang.lf.Action)3 Type (org.lflang.lf.Type)3 TimeValue (org.lflang.TimeValue)2 ArrayList (java.util.ArrayList)1 Collections (java.util.Collections)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1 Collectors (java.util.stream.Collectors)1 EcoreUtil (org.eclipse.emf.ecore.util.EcoreUtil)1 ASTUtils (org.lflang.ASTUtils)1 SupportedSerializers (org.lflang.federated.serialization.SupportedSerializers)1 GeneratorBase (org.lflang.generator.GeneratorBase)1