use of org.lflang.lf.Port in project lingua-franca by lf-lang.
the class CReactionGenerator method generateIntendedTagInheritence.
/**
* Generate code that passes existing intended tag to all output ports
* and actions. This intended tag is the minimum intended tag of the
* triggering inputs of the reaction.
*
* @param body The body of the reaction. Used to check for the DISABLE_REACTION_INITIALIZATION_MARKER.
* @param reaction The initialization code will be generated for this specific reaction
* @param decl The reactor that has the reaction
* @param reactionIndex The index of the reaction relative to other reactions in the reactor, starting from 0
*/
public static String generateIntendedTagInheritence(String body, Reaction reaction, ReactorDecl decl, int reactionIndex, CTypes types, boolean isFederatedAndDecentralized) {
// Construct the intended_tag inheritance code to go into
// the body of the function.
CodeBuilder intendedTagInheritenceCode = new CodeBuilder();
// Check if the coordination mode is decentralized and if the reaction has any effects to inherit the STP violation
if (isFederatedAndDecentralized && !(reaction.getEffects() == null || reaction.getEffects().isEmpty())) {
intendedTagInheritenceCode.pr(String.join("\n", "#pragma GCC diagnostic push", "#pragma GCC diagnostic ignored \"-Wunused-variable\"", "if (self->_lf__reaction_" + reactionIndex + ".is_STP_violated == true) {"));
intendedTagInheritenceCode.indent();
intendedTagInheritenceCode.pr(String.join("\n", "// The operations inside this if clause (if any exists) are expensive ", "// and must only be done if the reaction has unhandled STP violation.", "// Otherwise, all intended_tag values are (NEVER, 0) by default.", "", "// Inherited intended tag. This will take the minimum", "// intended_tag of all input triggers", types.getTargetTagType() + " inherited_min_intended_tag = (" + types.getTargetTagType() + ") { .time = FOREVER, .microstep = UINT_MAX };"));
intendedTagInheritenceCode.pr("// Find the minimum intended tag");
// value of intended_tag to choose the minimum.
for (TriggerRef inputTrigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
if (inputTrigger instanceof VarRef) {
VarRef inputTriggerAsVarRef = (VarRef) inputTrigger;
Variable variable = inputTriggerAsVarRef.getVariable();
String variableName = inputTriggerAsVarRef.getVariable().getName();
if (variable instanceof Output) {
// Output from a contained reactor
String containerName = inputTriggerAsVarRef.getContainer().getName();
Output outputPort = (Output) variable;
if (ASTUtils.isMultiport(outputPort)) {
intendedTagInheritenceCode.pr(String.join("\n", "for (int i=0; i < " + containerName + "." + generateWidthVariable(variableName) + "; i++) {", " if (lf_tag_compare(" + containerName + "." + variableName + "[i]->intended_tag,", " inherited_min_intended_tag) < 0) {", " inherited_min_intended_tag = " + containerName + "." + variableName + "[i]->intended_tag;", " }", "}"));
} else
intendedTagInheritenceCode.pr(String.join("\n", "if (lf_tag_compare(" + containerName + "." + variableName + "->intended_tag,", " inherited_min_intended_tag) < 0) {", " inherited_min_intended_tag = " + containerName + "." + variableName + "->intended_tag;", "}"));
} else if (variable instanceof Port) {
// Input port
Port inputPort = (Port) variable;
if (ASTUtils.isMultiport(inputPort)) {
intendedTagInheritenceCode.pr(String.join("\n", "for (int i=0; i < " + generateWidthVariable(variableName) + "; i++) {", " if (lf_tag_compare(" + variableName + "[i]->intended_tag, inherited_min_intended_tag) < 0) {", " inherited_min_intended_tag = " + variableName + "[i]->intended_tag;", " }", "}"));
} else {
intendedTagInheritenceCode.pr(String.join("\n", "if (lf_tag_compare(" + variableName + "->intended_tag, inherited_min_intended_tag) < 0) {", " inherited_min_intended_tag = " + variableName + "->intended_tag;", "}"));
}
} else if (variable instanceof Action) {
intendedTagInheritenceCode.pr(String.join("\n", "if (lf_tag_compare(" + variableName + "->trigger->intended_tag, inherited_min_intended_tag) < 0) {", " inherited_min_intended_tag = " + variableName + "->trigger->intended_tag;", "}"));
}
}
}
if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
// NOTE: this does not include contained outputs.
for (Input input : ((Reactor) reaction.eContainer()).getInputs()) {
intendedTagInheritenceCode.pr(String.join("\n", "if (lf_tag_compare(" + input.getName() + "->intended_tag, inherited_min_intended_tag) > 0) {", " inherited_min_intended_tag = " + input.getName() + "->intended_tag;", "}"));
}
}
// Once the minimum intended tag has been found,
// it will be passed down to the port effects
// of the reaction. Note that the intended tag
// will not pass on to actions downstream.
// Last reaction that sets the intended tag for the effect
// will be seen.
intendedTagInheritenceCode.pr(String.join("\n", "// All effects inherit the minimum intended tag of input triggers", "if (inherited_min_intended_tag.time != NEVER) {"));
intendedTagInheritenceCode.indent();
for (VarRef effect : ASTUtils.convertToEmptyListIfNull(reaction.getEffects())) {
Variable effectVar = effect.getVariable();
Instantiation effContainer = effect.getContainer();
if (effectVar instanceof Input) {
if (ASTUtils.isMultiport((Port) effectVar)) {
intendedTagInheritenceCode.pr(String.join("\n", "for(int i=0; i < " + effContainer.getName() + "." + generateWidthVariable(effectVar.getName()) + "; i++) {", " " + effContainer.getName() + "." + effectVar.getName() + "[i]->intended_tag = inherited_min_intended_tag;", "}"));
} else {
if (effContainer.getWidthSpec() != null) {
// Contained reactor is a bank.
intendedTagInheritenceCode.pr(String.join("\n", "for (int bankIndex = 0; bankIndex < self->_lf_" + generateWidthVariable(effContainer.getName()) + "; bankIndex++) {", " " + effContainer.getName() + "[bankIndex]." + effectVar.getName() + " = &(self->_lf_" + effContainer.getName() + "[bankIndex]." + effectVar.getName() + ");", "}"));
} else {
// Input to a contained reaction
intendedTagInheritenceCode.pr(String.join("\n", "// Don't reset the intended tag of the output port if it has already been set.", effContainer.getName() + "." + effectVar.getName() + "->intended_tag = inherited_min_intended_tag;"));
}
}
}
}
intendedTagInheritenceCode.unindent();
intendedTagInheritenceCode.pr("}");
intendedTagInheritenceCode.unindent();
intendedTagInheritenceCode.pr("#pragma GCC diagnostic pop");
intendedTagInheritenceCode.pr("}");
}
return intendedTagInheritenceCode.toString();
}
use of org.lflang.lf.Port in project lingua-franca by lf-lang.
the class ASTUtils method insertGeneratedDelays.
/**
* Find connections in the given resource that have a delay associated with them,
* and reroute them via a generated delay reactor.
* @param resource The AST.
* @param generator A code generator.
*/
public static void insertGeneratedDelays(Resource resource, GeneratorBase generator) {
// The resulting changes to the AST are performed _after_ iterating
// in order to avoid concurrent modification problems.
List<Connection> oldConnections = new ArrayList<>();
Map<EObject, List<Connection>> newConnections = new LinkedHashMap<>();
Map<EObject, List<Instantiation>> delayInstances = new LinkedHashMap<>();
// Iterate over the connections in the tree.
for (Reactor container : getAllReactors(resource)) {
for (Connection connection : allConnections(container)) {
if (connection.getDelay() != null) {
EObject parent = connection.eContainer();
// Assume all the types are the same, so just use the first on the right.
Type type = ((Port) connection.getRightPorts().get(0).getVariable()).getType();
Reactor delayClass = getDelayClass(type, generator);
String generic = generator.getTargetTypes().supportsGenerics() ? generator.getTargetTypes().getTargetType(InferredType.fromAST(type)) : "";
Instantiation delayInstance = getDelayInstance(delayClass, connection, generic, !generator.generateAfterDelaysWithVariableWidth());
// Stage the new connections for insertion into the tree.
List<Connection> connections = convertToEmptyListIfNull(newConnections.get(parent));
connections.addAll(rerouteViaDelay(connection, delayInstance));
newConnections.put(parent, connections);
// Stage the original connection for deletion from the tree.
oldConnections.add(connection);
// Stage the newly created delay reactor instance for insertion
List<Instantiation> instances = convertToEmptyListIfNull(delayInstances.get(parent));
instances.add(delayInstance);
delayInstances.put(parent, instances);
}
}
}
// Remove old connections; insert new ones.
oldConnections.forEach(connection -> {
var container = connection.eContainer();
if (container instanceof Reactor) {
((Reactor) container).getConnections().remove(connection);
} else if (container instanceof Mode) {
((Mode) container).getConnections().remove(connection);
}
});
newConnections.forEach((container, connections) -> {
if (container instanceof Reactor) {
((Reactor) container).getConnections().addAll(connections);
} else if (container instanceof Mode) {
((Mode) container).getConnections().addAll(connections);
}
});
// Finally, insert the instances and, before doing so, assign them a unique name.
delayInstances.forEach((container, instantiations) -> instantiations.forEach(instantiation -> {
if (container instanceof Reactor) {
instantiation.setName(getUniqueIdentifier((Reactor) container, "delay"));
((Reactor) container).getInstantiations().add(instantiation);
} else if (container instanceof Mode) {
instantiation.setName(getUniqueIdentifier((Reactor) container.eContainer(), "delay"));
((Mode) container).getInstantiations().add(instantiation);
}
}));
}
use of org.lflang.lf.Port in project lingua-franca by lf-lang.
the class CNetworkGenerator method generateNetworkReceiverBody.
/**
* Generate code for the body of a reaction that handles the
* action that is triggered by receiving a message from a remote
* federate.
* @param action The action.
* @param sendingPort The output port providing the data to send.
* @param receivingPort The ID of the destination port.
* @param receivingPortID The ID of the destination port.
* @param sendingFed The sending federate.
* @param receivingFed The destination federate.
* @param receivingBankIndex The receiving federate's bank index, if it is in a bank.
* @param receivingChannelIndex The receiving federate's channel index, if it is a multiport.
* @param type The type.
* @param isPhysical Indicates whether or not the connection is physical
* @param serializer The serializer used on the connection.
* @param coordinationType The coordination type
*/
public static String generateNetworkReceiverBody(Action action, VarRef sendingPort, VarRef receivingPort, int receivingPortID, FederateInstance sendingFed, FederateInstance receivingFed, int receivingBankIndex, int receivingChannelIndex, InferredType type, boolean isPhysical, SupportedSerializers serializer, CTypes types, CoordinationType coordinationType) {
// downstream patches to generated strings rather than fixing them at their source.
if (types.getTargetType(action).equals("string")) {
action.getType().setCode(null);
action.getType().setId("char*");
}
if (types.getTargetType((Port) receivingPort.getVariable()).equals("string")) {
((Port) receivingPort.getVariable()).getType().setCode(null);
((Port) receivingPort.getVariable()).getType().setId("char*");
}
var receiveRef = CUtil.portRefInReaction(receivingPort, receivingBankIndex, receivingChannelIndex);
var result = new CodeBuilder();
// We currently have no way to mark a reaction "unordered"
// in the AST, so we use a magic string at the start of the body.
result.pr("// " + ReactionInstance.UNORDERED_REACTION_MARKER);
// Transfer the physical time of arrival from the action to the port
result.pr(receiveRef + "->physical_time_of_arrival = self->_lf__" + action.getName() + ".physical_time_of_arrival;");
if (coordinationType == CoordinationType.DECENTRALIZED && !isPhysical) {
// Transfer the intended tag.
result.pr(receiveRef + "->intended_tag = self->_lf__" + action.getName() + ".intended_tag;\n");
}
var value = "";
switch(serializer) {
case NATIVE:
{
// NOTE: Docs say that malloc'd char* is freed on conclusion of the time step.
// So passing it downstream should be OK.
value = action.getName() + "->value";
if (CUtil.isTokenType(type, types)) {
result.pr("lf_set_token(" + receiveRef + ", " + action.getName() + "->token);");
} else {
result.pr("lf_set(" + receiveRef + ", " + value + ");");
}
break;
}
case PROTO:
{
throw new UnsupportedOperationException("Protobuf serialization is not supported yet.");
}
case ROS2:
{
var portType = ASTUtils.getInferredType(((Port) receivingPort.getVariable()));
var portTypeStr = types.getTargetType(portType);
if (CUtil.isTokenType(portType, types)) {
throw new UnsupportedOperationException("Cannot handle ROS serialization when ports are pointers.");
} else if (isSharedPtrType(portType, types)) {
var matcher = sharedPointerVariable.matcher(portTypeStr);
if (matcher.find()) {
portTypeStr = matcher.group("type");
}
}
var ROSDeserializer = new FedROS2CPPSerialization();
value = FedROS2CPPSerialization.deserializedVarName;
result.pr(ROSDeserializer.generateNetworkDeserializerCode("self->_lf__" + action.getName(), portTypeStr));
if (isSharedPtrType(portType, types)) {
result.pr("auto msg_shared_ptr = std::make_shared<" + portTypeStr + ">(" + value + ");");
result.pr("lf_set(" + receiveRef + ", msg_shared_ptr);");
} else {
result.pr("lf_set(" + receiveRef + ", std::move(" + value + "));");
}
break;
}
}
return result.toString();
}
Aggregations