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);
}
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;
}
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);
}
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);
}
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);
}
Aggregations