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