[hal,wpilib,cmd] Update POVs to use enums (#7978)

This commit is contained in:
Joseph Eng
2025-06-29 18:32:26 -07:00
committed by GitHub
parent e13d237390
commit f55564729b
30 changed files with 538 additions and 378 deletions

View File

@@ -106,7 +106,7 @@ public class DriverStationDataJNI extends JNIWrapper {
public static native void setJoystickAxis(int stick, int axis, double value);
public static native void setJoystickPOV(int stick, int pov, int value);
public static native void setJoystickPOV(int stick, int pov, byte value);
public static native void setJoystickButtonsValue(int stick, int buttons);

View File

@@ -467,7 +467,7 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickPOVs
arraySize < HAL_kMaxJoystickPOVs ? arraySize : HAL_kMaxJoystickPOVs;
povs.count = maxCount;
for (int i = 0; i < maxCount; i++) {
povs.povs[i] = arrayRef[i];
povs.povs[i] = static_cast<HAL_JoystickPOV>(arrayRef[i]);
}
}
HALSIM_SetJoystickPOVs(joystickNum, &povs);
@@ -642,13 +642,13 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickAxis
/*
* Class: edu_wpi_first_hal_simulation_DriverStationDataJNI
* Method: setJoystickPOV
* Signature: (III)V
* Signature: (IIB)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickPOV
(JNIEnv*, jclass, jint stick, jint pov, jint value)
(JNIEnv*, jclass, jint stick, jint pov, jbyte value)
{
HALSIM_SetJoystickPOV(stick, pov, value);
HALSIM_SetJoystickPOV(stick, pov, static_cast<HAL_JoystickPOV>(value));
}
/*

View File

@@ -88,9 +88,30 @@ struct HAL_JoystickAxes {
};
typedef struct HAL_JoystickAxes HAL_JoystickAxes;
HAL_ENUM_WITH_UNDERLYING_TYPE(HAL_JoystickPOV, uint8_t){
/** Centered */
HAL_JoystickPOV_kCentered = 0x00u,
/** Up */
HAL_JoystickPOV_kUp = 0x01u,
/** Right */
HAL_JoystickPOV_kRight = 0x02u,
/** Down */
HAL_JoystickPOV_kDown = 0x04u,
/** Left */
HAL_JoystickPOV_kLeft = 0x08u,
/** Right-Up */
HAL_JoystickPOV_kRightUp = HAL_JoystickPOV_kRight | HAL_JoystickPOV_kUp,
/** Right-Down */
HAL_JoystickPOV_kRightDown = HAL_JoystickPOV_kRight | HAL_JoystickPOV_kDown,
/** Left-Up */
HAL_JoystickPOV_kLeftUp = HAL_JoystickPOV_kLeft | HAL_JoystickPOV_kUp,
/** Left-Down */
HAL_JoystickPOV_kLeftDown = HAL_JoystickPOV_kLeft | HAL_JoystickPOV_kDown,
};
struct HAL_JoystickPOVs {
int16_t count;
uint8_t povs[HAL_kMaxJoystickPOVs];
HAL_JoystickPOV povs[HAL_kMaxJoystickPOVs];
};
typedef struct HAL_JoystickPOVs HAL_JoystickPOVs;

View File

@@ -73,18 +73,20 @@ typedef HAL_Handle HAL_CANStreamHandle;
typedef int32_t HAL_Bool;
#ifdef __cplusplus
#define HAL_ENUM(name) enum name : int32_t
#define HAL_ENUM_WITH_UNDERLYING_TYPE(name, type) enum name : type
#elif defined(__clang__)
#define HAL_ENUM(name) \
enum name : int32_t; \
typedef enum name name; \
enum name : int32_t
#define HAL_ENUM_WITH_UNDERLYING_TYPE(name, type) \
enum name : type; \
typedef enum name name; \
enum name : type
#else
#define HAL_ENUM(name) \
typedef int32_t name; \
#define HAL_ENUM_WITH_UNDERLYING_TYPE(name, type) \
typedef type name; \
enum name
#endif
#define HAL_ENUM(name) HAL_ENUM_WITH_UNDERLYING_TYPE(name, int32_t)
#ifdef __cplusplus
namespace hal {
/**

View File

@@ -139,7 +139,7 @@ void HALSIM_SetMatchInfo(const HAL_MatchInfo* info);
void HALSIM_SetJoystickButton(int32_t stick, int32_t button, HAL_Bool state);
void HALSIM_SetJoystickAxis(int32_t stick, int32_t axis, double value);
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, int32_t value);
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, HAL_JoystickPOV value);
void HALSIM_SetJoystickButtonsValue(int32_t stick, uint32_t buttons);
void HALSIM_SetJoystickAxisCount(int32_t stick, int32_t count);
void HALSIM_SetJoystickPOVCount(int32_t stick, int32_t count);

View File

@@ -251,7 +251,7 @@ void DriverStationData::SetJoystickAxis(int32_t stick, int32_t axis,
}
void DriverStationData::SetJoystickPOV(int32_t stick, int32_t pov,
int32_t value) {
HAL_JoystickPOV value) {
if (stick < 0 || stick >= kNumJoysticks) {
return;
}
@@ -507,7 +507,7 @@ void HALSIM_SetJoystickAxis(int32_t stick, int32_t axis, double value) {
SimDriverStationData->SetJoystickAxis(stick, axis, value);
}
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, int32_t value) {
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, HAL_JoystickPOV value) {
SimDriverStationData->SetJoystickPOV(stick, pov, value);
}

View File

@@ -97,7 +97,7 @@ class DriverStationData {
void SetJoystickButton(int32_t stick, int32_t button, HAL_Bool state);
void SetJoystickAxis(int32_t stick, int32_t axis, double value);
void SetJoystickPOV(int32_t stick, int32_t pov, int32_t value);
void SetJoystickPOV(int32_t stick, int32_t pov, HAL_JoystickPOV value);
void SetJoystickButtons(int32_t stick, uint32_t buttons);
void SetJoystickAxisCount(int32_t stick, int32_t count);
void SetJoystickPOVCount(int32_t stick, int32_t count);

View File

@@ -263,7 +263,7 @@ void JoystickDataCache::Update(const mrc::ControlData& data) {
povs[count].count = newPovs.size();
for (size_t i = 0; i < newPovs.size(); i++) {
povs[count].povs[i] = newPovs[i];
povs[count].povs[i] = static_cast<HAL_JoystickPOV>(newPovs[i]);
}
buttons[count].count = newStick.Buttons.GetMaxAvailableCount();

View File

@@ -82,7 +82,7 @@ void HALSIM_SetJoystickButton(int32_t stick, int32_t button, HAL_Bool state) {}
void HALSIM_SetJoystickAxis(int32_t stick, int32_t axis, double value) {}
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, int32_t value) {}
void HALSIM_SetJoystickPOV(int32_t stick, int32_t pov, HAL_JoystickPOV value) {}
void HALSIM_SetJoystickButtonsValue(int32_t stick, uint32_t buttons) {}

View File

@@ -53,9 +53,9 @@ TEST(DriverStationTest, Joystick) {
}
set_povs.count = 3;
for (int i = 0; i < set_povs.count; ++i) {
set_povs.povs[i] = i * 15 + 12;
}
set_povs.povs[0] = HAL_JoystickPOV_kUp;
set_povs.povs[1] = HAL_JoystickPOV_kRight;
set_povs.povs[2] = HAL_JoystickPOV_kDown;
set_buttons.count = 8;
set_buttons.buttons = 0xDEADBEEF;
@@ -82,9 +82,9 @@ TEST(DriverStationTest, Joystick) {
EXPECT_NEAR(0, axes.axes[6], 0.000001); // Should not have been set, still 0
EXPECT_EQ(3, povs.count);
EXPECT_EQ(12, povs.povs[0]);
EXPECT_EQ(27, povs.povs[1]);
EXPECT_EQ(42, povs.povs[2]);
EXPECT_EQ(HAL_JoystickPOV_kUp, povs.povs[0]);
EXPECT_EQ(HAL_JoystickPOV_kRight, povs.povs[1]);
EXPECT_EQ(HAL_JoystickPOV_kDown, povs.povs[2]);
EXPECT_EQ(0, povs.povs[3]); // Should not have been set, still 0
EXPECT_EQ(0, povs.povs[4]); // Should not have been set, still 0
EXPECT_EQ(0, povs.povs[5]); // Should not have been set, still 0

View File

@@ -16,6 +16,30 @@
using namespace halsim;
HAL_JoystickPOV DegreesToPOV(int degrees) {
switch (degrees) {
case 0:
return HAL_JoystickPOV_kUp;
case 45:
return HAL_JoystickPOV_kRightUp;
case 90:
return HAL_JoystickPOV_kRight;
case 135:
return HAL_JoystickPOV_kRightDown;
case 180:
return HAL_JoystickPOV_kDown;
case 225:
return HAL_JoystickPOV_kLeftDown;
case 270:
return HAL_JoystickPOV_kLeft;
case 315:
return HAL_JoystickPOV_kLeftUp;
case -1:
default:
return HAL_JoystickPOV_kCentered;
}
}
DSCommPacket::DSCommPacket() {
for (auto& i : m_joystick_packets) {
i.ResetTcp();
@@ -101,7 +125,8 @@ void DSCommPacket::ReadJoystickTag(std::span<const uint8_t> dataInput,
int povsLength = dataInput[0];
for (int i = 0; i < povsLength * 2; i += 2) {
stick.povs.povs[i] = (dataInput[1 + i] << 8) | dataInput[2 + i];
stick.povs.povs[i] =
DegreesToPOV((dataInput[1 + i] << 8) | dataInput[2 + i]);
}
stick.povs.count = povsLength;

View File

@@ -142,14 +142,14 @@ class KeyboardJoystick : public SystemJoystick {
struct PovConfig {
explicit PovConfig(glass::Storage& storage);
int& key0;
int& key45;
int& key90;
int& key135;
int& key180;
int& key225;
int& key270;
int& key315;
int& keyUp;
int& keyUpRight;
int& keyRight;
int& keyDownRight;
int& keyDown;
int& keyDownLeft;
int& keyLeft;
int& keyUpLeft;
};
std::vector<std::unique_ptr<glass::Storage>>& m_povStorage;
@@ -459,7 +459,9 @@ void GlfwSystemJoystick::GetData(HALJoystickData* data, bool mapGamepad) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif // __GNUC__ >= 12
data->povs.povs[j] = m_hats[j];
// From https://www.glfw.org/docs/latest/group__hat__state.html, GLFW hat
// states use the same format
data->povs.povs[j] = static_cast<HAL_JoystickPOV>(m_hats[j]);
#if __GNUC__ >= 12
#pragma GCC diagnostic pop
#endif // __GNUC__ >= 12
@@ -482,38 +484,38 @@ KeyboardJoystick::AxisConfig::AxisConfig(glass::Storage& storage)
}
KeyboardJoystick::PovConfig::PovConfig(glass::Storage& storage)
: key0{storage.GetInt("key0", -1)},
key45{storage.GetInt("key45", -1)},
key90{storage.GetInt("key90", -1)},
key135{storage.GetInt("key135", -1)},
key180{storage.GetInt("key180", -1)},
key225{storage.GetInt("key225", -1)},
key270{storage.GetInt("key270", -1)},
key315{storage.GetInt("key315", -1)} {
: keyUp{storage.GetInt("keyUp", -1)},
keyUpRight{storage.GetInt("keyUpRight", -1)},
keyRight{storage.GetInt("keyRight", -1)},
keyDownRight{storage.GetInt("keyDownRight", -1)},
keyDown{storage.GetInt("keyDown", -1)},
keyDownLeft{storage.GetInt("keyDownLeft", -1)},
keyLeft{storage.GetInt("keyLeft", -1)},
keyUpLeft{storage.GetInt("keyUpLeft", -1)} {
// sanity check the key ranges
if (key0 < -1 || key0 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key0 = -1;
if (keyUp < -1 || keyUp >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyUp = -1;
}
if (key45 < -1 || key45 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key45 = -1;
if (keyUpRight < -1 || keyUpRight >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyUpRight = -1;
}
if (key90 < -1 || key90 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key90 = -1;
if (keyRight < -1 || keyRight >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyRight = -1;
}
if (key135 < -1 || key135 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key135 = -1;
if (keyDownRight < -1 || keyDownRight >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyDownRight = -1;
}
if (key180 < -1 || key180 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key180 = -1;
if (keyDown < -1 || keyDown >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyDown = -1;
}
if (key225 < -1 || key225 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key225 = -1;
if (keyDownLeft < -1 || keyDownLeft >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyDownLeft = -1;
}
if (key270 < -1 || key270 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key270 = -1;
if (keyLeft < -1 || keyLeft >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyLeft = -1;
}
if (key315 < -1 || key315 >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
key315 = -1;
if (keyUpLeft < -1 || keyUpLeft >= IM_ARRAYSIZE(ImGuiIO::KeysDown)) {
keyUpLeft = -1;
}
}
@@ -670,14 +672,14 @@ void KeyboardJoystick::SettingsDisplay() {
wpi::format_to_n_c_str(label, sizeof(label), "POV {}", i);
if (ImGui::TreeNodeEx(label, ImGuiTreeNodeFlags_DefaultOpen)) {
EditKey(" 0 deg", &m_povConfig[i].key0);
EditKey(" 45 deg", &m_povConfig[i].key45);
EditKey(" 90 deg", &m_povConfig[i].key90);
EditKey("135 deg", &m_povConfig[i].key135);
EditKey("180 deg", &m_povConfig[i].key180);
EditKey("225 deg", &m_povConfig[i].key225);
EditKey("270 deg", &m_povConfig[i].key270);
EditKey("315 deg", &m_povConfig[i].key315);
EditKey(" Up", &m_povConfig[i].keyUp);
EditKey(" Up Right", &m_povConfig[i].keyUpRight);
EditKey(" Right", &m_povConfig[i].keyRight);
EditKey("Down Right", &m_povConfig[i].keyDownRight);
EditKey(" Down", &m_povConfig[i].keyDown);
EditKey(" Down Left", &m_povConfig[i].keyDownLeft);
EditKey(" Left", &m_povConfig[i].keyLeft);
EditKey(" Up Left", &m_povConfig[i].keyUpLeft);
ImGui::TreePop();
}
}
@@ -758,37 +760,27 @@ void KeyboardJoystick::Update() {
}
}
#define SDL_HAT_CENTERED 0x00u
#define SDL_HAT_UP 0x01u
#define SDL_HAT_RIGHT 0x02u
#define SDL_HAT_DOWN 0x04u
#define SDL_HAT_LEFT 0x08u
#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT | SDL_HAT_UP)
#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT | SDL_HAT_DOWN)
#define SDL_HAT_LEFTUP (SDL_HAT_LEFT | SDL_HAT_UP)
#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT | SDL_HAT_DOWN)
// povs
for (int i = 0; i < m_data.povs.count; ++i) {
auto& config = m_povConfig[i];
auto& povValue = m_data.povs.povs[i];
povValue = 0;
if (IsKeyDown(io, config.key0)) {
povValue = SDL_HAT_UP;
} else if (IsKeyDown(io, config.key45)) {
povValue = SDL_HAT_RIGHTUP;
} else if (IsKeyDown(io, config.key90)) {
povValue = SDL_HAT_RIGHT;
} else if (IsKeyDown(io, config.key135)) {
povValue = SDL_HAT_RIGHTDOWN;
} else if (IsKeyDown(io, config.key180)) {
povValue = SDL_HAT_DOWN;
} else if (IsKeyDown(io, config.key225)) {
povValue = SDL_HAT_LEFTDOWN;
} else if (IsKeyDown(io, config.key270)) {
povValue = SDL_HAT_LEFT;
} else if (IsKeyDown(io, config.key315)) {
povValue = SDL_HAT_LEFTUP;
povValue = HAL_JoystickPOV_kCentered;
if (IsKeyDown(io, config.keyUp)) {
povValue = HAL_JoystickPOV_kUp;
} else if (IsKeyDown(io, config.keyUpRight)) {
povValue = HAL_JoystickPOV_kRightUp;
} else if (IsKeyDown(io, config.keyRight)) {
povValue = HAL_JoystickPOV_kRight;
} else if (IsKeyDown(io, config.keyDownRight)) {
povValue = HAL_JoystickPOV_kRightDown;
} else if (IsKeyDown(io, config.keyDown)) {
povValue = HAL_JoystickPOV_kDown;
} else if (IsKeyDown(io, config.keyDownLeft)) {
povValue = HAL_JoystickPOV_kLeftDown;
} else if (IsKeyDown(io, config.keyLeft)) {
povValue = HAL_JoystickPOV_kLeft;
} else if (IsKeyDown(io, config.keyUpLeft)) {
povValue = HAL_JoystickPOV_kLeftUp;
}
}
@@ -821,29 +813,29 @@ void KeyboardJoystick::ClearKey(int key) {
}
}
for (auto&& config : m_povConfig) {
if (config.key0 == key) {
config.key0 = -1;
if (config.keyUp == key) {
config.keyUp = -1;
}
if (config.key45 == key) {
config.key45 = -1;
if (config.keyUpRight == key) {
config.keyUpRight = -1;
}
if (config.key90 == key) {
config.key90 = -1;
if (config.keyRight == key) {
config.keyRight = -1;
}
if (config.key135 == key) {
config.key135 = -1;
if (config.keyDownRight == key) {
config.keyDownRight = -1;
}
if (config.key180 == key) {
config.key180 = -1;
if (config.keyDown == key) {
config.keyDown = -1;
}
if (config.key225 == key) {
config.key225 = -1;
if (config.keyDownLeft == key) {
config.keyDownLeft = -1;
}
if (config.key270 == key) {
config.key270 = -1;
if (config.keyLeft == key) {
config.keyLeft = -1;
}
if (config.key315 == key) {
config.key315 = -1;
if (config.keyUpLeft == key) {
config.keyUpLeft = -1;
}
}
}
@@ -879,14 +871,14 @@ GlfwKeyboardJoystick::GlfwKeyboardJoystick(glass::Storage& storage, int index)
m_povCount = 1;
m_povStorage.emplace_back(std::make_unique<glass::Storage>());
m_povConfig.emplace_back(*m_povStorage.back());
m_povConfig[0].key0 = GLFW_KEY_KP_8;
m_povConfig[0].key45 = GLFW_KEY_KP_9;
m_povConfig[0].key90 = GLFW_KEY_KP_6;
m_povConfig[0].key135 = GLFW_KEY_KP_3;
m_povConfig[0].key180 = GLFW_KEY_KP_2;
m_povConfig[0].key225 = GLFW_KEY_KP_1;
m_povConfig[0].key270 = GLFW_KEY_KP_4;
m_povConfig[0].key315 = GLFW_KEY_KP_7;
m_povConfig[0].keyUp = GLFW_KEY_KP_8;
m_povConfig[0].keyUpRight = GLFW_KEY_KP_9;
m_povConfig[0].keyRight = GLFW_KEY_KP_6;
m_povConfig[0].keyDownRight = GLFW_KEY_KP_3;
m_povConfig[0].keyDown = GLFW_KEY_KP_2;
m_povConfig[0].keyDownLeft = GLFW_KEY_KP_1;
m_povConfig[0].keyLeft = GLFW_KEY_KP_4;
m_povConfig[0].keyUpLeft = GLFW_KEY_KP_7;
}
} else if (index == 1) {
if (m_axisCount == -1 && m_axisStorage.empty()) {

View File

@@ -5,6 +5,7 @@
package edu.wpi.first.wpilibj2.command.button;
import edu.wpi.first.math.Pair;
import edu.wpi.first.wpilibj.DriverStation.POVDirection;
import edu.wpi.first.wpilibj.GenericHID;
import edu.wpi.first.wpilibj.event.EventLoop;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
@@ -74,121 +75,115 @@ public class CommandGenericHID {
* attached to {@link CommandScheduler#getDefaultButtonLoop() the default command scheduler button
* loop}.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (e.g. right is 90,
* upper-left is 315).
*
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
public Trigger pov(int angle) {
public Trigger pov(POVDirection angle) {
return pov(0, angle, CommandScheduler.getInstance().getDefaultButtonLoop());
}
/**
* Constructs a Trigger instance based around this angle of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (e.g. right is 90,
* upper-left is 315).
*
* @param pov index of the POV to read (starting at 0). Defaults to 0.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @param loop the event loop instance to attach the event to. Defaults to {@link
* CommandScheduler#getDefaultButtonLoop() the default command scheduler button loop}.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
public Trigger pov(int pov, int angle, EventLoop loop) {
public Trigger pov(int pov, POVDirection angle, EventLoop loop) {
var cache = m_povCache.computeIfAbsent(loop, k -> new HashMap<>());
// angle can be -1, so use 3600 instead of 360
// angle.value is a 4 bit bitfield
return cache.computeIfAbsent(
pov * 3600 + angle, k -> new Trigger(loop, () -> m_hid.getPOV(pov) == angle));
pov * 16 + angle.value, k -> new Trigger(loop, () -> m_hid.getPOV(pov) == angle));
}
/**
* Constructs a Trigger instance based around the 0 degree angle (up) of the default (index 0) POV
* Constructs a Trigger instance based around the up direction of the default (index 0) POV on the
* HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command scheduler
* button loop}.
*
* @return a Trigger instance based around the up direction of a POV on the HID.
*/
public Trigger povUp() {
return pov(POVDirection.Up);
}
/**
* Constructs a Trigger instance based around the up right direction of the default (index 0) POV
* on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 0 degree angle of a POV on the HID.
*/
public Trigger povUp() {
return pov(0);
}
/**
* Constructs a Trigger instance based around the 45 degree angle (right up) of the default (index
* 0) POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default
* command scheduler button loop}.
*
* @return a Trigger instance based around the 45 degree angle of a POV on the HID.
* @return a Trigger instance based around the up right direction of a POV on the HID.
*/
public Trigger povUpRight() {
return pov(45);
return pov(POVDirection.UpRight);
}
/**
* Constructs a Trigger instance based around the 90 degree angle (right) of the default (index 0)
* POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* Constructs a Trigger instance based around the right direction of the default (index 0) POV on
* the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 90 degree angle of a POV on the HID.
* @return a Trigger instance based around the right direction of a POV on the HID.
*/
public Trigger povRight() {
return pov(90);
return pov(POVDirection.Right);
}
/**
* Constructs a Trigger instance based around the 135 degree angle (right down) of the default
* (index 0) POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the
* default command scheduler button loop}.
* Constructs a Trigger instance based around the down right direction of the default (index 0)
* POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 135 degree angle of a POV on the HID.
* @return a Trigger instance based around the down right direction of a POV on the HID.
*/
public Trigger povDownRight() {
return pov(135);
return pov(POVDirection.DownRight);
}
/**
* Constructs a Trigger instance based around the 180 degree angle (down) of the default (index 0)
* POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* Constructs a Trigger instance based around the down direction of the default (index 0) POV on
* the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 180 degree angle of a POV on the HID.
* @return a Trigger instance based around the down direction of a POV on the HID.
*/
public Trigger povDown() {
return pov(180);
return pov(POVDirection.Down);
}
/**
* Constructs a Trigger instance based around the 225 degree angle (down left) of the default
* (index 0) POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the
* default command scheduler button loop}.
*
* @return a Trigger instance based around the 225 degree angle of a POV on the HID.
*/
public Trigger povDownLeft() {
return pov(225);
}
/**
* Constructs a Trigger instance based around the 270 degree angle (left) of the default (index 0)
* Constructs a Trigger instance based around the down left POV direction of the default (index 0)
* POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 270 degree angle of a POV on the HID.
* @return a Trigger instance based around the down left POV direction of a POV on the HID.
*/
public Trigger povLeft() {
return pov(270);
public Trigger povDownLeft() {
return pov(POVDirection.DownLeft);
}
/**
* Constructs a Trigger instance based around the 315 degree angle (left up) of the default (index
* 0) POV on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default
* command scheduler button loop}.
* Constructs a Trigger instance based around the left direction of the default (index 0) POV on
* the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the 315 degree angle of a POV on the HID.
* @return a Trigger instance based around the left direction of a POV on the HID.
*/
public Trigger povLeft() {
return pov(POVDirection.Left);
}
/**
* Constructs a Trigger instance based around the up left direction of the default (index 0) POV
* on the HID, attached to {@link CommandScheduler#getDefaultButtonLoop() the default command
* scheduler button loop}.
*
* @return a Trigger instance based around the up left direction of a POV on the HID.
*/
public Trigger povUpLeft() {
return pov(315);
return pov(POVDirection.UpLeft);
}
/**
@@ -199,7 +194,7 @@ public class CommandGenericHID {
* @return a Trigger instance based around the center position of a POV on the HID.
*/
public Trigger povCenter() {
return pov(-1);
return pov(POVDirection.Center);
}
/**

View File

@@ -6,6 +6,7 @@ package edu.wpi.first.wpilibj2.command.button;
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.wpilibj.DriverStation.POVDirection;
import edu.wpi.first.wpilibj.GenericHID;
/**
@@ -18,10 +19,10 @@ public class POVButton extends Trigger {
* Creates a POV button for triggering commands.
*
* @param joystick The GenericHID object that has the POV
* @param angle The desired angle in degrees (e.g. 90, 270)
* @param angle The desired angle
* @param povNumber The POV number (see {@link GenericHID#getPOV(int)})
*/
public POVButton(GenericHID joystick, int angle, int povNumber) {
public POVButton(GenericHID joystick, POVDirection angle, int povNumber) {
super(() -> joystick.getPOV(povNumber) == angle);
requireNonNullParam(joystick, "joystick", "POVButton");
}
@@ -30,9 +31,9 @@ public class POVButton extends Trigger {
* Creates a POV button for triggering commands. By default, acts on POV 0
*
* @param joystick The GenericHID object that has the POV
* @param angle The desired angle (e.g. 90, 270)
* @param angle The desired angle
*/
public POVButton(GenericHID joystick, int angle) {
public POVButton(GenericHID joystick, POVDirection angle) {
this(joystick, angle, 0);
}
}

View File

@@ -16,49 +16,51 @@ Trigger CommandGenericHID::Button(int button, frc::EventLoop* loop) const {
return Trigger(loop, [this, button] { return m_hid.GetRawButton(button); });
}
Trigger CommandGenericHID::POV(int angle, frc::EventLoop* loop) const {
Trigger CommandGenericHID::POV(frc::DriverStation::POVDirection angle,
frc::EventLoop* loop) const {
return POV(0, angle, loop);
}
Trigger CommandGenericHID::POV(int pov, int angle, frc::EventLoop* loop) const {
Trigger CommandGenericHID::POV(int pov, frc::DriverStation::POVDirection angle,
frc::EventLoop* loop) const {
return Trigger(loop,
[this, pov, angle] { return m_hid.GetPOV(pov) == angle; });
}
Trigger CommandGenericHID::POVUp(frc::EventLoop* loop) const {
return POV(0, loop);
return POV(frc::DriverStation::POVDirection::kUp, loop);
}
Trigger CommandGenericHID::POVUpRight(frc::EventLoop* loop) const {
return POV(45, loop);
return POV(frc::DriverStation::POVDirection::kUpRight, loop);
}
Trigger CommandGenericHID::POVRight(frc::EventLoop* loop) const {
return POV(90, loop);
return POV(frc::DriverStation::POVDirection::kRight, loop);
}
Trigger CommandGenericHID::POVDownRight(frc::EventLoop* loop) const {
return POV(135, loop);
return POV(frc::DriverStation::POVDirection::kDownRight, loop);
}
Trigger CommandGenericHID::POVDown(frc::EventLoop* loop) const {
return POV(180, loop);
return POV(frc::DriverStation::POVDirection::kDown, loop);
}
Trigger CommandGenericHID::POVDownLeft(frc::EventLoop* loop) const {
return POV(225, loop);
return POV(frc::DriverStation::POVDirection::kDownLeft, loop);
}
Trigger CommandGenericHID::POVLeft(frc::EventLoop* loop) const {
return POV(270, loop);
return POV(frc::DriverStation::POVDirection::kLeft, loop);
}
Trigger CommandGenericHID::POVUpLeft(frc::EventLoop* loop) const {
return POV(315, loop);
return POV(frc::DriverStation::POVDirection::kUpLeft, loop);
}
Trigger CommandGenericHID::POVCenter(frc::EventLoop* loop) const {
return POV(360, loop);
return POV(frc::DriverStation::POVDirection::kCenter, loop);
}
Trigger CommandGenericHID::AxisLessThan(int axis, double threshold,

View File

@@ -3,6 +3,8 @@
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/DriverStation.h>
#include <frc/GenericHID.h>
#include "Trigger.h"
@@ -49,133 +51,127 @@ class CommandGenericHID {
/**
* Constructs a Trigger instance based around this angle of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise
* (eg right is 90, upper-left is 315).
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
Trigger POV(int angle,
Trigger POV(frc::DriverStation::POVDirection angle,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around this angle of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise
* (eg right is 90, upper-left is 315).
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @param pov index of the POV to read (starting at 0). Defaults to 0.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
Trigger POV(int pov, int angle,
Trigger POV(int pov, frc::DriverStation::POVDirection angle,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 0 degree angle (up) of the
* Constructs a Trigger instance based around the up direction of the
* default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 0 degree angle of a POV on the
* @return a Trigger instance based around the up direction of a POV on the
* HID.
*/
Trigger POVUp(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 45 degree angle (right up)
* Constructs a Trigger instance based around the up right direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 45 degree angle of a POV on the
* HID.
* @return a Trigger instance based around the up right direction of a POV on
* the HID.
*/
Trigger POVUpRight(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 90 degree angle (right) of
* Constructs a Trigger instance based around the right direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 90 degree angle of a POV on the
* @return a Trigger instance based around the right direction of a POV on the
* HID.
*/
Trigger POVRight(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 135 degree angle (right
* down) of the default (index 0) POV on the HID.
* Constructs a Trigger instance based around the down right direction
* of the default (index 0) POV on the HID.
*
* @return a Trigger instance based around the 135 degree angle of a POV on
* the HID.
* @return a Trigger instance based around the down right direction of a POV
* on the HID.
*/
Trigger POVDownRight(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 180 degree angle (down) of
* Constructs a Trigger instance based around the down direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 180 degree angle of a POV on
* @return a Trigger instance based around the down direction of a POV on
* the HID.
*/
Trigger POVDown(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 225 degree angle (down left)
* Constructs a Trigger instance based around the down left direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 225 degree angle of a POV on
* @return a Trigger instance based around the down left direction of a POV on
* the HID.
*/
Trigger POVDownLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 270 degree angle (left) of
* Constructs a Trigger instance based around the left direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 270 degree angle of a POV on
* @return a Trigger instance based around the left direction of a POV on
* the HID.
*/
Trigger POVLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the 315 degree angle (left up)
* Constructs a Trigger instance based around the up left direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the 315 degree angle of a POV on
* @return a Trigger instance based around the up left direction of a POV on
* the HID.
*/
Trigger POVUpLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()

View File

@@ -4,6 +4,7 @@
#pragma once
#include <frc/DriverStation.h>
#include <frc/GenericHID.h>
#include "Trigger.h"
@@ -26,7 +27,8 @@ class POVButton : public Trigger {
* @param angle The angle of the POV corresponding to a button press.
* @param povNumber The number of the POV on the joystick.
*/
POVButton(frc::GenericHID* joystick, int angle, int povNumber = 0)
POVButton(frc::GenericHID* joystick, frc::DriverStation::POVDirection angle,
int povNumber = 0)
: Trigger([joystick, angle, povNumber] {
return joystick->GetPOV(povNumber) == angle;
}) {}

View File

@@ -2,6 +2,7 @@
// 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.
#include <frc/DriverStation.h>
#include <frc/Joystick.h>
#include <frc/simulation/JoystickSim.h>
#include <gtest/gtest.h>
@@ -17,7 +18,7 @@ class POVButtonTest : public CommandTestBase {};
TEST_F(POVButtonTest, SetPOV) {
frc::sim::JoystickSim joysim(1);
joysim.SetPOV(0);
joysim.SetPOV(frc::DriverStation::kUp);
joysim.NotifyNewData();
auto& scheduler = CommandScheduler::GetInstance();
@@ -26,11 +27,11 @@ TEST_F(POVButtonTest, SetPOV) {
WaitUntilCommand command([&finished] { return finished; });
frc::Joystick joy(1);
POVButton(&joy, 90).OnTrue(&command);
POVButton(&joy, frc::DriverStation::kRight).OnTrue(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
joysim.SetPOV(90);
joysim.SetPOV(frc::DriverStation::kRight);
joysim.NotifyNewData();
scheduler.Run();

View File

@@ -315,14 +315,14 @@ double DriverStation::GetStickAxis(int stick, int axis) {
return axes.axes[axis];
}
int DriverStation::GetStickPOV(int stick, int pov) {
DriverStation::POVDirection DriverStation::GetStickPOV(int stick, int pov) {
if (stick < 0 || stick >= kJoystickPorts) {
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
return -1;
return kCenter;
}
if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
FRC_ReportError(warn::BadJoystickAxis, "POV {} out of range", pov);
return -1;
return kCenter;
}
HAL_JoystickPOVs povs;
@@ -333,10 +333,10 @@ int DriverStation::GetStickPOV(int stick, int pov) {
"Joystick POV {} missing (max {}), check if all controllers are "
"plugged in",
pov, povs.count);
return -1;
return kCenter;
}
return povs.povs[pov];
return static_cast<POVDirection>(povs.povs[pov]);
}
int DriverStation::GetStickButtons(int stick) {

View File

@@ -42,53 +42,55 @@ double GenericHID::GetRawAxis(int axis) const {
return DriverStation::GetStickAxis(m_port, axis);
}
int GenericHID::GetPOV(int pov) const {
DriverStation::POVDirection GenericHID::GetPOV(int pov) const {
return DriverStation::GetStickPOV(m_port, pov);
}
BooleanEvent GenericHID::POV(int angle, EventLoop* loop) const {
BooleanEvent GenericHID::POV(DriverStation::POVDirection angle,
EventLoop* loop) const {
return POV(0, angle, loop);
}
BooleanEvent GenericHID::POV(int pov, int angle, EventLoop* loop) const {
BooleanEvent GenericHID::POV(int pov, DriverStation::POVDirection angle,
EventLoop* loop) const {
return BooleanEvent(
loop, [this, pov, angle] { return this->GetPOV(pov) == angle; });
}
BooleanEvent GenericHID::POVUp(EventLoop* loop) const {
return POV(0, loop);
return POV(DriverStation::kUp, loop);
}
BooleanEvent GenericHID::POVUpRight(EventLoop* loop) const {
return POV(45, loop);
return POV(DriverStation::kUpRight, loop);
}
BooleanEvent GenericHID::POVRight(EventLoop* loop) const {
return POV(90, loop);
return POV(DriverStation::kRight, loop);
}
BooleanEvent GenericHID::POVDownRight(EventLoop* loop) const {
return POV(135, loop);
return POV(DriverStation::kDownRight, loop);
}
BooleanEvent GenericHID::POVDown(EventLoop* loop) const {
return POV(180, loop);
return POV(DriverStation::kDown, loop);
}
BooleanEvent GenericHID::POVDownLeft(EventLoop* loop) const {
return POV(225, loop);
return POV(DriverStation::kDownLeft, loop);
}
BooleanEvent GenericHID::POVLeft(EventLoop* loop) const {
return POV(270, loop);
return POV(DriverStation::kLeft, loop);
}
BooleanEvent GenericHID::POVUpLeft(EventLoop* loop) const {
return POV(315, loop);
return POV(DriverStation::kUpLeft, loop);
}
BooleanEvent GenericHID::POVCenter(EventLoop* loop) const {
return POV(360, loop);
return POV(DriverStation::kCenter, loop);
}
BooleanEvent GenericHID::AxisLessThan(int axis, double threshold,

View File

@@ -205,8 +205,9 @@ void DriverStationSim::SetJoystickAxis(int stick, int axis, double value) {
HALSIM_SetJoystickAxis(stick, axis, value);
}
void DriverStationSim::SetJoystickPOV(int stick, int pov, int value) {
HALSIM_SetJoystickPOV(stick, pov, value);
void DriverStationSim::SetJoystickPOV(int stick, int pov,
DriverStation::POVDirection value) {
HALSIM_SetJoystickPOV(stick, pov, static_cast<HAL_JoystickPOV>(value));
}
void DriverStationSim::SetJoystickButtons(int stick, uint32_t buttons) {

View File

@@ -4,6 +4,7 @@
#include "frc/simulation/GenericHIDSim.h"
#include "frc/DriverStation.h"
#include "frc/GenericHID.h"
#include "frc/simulation/DriverStationSim.h"
@@ -27,11 +28,11 @@ void GenericHIDSim::SetRawAxis(int axis, double value) {
DriverStationSim::SetJoystickAxis(m_port, axis, value);
}
void GenericHIDSim::SetPOV(int pov, int value) {
void GenericHIDSim::SetPOV(int pov, DriverStation::POVDirection value) {
DriverStationSim::SetJoystickPOV(m_port, pov, value);
}
void GenericHIDSim::SetPOV(int value) {
void GenericHIDSim::SetPOV(DriverStation::POVDirection value) {
SetPOV(0, value);
}

View File

@@ -4,9 +4,12 @@
#pragma once
#include <frc/geometry/Rotation2d.h>
#include <optional>
#include <string>
#include <hal/DriverStationTypes.h>
#include <units/time.h>
#include <wpi/Synchronization.h>
@@ -46,6 +49,62 @@ class DriverStation final {
kElimination
};
/**
* A controller POV direction.
*/
enum POVDirection : uint8_t {
/// POV center.
kCenter = HAL_JoystickPOV_kCentered,
/// POV up.
kUp = HAL_JoystickPOV_kUp,
/// POV up right.
kUpRight = HAL_JoystickPOV_kRightUp,
/// POV right.
kRight = HAL_JoystickPOV_kRight,
/// POV down right.
kDownRight = HAL_JoystickPOV_kRightDown,
/// POV down.
kDown = HAL_JoystickPOV_kDown,
/// POV down left.
kDownLeft = HAL_JoystickPOV_kLeftDown,
/// POV left.
kLeft = HAL_JoystickPOV_kLeft,
/// POV up left.
kUpLeft = HAL_JoystickPOV_kLeftUp,
};
/**
* Gets the angle of a POVDirection.
*
* @param angle The POVDirection to convert.
* @return The angle clockwise from straight up, or std::nullopt if the
* POVDirection is kCenter.
*/
static constexpr std::optional<Rotation2d> GetAngle(POVDirection angle) {
switch (angle) {
case kCenter:
return std::nullopt;
case kUp:
return Rotation2d{0_deg};
case kUpRight:
return Rotation2d{45_deg};
case kRight:
return Rotation2d{90_deg};
case kDownRight:
return Rotation2d{135_deg};
case kDown:
return Rotation2d{180_deg};
case kDownLeft:
return Rotation2d{225_deg};
case kLeft:
return Rotation2d{270_deg};
case kUpLeft:
return Rotation2d{315_deg};
default:
return std::nullopt;
}
}
/// Number of Joystick ports.
static constexpr int kJoystickPorts = 6;
@@ -93,9 +152,9 @@ class DriverStation final {
/**
* Get the state of a POV on the joystick.
*
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
* @return the angle of the POV.
*/
static int GetStickPOV(int stick, int pov);
static POVDirection GetStickPOV(int stick, int pov);
/**
* The state of the buttons on the joystick.

View File

@@ -8,6 +8,8 @@
#include <string>
#include "frc/DriverStation.h"
namespace frc {
class BooleanEvent;
@@ -141,113 +143,105 @@ class GenericHID {
double GetRawAxis(int axis) const;
/**
* Get the angle in degrees of a POV on the HID.
*
* The POV angles start at 0 in the up direction, and increase clockwise
* (e.g. right is 90, upper-left is 315).
* Get the angle of a POV on the HID.
*
* @param pov The index of the POV to read (starting at 0)
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
* @return the angle of the POV.
*/
int GetPOV(int pov = 0) const;
DriverStation::POVDirection GetPOV(int pov = 0) const;
/**
* Constructs a BooleanEvent instance based around this angle of a POV on the
* HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise
* (eg right is 90, upper-left is 315).
*
* @param loop the event loop instance to attach the event to.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @return a BooleanEvent instance based around this angle of a POV on the
* HID.
*/
BooleanEvent POV(int angle, EventLoop* loop) const;
BooleanEvent POV(DriverStation::POVDirection angle, EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around this angle of a POV on the
* HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise
* (eg right is 90, upper-left is 315).
*
* @param loop the event loop instance to attach the event to.
* @param pov index of the POV to read (starting at 0). Defaults to 0.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @return a BooleanEvent instance based around this angle of a POV on the
* HID.
*/
BooleanEvent POV(int pov, int angle, EventLoop* loop) const;
BooleanEvent POV(int pov, DriverStation::POVDirection angle,
EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 0 degree angle (up) of
* Constructs a BooleanEvent instance based around the up direction of
* the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 0 degree angle of a POV on
* @return a BooleanEvent instance based around the up direction of a POV on
* the HID.
*/
BooleanEvent POVUp(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 45 degree angle (right
* up) of the default (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the up right direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 45 degree angle of a POV
* on the HID.
* @return a BooleanEvent instance based around the up right direction of a
* POV on the HID.
*/
BooleanEvent POVUpRight(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 90 degree angle (right)
* Constructs a BooleanEvent instance based around the right direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 90 degree angle of a POV
* @return a BooleanEvent instance based around the right direction of a POV
* on the HID.
*/
BooleanEvent POVRight(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 135 degree angle (right
* down) of the default (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the down right direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 135 degree angle of a POV
* on the HID.
* @return a BooleanEvent instance based around the down right direction of a
* POV on the HID.
*/
BooleanEvent POVDownRight(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 180 degree angle (down)
* Constructs a BooleanEvent instance based around the down direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 180 degree angle of a POV
* @return a BooleanEvent instance based around the down direction of a POV
* on the HID.
*/
BooleanEvent POVDown(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 225 degree angle (down
* left) of the default (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the down left direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 225 degree angle of a POV
* on the HID.
* @return a BooleanEvent instance based around the down left direction of a
* POV on the HID.
*/
BooleanEvent POVDownLeft(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 270 degree angle (left)
* Constructs a BooleanEvent instance based around the left direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 270 degree angle of a POV
* @return a BooleanEvent instance based around the left direction of a POV
* on the HID.
*/
BooleanEvent POVLeft(EventLoop* loop) const;
/**
* Constructs a BooleanEvent instance based around the 315 degree angle (left
* up) of the default (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the up left direction
* of the default (index 0) POV on the HID.
*
* @return a BooleanEvent instance based around the 315 degree angle of a POV
* @return a BooleanEvent instance based around the up left direction of a POV
* on the HID.
*/
BooleanEvent POVUpLeft(EventLoop* loop) const;

View File

@@ -286,9 +286,10 @@ class DriverStationSim {
*
* @param stick The joystick number
* @param pov The POV number
* @param value the angle of the POV in degrees, or -1 for not pressed
* @param value the angle of the POV
*/
static void SetJoystickPOV(int stick, int pov, int value);
static void SetJoystickPOV(int stick, int pov,
DriverStation::POVDirection value);
/**
* Sets the state of all the buttons on a joystick.

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include "frc/DriverStation.h"
#include "frc/GenericHID.h"
namespace frc {
@@ -60,14 +61,14 @@ class GenericHIDSim {
* @param pov the POV to set
* @param value the new value
*/
void SetPOV(int pov, int value);
void SetPOV(int pov, DriverStation::POVDirection value);
/**
* Set the value of the default POV (port 0).
*
* @param value the new value
*/
void SetPOV(int value);
void SetPOV(DriverStation::POVDirection value);
/**
* Set the axis count of this device.

View File

@@ -14,6 +14,7 @@ import edu.wpi.first.hal.ControlWord;
import edu.wpi.first.hal.DriverStationJNI;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.MatchInfoData;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.networktables.BooleanPublisher;
import edu.wpi.first.networktables.IntegerPublisher;
import edu.wpi.first.networktables.NetworkTableInstance;
@@ -89,6 +90,79 @@ public final class DriverStation {
Elimination
}
/** A controller POV direction. */
public enum POVDirection {
/** POV center. */
Center(0x00),
/** POV up. */
Up(0x01),
/** POV up right. */
UpRight(0x01 | 0x02),
/** POV right. */
Right(0x02),
/** POV down right. */
DownRight(0x02 | 0x04),
/** POV down. */
Down(0x04),
/** POV down left. */
DownLeft(0x04 | 0x08),
/** POV left. */
Left(0x08),
/** POV up left. */
UpLeft(0x01 | 0x08);
private static final double INVALID_POV_VALUE_INTERVAL = 1.0;
private static double s_nextMessageTime;
/**
* Converts a byte value into a POVDirection enum value.
*
* @param value The byte value to convert.
* @return The corresponding POVDirection enum value.
* @throws IllegalArgumentException If value does not correspond to a POVDirection.
*/
private static POVDirection of(byte value) {
for (var direction : values()) {
if (direction.value == value) {
return direction;
}
}
double currentTime = Timer.getTimestamp();
if (currentTime > s_nextMessageTime) {
reportError("Invalid POV value " + value + "!", false);
s_nextMessageTime = currentTime + INVALID_POV_VALUE_INTERVAL;
}
return Center;
}
/** The corresponding HAL value. */
public final byte value;
POVDirection(int value) {
this.value = (byte) value;
}
/**
* Gets the angle of a POVDirection.
*
* @return The angle clockwise from straight up, or Optional.empty() if this POVDirection is
* Center.
*/
public Optional<Rotation2d> getAngle() {
return switch (this) {
case Center -> Optional.empty();
case Up -> Optional.of(Rotation2d.fromDegrees(0));
case UpRight -> Optional.of(Rotation2d.fromDegrees(45));
case Right -> Optional.of(Rotation2d.fromDegrees(90));
case DownRight -> Optional.of(Rotation2d.fromDegrees(135));
case Down -> Optional.of(Rotation2d.fromDegrees(180));
case DownLeft -> Optional.of(Rotation2d.fromDegrees(225));
case Left -> Optional.of(Rotation2d.fromDegrees(270));
case UpLeft -> Optional.of(Rotation2d.fromDegrees(315));
};
}
}
private static final double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
private static double m_nextMessageTime;
@@ -674,9 +748,9 @@ public final class DriverStation {
*
* @param stick The joystick to read.
* @param pov The POV to read.
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
* @return the angle of the POV.
*/
public static int getStickPOV(int stick, int pov) {
public static POVDirection getStickPOV(int stick, int pov) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -687,7 +761,7 @@ public final class DriverStation {
m_cacheDataMutex.lock();
try {
if (pov < m_joystickPOVs[stick].m_count) {
return m_joystickPOVs[stick].m_povs[pov];
return POVDirection.of(m_joystickPOVs[stick].m_povs[pov]);
}
} finally {
m_cacheDataMutex.unlock();
@@ -699,7 +773,7 @@ public final class DriverStation {
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
return -1;
return POVDirection.Center;
}
/**

View File

@@ -7,6 +7,7 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.DriverStationJNI;
import edu.wpi.first.math.MathUtil;
import edu.wpi.first.math.Pair;
import edu.wpi.first.wpilibj.DriverStation.POVDirection;
import edu.wpi.first.wpilibj.event.BooleanEvent;
import edu.wpi.first.wpilibj.event.EventLoop;
import java.util.HashMap;
@@ -183,150 +184,138 @@ public class GenericHID {
}
/**
* Get the angle in degrees of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (e.g. right is 90,
* upper-left is 315).
* Get the angle of a POV on the HID.
*
* @param pov The index of the POV to read (starting at 0). Defaults to 0.
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
* @return the angle of the POV.
*/
public int getPOV(int pov) {
public POVDirection getPOV(int pov) {
return DriverStation.getStickPOV(m_port, pov);
}
/**
* Get the angle in degrees of the default POV (index 0) on the HID.
* Get the angle of the default POV (index 0) on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (e.g. right is 90,
* upper-left is 315).
*
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
* @return the angle of the POV.
*/
public int getPOV() {
public POVDirection getPOV() {
return getPOV(0);
}
/**
* Constructs a BooleanEvent instance based around this angle of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (eg right is 90,
* upper-left is 315).
*
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @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.
*/
public BooleanEvent pov(int angle, EventLoop loop) {
public BooleanEvent pov(POVDirection angle, EventLoop loop) {
return pov(0, angle, loop);
}
/**
* Constructs a BooleanEvent instance based around this angle of a POV on the HID.
*
* <p>The POV angles start at 0 in the up direction, and increase clockwise (e.g. right is 90,
* upper-left is 315).
*
* @param pov index of the POV to read (starting at 0). Defaults to 0.
* @param angle POV angle in degrees, or -1 for the center / not pressed.
* @param angle POV angle.
* @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.
*/
public BooleanEvent pov(int pov, int angle, EventLoop loop) {
public BooleanEvent pov(int pov, POVDirection angle, EventLoop loop) {
synchronized (m_povCache) {
var cache = m_povCache.computeIfAbsent(loop, k -> new HashMap<>());
// angle can be -1, so use 3600 instead of 360
// angle.value is a 4 bit bitfield
return cache.computeIfAbsent(
pov * 3600 + angle, k -> new BooleanEvent(loop, () -> getPOV(pov) == angle));
pov * 16 + angle.value, k -> new BooleanEvent(loop, () -> getPOV(pov) == angle));
}
}
/**
* Constructs a BooleanEvent instance based around the 0 degree angle (up) of the default (index
* Constructs a BooleanEvent instance based around the up direction 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 up direction a POV on the HID.
*/
public BooleanEvent povUp(EventLoop loop) {
return pov(POVDirection.Up, loop);
}
/**
* Constructs a BooleanEvent instance based around the up right direction 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 up right direction of a POV on the HID.
*/
public BooleanEvent povUpRight(EventLoop loop) {
return pov(POVDirection.UpRight, loop);
}
/**
* Constructs a BooleanEvent instance based around the right direction 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 right direction of a POV on the HID.
*/
public BooleanEvent povRight(EventLoop loop) {
return pov(POVDirection.Right, loop);
}
/**
* Constructs a BooleanEvent instance based around the down right direction 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 0 degree angle of a POV on the HID.
*/
public BooleanEvent povUp(EventLoop loop) {
return pov(0, loop);
}
/**
* Constructs a BooleanEvent instance based around the 45 degree angle (right up) 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 45 degree angle of a POV on the HID.
*/
public BooleanEvent povUpRight(EventLoop loop) {
return pov(45, loop);
}
/**
* Constructs a BooleanEvent instance based around the 90 degree angle (right) 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 90 degree angle of a POV on the HID.
*/
public BooleanEvent povRight(EventLoop loop) {
return pov(90, loop);
}
/**
* Constructs a BooleanEvent instance based around the 135 degree angle (right down) 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 135 degree angle of a POV on the HID.
* @return a BooleanEvent instance based around the down right direction of a POV on the HID.
*/
public BooleanEvent povDownRight(EventLoop loop) {
return pov(135, loop);
return pov(POVDirection.DownRight, loop);
}
/**
* Constructs a BooleanEvent instance based around the 180 degree angle (down) of the default
* (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the down direction 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 180 degree angle of a POV on the HID.
* @return a BooleanEvent instance based around the down direction of a POV on the HID.
*/
public BooleanEvent povDown(EventLoop loop) {
return pov(180, loop);
return pov(POVDirection.Down, loop);
}
/**
* Constructs a BooleanEvent instance based around the 225 degree angle (down left) of the default
* (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the down left direction 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 225 degree angle of a POV on the HID.
* @return a BooleanEvent instance based around the down left direction of a POV on the HID.
*/
public BooleanEvent povDownLeft(EventLoop loop) {
return pov(225, loop);
return pov(POVDirection.DownLeft, loop);
}
/**
* Constructs a BooleanEvent instance based around the 270 degree angle (left) of the default
* (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the left direction 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 270 degree angle of a POV on the HID.
* @return a BooleanEvent instance based around the left direction of a POV on the HID.
*/
public BooleanEvent povLeft(EventLoop loop) {
return pov(270, loop);
return pov(POVDirection.Left, loop);
}
/**
* Constructs a BooleanEvent instance based around the 315 degree angle (left up) of the default
* (index 0) POV on the HID.
* Constructs a BooleanEvent instance based around the up left direction 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 315 degree angle of a POV on the HID.
* @return a BooleanEvent instance based around the up left direction of a POV on the HID.
*/
public BooleanEvent povUpLeft(EventLoop loop) {
return pov(315, loop);
return pov(POVDirection.UpLeft, loop);
}
/**
@@ -337,7 +326,7 @@ public class GenericHID {
* @return a BooleanEvent instance based around the center of a POV on the HID.
*/
public BooleanEvent povCenter(EventLoop loop) {
return pov(-1, loop);
return pov(POVDirection.Center, loop);
}
/**

View File

@@ -364,10 +364,10 @@ public final class DriverStationSim {
*
* @param stick The joystick number
* @param pov The POV number
* @param value the angle of the POV in degrees, or -1 for not pressed
* @param value the angle of the POV
*/
public static void setJoystickPOV(int stick, int pov, int value) {
DriverStationDataJNI.setJoystickPOV(stick, pov, value);
public static void setJoystickPOV(int stick, int pov, DriverStation.POVDirection value) {
DriverStationDataJNI.setJoystickPOV(stick, pov, value.value);
}
/**

View File

@@ -4,6 +4,7 @@
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.GenericHID;
/** Class to control a simulated generic joystick. */
@@ -60,7 +61,7 @@ public class GenericHIDSim {
* @param pov the POV to set
* @param value the new value
*/
public void setPOV(int pov, int value) {
public void setPOV(int pov, DriverStation.POVDirection value) {
DriverStationSim.setJoystickPOV(m_port, pov, value);
}
@@ -69,7 +70,7 @@ public class GenericHIDSim {
*
* @param value the new value
*/
public void setPOV(int value) {
public void setPOV(DriverStation.POVDirection value) {
setPOV(0, value);
}