2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2025-11-07 19:55:43 -05:00
|
|
|
package org.wpilib.driverstation;
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2025-11-07 19:57:21 -05:00
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
2025-11-07 19:55:43 -05:00
|
|
|
import org.wpilib.driverstation.DriverStation.POVDirection;
|
|
|
|
|
import org.wpilib.event.BooleanEvent;
|
|
|
|
|
import org.wpilib.event.EventLoop;
|
2025-11-07 19:57:21 -05:00
|
|
|
import org.wpilib.hardware.hal.DriverStationJNI;
|
|
|
|
|
import org.wpilib.math.util.Pair;
|
2017-10-27 21:45:56 -07:00
|
|
|
|
2021-08-14 20:00:46 +03:00
|
|
|
/**
|
|
|
|
|
* Handle input from standard HID devices connected to the Driver Station.
|
|
|
|
|
*
|
|
|
|
|
* <p>This class handles standard input that comes from the Driver Station. Each time a value is
|
|
|
|
|
* requested the most recent value is returned. There is a single class instance for each device and
|
|
|
|
|
* the mapping of ports to hardware buttons depends on the code in the Driver Station.
|
|
|
|
|
*/
|
|
|
|
|
public class GenericHID {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Represents a rumble output on the Joystick. */
|
2016-11-18 23:05:37 -08:00
|
|
|
public enum RumbleType {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Left rumble motor. */
|
2020-12-29 22:45:16 -08:00
|
|
|
kLeftRumble,
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Right rumble motor. */
|
2022-12-24 14:28:52 -05:00
|
|
|
kRightRumble,
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Both left and right rumble motors. */
|
2022-12-24 14:28:52 -05:00
|
|
|
kBothRumble
|
2016-11-18 23:05:37 -08:00
|
|
|
}
|
|
|
|
|
|
2024-01-05 00:36:26 -05:00
|
|
|
/** USB HID interface type. */
|
2016-11-18 23:05:37 -08:00
|
|
|
public enum HIDType {
|
2024-01-05 00:36:26 -05:00
|
|
|
/** Unknown. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kUnknown(-1),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputUnknown. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputUnknown(0),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputGamepad. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputGamepad(1),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputWheel. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputWheel(2),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputArcadeStick. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputArcadeStick(3),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputFlightStick. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputFlightStick(4),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputDancePad. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputDancePad(5),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputGuitar. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputGuitar(6),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputGuitar2. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputGuitar2(7),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputDrumKit. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputDrumKit(8),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputGuitar3. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputGuitar3(11),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** XInputArcadePad. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kXInputArcadePad(19),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** HIDJoystick. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kHIDJoystick(20),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** HIDGamepad. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kHIDGamepad(21),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** HIDDriving. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kHIDDriving(22),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** HIDFlight. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kHIDFlight(23),
|
2024-01-05 00:36:26 -05:00
|
|
|
/** HID1stPerson. */
|
2016-11-18 23:05:37 -08:00
|
|
|
kHID1stPerson(24);
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/** HIDType value. */
|
2016-11-18 23:05:37 -08:00
|
|
|
public final int value;
|
2020-12-29 22:45:16 -08:00
|
|
|
|
2018-04-29 23:56:00 -07:00
|
|
|
private static final Map<Integer, HIDType> map = new HashMap<>();
|
2016-11-18 23:05:37 -08:00
|
|
|
|
2017-10-17 21:47:55 -07:00
|
|
|
HIDType(int value) {
|
2016-11-18 23:05:37 -08:00
|
|
|
this.value = value;
|
|
|
|
|
}
|
2018-04-29 23:56:00 -07:00
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
for (HIDType hidType : HIDType.values()) {
|
|
|
|
|
map.put(hidType.value, hidType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/**
|
|
|
|
|
* Creates an HIDType with the given value.
|
|
|
|
|
*
|
|
|
|
|
* @param value HIDType's value.
|
|
|
|
|
* @return HIDType with the given value.
|
|
|
|
|
*/
|
2018-04-29 23:56:00 -07:00
|
|
|
public static HIDType of(int value) {
|
2018-06-03 10:00:53 -07:00
|
|
|
return map.get(value);
|
2018-04-29 23:56:00 -07:00
|
|
|
}
|
2016-11-18 23:05:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private final int m_port;
|
2017-10-27 21:45:56 -07:00
|
|
|
private int m_outputs;
|
2024-05-04 11:36:40 -04:00
|
|
|
private int m_leftRumble;
|
|
|
|
|
private int m_rightRumble;
|
2024-07-29 10:58:23 -04:00
|
|
|
private final Map<EventLoop, Map<Integer, BooleanEvent>> m_buttonCache = new HashMap<>();
|
|
|
|
|
private final Map<EventLoop, Map<Pair<Integer, Double>, BooleanEvent>> m_axisLessThanCache =
|
|
|
|
|
new HashMap<>();
|
|
|
|
|
private final Map<EventLoop, Map<Pair<Integer, Double>, BooleanEvent>> m_axisGreaterThanCache =
|
|
|
|
|
new HashMap<>();
|
|
|
|
|
private final Map<EventLoop, Map<Integer, BooleanEvent>> m_povCache = new HashMap<>();
|
2016-11-18 23:05:37 -08:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2021-08-14 20:00:46 +03:00
|
|
|
* Construct an instance of a device.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2021-08-14 20:00:46 +03:00
|
|
|
* @param port The port index on the Driver Station that the device is plugged into.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2021-08-14 20:00:46 +03:00
|
|
|
public GenericHID(int port) {
|
|
|
|
|
m_port = port;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2017-10-27 21:45:56 -07:00
|
|
|
* Get the button value (starting at button 1).
|
|
|
|
|
*
|
|
|
|
|
* <p>The buttons are returned in a single 16 bit value with one bit representing the state of
|
|
|
|
|
* each button. The appropriate button is returned as a boolean value.
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>This method returns true if the button is being held down at the time that this method is
|
|
|
|
|
* being called.
|
2020-03-15 22:54:23 -04:00
|
|
|
*
|
2017-10-27 21:45:56 -07:00
|
|
|
* @param button The button number to be read (starting at 1)
|
|
|
|
|
* @return The state of the button.
|
|
|
|
|
*/
|
|
|
|
|
public boolean getRawButton(int button) {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getStickButton(m_port, (byte) button);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Whether the button was pressed since the last check. Button indexes begin at 1.
|
2017-10-27 21:45:56 -07:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>This method returns true if the button went from not pressed to held down since the last
|
|
|
|
|
* time this method was called. This is useful if you only want to call a function once when you
|
|
|
|
|
* press the button.
|
2020-03-15 22:54:23 -04:00
|
|
|
*
|
2025-10-25 23:03:50 -07:00
|
|
|
* @param button The button index, beginning at 0.
|
2017-10-27 21:45:56 -07:00
|
|
|
* @return Whether the button was pressed since the last check.
|
|
|
|
|
*/
|
|
|
|
|
public boolean getRawButtonPressed(int button) {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getStickButtonPressed(m_port, (byte) button);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-12-29 22:45:16 -08:00
|
|
|
* Whether the button was released since the last check. Button indexes begin at 1.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>This method returns true if the button went from held down to not pressed since the last
|
|
|
|
|
* time this method was called. This is useful if you only want to call a function once when you
|
|
|
|
|
* release the button.
|
2020-03-15 22:54:23 -04:00
|
|
|
*
|
2025-10-25 23:03:50 -07:00
|
|
|
* @param button The button index, beginning at 0.
|
2017-10-27 21:45:56 -07:00
|
|
|
* @return Whether the button was released since the last check.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public boolean getRawButtonReleased(int button) {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getStickButtonReleased(m_port, button);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2022-06-14 08:48:16 +03:00
|
|
|
/**
|
|
|
|
|
* Constructs an event instance around this button's digital signal.
|
|
|
|
|
*
|
|
|
|
|
* @param button the button index
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return an event instance representing the button's digital signal attached to the given loop.
|
|
|
|
|
*/
|
|
|
|
|
public BooleanEvent button(int button, EventLoop loop) {
|
2024-07-29 10:58:23 -04:00
|
|
|
synchronized (m_buttonCache) {
|
|
|
|
|
var cache = m_buttonCache.computeIfAbsent(loop, k -> new HashMap<>());
|
|
|
|
|
return cache.computeIfAbsent(button, k -> new BooleanEvent(loop, () -> getRawButton(k)));
|
|
|
|
|
}
|
2022-06-14 08:48:16 +03:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2017-10-27 21:45:56 -07:00
|
|
|
* Get the value of the axis.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2017-10-27 21:45:56 -07:00
|
|
|
* @param axis The axis to read, starting at 0.
|
|
|
|
|
* @return The value of the axis.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public double getRawAxis(int axis) {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getStickAxis(m_port, axis);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Get the angle of a POV on the HID.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2021-08-14 20:00:46 +03:00
|
|
|
* @param pov The index of the POV to read (starting at 0). Defaults to 0.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return the angle of the POV.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2025-06-29 18:32:26 -07:00
|
|
|
public POVDirection getPOV(int pov) {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getStickPOV(m_port, pov);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2021-08-14 20:00:46 +03:00
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Get the angle of the default POV (index 0) on the HID.
|
2021-08-14 20:00:46 +03:00
|
|
|
*
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return the angle of the POV.
|
2021-08-14 20:00:46 +03:00
|
|
|
*/
|
2025-06-29 18:32:26 -07:00
|
|
|
public POVDirection getPOV() {
|
2016-11-18 23:05:37 -08:00
|
|
|
return getPOV(0);
|
|
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2022-10-23 22:09:44 +03:00
|
|
|
/**
|
|
|
|
|
* Constructs a BooleanEvent instance based around this angle of a POV on the HID.
|
|
|
|
|
*
|
2025-06-29 18:32:26 -07:00
|
|
|
* @param angle POV angle.
|
2022-10-23 22:09:44 +03:00
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return a BooleanEvent instance based around this angle of a POV on the HID.
|
|
|
|
|
*/
|
2025-06-29 18:32:26 -07:00
|
|
|
public BooleanEvent pov(POVDirection angle, EventLoop loop) {
|
2022-10-23 22:09:44 +03:00
|
|
|
return pov(0, angle, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a BooleanEvent instance based around this angle of a POV on the HID.
|
|
|
|
|
*
|
|
|
|
|
* @param pov index of the POV to read (starting at 0). Defaults to 0.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @param angle POV angle.
|
2022-10-23 22:09:44 +03:00
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return a BooleanEvent instance based around this angle of a POV on the HID.
|
|
|
|
|
*/
|
2025-06-29 18:32:26 -07:00
|
|
|
public BooleanEvent pov(int pov, POVDirection angle, EventLoop loop) {
|
2024-07-29 10:58:23 -04:00
|
|
|
synchronized (m_povCache) {
|
|
|
|
|
var cache = m_povCache.computeIfAbsent(loop, k -> new HashMap<>());
|
2025-06-29 18:32:26 -07:00
|
|
|
// angle.value is a 4 bit bitfield
|
2024-07-29 10:58:23 -04:00
|
|
|
return cache.computeIfAbsent(
|
2025-06-29 18:32:26 -07:00
|
|
|
pov * 16 + angle.value, k -> new BooleanEvent(loop, () -> getPOV(pov) == angle));
|
2024-07-29 10:58:23 -04:00
|
|
|
}
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the up direction of the default (index 0) POV
|
|
|
|
|
* on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the up direction a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povUp(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.Up, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the up right direction of the default (index 0)
|
|
|
|
|
* POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the up right direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povUpRight(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.UpRight, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the right direction of the default (index 0)
|
|
|
|
|
* POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the right direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povRight(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.Right, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the down right direction of the default (index
|
|
|
|
|
* 0) POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the down right direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povDownRight(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.DownRight, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the down direction of the default (index 0) POV
|
|
|
|
|
* on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the down direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povDown(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.Down, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the down left direction of the default (index
|
|
|
|
|
* 0) POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the down left direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povDownLeft(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.DownLeft, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the left direction of the default (index 0) POV
|
|
|
|
|
* on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the left direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povLeft(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.Left, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-29 18:32:26 -07:00
|
|
|
* Constructs a BooleanEvent instance based around the up left direction of the default (index 0)
|
|
|
|
|
* POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
2025-06-29 18:32:26 -07:00
|
|
|
* @return a BooleanEvent instance based around the up left direction of a POV on the HID.
|
2022-10-23 22:09:44 +03:00
|
|
|
*/
|
|
|
|
|
public BooleanEvent povUpLeft(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.UpLeft, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a BooleanEvent instance based around the center (not pressed) of the default (index
|
|
|
|
|
* 0) POV on the HID.
|
|
|
|
|
*
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return a BooleanEvent instance based around the center of a POV on the HID.
|
|
|
|
|
*/
|
|
|
|
|
public BooleanEvent povCenter(EventLoop loop) {
|
2025-06-29 18:32:26 -07:00
|
|
|
return pov(POVDirection.Center, loop);
|
2022-10-23 22:09:44 +03:00
|
|
|
}
|
|
|
|
|
|
2022-12-26 14:29:14 -05:00
|
|
|
/**
|
|
|
|
|
* Constructs an event instance that is true when the axis value is less than {@code threshold},
|
|
|
|
|
* attached to the given loop.
|
|
|
|
|
*
|
|
|
|
|
* @param axis The axis to read, starting at 0
|
|
|
|
|
* @param threshold The value below which this event should return true.
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return an event instance that is true when the axis value is less than the provided threshold.
|
|
|
|
|
*/
|
|
|
|
|
public BooleanEvent axisLessThan(int axis, double threshold, EventLoop loop) {
|
2024-07-29 10:58:23 -04:00
|
|
|
synchronized (m_axisLessThanCache) {
|
|
|
|
|
var cache = m_axisLessThanCache.computeIfAbsent(loop, k -> new HashMap<>());
|
|
|
|
|
return cache.computeIfAbsent(
|
|
|
|
|
Pair.of(axis, threshold),
|
|
|
|
|
k -> new BooleanEvent(loop, () -> getRawAxis(axis) < threshold));
|
|
|
|
|
}
|
2022-12-26 14:29:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs an event instance that is true when the axis value is greater than {@code
|
|
|
|
|
* threshold}, attached to the given loop.
|
|
|
|
|
*
|
|
|
|
|
* @param axis The axis to read, starting at 0
|
|
|
|
|
* @param threshold The value above which this event should return true.
|
|
|
|
|
* @param loop the event loop instance to attach the event to.
|
|
|
|
|
* @return an event instance that is true when the axis value is greater than the provided
|
|
|
|
|
* threshold.
|
|
|
|
|
*/
|
|
|
|
|
public BooleanEvent axisGreaterThan(int axis, double threshold, EventLoop loop) {
|
2024-07-29 10:58:23 -04:00
|
|
|
synchronized (m_axisGreaterThanCache) {
|
|
|
|
|
var cache = m_axisGreaterThanCache.computeIfAbsent(loop, k -> new HashMap<>());
|
|
|
|
|
return cache.computeIfAbsent(
|
|
|
|
|
Pair.of(axis, threshold),
|
|
|
|
|
k -> new BooleanEvent(loop, () -> getRawAxis(axis) > threshold));
|
|
|
|
|
}
|
2022-12-26 14:29:14 -05:00
|
|
|
}
|
|
|
|
|
|
2025-10-25 23:03:50 -07:00
|
|
|
/**
|
|
|
|
|
* Get the maximum axis index for the joystick.
|
|
|
|
|
*
|
|
|
|
|
* @return the maximum axis index for the joystick
|
|
|
|
|
*/
|
|
|
|
|
public int getAxesMaximumIndex() {
|
|
|
|
|
return DriverStation.getStickAxesMaximumIndex(m_port);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-27 21:45:56 -07:00
|
|
|
/**
|
|
|
|
|
* Get the number of axes for the HID.
|
|
|
|
|
*
|
|
|
|
|
* @return the number of axis for the current HID
|
|
|
|
|
*/
|
2025-10-25 23:03:50 -07:00
|
|
|
public int getAxesAvailable() {
|
|
|
|
|
return DriverStation.getStickAxesAvailable(m_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the maximum POV index for the joystick.
|
|
|
|
|
*
|
|
|
|
|
* @return the maximum POV index for the joystick
|
|
|
|
|
*/
|
|
|
|
|
public int getPOVsMaximumIndex() {
|
|
|
|
|
return DriverStation.getStickPOVsMaximumIndex(m_port);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
|
|
|
|
* For the current HID, return the number of POVs.
|
|
|
|
|
*
|
|
|
|
|
* @return the number of POVs for the current HID
|
|
|
|
|
*/
|
2025-10-25 23:03:50 -07:00
|
|
|
public int getPOVsAvailable() {
|
|
|
|
|
return DriverStation.getStickPOVsAvailable(m_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the maximum button index for the joystick.
|
|
|
|
|
*
|
|
|
|
|
* @return the maximum button index for the joystick
|
|
|
|
|
*/
|
|
|
|
|
public int getButtonsMaximumIndex() {
|
|
|
|
|
return DriverStation.getStickButtonsMaximumIndex(m_port);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
|
|
|
|
* For the current HID, return the number of buttons.
|
|
|
|
|
*
|
|
|
|
|
* @return the number of buttons for the current HID
|
|
|
|
|
*/
|
2025-10-25 23:03:50 -07:00
|
|
|
public long getButtonsAvailable() {
|
|
|
|
|
return DriverStation.getStickButtonsAvailable(m_port);
|
2016-11-18 23:05:37 -08:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2020-11-13 14:11:10 -05:00
|
|
|
/**
|
|
|
|
|
* Get if the HID is connected.
|
|
|
|
|
*
|
|
|
|
|
* @return true if the HID is connected
|
|
|
|
|
*/
|
|
|
|
|
public boolean isConnected() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isJoystickConnected(m_port);
|
2020-11-13 14:11:10 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2016-11-18 23:05:37 -08:00
|
|
|
* Get the type of the HID.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2016-11-18 23:05:37 -08:00
|
|
|
* @return the type of the HID.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public HIDType getType() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return HIDType.of(DriverStation.getJoystickType(m_port));
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
/**
|
2016-11-18 23:05:37 -08:00
|
|
|
* Get the name of the HID.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2016-11-18 23:05:37 -08:00
|
|
|
* @return the name of the HID.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public String getName() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.getJoystickName(m_port);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the port number of the HID.
|
|
|
|
|
*
|
|
|
|
|
* @return The port number of the HID.
|
|
|
|
|
*/
|
|
|
|
|
public int getPort() {
|
|
|
|
|
return m_port;
|
|
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
/**
|
2016-11-18 23:05:37 -08:00
|
|
|
* Set a single HID output value for the HID.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2016-11-18 23:05:37 -08:00
|
|
|
* @param outputNumber The index of the output to set (1-32)
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param value The value to set the output to
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public void setOutput(int outputNumber, boolean value) {
|
|
|
|
|
m_outputs = (m_outputs & ~(1 << (outputNumber - 1))) | ((value ? 1 : 0) << (outputNumber - 1));
|
[hal, wpilib] New DS thread model and implementation (#3787)
The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data.
This change completely rethinks how threading works in the driver station model.
First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data.
After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go.
Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem.
The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed.
IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state.
All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date.
As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
|
|
|
DriverStationJNI.setJoystickOutputs((byte) m_port, m_outputs, m_leftRumble, m_rightRumble);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
/**
|
2016-11-18 23:05:37 -08:00
|
|
|
* Set all HID output values for the HID.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2016-11-18 23:05:37 -08:00
|
|
|
* @param value The 32 bit output value (1 bit for each output)
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public void setOutputs(int value) {
|
|
|
|
|
m_outputs = value;
|
[hal, wpilib] New DS thread model and implementation (#3787)
The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data.
This change completely rethinks how threading works in the driver station model.
First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data.
After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go.
Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem.
The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed.
IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state.
All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date.
As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
|
|
|
DriverStationJNI.setJoystickOutputs((byte) m_port, m_outputs, m_leftRumble, m_rightRumble);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
|
|
|
|
/**
|
2016-11-18 23:05:37 -08:00
|
|
|
* Set the rumble output for the HID. The DS currently supports 2 rumble values, left rumble and
|
|
|
|
|
* right rumble.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* @param type Which rumble value to set
|
2016-11-18 23:05:37 -08:00
|
|
|
* @param value The normalized value (0 to 1) to set the rumble to
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
2017-10-27 21:45:56 -07:00
|
|
|
public void setRumble(RumbleType type, double value) {
|
2025-08-23 06:01:51 -10:00
|
|
|
value = Math.clamp(value, 0, 1);
|
2024-05-04 11:36:40 -04:00
|
|
|
int rumbleValue = (int) (value * 65535);
|
2022-12-24 14:28:52 -05:00
|
|
|
switch (type) {
|
2024-06-05 00:09:10 -04:00
|
|
|
case kLeftRumble -> this.m_leftRumble = rumbleValue;
|
|
|
|
|
case kRightRumble -> this.m_rightRumble = rumbleValue;
|
|
|
|
|
default -> {
|
2022-12-24 14:28:52 -05:00
|
|
|
this.m_leftRumble = rumbleValue;
|
|
|
|
|
this.m_rightRumble = rumbleValue;
|
2024-06-05 00:09:10 -04:00
|
|
|
}
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2022-12-24 14:28:52 -05:00
|
|
|
|
|
|
|
|
DriverStationJNI.setJoystickOutputs(
|
|
|
|
|
(byte) this.m_port, this.m_outputs, this.m_leftRumble, this.m_rightRumble);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|