Search in sources :

Example 11 with Port

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();
}
Also used : VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) Variable(org.lflang.lf.Variable) CUtil.generateWidthVariable(org.lflang.generator.c.CUtil.generateWidthVariable) Output(org.lflang.lf.Output) Port(org.lflang.lf.Port) TriggerRef(org.lflang.lf.TriggerRef) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 12 with Port

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);
        }
    }));
}
Also used : Code(org.lflang.lf.Code) LfPackage(org.lflang.lf.LfPackage) WidthSpec(org.lflang.lf.WidthSpec) EStructuralFeature(org.eclipse.emf.ecore.EStructuralFeature) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) StateVar(org.lflang.lf.StateVar) Expression(org.lflang.lf.Expression) Matcher(java.util.regex.Matcher) HashMultimap(com.google.common.collect.HashMultimap) Port(org.lflang.lf.Port) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) INode(org.eclipse.xtext.nodemodel.INode) Connection(org.lflang.lf.Connection) GeneratorBase(org.lflang.generator.GeneratorBase) Element(org.lflang.lf.Element) TypeParm(org.lflang.lf.TypeParm) Collection(java.util.Collection) CompositeNode(org.eclipse.xtext.nodemodel.impl.CompositeNode) Set(java.util.Set) InvalidSourceException(org.lflang.generator.InvalidSourceException) EObject(org.eclipse.emf.ecore.EObject) ICompositeNode(org.eclipse.xtext.nodemodel.ICompositeNode) Collectors(java.util.stream.Collectors) Mode(org.lflang.lf.Mode) Parameter(org.lflang.lf.Parameter) List(java.util.List) CodeMap(org.lflang.generator.CodeMap) WidthTerm(org.lflang.lf.WidthTerm) Assignment(org.lflang.lf.Assignment) Resource(org.eclipse.emf.ecore.resource.Resource) ActionOrigin(org.lflang.lf.ActionOrigin) Pattern(java.util.regex.Pattern) StringExtensions(org.eclipse.xtext.xbase.lib.StringExtensions) Output(org.lflang.lf.Output) Variable(org.lflang.lf.Variable) LfFactory(org.lflang.lf.LfFactory) NodeModelUtils(org.eclipse.xtext.nodemodel.util.NodeModelUtils) ImportedReactor(org.lflang.lf.ImportedReactor) Iterators(com.google.common.collect.Iterators) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Pair(org.eclipse.xtext.util.Pair) TargetDecl(org.lflang.lf.TargetDecl) StringUtil(org.lflang.util.StringUtil) StreamSupport(java.util.stream.StreamSupport) Reaction(org.lflang.lf.Reaction) Type(org.lflang.lf.Type) LinkedHashSet(java.util.LinkedHashSet) Tuples(org.eclipse.xtext.util.Tuples) Literal(org.lflang.lf.Literal) XtextResource(org.eclipse.xtext.resource.XtextResource) HiddenLeafNode(org.eclipse.xtext.nodemodel.impl.HiddenLeafNode) Model(org.lflang.lf.Model) ReactorDecl(org.lflang.lf.ReactorDecl) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) ParameterReference(org.lflang.lf.ParameterReference) Time(org.lflang.lf.Time) ToText(org.lflang.ast.ToText) EList(org.eclipse.emf.common.util.EList) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) TerminalRule(org.eclipse.xtext.TerminalRule) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) Timer(org.lflang.lf.Timer) Port(org.lflang.lf.Port) Mode(org.lflang.lf.Mode) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Type(org.lflang.lf.Type) EObject(org.eclipse.emf.ecore.EObject) List(java.util.List) ArrayList(java.util.ArrayList) EList(org.eclipse.emf.common.util.EList) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation)

Example 13 with Port

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();
}
Also used : Port(org.lflang.lf.Port) FedROS2CPPSerialization(org.lflang.federated.serialization.FedROS2CPPSerialization) CodeBuilder(org.lflang.generator.CodeBuilder)

Aggregations

Port (org.lflang.lf.Port)13 VarRef (org.lflang.lf.VarRef)9 Instantiation (org.lflang.lf.Instantiation)7 Reactor (org.lflang.lf.Reactor)7 Input (org.lflang.lf.Input)6 LinkedHashSet (java.util.LinkedHashSet)5 Action (org.lflang.lf.Action)5 Output (org.lflang.lf.Output)5 ArrayList (java.util.ArrayList)3 LinkedHashMap (java.util.LinkedHashMap)3 CodeBuilder (org.lflang.generator.CodeBuilder)3 Variable (org.lflang.lf.Variable)3 HashMultimap (com.google.common.collect.HashMultimap)2 Iterators (com.google.common.collect.Iterators)2 Collection (java.util.Collection)2 HashSet (java.util.HashSet)2 List (java.util.List)2 Map (java.util.Map)2 Set (java.util.Set)2 Matcher (java.util.regex.Matcher)2