/* * Copyright 2013-2015 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.instinct; import ccre.channel.BooleanInput; import ccre.channel.CancelOutput; import ccre.channel.EventInput; import ccre.channel.EventOutput; import ccre.channel.FloatInput; import ccre.log.Logger; import ccre.time.Time; /** * The base class for the different kinds of user-extendable Instinct modules. * * @author skeggsc */ public abstract class InstinctBaseModule { /** * Wait until the specified BooleanInput becomes true before returning. * * @param waitFor The condition to wait until. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitUntil(BooleanInput waitFor) throws AutonomousModeOverException, InterruptedException { // TODO: make this dynamic while (true) { ensureShouldBeRunning(); if (waitFor.get()) { return; } waitCycle(); } } /** * Wait until the specified BooleanInput becomes true before returning, or * for a timeout to elapse. * * @param timeout the maximum amount of time to wait, in milliseconds. * @param waitFor the condition to wait until. * @return true if the condition became true, or false if the timeout * elapsed. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected boolean waitUntil(long timeout, BooleanInput waitFor) throws AutonomousModeOverException, InterruptedException { long doneAt = Time.currentTimeMillis() + timeout; // TODO: make this dynamic while (Time.currentTimeMillis() < doneAt) { ensureShouldBeRunning(); if (waitFor.get()) { return true; } waitCycle(); } return false; } /** * Wait until the specified BooleanInput becomes false before returning. * * @param waitFor The condition to wait until not true. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitUntilNot(BooleanInput waitFor) throws AutonomousModeOverException, InterruptedException { // TODO: make this dynamic while (true) { ensureShouldBeRunning(); if (!waitFor.get()) { return; } waitCycle(); } } /** * Wait until the specified BooleanInput becomes false before returning, or * for a timeout to elapse. * * @param timeout the maximum amount of time to wait, in milliseconds. * @param waitFor the condition to wait until not true. * @return true if the condition became false, or false if the timeout * elapsed. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected boolean waitUntilNot(long timeout, BooleanInput waitFor) throws AutonomousModeOverException, InterruptedException { long doneAt = Time.currentTimeMillis() + timeout; // TODO: make this dynamic while (Time.currentTimeMillis() < doneAt) { ensureShouldBeRunning(); if (!waitFor.get()) { return true; } waitCycle(); } return false; } /** * Wait until the specified EventInput is produced before returning. * * @param source The event to wait for. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitForEvent(EventInput source) throws AutonomousModeOverException, InterruptedException { final boolean[] b = new boolean[1]; EventOutput c = new EventOutput() { @Override public void event() { synchronized (b) { b[0] = true; b.notifyAll(); } } }; CancelOutput unbind = source.send(c); try { synchronized (b) { while (!b[0]) { ensureShouldBeRunning(); b.wait(); } } } finally { unbind.cancel(); } } /** * Wait for one of the specified conditions to become true before returning, * or for the timeout to elapse. * * @param timeout the maximum amount of time to wait, in milliseconds. * @param waitFor The conditions to check. * @return the index of the first condition that became true, or -1 if this * method timed out. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected int waitUntilOneOf(long timeout, BooleanInput... waitFor) throws AutonomousModeOverException, InterruptedException { long doneAt = Time.currentTimeMillis() + timeout; // TODO: make this dynamic while (Time.currentTimeMillis() < doneAt) { ensureShouldBeRunning(); for (int i = 0; i < waitFor.length; i++) { if (waitFor[i].get()) { return i; } } waitCycle(); } return -1; } /** * Wait for one of the specified conditions to become true before returning. * * @param waitFor The conditions to check. * @return The index of the first condition that became true. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected int waitUntilOneOf(BooleanInput... waitFor) throws AutonomousModeOverException, InterruptedException { // TODO: make this dynamic while (true) { ensureShouldBeRunning(); for (int i = 0; i < waitFor.length; i++) { if (waitFor[i].get()) { return i; } } waitCycle(); } } /** * Wait until the specified FloatInput reaches or rises above the specified * minimum. * * @param waitFor The value to monitor. * @param minimum The threshold to wait for the value to reach. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitUntilAtLeast(FloatInput waitFor, float minimum) throws AutonomousModeOverException, InterruptedException { // TODO: make sure that nothing is accidentally kept around after this waitUntil(waitFor.atLeast(minimum)); } /** * Wait until the specified FloatInput reaches or falls below the specified * maximum. * * @param waitFor The value to monitor. * @param maximum The threshold to wait for the value to reach. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitUntilAtMost(FloatInput waitFor, float maximum) throws AutonomousModeOverException, InterruptedException { // TODO: make sure that nothing is accidentally kept around after this waitUntil(waitFor.atMost(maximum)); } /** * Wait for the specified amount of time. * * @param milliseconds The amount of time to wait for, in milliseconds. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitForTime(long milliseconds) throws InterruptedException, AutonomousModeOverException { if (milliseconds < 0) { Logger.warning("Negative wait in Instinct: " + milliseconds); return; } else if (milliseconds == 0) { return;// Do nothing. } ensureShouldBeRunning(); try { Time.sleep(milliseconds); } finally { ensureShouldBeRunning(); } } /** * Wait for the specified amount of time, fetched from a FloatInput * specified in seconds. * * WARNING: If the time changes during the call to this method, the updated * value will not be used. Only the value from when the call was originally * made will count. * * @param seconds The amount of time to wait for, in seconds. * @throws AutonomousModeOverException If the autonomous mode has ended. * @throws InterruptedException Possibly also if autonomous mode has ended. */ protected void waitForTime(FloatInput seconds) throws InterruptedException, AutonomousModeOverException { waitForTime((long) (1000 * seconds.get() + 0.5f)); } /** * The location for the main code of this InstinctModule. * * @throws AutonomousModeOverException Propagate this up here when thrown by * any waiting method. * @throws InterruptedException Propagate this up here when thrown by any * waiting method. * @throws Throwable If you want to fail for some other reason. */ protected abstract void autonomousMain() throws Throwable; /** * Wait until the next time that this module should update. */ abstract void waitCycle() throws InterruptedException; /** * Make sure that the autonomous mode should still be running. * * @throws AutonomousModeOverException if the autonomous mode shouldn't be * running. */ abstract void ensureShouldBeRunning() throws AutonomousModeOverException; }