001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2017. All Rights Reserved. */ 003/* Open Source Software - may be modified and shared by FRC teams. The code */ 004/* must be accompanied by the FIRST BSD license file in the root directory of */ 005/* the project. */ 006/*----------------------------------------------------------------------------*/ 007 008package edu.wpi.first.wpilibj.command; 009 010import java.util.Enumeration; 011 012/** 013 * A {@link ConditionalCommand} is a {@link Command} that starts one of two commands. 014 * 015 * <p> 016 * A {@link ConditionalCommand} uses m_condition to determine whether it should run m_onTrue or 017 * m_onFalse. 018 * </p> 019 * 020 * <p> 021 * A {@link ConditionalCommand} adds the proper {@link Command} to the {@link Scheduler} during 022 * {@link ConditionalCommand#initialize()} and then {@link ConditionalCommand#isFinished()} will 023 * return true once that {@link Command} has finished executing. 024 * </p> 025 * 026 * <p> 027 * If no {@link Command} is specified for m_onFalse, the occurrence of that condition will be a 028 * no-op. 029 * </p> 030 * 031 * @see Command 032 * @see Scheduler 033 */ 034public abstract class ConditionalCommand extends Command { 035 /** 036 * The Command to execute if {@link ConditionalCommand#condition()} returns true. 037 */ 038 private Command m_onTrue; 039 040 /** 041 * The Command to execute if {@link ConditionalCommand#condition()} returns false. 042 */ 043 private Command m_onFalse; 044 045 /** 046 * Stores command chosen by condition. 047 */ 048 private Command m_chosenCommand = null; 049 050 /** 051 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 052 * 053 * <p>Users of this constructor should also override condition(). 054 * 055 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 056 */ 057 public ConditionalCommand(Command onTrue) { 058 this(onTrue, new InstantCommand()); 059 } 060 061 /** 062 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 063 * 064 * <p>Users of this constructor should also override condition(). 065 * 066 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 067 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 068 */ 069 public ConditionalCommand(Command onTrue, Command onFalse) { 070 m_onTrue = onTrue; 071 m_onFalse = onFalse; 072 073 for (Enumeration e = m_onTrue.getRequirements(); e.hasMoreElements(); ) { 074 requires((Subsystem) e.nextElement()); 075 } 076 077 for (Enumeration e = m_onFalse.getRequirements(); e.hasMoreElements(); ) { 078 requires((Subsystem) e.nextElement()); 079 } 080 } 081 082 /** 083 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 084 * 085 * <p>Users of this constructor should also override condition(). 086 * 087 * @param name the name for this command group 088 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 089 */ 090 public ConditionalCommand(String name, Command onTrue) { 091 this(name, onTrue, new InstantCommand()); 092 } 093 094 /** 095 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 096 * 097 * <p>Users of this constructor should also override condition(). 098 * 099 * @param name the name for this command group 100 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 101 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 102 */ 103 public ConditionalCommand(String name, Command onTrue, Command onFalse) { 104 super(name); 105 m_onTrue = onTrue; 106 m_onFalse = onFalse; 107 108 for (Enumeration e = m_onTrue.getRequirements(); e.hasMoreElements(); ) { 109 requires((Subsystem) e.nextElement()); 110 } 111 112 for (Enumeration e = m_onFalse.getRequirements(); e.hasMoreElements(); ) { 113 requires((Subsystem) e.nextElement()); 114 } 115 } 116 117 /** 118 * The Condition to test to determine which Command to run. 119 * 120 * @return true if m_onTrue should be run or false if m_onFalse should be run. 121 */ 122 protected abstract boolean condition(); 123 124 /** 125 * Calls {@link ConditionalCommand#condition()} and runs the proper command. 126 */ 127 @Override 128 protected void _initialize() { 129 if (condition()) { 130 m_chosenCommand = m_onTrue; 131 } else { 132 m_chosenCommand = m_onFalse; 133 } 134 135 // This is a hack to make cancelling the chosen command inside a CommandGroup work properly 136 m_chosenCommand.clearRequirements(); 137 138 m_chosenCommand.start(); 139 } 140 141 @Override 142 protected void _cancel() { 143 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 144 m_chosenCommand.cancel(); 145 } 146 147 super._cancel(); 148 } 149 150 @Override 151 protected boolean isFinished() { 152 return m_chosenCommand != null && m_chosenCommand.isRunning() 153 && m_chosenCommand.isFinished(); 154 } 155 156 @Override 157 protected void interrupted() { 158 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 159 m_chosenCommand.cancel(); 160 } 161 162 super.interrupted(); 163 } 164}