Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diagram support for watchdogs #2356

Merged
merged 5 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)*
edwardalee marked this conversation as resolved.
Show resolved Hide resolved
'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,33 @@ 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);
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);
}
edwardalee marked this conversation as resolved.
Show resolved Hide resolved
}

// 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) {
edwardalee marked this conversation as resolved.
Show resolved Hide resolved
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 <benjamintasch@berkeley.edu>}
*/
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
Loading