-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into cpp-examples
- Loading branch information
Showing
4 changed files
with
144 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Watchdog -- Reacting to Absent Inputs | ||
|
||
The LF deadline handlers react to inputs that are late. | ||
What if you want to react the fact that an input has _not_ arrived by a certain time? | ||
The deadline construct, by itself, will not do this. | ||
It does not react until an input actually arrives. | ||
|
||
The watchdog construct provides a mechanism for this. | ||
A watchdog is started using `lf_watchdog_start` at some logical time _t_. | ||
It will expire at _physical_ time _t_ + _W_, where _W_ is the watchdog delay, | ||
unless it gets restarted with `lf_watchdog_start` or stopped using `lf_watchdog_stop` | ||
before that physical time elapses. | ||
|
||
When a watchdog expires, two things happen. First, the watchdog handler is invoked. | ||
Second, an event identified by the name of the watchdog is scheduled at the earliest | ||
available tag (typically the current tag plus one microstep). | ||
The watchdog handler is invoked asynchronously, and therefore has limited access | ||
to the reactor's infrastructure, such as inputs and outputs. | ||
However, the scheduled watchdog event can trigger an ordinary reaction | ||
which has full access to the state variables and inputs and outputs of the reactor. | ||
|
||
<table> | ||
<tr> | ||
<td> <img src="img/Watchdog.png" alt="Watchdog" width="400"> | ||
<td> <a href="Watchdog.lf">Watchdog.lf</a>: Illustration of the use of the watchdogs in LF.</td> | ||
</tr> | ||
</table> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/** | ||
* @brief Demonstration of watchdogs in LF. | ||
* | ||
* This program has a periodic source that triggers events every 500 ms, but where every fourth | ||
* event is delayed before being delivered to the downstream Watcher. This delay models either | ||
* communication or computation time. | ||
* | ||
* The Watcher has a deadline of 200 ms. It wants to see events within 200 ms of their logical time, | ||
* but, because of the delay every fourth event, the deadline will be violated. The deadline | ||
* violation handler is invoked in this case, but it is only invoked after the event arrives, which | ||
* is late. What if we need to react to the deadline violation sooner, e.g. in order to drive an | ||
* actuator? | ||
* | ||
* To handle this, the Watcher includes watchdog named "dog" that triggers if any input event is | ||
* more than 250 ms late. | ||
* | ||
* @author Benjamin Asch | ||
* @author Edward A. Lee | ||
*/ | ||
target C { | ||
timeout: 5 s | ||
} | ||
|
||
reactor SometimesSlowSource { | ||
output out: int | ||
timer t(500 ms, 500 ms) // Offset ameliorates startup time. | ||
state count: int = 1 | ||
|
||
reaction(t) -> out {= | ||
if (self->count % 4 == 0) { | ||
// Be slow. | ||
lf_sleep(MSEC(300)); | ||
} | ||
lf_set(out, self->count++); | ||
=} | ||
} | ||
|
||
reactor Watcher { | ||
input in: int | ||
output out: int | ||
state count: int = 1 | ||
logical action a(500 ms) | ||
|
||
watchdog dog(750 ms) {= | ||
instant_t p = lf_time_physical_elapsed(); | ||
lf_print("******** Watchdog timed out at elapsed physical time: " PRINTF_TIME, p); | ||
=} | ||
|
||
reaction(in) -> dog, out {= | ||
// Reset the watchdog. The next event is expected in 500 ms. | ||
// This watchdog will trigger if the event does not arrive within 750 ms from now, | ||
// or is more than 250 ms late. | ||
lf_watchdog_start(dog, 0); | ||
lf_print("Watchdog started at physical time " PRINTF_TIME, lf_time_physical_elapsed()); | ||
lf_print("Will expire at " PRINTF_TIME, lf_time_logical_elapsed() + MSEC(750)); | ||
lf_set(out, in->value); | ||
self->count++; | ||
=} deadline(200 ms) {= | ||
// This input is more than 200 ms late. It must have been from the slow cycles. | ||
lf_print("Watcher received late input %d. Ignoring it.", in->value); | ||
=} | ||
|
||
reaction(dog) -> a {= | ||
// Note that this reaction will trigger at the earliest available tag, which | ||
// will be one microstep later than the most recent input or watchdog violation. | ||
lf_print("******** Watchdog triggered. Scheduling output for next logical time."); | ||
// Use a logical action so that the logical time of the output aligns. | ||
lf_schedule(a, 0); | ||
=} | ||
|
||
reaction(a) -> out, dog {= | ||
lf_print("******** Backup output being produced."); | ||
lf_set(out, self->count++); | ||
// Start another watchdog cycle in case the very next input is also delayed. | ||
lf_watchdog_start(dog, 0); | ||
lf_print("Watchdog started at physical time " PRINTF_TIME, lf_time_physical_elapsed()); | ||
lf_print("Will expire at " PRINTF_TIME, lf_time_logical_elapsed() + MSEC(750)); | ||
=} | ||
|
||
reaction(shutdown) -> dog {= | ||
lf_watchdog_stop(dog); | ||
=} | ||
} | ||
|
||
reactor Checker { | ||
input in: int | ||
state count: int = 1 | ||
|
||
reaction(in) {= | ||
lf_print("Checker received %d at logical time " PRINTF_TIME | ||
" and physical time " PRINTF_TIME, in->value, | ||
lf_time_logical_elapsed(), | ||
lf_time_physical_elapsed()); | ||
if (in->value != self->count) { | ||
lf_print_error_and_exit("Expected %d", self->count); | ||
} | ||
self->count++; | ||
=} | ||
|
||
reaction(shutdown) {= | ||
if (self->count < 10) { | ||
lf_print_error_and_exit("Received %d inputs. Expected at least 10.", self->count); | ||
} | ||
=} | ||
} | ||
|
||
federated reactor { | ||
s = new SometimesSlowSource() | ||
w = new Watcher() | ||
c = new Checker() | ||
|
||
s.out -> w.in | ||
w.out -> c.in | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.