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. Note that the timeout only
068   * applies to the command returned by this method; the calling command is not itself changed.
069   *
070   * <p>Note: This decorator works by adding this command to a composition. The command the
071   * decorator was called on cannot be scheduled independently or be added to a different
072   * composition (namely, decorators), unless it is manually cleared from the list of composed
073   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
074   * returned from this method can be further decorated without issue.
075   *
076   * @param seconds the timeout duration
077   * @return the command with the timeout added
078   */
079  default ParallelRaceGroup withTimeout(double seconds) {
080    return raceWith(new WaitCommand(seconds));
081  }
082
083  /**
084   * Decorates this command with an interrupt condition. If the specified condition becomes true
085   * before the command finishes normally, the command will be interrupted and un-scheduled. Note
086   * that this only applies to the command returned by this method; the calling command is not
087   * itself changed.
088   *
089   * <p>Note: This decorator works by adding this command to a composition. The command the
090   * decorator was called on cannot be scheduled independently or be added to a different
091   * composition (namely, decorators), unless it is manually cleared from the list of composed
092   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
093   * returned from this method can be further decorated without issue.
094   *
095   * @param condition the interrupt condition
096   * @return the command with the interrupt condition added
097   */
098  default ParallelRaceGroup until(BooleanSupplier condition) {
099    return raceWith(new WaitUntilCommand(condition));
100  }
101
102  /**
103   * Decorates this command with an interrupt condition. If the specified condition becomes true
104   * before the command finishes normally, the command will be interrupted and un-scheduled. Note
105   * that this only applies to the command returned by this method; the calling command is not
106   * itself changed.
107   *
108   * <p>Note: This decorator works by adding this command to a composition. The command the
109   * decorator was called on cannot be scheduled independently or be added to a different
110   * composition (namely, decorators), unless it is manually cleared from the list of composed
111   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
112   * returned from this method can be further decorated without issue.
113   *
114   * @param condition the interrupt condition
115   * @return the command with the interrupt condition added
116   * @deprecated Replace with {@link #until(BooleanSupplier)}
117   */
118  @Deprecated(since = "2023")
119  default ParallelRaceGroup withInterrupt(BooleanSupplier condition) {
120    return until(condition);
121  }
122
123  /**
124   * Decorates this command with a runnable to run before this command starts.
125   *
126   * <p>Note: This decorator works by adding this command to a composition. The command the
127   * decorator was called on cannot be scheduled independently or be added to a different
128   * composition (namely, decorators), unless it is manually cleared from the list of composed
129   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
130   * returned from this method can be further decorated without issue.
131   *
132   * @param toRun the Runnable to run
133   * @param requirements the required subsystems
134   * @return the decorated command
135   */
136  default SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) {
137    return beforeStarting(new InstantCommand(toRun, requirements));
138  }
139
140  /**
141   * Decorates this command with another command to run before this command starts.
142   *
143   * <p>Note: This decorator works by adding this command to a composition. The command the
144   * decorator was called on cannot be scheduled independently or be added to a different
145   * composition (namely, decorators), unless it is manually cleared from the list of composed
146   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
147   * returned from this method can be further decorated without issue.
148   *
149   * @param before the command to run before this one
150   * @return the decorated command
151   */
152  default SequentialCommandGroup beforeStarting(Command before) {
153    return new SequentialCommandGroup(before, this);
154  }
155
156  /**
157   * Decorates this command with a runnable to run after the command finishes.
158   *
159   * <p>Note: This decorator works by adding this command to a composition. The command the
160   * decorator was called on cannot be scheduled independently or be added to a different
161   * composition (namely, decorators), unless it is manually cleared from the list of composed
162   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
163   * returned from this method can be further decorated without issue.
164   *
165   * @param toRun the Runnable to run
166   * @param requirements the required subsystems
167   * @return the decorated command
168   */
169  default SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) {
170    return andThen(new InstantCommand(toRun, requirements));
171  }
172
173  /**
174   * Decorates this command with a set of commands to run after it in sequence. Often more
175   * convenient/less-verbose than constructing a new {@link SequentialCommandGroup} explicitly.
176   *
177   * <p>Note: This decorator works by adding this command to a composition. The command the
178   * decorator was called on cannot be scheduled independently or be added to a different
179   * composition (namely, decorators), unless it is manually cleared from the list of composed
180   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
181   * returned from this method can be further decorated without issue.
182   *
183   * @param next the commands to run next
184   * @return the decorated command
185   */
186  default SequentialCommandGroup andThen(Command... next) {
187    SequentialCommandGroup group = new SequentialCommandGroup(this);
188    group.addCommands(next);
189    return group;
190  }
191
192  /**
193   * Decorates this command with a set of commands to run parallel to it, ending when the calling
194   * command ends and interrupting all the others. Often more convenient/less-verbose than
195   * constructing a new {@link ParallelDeadlineGroup} explicitly.
196   *
197   * <p>Note: This decorator works by adding this command to a composition. The command the
198   * decorator was called on cannot be scheduled independently or be added to a different
199   * composition (namely, decorators), unless it is manually cleared from the list of composed
200   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
201   * returned from this method can be further decorated without issue.
202   *
203   * @param parallel the commands to run in parallel
204   * @return the decorated command
205   */
206  default ParallelDeadlineGroup deadlineWith(Command... parallel) {
207    return new ParallelDeadlineGroup(this, parallel);
208  }
209
210  /**
211   * Decorates this command with a set of commands to run parallel to it, ending when the last
212   * command ends. Often more convenient/less-verbose than constructing a new {@link
213   * ParallelCommandGroup} explicitly.
214   *
215   * <p>Note: This decorator works by adding this command to a composition. The command the
216   * decorator was called on cannot be scheduled independently or be added to a different
217   * composition (namely, decorators), unless it is manually cleared from the list of composed
218   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
219   * returned from this method can be further decorated without issue.
220   *
221   * @param parallel the commands to run in parallel
222   * @return the decorated command
223   */
224  default ParallelCommandGroup alongWith(Command... parallel) {
225    ParallelCommandGroup group = new ParallelCommandGroup(this);
226    group.addCommands(parallel);
227    return group;
228  }
229
230  /**
231   * Decorates this command with a set of commands to run parallel to it, ending when the first
232   * command ends. Often more convenient/less-verbose than constructing a new {@link
233   * ParallelRaceGroup} explicitly.
234   *
235   * <p>Note: This decorator works by adding this command to a composition. The command the
236   * decorator was called on cannot be scheduled independently or be added to a different
237   * composition (namely, decorators), unless it is manually cleared from the list of composed
238   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
239   * returned from this method can be further decorated without issue.
240   *
241   * @param parallel the commands to run in parallel
242   * @return the decorated command
243   */
244  default ParallelRaceGroup raceWith(Command... parallel) {
245    ParallelRaceGroup group = new ParallelRaceGroup(this);
246    group.addCommands(parallel);
247    return group;
248  }
249
250  /**
251   * Decorates this command to run perpetually, ignoring its ordinary end conditions. The decorated
252   * command can still be interrupted or canceled.
253   *
254   * <p>Note: This decorator works by adding this command to a composition. The command the
255   * decorator was called on cannot be scheduled independently or be added to a different
256   * composition (namely, decorators), unless it is manually cleared from the list of composed
257   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
258   * returned from this method can be further decorated without issue.
259   *
260   * @return the decorated command
261   * @deprecated PerpetualCommand violates the assumption that execute() doesn't get called after
262   *     isFinished() returns true -- an assumption that should be valid. This was unsafe/undefined
263   *     behavior from the start, and RepeatCommand provides an easy way to achieve similar end
264   *     results with slightly different (and safe) semantics.
265   */
266  @SuppressWarnings("removal") // PerpetualCommand
267  @Deprecated(forRemoval = true, since = "2023")
268  default PerpetualCommand perpetually() {
269    return new PerpetualCommand(this);
270  }
271
272  /**
273   * Decorates this command to run repeatedly, restarting it when it ends, until this command is
274   * interrupted. The decorated command can still be canceled.
275   *
276   * <p>Note: This decorator works by adding this command to a composition. The command the
277   * decorator was called on cannot be scheduled independently or be added to a different
278   * composition (namely, decorators), unless it is manually cleared from the list of composed
279   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
280   * returned from this method can be further decorated without issue.
281   *
282   * @return the decorated command
283   */
284  default RepeatCommand repeatedly() {
285    return new RepeatCommand(this);
286  }
287
288  /**
289   * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. This is
290   * useful for "forking off" from command compositions when the user does not wish to extend the
291   * command's requirements to the entire command composition.
292   *
293   * @return the decorated command
294   */
295  default ProxyCommand asProxy() {
296    return new ProxyCommand(this);
297  }
298
299  /**
300   * Decorates this command to only run if this condition is not met. If the command is already
301   * running and the condition changes to true, the command will not stop running. The requirements
302   * of this command will be kept for the new conditional command.
303   *
304   * @param condition the condition that will prevent the command from running
305   * @return the decorated command
306   */
307  default ConditionalCommand unless(BooleanSupplier condition) {
308    return new ConditionalCommand(new InstantCommand(), this, condition);
309  }
310
311  /**
312   * Decorates this command to run or stop when disabled.
313   *
314   * @param doesRunWhenDisabled true to run when disabled.
315   * @return the decorated command
316   */
317  default WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
318    return new WrapperCommand(this) {
319      @Override
320      public boolean runsWhenDisabled() {
321        return doesRunWhenDisabled;
322      }
323    };
324  }
325
326  /**
327   * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}.
328   *
329   * @param interruptBehavior the desired interrupt behavior
330   * @return the decorated command
331   */
332  default WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
333    return new WrapperCommand(this) {
334      @Override
335      public InterruptionBehavior getInterruptionBehavior() {
336        return interruptBehavior;
337      }
338    };
339  }
340
341  /**
342   * Decorates this command with a lambda to call on interrupt or end, following the command's
343   * inherent {@link #end(boolean)} method.
344   *
345   * @param end a lambda accepting a boolean parameter specifying whether the command was
346   *     interrupted.
347   * @return the decorated command
348   */
349  default WrapperCommand finallyDo(BooleanConsumer end) {
350    requireNonNullParam(end, "end", "Command.finallyDo()");
351    return new WrapperCommand(this) {
352      @Override
353      public void end(boolean interrupted) {
354        super.end(interrupted);
355        end.accept(interrupted);
356      }
357    };
358  }
359
360  /**
361   * Decorates this command with a lambda to call on interrupt, following the command's inherent
362   * {@link #end(boolean)} method.
363   *
364   * @param handler a lambda to run when the command is interrupted
365   * @return the decorated command
366   */
367  default WrapperCommand handleInterrupt(Runnable handler) {
368    requireNonNullParam(handler, "handler", "Command.handleInterrupt()");
369    return finallyDo(
370        interrupted -> {
371          if (interrupted) {
372            handler.run();
373          }
374        });
375  }
376
377  /** Schedules this command. */
378  default void schedule() {
379    CommandScheduler.getInstance().schedule(this);
380  }
381
382  /**
383   * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled
384   * regardless of {@link InterruptionBehavior interruption behavior}.
385   *
386   * @see CommandScheduler#cancel(Command...)
387   */
388  default void cancel() {
389    CommandScheduler.getInstance().cancel(this);
390  }
391
392  /**
393   * Whether the command is currently scheduled. Note that this does not detect whether the command
394   * is in a composition, only whether it is directly being run by the scheduler.
395   *
396   * @return Whether the command is scheduled.
397   */
398  default boolean isScheduled() {
399    return CommandScheduler.getInstance().isScheduled(this);
400  }
401
402  /**
403   * Whether the command requires a given subsystem.
404   *
405   * @param requirement the subsystem to inquire about
406   * @return whether the subsystem is required
407   */
408  default boolean hasRequirement(Subsystem requirement) {
409    return getRequirements().contains(requirement);
410  }
411
412  /**
413   * How the command behaves when another command with a shared requirement is scheduled.
414   *
415   * @return a variant of {@link InterruptionBehavior}, defaulting to {@link
416   *     InterruptionBehavior#kCancelSelf kCancelSelf}.
417   */
418  default InterruptionBehavior getInterruptionBehavior() {
419    return InterruptionBehavior.kCancelSelf;
420  }
421
422  /**
423   * Whether the given command should run when the robot is disabled. Override to return true if the
424   * command should run when disabled.
425   *
426   * @return whether the command should run when the robot is disabled
427   */
428  default boolean runsWhenDisabled() {
429    return false;
430  }
431
432  /**
433   * Gets the name of this Command. Defaults to the simple class name if not overridden.
434   *
435   * @return The display name of the Command
436   */
437  default String getName() {
438    return this.getClass().getSimpleName();
439  }
440
441  /**
442   * Sets the name of this Command. Nullop if not overridden.
443   *
444   * @param name The display name of the Command.
445   */
446  default void setName(String name) {}
447
448  /**
449   * Decorates this Command with a name.
450   *
451   * @param name name
452   * @return the decorated Command
453   */
454  default WrapperCommand withName(String name) {
455    WrapperCommand wrapper = new WrapperCommand(Command.this) {};
456    wrapper.setName(name);
457    return wrapper;
458  }
459
460  /**
461   * An enum describing the command's behavior when another command with a shared requirement is
462   * scheduled.
463   */
464  enum InterruptionBehavior {
465    /**
466     * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is
467     * scheduled normally.
468     *
469     * <p>This is the default behavior.
470     */
471    kCancelSelf,
472    /** This command continues, and the incoming command is not scheduled. */
473    kCancelIncoming
474  }
475}