blob: 47fe7f1deb15e882dc50b72ab7828ef97f8e93ad [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2011-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#ifndef __COMMAND_H__
9#define __COMMAND_H__
10
11#include "ErrorBase.h"
12#include "SmartDashboard/NamedSendable.h"
13#include "tables/ITableListener.h"
14#include <set>
15#include <string>
16#include <memory>
17
18class CommandGroup;
19class Subsystem;
20
21/**
22 * The Command class is at the very core of the entire command framework.
23 * Every command can be started with a call to {@link Command#Start() Start()}.
24 * Once a command is started it will call {@link Command#Initialize()
25 * Initialize()}, and then
26 * will repeatedly call {@link Command#Execute() Execute()} until the {@link
27 *Command#IsFinished() IsFinished()}
28 * returns true. Once it does, {@link Command#End() End()} will be called.
29 *
30 * <p>However, if at any point while it is running {@link Command#Cancel()
31 * Cancel()} is called, then
32 * the command will be stopped and {@link Command#Interrupted() Interrupted()}
33 * will be called.</p>
34 *
35 * <p>If a command uses a {@link Subsystem}, then it should specify that it does
36 * so by
37 * calling the {@link Command#Requires(Subsystem) Requires(...)} method
38 * in its constructor. Note that a Command may have multiple requirements, and
39 * {@link Command#Requires(Subsystem) Requires(...)} should be
40 * called for each one.</p>
41 *
42 * <p>If a command is running and a new command with shared requirements is
43 * started,
44 * then one of two things will happen. If the active command is interruptible,
45 * then {@link Command#Cancel() Cancel()} will be called and the command will be
46 * removed
47 * to make way for the new one. If the active command is not interruptible, the
48 * other one will not even be started, and the active one will continue
49 * functioning.</p>
50 *
51 * @see CommandGroup
52 * @see Subsystem
53 */
54class Command : public ErrorBase, public NamedSendable, public ITableListener {
55 friend class CommandGroup;
56 friend class Scheduler;
57
58 public:
59 Command();
60 Command(const std::string &name);
61 Command(double timeout);
62 Command(const std::string &name, double timeout);
63 virtual ~Command();
64 double TimeSinceInitialized() const;
65 void Requires(Subsystem *s);
66 bool IsCanceled() const;
67 void Start();
68 bool Run();
69 void Cancel();
70 bool IsRunning() const;
71 bool IsInterruptible() const;
72 void SetInterruptible(bool interruptible);
73 bool DoesRequire(Subsystem *subsystem) const;
74 typedef std::set<Subsystem *> SubsystemSet;
75 SubsystemSet GetRequirements() const;
76 CommandGroup *GetGroup() const;
77 void SetRunWhenDisabled(bool run);
78 bool WillRunWhenDisabled() const;
79 int GetID() const;
80
81 protected:
82 void SetTimeout(double timeout);
83 bool IsTimedOut() const;
84 bool AssertUnlocked(const std::string &message);
85 void SetParent(CommandGroup *parent);
86 /**
87 * The initialize method is called the first time this Command is run after
88 * being started.
89 */
90 virtual void Initialize() = 0;
91 /**
92 * The execute method is called repeatedly until this Command either finishes
93 * or is canceled.
94 */
95 virtual void Execute() = 0;
96 /**
97 * Returns whether this command is finished.
98 * If it is, then the command will be removed
99 * and {@link Command#end() end()} will be called.
100 *
101 * <p>It may be useful for a team to reference the {@link Command#isTimedOut()
102 * isTimedOut()} method
103 * for time-sensitive commands.</p>
104 * @return whether this command is finished.
105 * @see Command#isTimedOut() isTimedOut()
106 */
107 virtual bool IsFinished() = 0;
108 /**
109 * Called when the command ended peacefully. This is where you may want
110 * to wrap up loose ends, like shutting off a motor that was being used
111 * in the command.
112 */
113 virtual void End() = 0;
114 /**
115 * Called when the command ends because somebody called {@link
116 *Command#cancel() cancel()}
117 * or another command shared the same requirements as this one, and booted
118 * it out.
119 *
120 * <p>This is where you may want
121 * to wrap up loose ends, like shutting off a motor that was being used
122 * in the command.</p>
123 *
124 * <p>Generally, it is useful to simply call the {@link Command#end() end()}
125 * method
126 * within this method</p>
127 */
128 virtual void Interrupted() = 0;
129 virtual void _Initialize();
130 virtual void _Interrupted();
131 virtual void _Execute();
132 virtual void _End();
133 virtual void _Cancel();
134
135 private:
136 void LockChanges();
137 /*synchronized*/ void Removed();
138 void StartRunning();
139 void StartTiming();
140
141 /** The name of this command */
142 std::string m_name;
143
144 /** The time since this command was initialized */
145 double m_startTime = -1;
146
147 /** The time (in seconds) before this command "times out" (or -1 if no
148 * timeout) */
149 double m_timeout;
150
151 /** Whether or not this command has been initialized */
152 bool m_initialized = false;
153
154 /** The requirements (or null if no requirements) */
155 SubsystemSet m_requirements;
156
157 /** Whether or not it is running */
158 bool m_running = false;
159
160 /** Whether or not it is interruptible*/
161 bool m_interruptible = true;
162
163 /** Whether or not it has been canceled */
164 bool m_canceled = false;
165
166 /** Whether or not it has been locked */
167 bool m_locked = false;
168
169 /** Whether this command should run when the robot is disabled */
170 bool m_runWhenDisabled = false;
171
172 /** The {@link CommandGroup} this is in */
173 CommandGroup *m_parent = nullptr;
174
175 int m_commandID = m_commandCounter++;
176 static int m_commandCounter;
177
178 public:
179 virtual std::string GetName() const;
180 virtual void InitTable(std::shared_ptr<ITable> table);
181 virtual std::shared_ptr<ITable> GetTable() const;
182 virtual std::string GetSmartDashboardType() const;
183 virtual void ValueChanged(ITable* source, llvm::StringRef key,
184 std::shared_ptr<nt::Value> value, bool isNew);
185
186 protected:
187 std::shared_ptr<ITable> m_table;
188};
189
190#endif