001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. 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.FRCNetComm.tResourceType;
011import edu.wpi.first.wpilibj.hal.HAL;
012
013/**
014 * Handle input from standard Joysticks connected to the Driver Station. This class handles standard
015 * input that comes from the Driver Station. Each time a value is requested the most recent value is
016 * returned. There is a single class instance for each joystick and the mapping of ports to hardware
017 * buttons depends on the code in the Driver Station.
018 */
019public class Joystick extends JoystickBase {
020
021  static final byte kDefaultXAxis = 0;
022  static final byte kDefaultYAxis = 1;
023  static final byte kDefaultZAxis = 2;
024  static final byte kDefaultTwistAxis = 2;
025  static final byte kDefaultThrottleAxis = 3;
026  static final int kDefaultTriggerButton = 1;
027  static final int kDefaultTopButton = 2;
028
029  /**
030   * Represents an analog axis on a joystick.
031   */
032  public enum AxisType {
033    kX(0), kY(1), kZ(2), kTwist(3), kThrottle(4), kNumAxis(5);
034
035    @SuppressWarnings("MemberName")
036    public final int value;
037
038    private AxisType(int value) {
039      this.value = value;
040    }
041  }
042
043  /**
044   * Represents a digital button on the JoyStick.
045   */
046  public enum ButtonType {
047    kTrigger(0), kTop(1), kNumButton(2);
048
049    @SuppressWarnings("MemberName")
050    public final int value;
051
052    private ButtonType(int value) {
053      this.value = value;
054    }
055  }
056
057  private final DriverStation m_ds;
058  private final byte[] m_axes;
059  private final byte[] m_buttons;
060  private int m_outputs;
061  private short m_leftRumble;
062  private short m_rightRumble;
063
064  /**
065   * Construct an instance of a joystick. The joystick index is the USB port on the drivers
066   * station.
067   *
068   * @param port The port on the Driver Station that the joystick is plugged into.
069   */
070  public Joystick(final int port) {
071    this(port, AxisType.kNumAxis.value, ButtonType.kNumButton.value);
072
073    m_axes[AxisType.kX.value] = kDefaultXAxis;
074    m_axes[AxisType.kY.value] = kDefaultYAxis;
075    m_axes[AxisType.kZ.value] = kDefaultZAxis;
076    m_axes[AxisType.kTwist.value] = kDefaultTwistAxis;
077    m_axes[AxisType.kThrottle.value] = kDefaultThrottleAxis;
078
079    m_buttons[ButtonType.kTrigger.value] = kDefaultTriggerButton;
080    m_buttons[ButtonType.kTop.value] = kDefaultTopButton;
081
082    HAL.report(tResourceType.kResourceType_Joystick, port);
083  }
084
085  /**
086   * Protected version of the constructor to be called by sub-classes.
087   *
088   * <p>This constructor allows the subclass to configure the number of constants for axes and
089   * buttons.
090   *
091   * @param port           The port on the Driver Station that the joystick is plugged into.
092   * @param numAxisTypes   The number of axis types in the enum.
093   * @param numButtonTypes The number of button types in the enum.
094   */
095  protected Joystick(int port, int numAxisTypes, int numButtonTypes) {
096    super(port);
097
098    m_ds = DriverStation.getInstance();
099    m_axes = new byte[numAxisTypes];
100    m_buttons = new byte[numButtonTypes];
101  }
102
103  /**
104   * Get the X value of the joystick. This depends on the mapping of the joystick connected to the
105   * current port.
106   *
107   * @param hand Unused
108   * @return The X value of the joystick.
109   */
110  @Override
111  public final double getX(Hand hand) {
112    return getRawAxis(m_axes[AxisType.kX.value]);
113  }
114
115  /**
116   * Get the Y value of the joystick. This depends on the mapping of the joystick connected to the
117   * current port.
118   *
119   * @param hand Unused
120   * @return The Y value of the joystick.
121   */
122  @Override
123  public final double getY(Hand hand) {
124    return getRawAxis(m_axes[AxisType.kY.value]);
125  }
126
127  @Override
128  public final double getZ(Hand hand) {
129    return getRawAxis(m_axes[AxisType.kZ.value]);
130  }
131
132  /**
133   * Get the twist value of the current joystick. This depends on the mapping of the joystick
134   * connected to the current port.
135   *
136   * @return The Twist value of the joystick.
137   */
138  public double getTwist() {
139    return getRawAxis(m_axes[AxisType.kTwist.value]);
140  }
141
142  /**
143   * Get the throttle value of the current joystick. This depends on the mapping of the joystick
144   * connected to the current port.
145   *
146   * @return The Throttle value of the joystick.
147   */
148  public double getThrottle() {
149    return getRawAxis(m_axes[AxisType.kThrottle.value]);
150  }
151
152  /**
153   * Get the value of the axis.
154   *
155   * @param axis The axis to read, starting at 0.
156   * @return The value of the axis.
157   */
158  public double getRawAxis(final int axis) {
159    return m_ds.getStickAxis(getPort(), axis);
160  }
161
162  /**
163   * For the current joystick, return the axis determined by the argument.
164   *
165   * <p>This is for cases where the joystick axis is returned programatically, otherwise one of the
166   * previous functions would be preferable (for example getX()).
167   *
168   * @param axis The axis to read.
169   * @return The value of the axis.
170   */
171  public double getAxis(final AxisType axis) {
172    switch (axis) {
173      case kX:
174        return getX();
175      case kY:
176        return getY();
177      case kZ:
178        return getZ();
179      case kTwist:
180        return getTwist();
181      case kThrottle:
182        return getThrottle();
183      default:
184        return 0.0;
185    }
186  }
187
188  /**
189   * For the current joystick, return the number of axis.
190   */
191  public int getAxisCount() {
192    return m_ds.getStickAxisCount(getPort());
193  }
194
195  /**
196   * Read the state of the trigger on the joystick.
197   *
198   * <p>Look up which button has been assigned to the trigger and read its state.
199   *
200   * @param hand This parameter is ignored for the Joystick class and is only here to complete the
201   *             GenericHID interface.
202   * @return The state of the trigger.
203   */
204  @SuppressWarnings("PMD.UnusedFormalParameter")
205  public boolean getTrigger(Hand hand) {
206    return getRawButton(m_buttons[ButtonType.kTrigger.value]);
207  }
208
209  /**
210   * Read the state of the top button on the joystick.
211   *
212   * <p>Look up which button has been assigned to the top and read its state.
213   *
214   * @param hand This parameter is ignored for the Joystick class and is only here to complete the
215   *             GenericHID interface.
216   * @return The state of the top button.
217   */
218  @SuppressWarnings("PMD.UnusedFormalParameter")
219  public boolean getTop(Hand hand) {
220    return getRawButton(m_buttons[ButtonType.kTop.value]);
221  }
222
223  @Override
224  public int getPOV(int pov) {
225    return m_ds.getStickPOV(getPort(), pov);
226  }
227
228  @Override
229  public int getPOVCount() {
230    return m_ds.getStickPOVCount(getPort());
231  }
232
233  /**
234   * This is not supported for the Joystick. This method is only here to complete the GenericHID
235   * interface.
236   *
237   * @param hand This parameter is ignored for the Joystick class and is only here to complete the
238   *             GenericHID interface.
239   * @return The state of the bumper (always false)
240   */
241  @SuppressWarnings("PMD.UnusedFormalParameter")
242  public boolean getBumper(Hand hand) {
243    return false;
244  }
245
246  /**
247   * Get the button value (starting at button 1).
248   *
249   * <p>The appropriate button is returned as a boolean value.
250   *
251   * @param button The button number to be read (starting at 1).
252   * @return The state of the button.
253   */
254  public boolean getRawButton(final int button) {
255    return m_ds.getStickButton(getPort(), (byte) button);
256  }
257
258  /**
259   * For the current joystick, return the number of buttons.
260   */
261  public int getButtonCount() {
262    return m_ds.getStickButtonCount(getPort());
263  }
264
265  /**
266   * Get buttons based on an enumerated type.
267   *
268   * <p>The button type will be looked up in the list of buttons and then read.
269   *
270   * @param button The type of button to read.
271   * @return The state of the button.
272   */
273  public boolean getButton(ButtonType button) {
274    switch (button) {
275      case kTrigger:
276        return getTrigger();
277      case kTop:
278        return getTop();
279      default:
280        return false;
281    }
282  }
283
284  /**
285   * Get the magnitude of the direction vector formed by the joystick's current position relative to
286   * its origin.
287   *
288   * @return The magnitude of the direction vector
289   */
290  public double getMagnitude() {
291    return Math.sqrt(Math.pow(getX(), 2) + Math.pow(getY(), 2));
292  }
293
294  /**
295   * Get the direction of the vector formed by the joystick and its origin in radians.
296   *
297   * @return The direction of the vector in radians
298   */
299  public double getDirectionRadians() {
300    return Math.atan2(getX(), -getY());
301  }
302
303  /**
304   * Get the direction of the vector formed by the joystick and its origin in degrees.
305   *
306   * <p>Uses acos(-1) to represent Pi due to absence of readily accessable Pi constant in C++
307   *
308   * @return The direction of the vector in degrees
309   */
310  public double getDirectionDegrees() {
311    return Math.toDegrees(getDirectionRadians());
312  }
313
314  /**
315   * Get the channel currently associated with the specified axis.
316   *
317   * @param axis The axis to look up the channel for.
318   * @return The channel fr the axis.
319   */
320  public int getAxisChannel(AxisType axis) {
321    return m_axes[axis.value];
322  }
323
324  /**
325   * Set the channel associated with a specified axis.
326   *
327   * @param axis    The axis to set the channel for.
328   * @param channel The channel to set the axis to.
329   */
330  public void setAxisChannel(AxisType axis, int channel) {
331    m_axes[axis.value] = (byte) channel;
332  }
333
334  /**
335   * Get the value of isXbox for the current joystick.
336   *
337   * @return A boolean that is true if the controller is an xbox controller.
338   */
339  public boolean getIsXbox() {
340    return m_ds.getJoystickIsXbox(getPort());
341  }
342
343  /**
344   * Get the axis type of a joystick axis.
345   *
346   * @return the axis type of a joystick axis.
347   */
348  public int getAxisType(int axis) {
349    return m_ds.getJoystickAxisType(getPort(), axis);
350  }
351
352  /**
353   * Get the type of the HID.
354   *
355   * @return the type of the HID.
356   */
357  @Override
358  public HIDType getType() {
359    return HIDType.values()[m_ds.getJoystickType(getPort())];
360  }
361
362  /**
363   * Get the name of the HID.
364   *
365   * @return the name of the HID.
366   */
367  @Override
368  public String getName() {
369    return m_ds.getJoystickName(getPort());
370  }
371
372  @Override
373  public void setOutput(int outputNumber, boolean value) {
374    m_outputs = (m_outputs & ~(1 << (outputNumber - 1))) | ((value ? 1 : 0) << (outputNumber - 1));
375    HAL.setJoystickOutputs((byte) getPort(), m_outputs, m_leftRumble, m_rightRumble);
376  }
377
378  @Override
379  public void setOutputs(int value) {
380    m_outputs = value;
381    HAL.setJoystickOutputs((byte) getPort(), m_outputs, m_leftRumble, m_rightRumble);
382  }
383
384  @Override
385  public void setRumble(RumbleType type, double value) {
386    if (value < 0) {
387      value = 0;
388    } else if (value > 1) {
389      value = 1;
390    }
391    if (type == RumbleType.kLeftRumble) {
392      m_leftRumble = (short) (value * 65535);
393    } else {
394      m_rightRumble = (short) (value * 65535);
395    }
396    HAL.setJoystickOutputs((byte) getPort(), m_outputs, m_leftRumble, m_rightRumble);
397  }
398}