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    }