Skip to content

Commit

Permalink
Merge pull request #2356 from lf-lang/watchdog-diagrams
Browse files Browse the repository at this point in the history
Diagram support for watchdogs
  • Loading branch information
edwardalee authored Jul 12, 2024
2 parents d24b3b1 + 9e4355c commit 862e8de
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 61 deletions.
14 changes: 3 additions & 11 deletions core/src/main/java/org/lflang/AttributeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,7 @@
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;
import org.lflang.ast.ASTUtils;
import org.lflang.lf.Action;
import org.lflang.lf.AttrParm;
import org.lflang.lf.Attribute;
import org.lflang.lf.Input;
import org.lflang.lf.Instantiation;
import org.lflang.lf.Output;
import org.lflang.lf.Parameter;
import org.lflang.lf.Reaction;
import org.lflang.lf.Reactor;
import org.lflang.lf.StateVar;
import org.lflang.lf.Timer;
import org.lflang.lf.*;
import org.lflang.util.StringUtil;

/**
Expand Down Expand Up @@ -83,6 +73,8 @@ public static List<Attribute> getAttributes(EObject node) {
return ((Output) node).getAttributes();
} else if (node instanceof Instantiation) {
return ((Instantiation) node).getAttributes();
} else if (node instanceof Watchdog) {
return ((Watchdog) node).getAttributes();
}
throw new IllegalArgumentException("Not annotatable: " + node);
}
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/lflang/LinguaFranca.xtext
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Deadline:
'deadline' '(' delay=Expression ')' code=Code;

Watchdog:
(attributes+=Attribute)*
'watchdog' name=ID '(' timeout=Expression ')'
('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)?
code=Code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
import org.lflang.generator.SendRange;
import org.lflang.generator.TimerInstance;
import org.lflang.generator.TriggerInstance;
import org.lflang.generator.WatchdogInstance;
import org.lflang.lf.Connection;
import org.lflang.lf.LfPackage;
import org.lflang.lf.Model;
Expand Down Expand Up @@ -1022,6 +1023,8 @@ private Collection<KNode> transformReactorNetwork(
Multimap<ActionInstance, KPort> actionDestinations = HashMultimap.create();
Multimap<ActionInstance, KPort> actionSources = HashMultimap.create();
Map<TimerInstance, KNode> timerNodes = new HashMap<>();
Multimap<WatchdogInstance, KPort> watchdogDestinations = HashMultimap.create();
Multimap<WatchdogInstance, KPort> watchdogSources = HashMultimap.create();
KNode startupNode = _kNodeExtensions.createNode();
TriggerInstance<?> startup = null;
KNode shutdownNode = _kNodeExtensions.createNode();
Expand Down Expand Up @@ -1145,6 +1148,8 @@ private Collection<KNode> transformReactorNetwork(
if (src != null) {
connect(createDependencyEdge(trigger.getDefinition()), src, port);
}
} else if (trigger instanceof WatchdogInstance) {
watchdogDestinations.put(((WatchdogInstance) trigger), port);
}
}

Expand Down Expand Up @@ -1204,6 +1209,8 @@ private Collection<KNode> transformReactorNetwork(
if (dst != null) {
connect(createDependencyEdge(effect), port, dst);
}
} else if (effect instanceof WatchdogInstance) {
watchdogSources.put((WatchdogInstance) effect, port);
}
}
}
Expand Down Expand Up @@ -1251,6 +1258,34 @@ private Collection<KNode> transformReactorNetwork(
}
}

// Connect watchdogs
Set<WatchdogInstance> watchdogs = new HashSet<>();
watchdogs.addAll(watchdogSources.keySet());
watchdogs.addAll(watchdogDestinations.keySet());

for (WatchdogInstance watchdog : watchdogs) {
KNode node = associateWith(_kNodeExtensions.createNode(), watchdog.getDefinition());
NamedInstanceUtil.linkInstance(node, watchdog);
_utilityExtensions.setID(node, watchdog.uniqueID());
nodes.add(node);
setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
Pair<KPort, KPort> ports = _linguaFrancaShapeExtensions.addWatchdogFigureAndPorts(node);
setAnnotatedLayoutOptions(watchdog.getDefinition(), node);
if (watchdog.getTimeout() != null) {
_kLabelExtensions.addOutsideBottomCenteredNodeLabel(
node, String.format("timeout: %s", watchdog.getTimeout().toString()), 7);
}
// connect source
for (KPort source : watchdogSources.get(watchdog)) {
connect(createDelayEdge(watchdog), source, ports.getKey());
}

// connect targets
for (KPort target : watchdogDestinations.get(watchdog)) {
connect(createDelayEdge(watchdog), ports.getValue(), target);
}
}

// Transform connections.
// First, collect all the source ports.
List<PortInstance> sourcePorts = new LinkedList<>(reactorInstance.inputs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import de.cau.cs.kieler.klighd.krendering.KArc;
import de.cau.cs.kieler.klighd.krendering.KAreaPlacementData;
import de.cau.cs.kieler.klighd.krendering.KContainerRendering;
import de.cau.cs.kieler.klighd.krendering.KDecoratorPlacementData;
import de.cau.cs.kieler.klighd.krendering.KEllipse;
import de.cau.cs.kieler.klighd.krendering.KGridPlacement;
import de.cau.cs.kieler.klighd.krendering.KPolygon;
Expand Down Expand Up @@ -672,6 +671,47 @@ public KEllipse addTimerFigure(KNode node, TimerInstance timer) {
return figure;
}

/** Creates the rectangular node with text and ports. */
public Pair<KPort, KPort> addWatchdogFigureAndPorts(KNode node) {
final float size = 18;
_kNodeExtensions.setMinimalNodeSize(node, size, size);
KRectangle figure = _kRenderingExtensions.addRectangle(node);
_kRenderingExtensions.setBackground(figure, Colors.WHITE);
_linguaFrancaStyleExtensions.boldLineSelectionStyle(figure);

// Add text to the watchdog figure
KText textToAdd = _kContainerRenderingExtensions.addText(figure, "W");
_kRenderingExtensions.setFontSize(textToAdd, 8);
_linguaFrancaStyleExtensions.noSelectionStyle(textToAdd);
DiagramSyntheses.suppressSelectability(textToAdd);
_kRenderingExtensions.setPointPlacementData(
textToAdd,
_kRenderingExtensions.LEFT,
0,
0.5f,
_kRenderingExtensions.TOP,
(size * 0.15f),
0.5f,
_kRenderingExtensions.H_CENTRAL,
_kRenderingExtensions.V_CENTRAL,
0,
0,
size,
size);

// Add input port
KPort in = _kPortExtensions.createPort();
node.getPorts().add(in);
in.setSize(0, 0);
DiagramSyntheses.setLayoutOption(in, CoreOptions.PORT_SIDE, PortSide.WEST);

// Add output port
KPort out = _kPortExtensions.createPort();
node.getPorts().add(out);
DiagramSyntheses.setLayoutOption(out, CoreOptions.PORT_SIDE, PortSide.EAST);
return new Pair<KPort, KPort>(in, out);
}

/** Creates the visual representation of a startup trigger. */
public KEllipse addStartupFigure(KNode node) {
_kNodeExtensions.setMinimalNodeSize(node, 18, 18);
Expand Down Expand Up @@ -839,53 +879,6 @@ public KText addTextButton(KContainerRendering container, String text) {
return textToAdd;
}

/** Creates the triangular line decorator with text. */
public KPolygon addActionDecorator(KPolyline line, String text) {
final float size = 18;

// Create action decorator
KPolygon actionDecorator = _kContainerRenderingExtensions.addPolygon(line);
_kRenderingExtensions.setBackground(actionDecorator, Colors.WHITE);
List<KPosition> pointsToAdd =
List.of(
_kRenderingExtensions.createKPosition(LEFT, 0, 0.5f, TOP, 0, 0),
_kRenderingExtensions.createKPosition(RIGHT, 0, 0, BOTTOM, 0, 0),
_kRenderingExtensions.createKPosition(LEFT, 0, 0, BOTTOM, 0, 0));
actionDecorator.getPoints().addAll(pointsToAdd);

// Set placement data of the action decorator
KDecoratorPlacementData placementData = _kRenderingFactory.createKDecoratorPlacementData();
placementData.setRelative(0.5f);
placementData.setAbsolute(-size / 2);
placementData.setWidth(size);
placementData.setHeight(size);
placementData.setYOffset(-size * 0.66f);
placementData.setRotateWithLine(true);
actionDecorator.setPlacementData(placementData);

// Add text to the action decorator
KText textToAdd = _kContainerRenderingExtensions.addText(actionDecorator, text);
_kRenderingExtensions.setFontSize(textToAdd, 8);
_linguaFrancaStyleExtensions.noSelectionStyle(textToAdd);
DiagramSyntheses.suppressSelectability(textToAdd);
_kRenderingExtensions.setPointPlacementData(
textToAdd,
_kRenderingExtensions.LEFT,
0,
0.5f,
_kRenderingExtensions.TOP,
size * 0.15f,
0.5f,
_kRenderingExtensions.H_CENTRAL,
_kRenderingExtensions.V_CENTRAL,
0,
0,
size,
size);

return actionDecorator;
}

/** Creates the triangular action node with text and ports. */
public Pair<KPort, KPort> addActionFigureAndPorts(KNode node, String text) {
final float size = 18;
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/lflang/generator/ReactionInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.lflang.lf.TriggerRef;
import org.lflang.lf.VarRef;
import org.lflang.lf.Variable;
import org.lflang.lf.Watchdog;

/**
* Representation of a compile-time instance of a reaction. Like {@link ReactorInstance}, if one or
Expand Down Expand Up @@ -108,6 +109,10 @@ public ReactionInstance(Reaction definition, ReactorInstance parent, int index)
this.triggers.add(timerInstance);
timerInstance.dependentReactions.add(this);
this.sources.add(timerInstance);
} else if (variable instanceof Watchdog) {
var watchdogInstance =
parent.lookupWatchdogInstance((Watchdog) ((VarRef) trigger).getVariable());
this.triggers.add(watchdogInstance);
}
} else if (trigger instanceof BuiltinTriggerRef) {
var builtinTriggerInstance = parent.getOrCreateBuiltinTrigger((BuiltinTriggerRef) trigger);
Expand Down Expand Up @@ -159,6 +164,9 @@ public ReactionInstance(Reaction definition, ReactorInstance parent, int index)
var actionInstance = parent.lookupActionInstance((Action) variable);
this.effects.add(actionInstance);
actionInstance.dependsOnReactions.add(this);
} else if (variable instanceof Watchdog) {
var watchdogInstance = parent.lookupWatchdogInstance((Watchdog) variable);
this.effects.add(watchdogInstance);
} else {
// Effect is either a mode or an unresolved reference.
// Do nothing, transitions will be set up by the ModeInstance.
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/org/lflang/generator/ReactorInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,23 @@ public ModeInstance lookupModeInstance(Mode mode) {
return null;
}

/**
* Return the watchdog instance within this reactor instance corresponding to the specified
* watchdog reference.
*
* @param watchdog The watchdog as an AST node.
* @return The corresponding watchdog instance or null if the watchdog does not belong to this
* reactor.
*/
public WatchdogInstance lookupWatchdogInstance(Watchdog watchdog) {
for (WatchdogInstance watchdogInstance : watchdogs) {
if (watchdogInstance.getDefinition() == watchdog) {
return watchdogInstance;
}
}
return null;
}

/** Return a descriptive string. */
@Override
public String toString() {
Expand Down Expand Up @@ -877,6 +894,8 @@ public ReactorInstance(
this.actions.add(new ActionInstance(actionDecl, this));
}

createWatchdogInstances();

establishPortConnections();

// Create the reaction instances in this reactor instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
*
* @author{Benjamin Asch <[email protected]>}
*/
public class WatchdogInstance {
public class WatchdogInstance extends TriggerInstance<Watchdog> {

/** Create a new watchdog instance associated with the given reactor instance. */
public WatchdogInstance(Watchdog definition, ReactorInstance reactor) {
super(definition, reactor);
if (definition.getTimeout() != null) {
// Get the timeout value given in the watchdog declaration.
this.timeout = reactor.getTimeValue(definition.getTimeout());
Expand Down

0 comments on commit 862e8de

Please sign in to comment.