001 /*----------------------------------------------------------------------------*/
002 /* Copyright (c) FIRST 2008-2012. 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
008 package edu.wpi.first.wpilibj.command;
009
010 import edu.wpi.first.wpilibj.NamedSendable;
011 import edu.wpi.first.wpilibj.tables.ITable;
012 import java.util.Enumeration;
013 import java.util.Vector;
014
015 /**
016 * This class defines a major component of the robot.
017 *
018 * <p>A good example of a subsystem is the driveline, or a claw if the robot has one.</p>
019 *
020 * <p>All motors should be a part of a subsystem. For instance, all the wheel motors should be
021 * a part of some kind of "Driveline" subsystem.</p>
022 *
023 * <p>Subsystems are used within the command system as requirements for {@link Command}.
024 * Only one command which requires a subsystem can run at a time. Also, subsystems
025 * can have default commands which are started if there is no command running which
026 * requires this subsystem.</p>
027 *
028 * @author Joe Grinstead
029 * @see Command
030 */
031 public abstract class Subsystem implements NamedSendable{
032
033 /** Whether or not getDefaultCommand() was called */
034 private boolean initializedDefaultCommand = false;
035 /** The current command */
036 private Command currentCommand;
037 private boolean currentCommandChanged;
038
039 /** The default command */
040 private Command defaultCommand;
041 /** The name */
042 private String name;
043 /** List of all subsystems created */
044 private static Vector allSubsystems = new Vector();
045
046 /**
047 * Creates a subsystem with the given name
048 * @param name the name of the subsystem
049 */
050 public Subsystem(String name) {
051 this.name = name;
052 Scheduler.getInstance().registerSubsystem(this);
053 }
054
055 /**
056 * Creates a subsystem. This will set the name to the name of the class.
057 */
058 public Subsystem() {
059 this.name = getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1);
060 Scheduler.getInstance().registerSubsystem(this);
061 currentCommandChanged = true;
062 }
063
064 /**
065 * Initialize the default command for a subsystem
066 * By default subsystems have no default command, but if they do, the default command is set
067 * with this method. It is called on all Subsystems by CommandBase in the users program after
068 * all the Subsystems are created.
069 */
070 protected abstract void initDefaultCommand();
071
072 /**
073 * Sets the default command. If this is not called or is called with null,
074 * then there will be no default command for the subsystem.
075 *
076 * <p><b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the subsystem is a
077 * singleton.</p>
078 *
079 * @param command the default command (or null if there should be none)
080 * @throws IllegalUseOfCommandException if the command does not require the subsystem
081 */
082 protected void setDefaultCommand(Command command) {
083 if (command == null) {
084 defaultCommand = null;
085 } else {
086 boolean found = false;
087 Enumeration requirements = command.getRequirements();
088 while (requirements.hasMoreElements()) {
089 if (requirements.nextElement().equals(this)) {
090 found = true;
091 // } else {
092 // throw new IllegalUseOfCommandException("A default command cannot require multiple subsystems");
093 }
094 }
095 if (!found) {
096 throw new IllegalUseOfCommandException("A default command must require the subsystem");
097 }
098 defaultCommand = command;
099 }
100 if (table != null) {
101 if (defaultCommand != null) {
102 table.putBoolean("hasDefault", true);
103 table.putString("default", defaultCommand.getName());
104 } else {
105 table.putBoolean("hasDefault", false);
106 }
107 }
108 }
109
110 /**
111 * Returns the default command (or null if there is none).
112 * @return the default command
113 */
114 protected Command getDefaultCommand() {
115 if (!initializedDefaultCommand) {
116 initializedDefaultCommand = true;
117 initDefaultCommand();
118 }
119 return defaultCommand;
120 }
121
122 /**
123 * Sets the current command
124 * @param command the new current command
125 */
126 void setCurrentCommand(Command command) {
127 currentCommand = command;
128 currentCommandChanged = true;
129 }
130
131 /**
132 * Call this to alert Subsystem that the current command is actually the command.
133 * Sometimes, the {@link Subsystem} is told that it has no command while the {@link Scheduler}
134 * is going through the loop, only to be soon after given a new one. This will avoid that situation.
135 */
136 void confirmCommand() {
137 if (currentCommandChanged) {
138 if (table != null) {
139 if (currentCommand != null) {
140 table.putBoolean("hasCommand", true);
141 table.putString("command", currentCommand.getName());
142 } else {
143 table.putBoolean("hasCommand", false);
144 }
145 }
146 currentCommandChanged = false;
147 }
148 }
149
150 /**
151 * Returns the command which currently claims this subsystem.
152 * @return the command which currently claims this subsystem
153 */
154 public Command getCurrentCommand() {
155 return currentCommand;
156 }
157
158 public String toString() {
159 return getName();
160 }
161
162 /**
163 * Returns the name of this subsystem, which is by default the class name.
164 * @return the name of this subsystem
165 */
166 public String getName() {
167 return name;
168 }
169
170 public String getSmartDashboardType(){
171 return "Subsystem";
172 }
173 private ITable table;
174 public void initTable(ITable table){
175 this.table = table;
176 if(table!=null){
177 if (defaultCommand != null) {
178 table.putBoolean("hasDefault", true);
179 table.putString("default", defaultCommand.getName());
180 } else {
181 table.putBoolean("hasDefault", false);
182 }
183 if (currentCommand != null) {
184 table.putBoolean("hasCommand", true);
185 table.putString("command", currentCommand.getName());
186 } else {
187 table.putBoolean("hasCommand", false);
188 }
189 }
190 }
191 /**
192 * {@inheritDoc}
193 */
194 public ITable getTable(){
195 return table;
196 }
197 }