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.sendable.Sendable;
010import edu.wpi.first.util.sendable.SendableBuilder;
011import edu.wpi.first.util.sendable.SendableRegistry;
012import java.util.HashSet;
013import java.util.Set;
014
015/**
016 * A {@link Sendable} base class for {@link Command}s.
017 *
018 * <p>This class is provided by the NewCommands VendorDep
019 */
020public abstract class CommandBase implements Sendable, Command {
021  protected Set<Subsystem> m_requirements = new HashSet<>();
022
023  protected CommandBase() {
024    String name = getClass().getName();
025    SendableRegistry.add(this, name.substring(name.lastIndexOf('.') + 1));
026  }
027
028  /**
029   * Adds the specified subsystems to the requirements of the command. The scheduler will prevent
030   * two commands that require the same subsystem from being scheduled simultaneously.
031   *
032   * <p>Note that the scheduler determines the requirements of a command when it is scheduled, so
033   * this method should normally be called from the command's constructor.
034   *
035   * @param requirements the requirements to add
036   */
037  public final void addRequirements(Subsystem... requirements) {
038    for (Subsystem requirement : requirements) {
039      m_requirements.add(requireNonNullParam(requirement, "requirement", "addRequirements"));
040    }
041  }
042
043  @Override
044  public Set<Subsystem> getRequirements() {
045    return m_requirements;
046  }
047
048  @Override
049  public String getName() {
050    return SendableRegistry.getName(this);
051  }
052
053  /**
054   * Sets the name of this Command.
055   *
056   * @param name name
057   */
058  @Override
059  public void setName(String name) {
060    SendableRegistry.setName(this, name);
061  }
062
063  /**
064   * Gets the subsystem name of this Command.
065   *
066   * @return Subsystem name
067   */
068  public String getSubsystem() {
069    return SendableRegistry.getSubsystem(this);
070  }
071
072  /**
073   * Sets the subsystem name of this Command.
074   *
075   * @param subsystem subsystem name
076   */
077  public void setSubsystem(String subsystem) {
078    SendableRegistry.setSubsystem(this, subsystem);
079  }
080
081  /**
082   * Initializes this sendable. Useful for allowing implementations to easily extend SendableBase.
083   *
084   * @param builder the builder used to construct this sendable
085   */
086  @Override
087  public void initSendable(SendableBuilder builder) {
088    builder.setSmartDashboardType("Command");
089    builder.addStringProperty(".name", this::getName, null);
090    builder.addBooleanProperty(
091        "running",
092        this::isScheduled,
093        value -> {
094          if (value) {
095            if (!isScheduled()) {
096              schedule();
097            }
098          } else {
099            if (isScheduled()) {
100              cancel();
101            }
102          }
103        });
104    builder.addBooleanProperty(
105        ".isParented", () -> CommandScheduler.getInstance().isComposed(this), null);
106    builder.addStringProperty(
107        "interruptBehavior", () -> getInterruptionBehavior().toString(), null);
108    builder.addBooleanProperty("runsWhenDisabled", this::runsWhenDisabled, null);
109  }
110}