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