001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2017-2018 FIRST. 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 private void requireAll() { 051 if (m_onTrue != null) { 052 for (Enumeration e = m_onTrue.getRequirements(); e.hasMoreElements(); ) { 053 requires((Subsystem) e.nextElement()); 054 } 055 } 056 057 if (m_onFalse != null) { 058 for (Enumeration e = m_onFalse.getRequirements(); e.hasMoreElements(); ) { 059 requires((Subsystem) e.nextElement()); 060 } 061 } 062 } 063 064 /** 065 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 066 * 067 * <p>Users of this constructor should also override condition(). 068 * 069 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 070 */ 071 public ConditionalCommand(Command onTrue) { 072 this(onTrue, null); 073 } 074 075 /** 076 * Creates a new ConditionalCommand with given onTrue and onFalse Commands. 077 * 078 * <p>Users of this constructor should also override condition(). 079 * 080 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 081 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 082 */ 083 public ConditionalCommand(Command onTrue, Command onFalse) { 084 m_onTrue = onTrue; 085 m_onFalse = onFalse; 086 087 requireAll(); 088 } 089 090 /** 091 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 092 * 093 * <p>Users of this constructor should also override condition(). 094 * 095 * @param name the name for this command group 096 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 097 */ 098 public ConditionalCommand(String name, Command onTrue) { 099 this(name, onTrue, null); 100 } 101 102 /** 103 * Creates a new ConditionalCommand with given name and onTrue and onFalse Commands. 104 * 105 * <p>Users of this constructor should also override condition(). 106 * 107 * @param name the name for this command group 108 * @param onTrue The Command to execute if {@link ConditionalCommand#condition()} returns true 109 * @param onFalse The Command to execute if {@link ConditionalCommand#condition()} returns false 110 */ 111 public ConditionalCommand(String name, Command onTrue, Command onFalse) { 112 super(name); 113 m_onTrue = onTrue; 114 m_onFalse = onFalse; 115 116 requireAll(); 117 } 118 119 /** 120 * The Condition to test to determine which Command to run. 121 * 122 * @return true if m_onTrue should be run or false if m_onFalse should be run. 123 */ 124 protected abstract boolean condition(); 125 126 /** 127 * Calls {@link ConditionalCommand#condition()} and runs the proper command. 128 */ 129 @Override 130 protected void _initialize() { 131 if (condition()) { 132 m_chosenCommand = m_onTrue; 133 } else { 134 m_chosenCommand = m_onFalse; 135 } 136 137 if (m_chosenCommand != null) { 138 /* 139 * This is a hack to make cancelling the chosen command inside a 140 * CommandGroup work properly 141 */ 142 m_chosenCommand.clearRequirements(); 143 144 m_chosenCommand.start(); 145 } 146 super._initialize(); 147 } 148 149 @Override 150 protected void _cancel() { 151 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 152 m_chosenCommand.cancel(); 153 } 154 155 super._cancel(); 156 } 157 158 @Override 159 protected boolean isFinished() { 160 if (m_chosenCommand != null) { 161 return m_chosenCommand.isCompleted(); 162 } else { 163 return true; 164 } 165 } 166 167 @Override 168 protected void _interrupted() { 169 if (m_chosenCommand != null && m_chosenCommand.isRunning()) { 170 m_chosenCommand.cancel(); 171 } 172 173 super._interrupted(); 174 } 175}