/* * Copyright 2013-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.instinct; import ccre.channel.BooleanCell; import ccre.channel.BooleanIO; import ccre.channel.BooleanInput; import ccre.concurrency.ReporterThread; import ccre.log.Logger; import ccre.time.Time; import ccre.verifier.SetupPhase; /** * The base class for an Instinct (the simple autonomous subsystem) module. * * @author skeggsc */ public abstract class InstinctModule extends InstinctBaseModule { /** * If the instinct module should currently be running. */ private BooleanInput shouldBeRunning; /** * The amount of time between condition checks for most things that auto is * waiting on. Must be positive. 20 milliseconds by default. */ private int autoCycleRate = 20; /** * The main thread for code running in this Instinct Module. */ private final ReporterThread main = new ReporterThread("Instinct") { @Override protected void threadBody() { instinctBody(); } }; { main.setPriority(Thread.MAX_PRIORITY - 1); } /** * Create a new InstinctModule with a BooleanInput controlling when this * module should run. * * @param shouldBeRunning The input to control the running of this module. */ public InstinctModule(BooleanInput shouldBeRunning) { setShouldBeRunning(shouldBeRunning); } /** * Create a new InstinctModule that needs to be registered before it will be * useful. * * @see ccre.frc.FRC#registerAutonomous(InstinctModule) */ public InstinctModule() { this.shouldBeRunning = null; } /** * Get the amount of time between condition checks for most things that auto * is waiting on. Must be positive. 20 milliseconds by default. * * @return the autoSynchTimeout */ public int getAutoCycleRate() { return autoCycleRate; } /** * Set the amount of time between condition checks for most things that auto * is waiting on. Must be positive. 20 milliseconds by default. * * @param autoCycleRate the autoCycleRate to set * @throws IllegalArgumentException if the specified timeout is not positive */ public void setAutoCycleRate(int autoCycleRate) throws IllegalArgumentException { if (autoCycleRate <= 0) { throw new IllegalArgumentException("AutoSynchTimeout must be positive!"); } this.autoCycleRate = autoCycleRate; } private void instinctBody() { while (true) { while (!shouldBeRunning.get()) { try { waitCycle(); } catch (InterruptedException ex) { } } if (Thread.interrupted()) { // got rid of interrupt } try { try { Logger.info("Started " + getTypeName() + "."); autonomousMain(); Logger.info("Completed " + getTypeName() + "."); } catch (InterruptedException ex) { Logger.info("Interrupted " + getTypeName() + "."); } catch (AutonomousModeOverException ex) { Logger.info("Exited " + getTypeName() + " by stop."); continue; } } catch (Throwable t) { Logger.severe("Exception thrown during Autonomous mode!", t); } while (shouldBeRunning.get()) { try { // Wait until no longer supposed to be running. waitCycle(); } catch (InterruptedException ex) { } } } } /** * The name of this control loop. Defaults to "autonomous mode". * * @return The name to use in printouts. */ protected String getTypeName() { return "autonomous mode"; } /** * Sets this module to run when the specified BooleanInput is true. * * @param when When this should be running. */ @SetupPhase public void setShouldBeRunning(BooleanInput when) { if (this.shouldBeRunning != null) { throw new IllegalStateException(); } if (when == null) { throw new NullPointerException(); } shouldBeRunning = when; if (!main.isAlive()) { // TODO: do I really need to check if it's alive? main.start(); } } @Override void waitCycle() throws InterruptedException { // TODO: inline this? Time.sleep(autoCycleRate); } @Override // TODO: ensure that this always gets used? void ensureShouldBeRunning() throws AutonomousModeOverException { if (!shouldBeRunning.get()) { throw new AutonomousModeOverException(); } } /** * Provides a BooleanIO that can be set to true or false to control whether * or not this Instinct module is running. * * @return the BooleanIO that controls this module */ public BooleanIO controlIO() { BooleanCell bc = new BooleanCell(); setShouldBeRunning(bc); return bc; } /** * Cancels this autonomous mode as soon as possible. */ public void abortMode() { main.interrupt(); } }