[hal,wpilib] Add support for joystick outputs (#8385)

Support joystick outputs, including Rumble and LEDs.

Also requires an update to Joystick descriptors, as that has also
changed in mrccomm to support showing what outputs are supported.
This commit is contained in:
Thad House
2025-11-17 14:36:14 -08:00
committed by GitHub
parent 5db6d2f500
commit ce6fd225a6
54 changed files with 1607 additions and 854 deletions

View File

@@ -171,14 +171,28 @@ Java_org_wpilib_hardware_hal_DriverStationJNI_getAllJoystickData
/*
* Class: org_wpilib_hardware_hal_DriverStationJNI
* Method: setJoystickOutputs
* Signature: (BIII)I
* Method: setJoystickRumble
* Signature: (BIIII)I
*/
JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_DriverStationJNI_setJoystickOutputs
(JNIEnv*, jclass, jbyte port, jint outputs, jint leftRumble, jint rightRumble)
Java_org_wpilib_hardware_hal_DriverStationJNI_setJoystickRumble
(JNIEnv*, jclass, jbyte port, jint leftRumble, jint rightRumble,
jint leftTriggerRumble, jint rightTriggerRumble)
{
return HAL_SetJoystickOutputs(port, outputs, leftRumble, rightRumble);
return HAL_SetJoystickRumble(port, leftRumble, rightRumble, leftTriggerRumble,
rightTriggerRumble);
}
/*
* Class: org_wpilib_hardware_hal_DriverStationJNI
* Method: setJoystickLeds
* Signature: (BI)I
*/
JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_DriverStationJNI_setJoystickLeds
(JNIEnv*, jclass, jbyte port, jint leds)
{
return HAL_SetJoystickLeds(port, leds);
}
/*
@@ -195,14 +209,26 @@ Java_org_wpilib_hardware_hal_DriverStationJNI_getJoystickIsGamepad
/*
* Class: org_wpilib_hardware_hal_DriverStationJNI
* Method: getJoystickType
* Method: getJoystickSupportedOutputs
* Signature: (B)I
*/
JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_DriverStationJNI_getJoystickType
Java_org_wpilib_hardware_hal_DriverStationJNI_getJoystickSupportedOutputs
(JNIEnv*, jclass, jbyte port)
{
return HAL_GetJoystickType(port);
return HAL_GetJoystickSupportedOutputs(port);
}
/*
* Class: org_wpilib_hardware_hal_DriverStationJNI
* Method: getJoystickGamepadType
* Signature: (B)I
*/
JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_DriverStationJNI_getJoystickGamepadType
(JNIEnv*, jclass, jbyte port)
{
return HAL_GetJoystickGamepadType(port);
}
/*

View File

@@ -493,18 +493,16 @@ Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_setJoystickButtons
/*
* Class: org_wpilib_hardware_hal_simulation_DriverStationDataJNI
* Method: getJoystickOutputs
* Signature: (I)J
* Method: getJoystickLeds
* Signature: (I)I
*/
JNIEXPORT jlong JNICALL
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_getJoystickOutputs
JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_getJoystickLeds
(JNIEnv* env, jclass, jint stick)
{
int64_t outputs = 0;
int32_t leftRumble;
int32_t rightRumble;
HALSIM_GetJoystickOutputs(stick, &outputs, &leftRumble, &rightRumble);
return outputs;
int32_t leds = 0;
HALSIM_GetJoystickLeds(stick, &leds);
return leds;
}
/*
@@ -516,11 +514,24 @@ JNIEXPORT jint JNICALL
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_getJoystickRumble
(JNIEnv* env, jclass, jint stick, jint rumbleNum)
{
int64_t outputs;
int32_t leftRumble = 0;
int32_t rightRumble = 0;
HALSIM_GetJoystickOutputs(stick, &outputs, &leftRumble, &rightRumble);
return rumbleNum == 0 ? leftRumble : rightRumble;
int32_t leftTriggerRumble = 0;
int32_t rightTriggerRumble = 0;
HALSIM_GetJoystickRumbles(stick, &leftRumble, &rightRumble,
&leftTriggerRumble, &rightTriggerRumble);
switch (rumbleNum) {
case 0:
return leftRumble;
case 1:
return rightRumble;
case 2:
return leftTriggerRumble;
case 3:
return rightTriggerRumble;
default:
return 0;
}
}
/*
@@ -713,14 +724,26 @@ Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_setJoystickIsGamepa
/*
* Class: org_wpilib_hardware_hal_simulation_DriverStationDataJNI
* Method: setJoystickType
* Method: setJoystickGamepadType
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_setJoystickType
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_setJoystickGamepadType
(JNIEnv*, jclass, jint stick, jint type)
{
HALSIM_SetJoystickType(stick, type);
HALSIM_SetJoystickGamepadType(stick, type);
}
/*
* Class: org_wpilib_hardware_hal_simulation_DriverStationDataJNI
* Method: setJoystickSupportedOutputs
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_org_wpilib_hardware_hal_simulation_DriverStationDataJNI_setJoystickSupportedOutputs
(JNIEnv*, jclass, jint stick, jint supportedOutputs)
{
HALSIM_SetJoystickSupportedOutputs(stick, supportedOutputs);
}
/*

View File

@@ -2,6 +2,8 @@
// 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 <utility>
#include "wpi/hal/proto/ControlData.h"
#include "wpi/util/protobuf/ProtobufCallbacks.hpp"
@@ -85,7 +87,7 @@ std::optional<mrc::ControlData> wpi::util::Protobuf<mrc::ControlData>::Unpack(
ControlData.SetJoystickCount(Joysticks.size());
for (size_t i = 0; i < ControlData.GetJoystickCount(); i++) {
ControlData.Joysticks()[i] = Joysticks[i];
ControlData.Joysticks()[i] = std::move(Joysticks[i]);
}
return ControlData;

View File

@@ -1,69 +0,0 @@
// 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.
#include <string>
#include <utility>
#include "wpi/hal/proto/JoystickDescriptor.h"
#include "wpi/util/protobuf/ProtobufCallbacks.hpp"
std::optional<mrc::JoystickDescriptor>
wpi::util::Protobuf<mrc::JoystickDescriptor>::Unpack(InputStream& Stream) {
wpi::util::UnpackCallback<std::string> JoystickNameCb;
wpi::util::UnpackCallback<uint8_t, MRC_MAX_NUM_AXES> AxisTypesCb;
mrc_proto_ProtobufJoystickDescriptor Msg;
Msg.JoystickName = JoystickNameCb.Callback();
Msg.AxisTypes = AxisTypesCb.Callback();
if (!Stream.Decode(Msg)) {
return {};
}
auto JoystickName = JoystickNameCb.Items();
auto AxisTypes = AxisTypesCb.Items();
if (JoystickName.empty()) {
return {};
}
mrc::JoystickDescriptor OutputData;
OutputData.MoveName(std::move(JoystickName[0]));
OutputData.SetAxesCount(AxisTypes.size());
for (size_t i = 0; i < OutputData.GetAxesCount(); i++) {
OutputData.AxesTypes()[i] = AxisTypes[i];
}
OutputData.SetPovsCount(Msg.PovCount);
OutputData.SetButtonsCount(Msg.ButtonCount);
OutputData.IsGamepad = Msg.IsGamepad ? 1 : 0;
OutputData.Type = Msg.JoystickType;
OutputData.RumbleCount = Msg.RumbleCount;
return OutputData;
}
bool wpi::util::Protobuf<mrc::JoystickDescriptor>::Pack(
OutputStream& Stream, const mrc::JoystickDescriptor& Value) {
std::string_view JoystickName = Value.GetName();
wpi::util::PackCallback JoystickNameCb{&JoystickName};
std::span<const uint8_t> AxisTypes = Value.AxesTypes();
wpi::util::PackCallback AxisTypesCb{AxisTypes};
mrc_proto_ProtobufJoystickDescriptor Msg{
.JoystickName = JoystickNameCb.Callback(),
.AxisTypes = AxisTypesCb.Callback(),
.IsGamepad = Value.IsGamepad ? true : false,
.JoystickType = Value.Type,
.ButtonCount = static_cast<int32_t>(Value.GetButtonsCount()),
.PovCount = static_cast<int32_t>(Value.GetPovsCount()),
.RumbleCount = Value.RumbleCount,
};
return Stream.Encode(Msg);
}

View File

@@ -0,0 +1,84 @@
// 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.
#include <string>
#include <utility>
#include "wpi/hal/proto/JoystickDescriptors.h"
#include "wpi/util/protobuf/ProtobufCallbacks.hpp"
std::optional<mrc::JoystickDescriptors>
wpi::util::Protobuf<mrc::JoystickDescriptors>::Unpack(InputStream& Stream) {
wpi::util::UnpackCallback<mrc::JoystickDescriptor, MRC_MAX_NUM_JOYSTICKS>
JoystickDescriptorsCb;
mrc_proto_ProtobufJoystickDescriptors Msg;
Msg.Descriptors = JoystickDescriptorsCb.Callback();
if (!Stream.Decode(Msg)) {
return {};
}
auto Descriptors = JoystickDescriptorsCb.Items();
mrc::JoystickDescriptors OutputData;
OutputData.SetDescriptorCount(Descriptors.size());
for (size_t i = 0; i < OutputData.GetDescriptorCount(); i++) {
OutputData.Descriptors()[i] = std::move(Descriptors[i]);
}
return OutputData;
}
bool wpi::util::Protobuf<mrc::JoystickDescriptors>::Pack(
OutputStream& Stream, const mrc::JoystickDescriptors& Value) {
std::span<const mrc::JoystickDescriptor> Descriptors = Value.Descriptors();
wpi::util::PackCallback JoystickDescriptorsCb{Descriptors};
mrc_proto_ProtobufJoystickDescriptors Msg{
.Descriptors = JoystickDescriptorsCb.Callback(),
};
return Stream.Encode(Msg);
}
std::optional<mrc::JoystickDescriptor>
wpi::util::Protobuf<mrc::JoystickDescriptor>::Unpack(InputStream& Stream) {
wpi::util::UnpackCallback<std::string> JoystickNameCb;
mrc_proto_ProtobufJoystickDescriptor Msg;
Msg.JoystickName = JoystickNameCb.Callback();
if (!Stream.Decode(Msg)) {
return {};
}
auto JoystickName = JoystickNameCb.Items();
mrc::JoystickDescriptor OutputData;
if (!JoystickName.empty()) {
OutputData.MoveName(std::move(JoystickName[0]));
}
OutputData.IsGamepad = Msg.IsGamepad ? 1 : 0;
OutputData.GamepadType = Msg.GamepadType;
OutputData.SupportedOutputs = Msg.SupportedOutputs;
return OutputData;
}
bool wpi::util::Protobuf<mrc::JoystickDescriptor>::Pack(
OutputStream& Stream, const mrc::JoystickDescriptor& Value) {
std::string_view JoystickName = Value.GetName();
wpi::util::PackCallback JoystickNameCb{&JoystickName};
mrc_proto_ProtobufJoystickDescriptor Msg{
.JoystickName = JoystickNameCb.Callback(),
.IsGamepad = Value.IsGamepad ? true : false,
.GamepadType = Value.GamepadType,
.SupportedOutputs = Value.SupportedOutputs,
};
return Stream.Encode(Msg);
}

View File

@@ -0,0 +1,79 @@
// 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.
#include <string>
#include <utility>
#include "wpi/hal/proto/JoystickOutput.h"
#include "wpi/util/protobuf/ProtobufCallbacks.hpp"
std::optional<mrc::JoystickOutputs>
wpi::util::Protobuf<mrc::JoystickOutputs>::Unpack(InputStream& Stream) {
wpi::util::UnpackCallback<mrc::JoystickOutput, MRC_MAX_NUM_JOYSTICKS>
JoystickOutputsCb;
mrc_proto_ProtobufJoystickOutputs Msg;
Msg.Outputs = JoystickOutputsCb.Callback();
if (!Stream.Decode(Msg)) {
return {};
}
auto Outputs = JoystickOutputsCb.Items();
mrc::JoystickOutputs OutputData;
OutputData.SetOutputCount(Outputs.size());
for (size_t i = 0; i < OutputData.GetOutputCount(); i++) {
OutputData.Outputs()[i] = std::move(Outputs[i]);
}
return OutputData;
}
bool wpi::util::Protobuf<mrc::JoystickOutputs>::Pack(
OutputStream& Stream, const mrc::JoystickOutputs& Value) {
std::span<const mrc::JoystickOutput> Outputs = Value.Outputs();
wpi::util::PackCallback JoystickOutputsCb{Outputs};
mrc_proto_ProtobufJoystickOutputs Msg{
.Outputs = JoystickOutputsCb.Callback(),
};
return Stream.Encode(Msg);
}
std::optional<mrc::JoystickOutput>
wpi::util::Protobuf<mrc::JoystickOutput>::Unpack(InputStream& Stream) {
mrc_proto_ProtobufJoystickOutput Msg;
if (!Stream.Decode(Msg)) {
return {};
}
return mrc::JoystickOutput{
.R = static_cast<uint8_t>((Msg.LEDs >> 16) & 0xFF),
.G = static_cast<uint8_t>((Msg.LEDs >> 8) & 0xFF),
.B = static_cast<uint8_t>(Msg.LEDs & 0xFF),
.LeftRumble = static_cast<uint16_t>((Msg.Rumble >> 16) & 0xFFFF),
.RightRumble = static_cast<uint16_t>(Msg.Rumble & 0xFFFF),
.LeftTriggerRumble =
static_cast<uint16_t>((Msg.TriggerRumble >> 16) & 0xFFFF),
.RightTriggerRumble = static_cast<uint16_t>(Msg.TriggerRumble & 0xFFFF),
};
}
bool wpi::util::Protobuf<mrc::JoystickOutput>::Pack(
OutputStream& Stream, const mrc::JoystickOutput& Value) {
mrc_proto_ProtobufJoystickOutput Msg{
.LEDs = (static_cast<uint32_t>(Value.R) << 16) |
(static_cast<uint32_t>(Value.G) << 8) |
static_cast<uint32_t>(Value.B),
.Rumble = (static_cast<uint32_t>(Value.LeftRumble) << 16) |
static_cast<uint32_t>(Value.RightRumble),
.TriggerRumble = (static_cast<uint32_t>(Value.LeftTriggerRumble) << 16) |
static_cast<uint32_t>(Value.RightTriggerRumble),
};
return Stream.Encode(Msg);
}

View File

@@ -1,41 +0,0 @@
// 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.
#include "wpi/hal/proto/JoystickRumbleData.h"
#include "wpi/util/protobuf/ProtobufCallbacks.hpp"
std::optional<mrc::JoystickRumbleData>
wpi::util::Protobuf<mrc::JoystickRumbleData>::Unpack(InputStream& Stream) {
wpi::util::UnpackCallback<uint16_t, MRC_MAX_NUM_RUMBLE> RumbleCb;
mrc_proto_ProtobufJoystickRumbleData Msg{
.Value = RumbleCb.Callback(),
};
if (!Stream.Decode(Msg)) {
return {};
}
auto Rumbles = RumbleCb.Items();
mrc::JoystickRumbleData Rumble;
Rumble.SetCount(Rumbles.size());
for (size_t i = 0; i < Rumble.GetCount(); i++) {
Rumble.Rumbles()[i] = Rumbles[i];
}
return Rumble;
}
bool wpi::util::Protobuf<mrc::JoystickRumbleData>::Pack(
OutputStream& Stream, const mrc::JoystickRumbleData& Value) {
wpi::util::PackCallback RumbleCb{Value.Rumbles()};
mrc_proto_ProtobufJoystickRumbleData Msg{
.Value = RumbleCb.Callback(),
};
return Stream.Encode(Msg);
}