node {
TimeMs nextTrig;
void evaluate(Context ctx) {
TimeMs tNow = transactionTime();
auto ival = getValue<input_Intervall>(ctx);
if (ival < 0) ival = 0;
TimeMs dt = ival * 1000;
TimeMs tNext = tNow + dt;
auto isEnabled = getValue<input_AnAus>(ctx);
auto isRstDirty = isInputDirty<input_Neustart>(ctx);
if (isTimedOut(ctx) && isEnabled && !isRstDirty) {
emitValue<output_Tick>(ctx, 1);
nextTrig = tNext;
setTimeout(ctx, dt);
}
if (isRstDirty || isInputDirty<input_AnAus>(ctx)) {
// Handle enable/disable/reset
if (!isEnabled) {
// Disable timeout loop on explicit false on EN
nextTrig = 0;
clearTimeout(ctx);
} else if (nextTrig < tNow || nextTrig > tNext) {
// Start timeout from scratch
nextTrig = tNext;
setTimeout(ctx, dt);
}
}
}
}| __time(ms) | Intervall | AnAus | Neustart | Tick |
|---|---|---|---|---|
| 0 | 0.1 | true | no-pulse | no-pulse |
| 100 | 0.1 | true | pulse | no-pulse |
| 120 | 0.1 | true | no-pulse | no-pulse |
| 201 | 0.1 | true | no-pulse | pulse |
| 250 | 0.1 | true | no-pulse | no-pulse |
| 302 | 0.1 | true | no-pulse | pulse |
| 350 | 0.1 | false | no-pulse | no-pulse |
| 403 | 0.1 | false | no-pulse | no-pulse |
| 0 | 1 | true | pulse | no-pulse |
| 500 | 1 | true | pulse | no-pulse |
| 1001 | 1 | true | no-pulse | no-pulse |
| 1501 | 1 | true | no-pulse | pulse |
| // edge case: when IVAL is 0, `clock` should constantly emit pulses | ||||
| 0 | 0 | true | no-pulse | pulse |
| 1 | 0 | true | no-pulse | pulse |
| 2 | 1 | true | no-pulse | pulse |
| 1003 | 1 | true | no-pulse | pulse |
| // edge case: when IVAL is negative, behave like it's 0 | ||||
| 0 | -1 | true | no-pulse | pulse |
| 1 | -1 | true | no-pulse | pulse |
| 2 | 1 | true | no-pulse | pulse |
| 1003 | 1 | true | no-pulse | pulse |