001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj2.command;
006
007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
008
009import edu.wpi.first.util.function.BooleanConsumer;
010import java.util.Set;
011import java.util.function.BooleanSupplier;
012
013/**
014 * A state machine representing a complete action to be performed by the robot. Commands are run by
015 * the {@link CommandScheduler}, and can be composed into CommandGroups to allow users to build
016 * complicated multistep actions without the need to roll the state machine logic themselves.
017 *
018 * <p>Commands are run synchronously from the main robot loop; no multithreading is used, unless
019 * specified explicitly from the command implementation.
020 *
021 * <p>This class is provided by the NewCommands VendorDep
022 */
023public interface Command {
024  /** The initial subroutine of a command. Called once when the command is initially scheduled. */
025  default void initialize() {}
026
027  /** The main body of a command. Called repeatedly while the command is scheduled. */
028  default void execute() {}
029
030  /**
031   * The action to take when the command ends. Called when either the command finishes normally, or
032   * when it interrupted/canceled.
033   *
034   * <p>Do not schedule commands here that share requirements with this command. Use {@link
035   * #andThen(Command...)} instead.
036   *
037   * @param interrupted whether the command was interrupted/canceled
038   */
039  default void end(boolean interrupted) {}
040
041  /**
042   * Whether the command has finished. Once a command finishes, the scheduler will call its end()
043   * method and un-schedule it.
044   *
045   * @return whether the command has finished.
046   */
047  default boolean isFinished() {
048    return false;
049  }
050
051  /**
052   * Specifies the set of subsystems used by this command. Two commands cannot use the same
053   * subsystem at the same time. If another command is scheduled that shares a requirement, {@link
054   * #getInterruptionBehavior()} will be checked and followed. If no subsystems are required, return
055   * an empty set.
056   *
057   * <p>Note: it is recommended that user implementations contain the requirements as a field, and
058   * return that field here, rather than allocating a new set every time this is called.
059   *
060   * @return the set of subsystems that are required
061   * @see InterruptionBehavior
062   */
063  Set<Subsystem> getRequirements();
064
065  /**
066   * Decorates this command with a timeout. If the specified timeout is exceeded before the command
067   * finishes normally, the command will be interrupted and un-scheduled.
068   *
069   * <p>Note: This decorator works by adding this command to a composition. The command the
070   * decorator was called on cannot be scheduled independently or be added to a different
071   * composition (namely, decorators), unless it is manually cleared from the list of composed
072   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
073   * returned from this method can be further decorated without issue.
074   *
075   * @param seconds the timeout duration
076   * @return the command with the timeout added
077   */
078  default ParallelRaceGroup withTimeout(double seconds) {
079    return raceWith(new WaitCommand(seconds));
080  }
081
082  /**
083   * Decorates this command with an interrupt condition. If the specified condition becomes true
084   * before the command finishes normally, the command will be interrupted and un-scheduled.
085   *
086   * <p>Note: This decorator works by adding this command to a composition. The command the
087   * decorator was called on cannot be scheduled independently or be added to a different
088   * composition (namely, decorators), unless it is manually cleared from the list of composed
089   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
090   * returned from this method can be further decorated without issue.
091   *
092   * @param condition the interrupt condition
093   * @return the command with the interrupt condition added
094   * @see #onlyWhile(BooleanSupplier)
095   */
096  default ParallelRaceGroup until(BooleanSupplier condition) {
097    return raceWith(new WaitUntilCommand(condition));
098  }
099
100  /**
101   * Decorates this command with a run condition. If the specified condition becomes false before
102   * the command finishes normally, the command will be interrupted and un-scheduled.
103   *
104   * <p>Note: This decorator works by adding this command to a composition. The command the
105   * decorator was called on cannot be scheduled independently or be added to a different
106   * composition (namely, decorators), unless it is manually cleared from the list of composed
107   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
108   * returned from this method can be further decorated without issue.
109   *
110   * @param condition the run condition
111   * @return the command with the run condition added
112   * @see #until(BooleanSupplier)
113   */
114  default ParallelRaceGroup onlyWhile(BooleanSupplier condition) {
115    return until(() -> !condition.getAsBoolean());
116  }
117
118  /**
119   * Decorates this command with a runnable to run before this command starts.
120   *
121   * <p>Note: This decorator works by adding this command to a composition. The command the
122   * decorator was called on cannot be scheduled independently or be added to a different
123   * composition (namely, decorators), unless it is manually cleared from the list of composed
124   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
125   * returned from this method can be further decorated without issue.
126   *
127   * @param toRun the Runnable to run
128   * @param requirements the required subsystems
129   * @return the decorated command
130   */
131  default SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) {
132    return beforeStarting(new InstantCommand(toRun, requirements));
133  }
134
135  /**
136   * Decorates this command with another command to run before this command starts.
137   *
138   * <p>Note: This decorator works by adding this command to a composition. The command the
139   * decorator was called on cannot be scheduled independently or be added to a different
140   * composition (namely, decorators), unless it is manually cleared from the list of composed
141   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
142   * returned from this method can be further decorated without issue.
143   *
144   * @param before the command to run before this one
145   * @return the decorated command
146   */
147  default SequentialCommandGroup beforeStarting(Command before) {
148    return new SequentialCommandGroup(before, this);
149  }
150
151  /**
152   * Decorates this command with a runnable to run after the command finishes.
153   *
154   * <p>Note: This decorator works by adding this command to a composition. The command the
155   * decorator was called on cannot be scheduled independently or be added to a different
156   * composition (namely, decorators), unless it is manually cleared from the list of composed
157   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
158   * returned from this method can be further decorated without issue.
159   *
160   * @param toRun the Runnable to run
161   * @param requirements the required subsystems
162   * @return the decorated command
163   */
164  default SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) {
165    return andThen(new InstantCommand(toRun, requirements));
166  }
167
168  /**
169   * Decorates this command with a set of commands to run after it in sequence. Often more
170   * convenient/less-verbose than constructing a new {@link SequentialCommandGroup} explicitly.
171   *
172   * <p>Note: This decorator works by adding this command to a composition. The command the
173   * decorator was called on cannot be scheduled independently or be added to a different
174   * composition (namely, decorators), unless it is manually cleared from the list of composed
175   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
176   * returned from this method can be further decorated without issue.
177   *
178   * @param next the commands to run next
179   * @return the decorated command
180   */
181  default SequentialCommandGroup andThen(Command... next) {
182    SequentialCommandGroup group = new SequentialCommandGroup(this);
183    group.addCommands(next);
184    return group;
185  }
186
187  /**
188   * Decorates this command with a set of commands to run parallel to it, ending when the calling
189   * command ends and interrupting all the others. Often more convenient/less-verbose than
190   * constructing a new {@link ParallelDeadlineGroup} explicitly.
191   *
192   * <p>Note: This decorator works by adding this command to a composition. The command the
193   * decorator was called on cannot be scheduled independently or be added to a different
194   * composition (namely, decorators), unless it is manually cleared from the list of composed
195   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
196   * returned from this method can be further decorated without issue.
197   *
198   * @param parallel the commands to run in parallel
199   * @return the decorated command
200   */
201  default ParallelDeadlineGroup deadlineWith(Command... parallel) {
202    return new ParallelDeadlineGroup(this, parallel);
203  }
204
205  /**
206   * Decorates this command with a set of commands to run parallel to it, ending when the last
207   * command ends. Often more convenient/less-verbose than constructing a new {@link
208   * ParallelCommandGroup} explicitly.
209   *
210   * <p>Note: This decorator works by adding this command to a composition. The command the
211   * decorator was called on cannot be scheduled independently or be added to a different
212   * composition (namely, decorators), unless it is manually cleared from the list of composed
213   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
214   * returned from this method can be further decorated without issue.
215   *
216   * @param parallel the commands to run in parallel
217   * @return the decorated command
218   */
219  default ParallelCommandGroup alongWith(Command... parallel) {
220    ParallelCommandGroup group = new ParallelCommandGroup(this);
221    group.addCommands(parallel);
222    return group;
223  }
224
225  /**
226   * Decorates this command with a set of commands to run parallel to it, ending when the first
227   * command ends. Often more convenient/less-verbose than constructing a new {@link
228   * ParallelRaceGroup} explicitly.
229   *
230   * <p>Note: This decorator works by adding this command to a composition. The command the
231   * decorator was called on cannot be scheduled independently or be added to a different
232   * composition (namely, decorators), unless it is manually cleared from the list of composed
233   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
234   * returned from this method can be further decorated without issue.
235   *
236   * @param parallel the commands to run in parallel
237   * @return the decorated command
238   */
239  default ParallelRaceGroup raceWith(Command... parallel) {
240    ParallelRaceGroup group = new ParallelRaceGroup(this);
241    group.addCommands(parallel);
242    return group;
243  }
244
245  /**
246   * Decorates this command to run repeatedly, restarting it when it ends, until this command is
247   * interrupted. The decorated command can still be canceled.
248   *
249   * <p>Note: This decorator works by adding this command to a composition. The command the
250   * decorator was called on cannot be scheduled independently or be added to a different
251   * composition (namely, decorators), unless it is manually cleared from the list of composed
252   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
253   * returned from this method can be further decorated without issue.
254   *
255   * @return the decorated command
256   */
257  default RepeatCommand repeatedly() {
258    return new RepeatCommand(this);
259  }
260
261  /**
262   * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. This is
263   * useful for "forking off" from command compositions when the user does not wish to extend the
264   * command's requirements to the entire command composition.
265   *
266   * @return the decorated command
267   */
268  default ProxyCommand asProxy() {
269    return new ProxyCommand(this);
270  }
271
272  /**
273   * Decorates this command to only run if this condition is not met. If the command is already
274   * running and the condition changes to true, the command will not stop running. The requirements
275   * of this command will be kept for the new conditional command.
276   *
277   * <p>Note: This decorator works by adding this command to a composition. The command the
278   * decorator was called on cannot be scheduled independently or be added to a different
279   * composition (namely, decorators), unless it is manually cleared from the list of composed
280   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
281   * returned from this method can be further decorated without issue.
282   *
283   * @param condition the condition that will prevent the command from running
284   * @return the decorated command
285   * @see #onlyIf(BooleanSupplier)
286   */
287  default ConditionalCommand unless(BooleanSupplier condition) {
288    return new ConditionalCommand(new InstantCommand(), this, condition);
289  }
290
291  /**
292   * Decorates this command to only run if this condition is met. If the command is already running
293   * and the condition changes to false, the command will not stop running. The requirements of this
294   * command will be kept for the new conditional command.
295   *
296   * <p>Note: This decorator works by adding this command to a composition. The command the
297   * decorator was called on cannot be scheduled independently or be added to a different
298   * composition (namely, decorators), unless it is manually cleared from the list of composed
299   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
300   * returned from this method can be further decorated without issue.
301   *
302   * @param condition the condition that will allow the command to run
303   * @return the decorated command
304   * @see #unless(BooleanSupplier)
305   */
306  default ConditionalCommand onlyIf(BooleanSupplier condition) {
307    return unless(() -> !condition.getAsBoolean());
308  }
309
310  /**
311   * Decorates this command to run or stop when disabled.
312   *
313   * @param doesRunWhenDisabled true to run when disabled.
314   * @return the decorated command
315   */
316  default WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
317    return new WrapperCommand(this) {
318      @Override
319      public boolean runsWhenDisabled() {
320        return doesRunWhenDisabled;
321      }
322    };
323  }
324
325  /**
326   * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}.
327   *
328   * @param interruptBehavior the desired interrupt behavior
329   * @return the decorated command
330   */
331  default WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
332    return new WrapperCommand(this) {
333      @Override
334      public InterruptionBehavior getInterruptionBehavior() {
335        return interruptBehavior;
336      }
337    };
338  }
339
340  /**
341   * Decorates this command with a lambda to call on interrupt or end, following the command's
342   * inherent {@link #end(boolean)} method.
343   *
344   * @param end a lambda accepting a boolean parameter specifying whether the command was
345   *     interrupted.
346   * @return the decorated command
347   */
348  default WrapperCommand finallyDo(BooleanConsumer end) {
349    requireNonNullParam(end, "end", "Command.finallyDo()");
350    return new WrapperCommand(this) {
351      @Override
352      public void end(boolean interrupted) {
353        super.end(interrupted);
354        end.accept(interrupted);
355      }
356    };
357  }
358
359  /**
360   * Decorates this command with a lambda to call on interrupt, following the command's inherent
361   * {@link #end(boolean)} method.
362   *
363   * @param handler a lambda to run when the command is interrupted
364   * @return the decorated command
365   */
366  default WrapperCommand handleInterrupt(Runnable handler) {
367    requireNonNullParam(handler, "handler", "Command.handleInterrupt()");
368    return finallyDo(
369        interrupted -> {
370          if (interrupted) {
371            handler.run();
372          }
373        });
374  }
375
376  /** Schedules this command. */
377  default void schedule() {
378    CommandScheduler.getInstance().schedule(this);
379  }
380
381  /**
382   * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled
383   * regardless of {@link InterruptionBehavior interruption behavior}.
384   *
385   * @see CommandScheduler#cancel(Command...)
386   */
387  default void cancel() {
388    CommandScheduler.getInstance().cancel(this);
389  }
390
391  /**
392   * Whether the command is currently scheduled. Note that this does not detect whether the command
393   * is in a composition, only whether it is directly being run by the scheduler.
394   *
395   * @return Whether the command is scheduled.
396   */
397  default boolean isScheduled() {
398    return CommandScheduler.getInstance().isScheduled(this);
399  }
400
401  /**
402   * Whether the command requires a given subsystem.
403   *
404   * @param requirement the subsystem to inquire about
405   * @return whether the subsystem is required
406   */
407  default boolean hasRequirement(Subsystem requirement) {
408    return getRequirements().contains(requirement);
409  }
410
411  /**
412   * How the command behaves when another command with a shared requirement is scheduled.
413   *
414   * @return a variant of {@link InterruptionBehavior}, defaulting to {@link
415   *     InterruptionBehavior#kCancelSelf kCancelSelf}.
416   */
417  default InterruptionBehavior getInterruptionBehavior() {
418    return InterruptionBehavior.kCancelSelf;
419  }
420
421  /**
422   * Whether the given command should run when the robot is disabled. Override to return true if the
423   * command should run when disabled.
424   *
425   * @return whether the command should run when the robot is disabled
426   */
427  default boolean runsWhenDisabled() {
428    return false;
429  }
430
431  /**
432   * Gets the name of this Command. Defaults to the simple class name if not overridden.
433   *
434   * @return The display name of the Command
435   */
436  default String getName() {
437    return this.getClass().getSimpleName();
438  }
439
440  /**
441   * Sets the name of this Command. Nullop if not overridden.
442   *
443   * @param name The display name of the Command.
444   */
445  default void setName(String name) {}
446
447  /**
448   * Decorates this Command with a name.
449   *
450   * @param name name
451   * @return the decorated Command
452   */
453  default WrapperCommand withName(String name) {
454    WrapperCommand wrapper = new WrapperCommand(Command.this) {};
455    wrapper.setName(name);
456    return wrapper;
457  }
458
459  /**
460   * An enum describing the command's behavior when another command with a shared requirement is
461   * scheduled.
462   */
463  enum InterruptionBehavior {
464    /**
465     * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is
466     * scheduled normally.
467     *
468     * <p>This is the default behavior.
469     */
470    kCancelSelf,
471    /** This command continues, and the incoming command is not scheduled. */
472    kCancelIncoming
473  }
474}