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.wpilibj.motorcontrol;
006
007import edu.wpi.first.hal.FRCNetComm.tResourceType;
008import edu.wpi.first.hal.HAL;
009import edu.wpi.first.util.sendable.Sendable;
010import edu.wpi.first.util.sendable.SendableBuilder;
011import edu.wpi.first.util.sendable.SendableRegistry;
012import edu.wpi.first.wpilibj.DigitalOutput;
013import edu.wpi.first.wpilibj.MotorSafety;
014import edu.wpi.first.wpilibj.PWM;
015
016/** Nidec Brushless Motor. */
017@SuppressWarnings("removal")
018public class NidecBrushless extends MotorSafety
019    implements MotorController, Sendable, AutoCloseable {
020  private boolean m_isInverted;
021  private final DigitalOutput m_dio;
022  private final PWM m_pwm;
023  private volatile double m_speed;
024  private volatile boolean m_disabled;
025
026  /**
027   * Constructor.
028   *
029   * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to. 0-9 are
030   *     on-board, 10-19 are on the MXP port
031   * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to. 0-9 are
032   *     on-board, 10-25 are on the MXP port
033   */
034  @SuppressWarnings("this-escape")
035  public NidecBrushless(final int pwmChannel, final int dioChannel) {
036    setSafetyEnabled(false);
037
038    // the dio controls the output (in PWM mode)
039    m_dio = new DigitalOutput(dioChannel);
040    SendableRegistry.addChild(this, m_dio);
041    m_dio.setPWMRate(15625);
042    m_dio.enablePWM(0.5);
043
044    // the pwm enables the controller
045    m_pwm = new PWM(pwmChannel);
046    SendableRegistry.addChild(this, m_pwm);
047
048    HAL.report(tResourceType.kResourceType_NidecBrushless, pwmChannel + 1);
049    SendableRegistry.addLW(this, "Nidec Brushless", pwmChannel);
050  }
051
052  @Override
053  public void close() {
054    SendableRegistry.remove(this);
055    m_dio.close();
056    m_pwm.close();
057  }
058
059  /**
060   * Set the PWM value.
061   *
062   * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the
063   * FPGA.
064   *
065   * @param speed The speed value between -1.0 and 1.0 to set.
066   */
067  @Override
068  public void set(double speed) {
069    if (!m_disabled) {
070      m_speed = speed;
071      m_dio.updateDutyCycle(0.5 + 0.5 * (m_isInverted ? -speed : speed));
072      m_pwm.setAlwaysHighMode();
073    }
074
075    feed();
076  }
077
078  /**
079   * Get the recently set value of the PWM.
080   *
081   * @return The most recently set value for the PWM between -1.0 and 1.0.
082   */
083  @Override
084  public double get() {
085    return m_speed;
086  }
087
088  @Override
089  public void setInverted(boolean isInverted) {
090    m_isInverted = isInverted;
091  }
092
093  @Override
094  public boolean getInverted() {
095    return m_isInverted;
096  }
097
098  /**
099   * Stop the motor. This is called by the MotorSafety object when it has a timeout for this PWM and
100   * needs to stop it from running. Calling set() will re-enable the motor.
101   */
102  @Override
103  public void stopMotor() {
104    m_dio.updateDutyCycle(0.5);
105    m_pwm.setDisabled();
106  }
107
108  @Override
109  public String getDescription() {
110    return "Nidec " + getChannel();
111  }
112
113  /** Disable the motor. The enable() function must be called to re-enable the motor. */
114  @Override
115  public void disable() {
116    m_disabled = true;
117    m_dio.updateDutyCycle(0.5);
118    m_pwm.setDisabled();
119  }
120
121  /**
122   * Re-enable the motor after disable() has been called. The set() function must be called to set a
123   * new motor speed.
124   */
125  public void enable() {
126    m_disabled = false;
127  }
128
129  /**
130   * Gets the channel number associated with the object.
131   *
132   * @return The channel number.
133   */
134  public int getChannel() {
135    return m_pwm.getChannel();
136  }
137
138  @Override
139  public void initSendable(SendableBuilder builder) {
140    builder.setSmartDashboardType("Nidec Brushless");
141    builder.setActuator(true);
142    builder.setSafeState(this::stopMotor);
143    builder.addDoubleProperty("Value", this::get, this::set);
144  }
145}