/* * Copyright 2016 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.scheduler; import ccre.channel.CancelOutput; import ccre.channel.EventOutput; import ccre.time.Time; import ccre.verifier.FlowPhase; import ccre.verifier.SetupPhase; class FullLoop { private final class FixedRateEvent extends CancellableScheduleEntry implements CancelOutput { private long nextScheduleAtNanos; private final long periodNanos; private final boolean skippable; private final String tag; public FixedRateEvent(String tag, long firstAtNanos, long periodNanos, boolean skippable, EventOutput o) { super(o); this.tag = tag; this.nextScheduleAtNanos = firstAtNanos; this.periodNanos = periodNanos; this.skippable = skippable; } @FlowPhase public void schedule() { // purposeful comparison order to avoid overflow errors if (this.skippable && this.nextScheduleAtNanos - Time.currentTimeNanos() < 0) { // skip a bit to deal with load this.nextScheduleAtNanos += this.periodNanos; } scheduleOnce(tag, this.nextScheduleAtNanos, this); this.nextScheduleAtNanos += this.periodNanos; } @Override public void event() { if (!cancel) { this.schedule(); this.o.event(); } } } private final class VariableRateEvent extends CancellableScheduleEntry implements CancelOutput { private final long periodNanos; private final String tag; public VariableRateEvent(String tag, long periodNanos, EventOutput o) { super(o); this.tag = tag; this.periodNanos = periodNanos; } @FlowPhase public void schedule() { scheduleOnce(tag, Time.currentTimeNanos() + this.periodNanos, this); } @Override public void event() { if (!cancel) { this.schedule(); this.o.event(); } } } private class CancellableScheduleEntry implements EventOutput { final EventOutput o; volatile boolean cancel; @FlowPhase public CancellableScheduleEntry(EventOutput o) { this.o = o; } @Override public void event() { if (!cancel) { this.o.event(); } } @FlowPhase public void cancel() { this.cancel = true; } } private final IRunLoop rl; FullLoop(IRunLoop rl) { this.rl = rl; } FullLoop() { this.rl = new RunLoop(); } @FlowPhase public void scheduleOnce(String tag, long timeAtNanos, EventOutput o) { rl.add(tag, o, timeAtNanos); } @FlowPhase public EventOutput scheduleCancellableOnce(String tag, long timeAtNanos, EventOutput o) { CancellableScheduleEntry event = new CancellableScheduleEntry(o); scheduleOnce(tag, timeAtNanos, event); return event::cancel; } @SetupPhase public CancelOutput scheduleFixedRate(String tag, long firstAtNanos, long periodNanos, boolean skippable, EventOutput o) { FixedRateEvent event = new FixedRateEvent(tag, firstAtNanos, periodNanos, skippable, o); event.schedule(); return event; } @SetupPhase public CancelOutput scheduleVariableRate(String tag, long periodNanos, EventOutput o) { VariableRateEvent event = new VariableRateEvent(tag, periodNanos, o); event.schedule(); return event; } @SetupPhase public void start() { rl.start(); } @SetupPhase public void terminate() { rl.terminate(); } }