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 org.wpilib.commands3;
006
007import edu.wpi.first.units.measure.Time;
008import java.util.List;
009import java.util.function.Consumer;
010import org.wpilib.annotation.NoDiscard;
011
012/**
013 * Generic base class to represent mechanisms on a robot. Commands can require sole ownership of a
014 * mechanism; when a command that requires a mechanism is running, no other commands may use it at
015 * the same time.
016 *
017 * <p>Even though this class is named "Mechanism", it may be used to represent other physical
018 * hardware on a robot that should be controlled with commands - for example, an LED strip or a
019 * vision processor that can switch between different pipelines could be represented as mechanisms.
020 */
021public class Mechanism {
022  private final String m_name;
023
024  private final Scheduler m_registeredScheduler;
025
026  /**
027   * Creates a new mechanism registered with the default scheduler instance and named using the name
028   * of the class. Intended to be used by subclasses to get sane defaults without needing to
029   * manually declare a constructor.
030   */
031  @SuppressWarnings("this-escape")
032  protected Mechanism() {
033    m_name = getClass().getSimpleName();
034    m_registeredScheduler = Scheduler.getDefault();
035    setDefaultCommand(idle());
036  }
037
038  /**
039   * Creates a new mechanism, registered with the default scheduler instance.
040   *
041   * @param name The name of the mechanism. Cannot be null.
042   */
043  public Mechanism(String name) {
044    this(name, Scheduler.getDefault());
045  }
046
047  /**
048   * Creates a new mechanism, registered with the given scheduler instance.
049   *
050   * @param name The name of the mechanism. Cannot be null.
051   * @param scheduler The registered scheduler. Cannot be null.
052   */
053  @SuppressWarnings("this-escape")
054  public Mechanism(String name, Scheduler scheduler) {
055    m_name = name;
056    m_registeredScheduler = scheduler;
057    setDefaultCommand(idle());
058  }
059
060  /**
061   * Gets the name of this mechanism.
062   *
063   * @return The name of the mechanism.
064   */
065  @NoDiscard
066  public String getName() {
067    return m_name;
068  }
069
070  /**
071   * Sets the default command to run on the mechanism when no other command is scheduled. The
072   * default command's priority is effectively the minimum allowable priority for any command
073   * requiring a mechanism. For this reason, it's recommended that a default command have a priority
074   * less than {@link Command#DEFAULT_PRIORITY} so it doesn't prevent low-priority commands from
075   * running.
076   *
077   * <p>The default command is initially an idle command that only owns the mechanism without doing
078   * anything. This command has the lowest possible priority to allow any other command to run.
079   *
080   * @param defaultCommand the new default command
081   */
082  public void setDefaultCommand(Command defaultCommand) {
083    m_registeredScheduler.setDefaultCommand(this, defaultCommand);
084  }
085
086  /**
087   * Gets the default command that was set by the latest call to {@link
088   * #setDefaultCommand(Command)}.
089   *
090   * @return The currently configured default command
091   */
092  public Command getDefaultCommand() {
093    return m_registeredScheduler.getDefaultCommandFor(this);
094  }
095
096  /**
097   * Starts building a command that requires this mechanism.
098   *
099   * @param commandBody The main function body of the command.
100   * @return The command builder, for further configuration.
101   */
102  public NeedsNameBuilderStage run(Consumer<Coroutine> commandBody) {
103    return new StagedCommandBuilder().requiring(this).executing(commandBody);
104  }
105
106  /**
107   * Starts building a command that requires this mechanism. The given function will be called
108   * repeatedly in an infinite loop. Useful for building commands that don't need state or multiple
109   * stages of logic.
110   *
111   * @param loopBody The body of the infinite loop.
112   * @return The command builder, for further configuration.
113   */
114  public NeedsNameBuilderStage runRepeatedly(Runnable loopBody) {
115    return run(
116        coroutine -> {
117          while (true) {
118            loopBody.run();
119            coroutine.yield();
120          }
121        });
122  }
123
124  /**
125   * Returns a command that idles this mechanism until another command claims it. The idle command
126   * has {@link Command#LOWEST_PRIORITY the lowest priority} and can be interrupted by any other
127   * command.
128   *
129   * <p>The {@link #getDefaultCommand() default command} for every mechanism is an idle command
130   * unless a different default command has been configured.
131   *
132   * @return A new idle command.
133   */
134  public Command idle() {
135    return run(Coroutine::park).withPriority(Command.LOWEST_PRIORITY).named(getName() + "[IDLE]");
136  }
137
138  /**
139   * Returns a command that idles this mechanism for the given duration of time.
140   *
141   * @param duration How long the mechanism should idle for.
142   * @return A new idle command.
143   */
144  public Command idleFor(Time duration) {
145    return idle().withTimeout(duration);
146  }
147
148  /**
149   * Gets all running commands that require this mechanism. Commands are returned in the order in
150   * which they were scheduled. The returned list is read-only. Every command in the list will have
151   * been scheduled by the previous entry in the list or by intermediate commands that do not
152   * require the mechanism.
153   *
154   * @return The currently running commands that require the mechanism.
155   */
156  @NoDiscard
157  public List<Command> getRunningCommands() {
158    return m_registeredScheduler.getRunningCommandsFor(this);
159  }
160
161  @Override
162  public String toString() {
163    return m_name;
164  }
165}