001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.hal.DIOJNI;
011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
012import edu.wpi.first.wpilibj.hal.HAL;
013import edu.wpi.first.wpilibj.hal.PWMJNI;
014import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
015
016/**
017 * Class implements the PWM generation in the FPGA.
018 *
019 * <p>The values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped to
020 * the hardware dependent values, in this case 0-2000 for the FPGA. Changes are immediately sent to
021 * the FPGA, and the update occurs at the next FPGA cycle (5.005ms). There is no delay.
022 *
023 * <p>As of revision 0.1.10 of the FPGA, the FPGA interprets the 0-2000 values as follows: - 2000 =
024 * maximum pulse width - 1999 to 1001 = linear scaling from "full forward" to "center" - 1000 =
025 * center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse
026 * width (currently .5ms) - 0 = disabled (i.e. PWM output is held low)
027 */
028public class PWM extends SendableBase implements Sendable {
029  /**
030   * Represents the amount to multiply the minimum servo-pulse pwm period by.
031   */
032  public enum PeriodMultiplier {
033    /**
034     * Period Multiplier: don't skip pulses. PWM pulses occur every 5.005 ms
035     */
036    k1X,
037    /**
038     * Period Multiplier: skip every other pulse. PWM pulses occur every 10.010 ms
039     */
040    k2X,
041    /**
042     * Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.020 ms
043     */
044    k4X
045  }
046
047  private int m_channel;
048  private int m_handle;
049
050  /**
051   * Allocate a PWM given a channel.
052   *
053   * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
054   */
055  public PWM(final int channel) {
056    SensorBase.checkPWMChannel(channel);
057    m_channel = channel;
058
059    m_handle = PWMJNI.initializePWMPort(DIOJNI.getPort((byte) channel));
060
061    setDisabled();
062
063    PWMJNI.setPWMEliminateDeadband(m_handle, false);
064
065    HAL.report(tResourceType.kResourceType_PWM, channel);
066    setName("PWM", channel);
067  }
068
069  /**
070   * Free the PWM channel.
071   *
072   * <p>Free the resource associated with the PWM channel and set the value to 0.
073   */
074  @Override
075  public void free() {
076    super.free();
077    if (m_handle == 0) {
078      return;
079    }
080    setDisabled();
081    PWMJNI.freePWMPort(m_handle);
082    m_handle = 0;
083  }
084
085  /**
086   * Optionally eliminate the deadband from a speed controller.
087   *
088   * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate the deadband
089   *                          in the middle of the range. Otherwise, keep the full range without
090   *                          modifying any values.
091   */
092  public void enableDeadbandElimination(boolean eliminateDeadband) {
093    PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband);
094  }
095
096  /**
097   * Set the bounds on the PWM pulse widths. This sets the bounds on the PWM values for a particular
098   * type of controller. The values determine the upper and lower speeds as well as the deadband
099   * bracket.
100   *
101   * @param max         The max PWM pulse width in ms
102   * @param deadbandMax The high end of the deadband range pulse width in ms
103   * @param center      The center (off) pulse width in ms
104   * @param deadbandMin The low end of the deadband pulse width in ms
105   * @param min         The minimum pulse width in ms
106   */
107  public void setBounds(double max, double deadbandMax, double center, double deadbandMin,
108                           double min) {
109    PWMJNI.setPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min);
110  }
111
112  /**
113   * Gets the bounds on the PWM pulse widths. This Gets the bounds on the PWM values for a
114   * particular type of controller. The values determine the upper and lower speeds as well
115   * as the deadband bracket.
116   */
117  public PWMConfigDataResult getRawBounds() {
118    return PWMJNI.getPWMConfigRaw(m_handle);
119  }
120
121  /**
122   * Gets the channel number associated with the PWM Object.
123   *
124   * @return The channel number.
125   */
126  public int getChannel() {
127    return m_channel;
128  }
129
130  /**
131   * Set the PWM value based on a position.
132   *
133   * <p>This is intended to be used by servos.
134   *
135   * @param pos The position to set the servo between 0.0 and 1.0.
136   * @pre SetMaxPositivePwm() called.
137   * @pre SetMinNegativePwm() called.
138   */
139  public void setPosition(double pos) {
140    PWMJNI.setPWMPosition(m_handle, pos);
141  }
142
143  /**
144   * Get the PWM value in terms of a position.
145   *
146   * <p>This is intended to be used by servos.
147   *
148   * @return The position the servo is set to between 0.0 and 1.0.
149   * @pre SetMaxPositivePwm() called.
150   * @pre SetMinNegativePwm() called.
151   */
152  public double getPosition() {
153    return PWMJNI.getPWMPosition(m_handle);
154  }
155
156  /**
157   * Set the PWM value based on a speed.
158   *
159   * <p>This is intended to be used by speed controllers.
160   *
161   * @param speed The speed to set the speed controller between -1.0 and 1.0.
162   * @pre SetMaxPositivePwm() called.
163   * @pre SetMinPositivePwm() called.
164   * @pre SetCenterPwm() called.
165   * @pre SetMaxNegativePwm() called.
166   * @pre SetMinNegativePwm() called.
167   */
168  public void setSpeed(double speed) {
169    PWMJNI.setPWMSpeed(m_handle, speed);
170  }
171
172  /**
173   * Get the PWM value in terms of speed.
174   *
175   * <p>This is intended to be used by speed controllers.
176   *
177   * @return The most recently set speed between -1.0 and 1.0.
178   * @pre SetMaxPositivePwm() called.
179   * @pre SetMinPositivePwm() called.
180   * @pre SetMaxNegativePwm() called.
181   * @pre SetMinNegativePwm() called.
182   */
183  public double getSpeed() {
184    return PWMJNI.getPWMSpeed(m_handle);
185  }
186
187  /**
188   * Set the PWM value directly to the hardware.
189   *
190   * <p>Write a raw value to a PWM channel.
191   *
192   * @param value Raw PWM value. Range 0 - 255.
193   */
194  public void setRaw(int value) {
195    PWMJNI.setPWMRaw(m_handle, (short) value);
196  }
197
198  /**
199   * Get the PWM value directly from the hardware.
200   *
201   * <p>Read a raw value from a PWM channel.
202   *
203   * @return Raw PWM control value. Range: 0 - 255.
204   */
205  public int getRaw() {
206    return PWMJNI.getPWMRaw(m_handle);
207  }
208
209  /**
210   * Temporarily disables the PWM output. The next set call will reenable
211   * the output.
212   */
213  public void setDisabled() {
214    PWMJNI.setPWMDisabled(m_handle);
215  }
216
217  /**
218   * Slow down the PWM signal for old devices.
219   *
220   * @param mult The period multiplier to apply to this channel
221   */
222  public void setPeriodMultiplier(PeriodMultiplier mult) {
223    switch (mult) {
224      case k4X:
225        // Squelch 3 out of 4 outputs
226        PWMJNI.setPWMPeriodScale(m_handle, 3);
227        break;
228      case k2X:
229        // Squelch 1 out of 2 outputs
230        PWMJNI.setPWMPeriodScale(m_handle, 1);
231        break;
232      case k1X:
233        // Don't squelch any outputs
234        PWMJNI.setPWMPeriodScale(m_handle, 0);
235        break;
236      default:
237        // Cannot hit this, limited by PeriodMultiplier enum
238    }
239  }
240
241  protected void setZeroLatch() {
242    PWMJNI.latchPWMZero(m_handle);
243  }
244
245  @Override
246  public void initSendable(SendableBuilder builder) {
247    builder.setSmartDashboardType("Speed Controller");
248    builder.setSafeState(this::setDisabled);
249    builder.addDoubleProperty("Value", this::getSpeed, this::setSpeed);
250  }
251}