[wpilib] Make joystick unplugged warning better in cases of out of range axis/button (#8614)

Closes #8594 
Fixes #7700 
Also fixes DS HAL to zero out joysticks not received from DS.
This commit is contained in:
Ryan Blue
2026-02-17 23:22:02 -05:00
committed by GitHub
parent 10fa2fced4
commit 0c44e63465
4 changed files with 74 additions and 87 deletions

View File

@@ -300,6 +300,13 @@ void JoystickDataCache::Update(const mrc::ControlData& data) {
}
}
}
// Mark remaining sticks as unavailable
for (size_t i = sticks.size(); i < HAL_kMaxJoysticks; i++) {
axes[i].available = 0;
povs[i].available = 0;
buttons[i].available = 0;
touchpads[i].count = 0;
}
}
#define CHECK_JOYSTICK_NUMBER(stickNum) \

View File

@@ -190,23 +190,23 @@ static Instance& GetInstance() {
static void SendMatchData();
template <typename S, typename... Args>
static inline void ReportJoystickUnpluggedError(const S& format,
Args&&... args) {
ReportJoystickUnpluggedErrorV(format, fmt::make_format_args(args...));
static inline void ReportJoystickError(int stick, const S& format,
Args&&... args) {
ReportJoystickErrorV(stick, format, fmt::make_format_args(args...));
}
/**
* Reports errors related to unplugged joysticks.
* Reports errors related to joystick availability.
*
* Throttles the errors so that they don't overwhelm the DS.
*/
static void ReportJoystickUnpluggedWarningV(fmt::string_view format,
fmt::format_args args);
static void ReportJoystickWarningV(int stick, fmt::string_view format,
fmt::format_args args);
template <typename S, typename... Args>
static inline void ReportJoystickUnpluggedWarning(const S& format,
Args&&... args) {
ReportJoystickUnpluggedWarningV(format, fmt::make_format_args(args...));
static inline void ReportJoystickWarning(int stick, const S& format,
Args&&... args) {
ReportJoystickWarningV(stick, format, fmt::make_format_args(args...));
}
Instance::Instance() {
@@ -245,11 +245,8 @@ bool DriverStation::GetStickButton(int stick, int button) {
HAL_GetJoystickButtons(stick, &buttons);
if ((buttons.available & mask) == 0) {
ReportJoystickUnpluggedWarning(
"Joystick Button {} missing (available {}), check if all controllers "
"are "
"plugged in",
button, buttons.available);
ReportJoystickWarning(stick, "Joystick Button {} on port {} not available",
button, stick);
return false;
}
@@ -297,11 +294,8 @@ bool DriverStation::GetStickButtonPressed(int stick, int button) {
uint64_t mask = 1LLU << button;
if ((buttons.available & mask) == 0) {
ReportJoystickUnpluggedWarning(
"Joystick Button {} missing (available {}), check if all controllers "
"are "
"plugged in",
button, buttons.available);
ReportJoystickWarning(stick, "Joystick Button {} on port {} not available",
button, stick);
return false;
}
auto& inst = ::GetInstance();
@@ -331,11 +325,8 @@ bool DriverStation::GetStickButtonReleased(int stick, int button) {
uint64_t mask = 1LLU << button;
if ((buttons.available & mask) == 0) {
ReportJoystickUnpluggedWarning(
"Joystick Button {} missing (available {}), check if all controllers "
"are "
"plugged in",
button, buttons.available);
ReportJoystickWarning(stick, "Joystick Button {} on port {} not available",
button, stick);
return false;
}
auto& inst = ::GetInstance();
@@ -364,10 +355,8 @@ double DriverStation::GetStickAxis(int stick, int axis) {
HAL_GetJoystickAxes(stick, &axes);
if ((axes.available & mask) == 0) {
ReportJoystickUnpluggedWarning(
"Joystick Axis {} missing (available {}), check if all controllers are "
"plugged in",
axis, axes.available);
ReportJoystickWarning(stick, "Joystick axis {} on port {} not available",
axis, stick);
return 0.0;
}
@@ -403,10 +392,10 @@ DriverStation::TouchpadFinger DriverStation::GetStickTouchpadFinger(
}
}
ReportJoystickUnpluggedWarning(
"Joystick Touchpad Finger {} missing, check if all controllers are "
"plugged in",
touchpad);
ReportJoystickWarning(
stick,
"Joystick touchpad finger {} on touchpad {} on port {} not available",
finger, touchpad, stick);
return TouchpadFinger{false, 0.0f, 0.0f};
}
@@ -478,10 +467,8 @@ DriverStation::POVDirection DriverStation::GetStickPOV(int stick, int pov) {
HAL_GetJoystickPOVs(stick, &povs);
if ((povs.available & mask) == 0) {
ReportJoystickUnpluggedWarning(
"Joystick POV {} missing (available {}), check if all controllers are "
"plugged in",
pov, povs.available);
ReportJoystickWarning(stick, "Joystick POV {} on port {} not available",
pov, stick);
return kCenter;
}
@@ -855,13 +842,21 @@ void DriverStation::StartDataLog(wpi::log::DataLog& log, bool logJoysticks) {
}
}
void ReportJoystickUnpluggedWarningV(fmt::string_view format,
fmt::format_args args) {
void ReportJoystickWarningV(int stick, fmt::string_view format,
fmt::format_args args) {
auto& inst = GetInstance();
if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
auto currentTime = Timer::GetTimestamp();
if (currentTime > inst.nextMessageTime) {
ReportErrorV(warn::Warning, "", 0, "", format, args);
if (DriverStation::IsJoystickConnected(stick)) {
ReportErrorV(warn::Warning, "", 0, "", format, args);
} else {
ReportError(
warn::Warning, "", 0, "",
"Joystick on port {} not available, check if all controllers are "
"plugged in",
stick);
}
inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
}
}

View File

@@ -65,15 +65,12 @@ INSTANTIATE_TEST_SUITE_P(
DriverStationTests, JoystickConnectionWarningTest,
::testing::Values(
std::make_tuple(false, true, true, ""),
std::make_tuple(
false, false, false,
"Warning: Joystick Button 1 missing (available 0), check if all "
"controllers are plugged in\n"),
std::make_tuple(
true, true, false,
"Warning: Joystick Button 1 missing (available 0), check if all "
"controllers are plugged in\n"),
std::make_tuple(
true, false, false,
"Warning: Joystick Button 1 missing (available 0), check if all "
"controllers are plugged in\n")));
std::make_tuple(false, false, false,
"Warning: Joystick on port 0 not available, check if "
"all controllers are plugged in\n"),
std::make_tuple(true, true, false,
"Warning: Joystick on port 0 not available, check if "
"all controllers are plugged in\n"),
std::make_tuple(true, false, false,
"Warning: Joystick on port 0 not available, check if "
"all controllers are plugged in\n")));

View File

@@ -714,12 +714,8 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
"Joystick Button "
+ button
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
reportJoystickWarning(
stick, "Joystick Button " + button + " on port " + stick + " not available");
return false;
}
@@ -783,12 +779,8 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
"Joystick Button "
+ button
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
reportJoystickWarning(
stick, "Joystick Button " + button + " on port " + stick + " not available");
return false;
}
@@ -824,12 +816,8 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
"Joystick Button "
+ button
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
reportJoystickWarning(
stick, "Joystick Button " + button + " on port " + stick + " not available");
return false;
}
@@ -860,12 +848,7 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
"Joystick axis "
+ axis
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
reportJoystickWarning(stick, "Joystick axis " + axis + " on port " + stick + " not available");
return 0.0;
}
@@ -903,14 +886,15 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
reportJoystickWarning(
stick,
"Joystick touchpad finger "
+ finger
+ " on touchpad "
+ touchpad
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
+ " not available");
return new TouchpadFinger(false, 0.0f, 0.0f);
}
@@ -1006,12 +990,7 @@ public final class DriverStation {
m_cacheDataMutex.unlock();
}
reportJoystickUnpluggedWarning(
"Joystick POV "
+ pov
+ " on port "
+ stick
+ " not available, check if controller is plugged in");
reportJoystickWarning(stick, "Joystick POV " + pov + " on port " + stick + " not available");
return POVDirection.Center;
}
@@ -1905,14 +1884,23 @@ public final class DriverStation {
}
/**
* Reports errors related to unplugged joysticks Throttles the errors so that they don't overwhelm
* the DS.
* Reports errors related to joystick availability. Throttles the errors so that they don't
* overwhelm the DS.
*
* @param stick The joystick port.
* @param message The message to report if the joystick is connected.
*/
private static void reportJoystickUnpluggedWarning(String message) {
private static void reportJoystickWarning(int stick, String message) {
if (isFMSAttached() || !m_silenceJoystickWarning) {
double currentTime = Timer.getTimestamp();
if (currentTime > m_nextMessageTime) {
reportWarning(message, false);
if (isJoystickConnected(stick)) {
reportWarning(message, false);
} else {
reportWarning(
"Joystick on port " + stick + " not available, check if controller is plugged in",
false);
}
m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
}
}