From b9feb812260fb4737bc021f9fcb763ab460cdacb Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 15 Jul 2020 00:33:57 -0700 Subject: [PATCH] [sim] Add joystick simulation support (#2595) This adds joystick functions to DriverStationSim, and new GenericHIDSim, JoystickSim, and XboxControllerSim classes. --- .../hal/simulation/DriverStationDataJNI.java | 32 ++ .../athena/mockdata/DriverStationData.cpp | 32 ++ .../jni/simulation/DriverStationDataJNI.cpp | 327 ++++++++++++++++++ .../hal/simulation/DriverStationData.h | 19 + .../native/sim/mockdata/DriverStationData.cpp | 201 ++++++++++- .../sim/mockdata/DriverStationDataInternal.h | 19 + .../include/frc/simulation/DriverStationSim.h | 258 +++++++++++++- .../include/frc/simulation/GenericHIDSim.h | 97 ++++++ .../include/frc/simulation/JoystickSim.h | 85 +++++ .../frc/simulation/XboxControllerSim.h | 111 ++++++ wpilibc/src/test/native/cpp/JoystickTest.cpp | 39 +++ .../test/native/cpp/XboxControllerTest.cpp | 74 ++++ .../java/edu/wpi/first/wpilibj/Joystick.java | 12 +- .../wpilibj/simulation/DriverStationSim.java | 284 ++++++++++++++- .../wpilibj/simulation/GenericHIDSim.java | 97 ++++++ .../first/wpilibj/simulation/JoystickSim.java | 76 ++++ .../wpilibj/simulation/XboxControllerSim.java | 102 ++++++ .../edu/wpi/first/wpilibj/JoystickTest.java | 47 +++ .../wpi/first/wpilibj/XboxControllerTest.java | 86 +++++ 19 files changed, 1979 insertions(+), 19 deletions(-) create mode 100644 wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h create mode 100644 wpilibc/src/main/native/include/frc/simulation/JoystickSim.h create mode 100644 wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h create mode 100644 wpilibc/src/test/native/cpp/JoystickTest.cpp create mode 100644 wpilibc/src/test/native/cpp/XboxControllerTest.cpp create mode 100644 wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java create mode 100644 wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java create mode 100644 wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java create mode 100644 wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java create mode 100644 wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java index 7be4857317..a1046c510b 100644 --- a/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java @@ -40,16 +40,48 @@ public class DriverStationDataJNI extends JNIWrapper { public static native boolean getDsAttached(); public static native void setDsAttached(boolean dsAttached); + public static native int registerAllianceStationIdCallback(NotifyCallback callback, boolean initialNotify); + public static native void cancelAllianceStationIdCallback(int uid); + public static native int getAllianceStationId(); + public static native void setAllianceStationId(int allianceStationId); + + public static native int registerMatchTimeCallback(NotifyCallback callback, boolean initialNotify); + public static native void cancelMatchTimeCallback(int uid); + public static native double getMatchTime(); + public static native void setMatchTime(double matchTime); + public static native void setJoystickAxes(byte joystickNum, float[] axesArray); public static native void setJoystickPOVs(byte joystickNum, short[] povsArray); public static native void setJoystickButtons(byte joystickNum, int buttons, int count); + public static native long getJoystickOutputs(int stick); + public static native int getJoystickRumble(int stick, int rumbleNum); public static native void setMatchInfo(String eventName, String gameSpecificMessage, int matchNumber, int replayNumber, int matchType); + public static native void registerAllCallbacks(NotifyCallback callback, boolean initialNotify); public static native void notifyNewData(); public static native void setSendError(boolean shouldSend); public static native void setSendConsoleLine(boolean shouldSend); + public static native void setJoystickButton(int stick, int button, boolean state); + 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 setJoystickButtonsValue(int stick, int buttons); + public static native void setJoystickAxisCount(int stick, int count); + public static native void setJoystickPOVCount(int stick, int count); + public static native void setJoystickButtonCount(int stick, int count); + + public static native void setJoystickIsXbox(int stick, boolean isXbox); + public static native void setJoystickType(int stick, int type); + public static native void setJoystickName(int stick, String name); + public static native void setJoystickAxisType(int stick, int axis, int type); + + public static native void setGameSpecificMessage(String message); + public static native void setEventName(String name); + public static native void setMatchType(int type); + public static native void setMatchNumber(int matchNumber); + public static native void setReplayNumber(int replayNumber); + public static native void resetData(); } diff --git a/hal/src/main/native/athena/mockdata/DriverStationData.cpp b/hal/src/main/native/athena/mockdata/DriverStationData.cpp index 744fc2b4a7..235ff7635b 100644 --- a/hal/src/main/native/athena/mockdata/DriverStationData.cpp +++ b/hal/src/main/native/athena/mockdata/DriverStationData.cpp @@ -45,6 +45,38 @@ void HALSIM_SetMatchInfo(const HAL_MatchInfo* info) {} void HALSIM_NotifyDriverStationNewData(void) {} +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_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) {} + +void HALSIM_SetJoystickButtonCount(int32_t stick, int32_t count) {} + +void HALSIM_SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox) {} + +void HALSIM_SetJoystickType(int32_t stick, int32_t type) {} + +void HALSIM_SetJoystickName(int32_t stick, const char* name) {} + +void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type) {} + +void HALSIM_SetGameSpecificMessage(const char* message) {} + +void HALSIM_SetEventName(const char* name) {} + +void HALSIM_SetMatchType(HAL_MatchType type) {} + +void HALSIM_SetMatchNumber(int32_t matchNumber) {} + +void HALSIM_SetReplayNumber(int32_t replayNumber) {} + void HALSIM_RegisterDriverStationAllCallbacks(HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {} diff --git a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp index 2c77b4b31c..7868e43389 100644 --- a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp @@ -325,6 +325,109 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setDsAttached HALSIM_SetDriverStationDsAttached(value); } +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: registerAllianceStationIdCallback + * Signature: (Ljava/lang/Object;Z)I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_registerAllianceStationIdCallback + (JNIEnv* env, jclass, jobject callback, jboolean initialNotify) +{ + return sim::AllocateCallbackNoIndex( + env, callback, initialNotify, + &HALSIM_RegisterDriverStationAllianceStationIdCallback); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: cancelAllianceStationIdCallback + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_cancelAllianceStationIdCallback + (JNIEnv* env, jclass, jint handle) +{ + return sim::FreeCallbackNoIndex( + env, handle, &HALSIM_CancelDriverStationAllianceStationIdCallback); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: getAllianceStationId + * Signature: ()I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_getAllianceStationId + (JNIEnv*, jclass) +{ + return HALSIM_GetDriverStationAllianceStationId(); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setAllianceStationId + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setAllianceStationId + (JNIEnv*, jclass, jint value) +{ + HALSIM_SetDriverStationAllianceStationId( + static_cast(value)); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: registerMatchTimeCallback + * Signature: (Ljava/lang/Object;Z)I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_registerMatchTimeCallback + (JNIEnv* env, jclass, jobject callback, jboolean initialNotify) +{ + return sim::AllocateCallbackNoIndex( + env, callback, initialNotify, + &HALSIM_RegisterDriverStationMatchTimeCallback); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: cancelMatchTimeCallback + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_cancelMatchTimeCallback + (JNIEnv* env, jclass, jint handle) +{ + return sim::FreeCallbackNoIndex(env, handle, + &HALSIM_CancelDriverStationMatchTimeCallback); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: getMatchTime + * Signature: ()D + */ +JNIEXPORT jdouble JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_getMatchTime + (JNIEnv*, jclass) +{ + return HALSIM_GetDriverStationMatchTime(); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setMatchTime + * Signature: (D)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setMatchTime + (JNIEnv*, jclass, jdouble value) +{ + HALSIM_SetDriverStationMatchTime(value); +} + /* * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI * Method: setJoystickAxes @@ -393,6 +496,38 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickButtons HALSIM_SetJoystickButtons(joystickNum, &joystickButtons); } +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: getJoystickOutputs + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_getJoystickOutputs + (JNIEnv* env, jclass, jint stick) +{ + int64_t outputs = 0; + int32_t leftRumble; + int32_t rightRumble; + HALSIM_GetJoystickOutputs(stick, &outputs, &leftRumble, &rightRumble); + return outputs; +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: getJoystickRumble + * Signature: (II)I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_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; +} + /* * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI * Method: setMatchInfo @@ -483,6 +618,198 @@ Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setSendConsoleLine } } +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickButton + * Signature: (IIZ)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickButton + (JNIEnv*, jclass, jint stick, jint button, jboolean state) +{ + HALSIM_SetJoystickButton(stick, button, state); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickAxis + * Signature: (IID)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickAxis + (JNIEnv*, jclass, jint stick, jint axis, jdouble value) +{ + HALSIM_SetJoystickAxis(stick, axis, value); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickPOV + * Signature: (III)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickPOV + (JNIEnv*, jclass, jint stick, jint pov, jint value) +{ + HALSIM_SetJoystickPOV(stick, pov, value); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickButtonsValue + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickButtonsValue + (JNIEnv*, jclass, jint stick, jint buttons) +{ + HALSIM_SetJoystickButtonsValue(stick, buttons); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickAxisCount + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickAxisCount + (JNIEnv*, jclass, jint stick, jint count) +{ + HALSIM_SetJoystickAxisCount(stick, count); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickPOVCount + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickPOVCount + (JNIEnv*, jclass, jint stick, jint count) +{ + HALSIM_SetJoystickPOVCount(stick, count); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickButtonCount + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickButtonCount + (JNIEnv*, jclass, jint stick, jint count) +{ + HALSIM_SetJoystickButtonCount(stick, count); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickIsXbox + * Signature: (IZ)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickIsXbox + (JNIEnv*, jclass, jint stick, jboolean isXbox) +{ + HALSIM_SetJoystickIsXbox(stick, isXbox); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickType + * Signature: (II)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickType + (JNIEnv*, jclass, jint stick, jint type) +{ + HALSIM_SetJoystickType(stick, type); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickName + * Signature: (ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickName + (JNIEnv* env, jclass, jint stick, jstring name) +{ + HALSIM_SetJoystickName(stick, JStringRef{env, name}.c_str()); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setJoystickAxisType + * Signature: (III)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setJoystickAxisType + (JNIEnv*, jclass, jint stick, jint axis, jint type) +{ + HALSIM_SetJoystickAxisType(stick, axis, type); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setGameSpecificMessage + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setGameSpecificMessage + (JNIEnv* env, jclass, jstring message) +{ + HALSIM_SetGameSpecificMessage(JStringRef{env, message}.c_str()); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setEventName + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setEventName + (JNIEnv* env, jclass, jstring name) +{ + HALSIM_SetEventName(JStringRef{env, name}.c_str()); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setMatchType + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setMatchType + (JNIEnv*, jclass, jint type) +{ + HALSIM_SetMatchType(static_cast(static_cast(type))); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setMatchNumber + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setMatchNumber + (JNIEnv*, jclass, jint matchNumber) +{ + HALSIM_SetMatchNumber(matchNumber); +} + +/* + * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI + * Method: setReplayNumber + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_DriverStationDataJNI_setReplayNumber + (JNIEnv*, jclass, jint replayNumber) +{ + HALSIM_SetReplayNumber(replayNumber); +} + /* * Class: edu_wpi_first_hal_simulation_DriverStationDataJNI * Method: resetData diff --git a/hal/src/main/native/include/hal/simulation/DriverStationData.h b/hal/src/main/native/include/hal/simulation/DriverStationData.h index e7c8cae8d9..bad6b26dc5 100644 --- a/hal/src/main/native/include/hal/simulation/DriverStationData.h +++ b/hal/src/main/native/include/hal/simulation/DriverStationData.h @@ -80,6 +80,25 @@ void HALSIM_GetJoystickOutputs(int32_t joystickNum, int64_t* outputs, 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_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); +void HALSIM_SetJoystickButtonCount(int32_t stick, int32_t count); + +void HALSIM_SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox); +void HALSIM_SetJoystickType(int32_t stick, int32_t type); +void HALSIM_SetJoystickName(int32_t stick, const char* name); +void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type); + +void HALSIM_SetGameSpecificMessage(const char* message); +void HALSIM_SetEventName(const char* name); +void HALSIM_SetMatchType(HAL_MatchType type); +void HALSIM_SetMatchNumber(int32_t matchNumber); +void HALSIM_SetReplayNumber(int32_t replayNumber); + void HALSIM_RegisterDriverStationAllCallbacks(HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify); diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp index ece98c8102..2f909c2d38 100644 --- a/hal/src/main/native/sim/mockdata/DriverStationData.cpp +++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------*/ -/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */ +/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ @@ -12,6 +12,8 @@ #include "DriverStationDataInternal.h" #include "hal/DriverStation.h" +static constexpr int kNumJoysticks = 6; + namespace hal { struct JoystickOutputStore { int64_t outputs = 0; @@ -47,13 +49,14 @@ void DriverStationData::ResetData() { { std::scoped_lock lock(m_joystickDataMutex); - m_joystickAxes = std::make_unique(6); - m_joystickPOVs = std::make_unique(6); - m_joystickButtons = std::make_unique(6); - m_joystickOutputs = std::make_unique(6); - m_joystickDescriptor = std::make_unique(6); + m_joystickAxes = std::make_unique(kNumJoysticks); + m_joystickPOVs = std::make_unique(kNumJoysticks); + m_joystickButtons = std::make_unique(kNumJoysticks); + m_joystickOutputs = std::make_unique(kNumJoysticks); + m_joystickDescriptor = + std::make_unique(kNumJoysticks); - for (int i = 0; i < 6; i++) { + for (int i = 0; i < kNumJoysticks; i++) { m_joystickAxes[i].count = 0; m_joystickPOVs[i].count = 0; m_joystickButtons[i].count = 0; @@ -71,21 +74,25 @@ void DriverStationData::ResetData() { void DriverStationData::GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); *axes = m_joystickAxes[joystickNum]; } void DriverStationData::GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); *povs = m_joystickPOVs[joystickNum]; } void DriverStationData::GetJoystickButtons(int32_t joystickNum, HAL_JoystickButtons* buttons) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); *buttons = m_joystickButtons[joystickNum]; } void DriverStationData::GetJoystickDescriptor( int32_t joystickNum, HAL_JoystickDescriptor* descriptor) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); *descriptor = m_joystickDescriptor[joystickNum]; // Always ensure name is null terminated @@ -95,6 +102,7 @@ void DriverStationData::GetJoystickOutputs(int32_t joystickNum, int64_t* outputs, int32_t* leftRumble, int32_t* rightRumble) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); *leftRumble = m_joystickOutputs[joystickNum].leftRumble; *outputs = m_joystickOutputs[joystickNum].outputs; @@ -107,22 +115,26 @@ void DriverStationData::GetMatchInfo(HAL_MatchInfo* info) { void DriverStationData::SetJoystickAxes(int32_t joystickNum, const HAL_JoystickAxes* axes) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); m_joystickAxes[joystickNum] = *axes; } void DriverStationData::SetJoystickPOVs(int32_t joystickNum, const HAL_JoystickPOVs* povs) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); m_joystickPOVs[joystickNum] = *povs; } void DriverStationData::SetJoystickButtons(int32_t joystickNum, const HAL_JoystickButtons* buttons) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); m_joystickButtons[joystickNum] = *buttons; } void DriverStationData::SetJoystickDescriptor( int32_t joystickNum, const HAL_JoystickDescriptor* descriptor) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); m_joystickDescriptor[joystickNum] = *descriptor; } @@ -130,6 +142,7 @@ void DriverStationData::SetJoystickDescriptor( void DriverStationData::SetJoystickOutputs(int32_t joystickNum, int64_t outputs, int32_t leftRumble, int32_t rightRumble) { + if (joystickNum < 0 || joystickNum >= kNumJoysticks) return; std::scoped_lock lock(m_joystickDataMutex); m_joystickOutputs[joystickNum].leftRumble = leftRumble; m_joystickOutputs[joystickNum].outputs = outputs; @@ -144,6 +157,116 @@ void DriverStationData::SetMatchInfo(const HAL_MatchInfo* info) { void DriverStationData::NotifyNewData() { HAL_ReleaseDSMutex(); } +void DriverStationData::SetJoystickButton(int32_t stick, int32_t button, + HAL_Bool state) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + if (state) + m_joystickButtons[stick].buttons |= 1 << (button - 1); + else + m_joystickButtons[stick].buttons &= ~(1 << (button - 1)); +} + +void DriverStationData::SetJoystickAxis(int32_t stick, int32_t axis, + double value) { + if (stick < 0 || stick >= kNumJoysticks) return; + if (axis < 0 || axis >= HAL_kMaxJoystickAxes) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickAxes[stick].axes[axis] = value; +} + +void DriverStationData::SetJoystickPOV(int32_t stick, int32_t pov, + int32_t value) { + if (stick < 0 || stick >= kNumJoysticks) return; + if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickPOVs[stick].povs[pov] = value; +} + +void DriverStationData::SetJoystickButtons(int32_t stick, uint32_t buttons) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickButtons[stick].buttons = buttons; +} + +void DriverStationData::SetJoystickAxisCount(int32_t stick, int32_t count) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickAxes[stick].count = count; + m_joystickDescriptor[stick].axisCount = count; +} + +void DriverStationData::SetJoystickPOVCount(int32_t stick, int32_t count) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickPOVs[stick].count = count; + m_joystickDescriptor[stick].povCount = count; +} + +void DriverStationData::SetJoystickButtonCount(int32_t stick, int32_t count) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickButtons[stick].count = count; + m_joystickDescriptor[stick].buttonCount = count; +} + +void DriverStationData::SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickDescriptor[stick].isXbox = isXbox; +} + +void DriverStationData::SetJoystickType(int32_t stick, int32_t type) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickDescriptor[stick].type = type; +} + +void DriverStationData::SetJoystickName(int32_t stick, const char* name) { + if (stick < 0 || stick >= kNumJoysticks) return; + std::scoped_lock lock(m_joystickDataMutex); + std::strncpy(m_joystickDescriptor[stick].name, name, + sizeof(m_joystickDescriptor[stick].name) - 1); +} + +void DriverStationData::SetJoystickAxisType(int32_t stick, int32_t axis, + int32_t type) { + if (stick < 0 || stick >= kNumJoysticks) return; + if (axis < 0 || axis >= HAL_kMaxJoystickAxes) return; + std::scoped_lock lock(m_joystickDataMutex); + m_joystickDescriptor[stick].axisTypes[axis] = type; +} + +void DriverStationData::SetGameSpecificMessage(const char* message) { + std::scoped_lock lock(m_matchInfoMutex); + std::strncpy(reinterpret_cast(m_matchInfo->gameSpecificMessage), + message, sizeof(m_matchInfo->gameSpecificMessage) - 1); + *(std::end(m_matchInfo->gameSpecificMessage) - 1) = '\0'; + m_matchInfo->gameSpecificMessageSize = std::strlen(message); +} + +void DriverStationData::SetEventName(const char* name) { + std::scoped_lock lock(m_matchInfoMutex); + std::strncpy(m_matchInfo->eventName, name, + sizeof(m_matchInfo->eventName) - 1); + *(std::end(m_matchInfo->eventName) - 1) = '\0'; +} + +void DriverStationData::SetMatchType(HAL_MatchType type) { + std::scoped_lock lock(m_matchInfoMutex); + m_matchInfo->matchType = type; +} + +void DriverStationData::SetMatchNumber(int32_t matchNumber) { + std::scoped_lock lock(m_matchInfoMutex); + m_matchInfo->matchNumber = matchNumber; +} + +void DriverStationData::SetReplayNumber(int32_t replayNumber) { + std::scoped_lock lock(m_matchInfoMutex); + m_matchInfo->replayNumber = replayNumber; +} + extern "C" { void HALSIM_ResetDriverStationData(void) { SimDriverStationData->ResetData(); } @@ -191,6 +314,70 @@ void HALSIM_NotifyDriverStationNewData(void) { SimDriverStationData->NotifyNewData(); } +void HALSIM_SetJoystickButton(int32_t stick, int32_t button, HAL_Bool state) { + SimDriverStationData->SetJoystickButton(stick, button, state); +} + +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) { + SimDriverStationData->SetJoystickPOV(stick, pov, value); +} + +void HALSIM_SetJoystickButtonsValue(int32_t stick, uint32_t buttons) { + SimDriverStationData->SetJoystickButtons(stick, buttons); +} + +void HALSIM_SetJoystickAxisCount(int32_t stick, int32_t count) { + SimDriverStationData->SetJoystickAxisCount(stick, count); +} + +void HALSIM_SetJoystickPOVCount(int32_t stick, int32_t count) { + SimDriverStationData->SetJoystickPOVCount(stick, count); +} + +void HALSIM_SetJoystickButtonCount(int32_t stick, int32_t count) { + SimDriverStationData->SetJoystickButtonCount(stick, count); +} + +void HALSIM_SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox) { + SimDriverStationData->SetJoystickIsXbox(stick, isXbox); +} + +void HALSIM_SetJoystickType(int32_t stick, int32_t type) { + SimDriverStationData->SetJoystickType(stick, type); +} + +void HALSIM_SetJoystickName(int32_t stick, const char* name) { + SimDriverStationData->SetJoystickName(stick, name); +} + +void HALSIM_SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type) { + SimDriverStationData->SetJoystickAxisType(stick, axis, type); +} + +void HALSIM_SetGameSpecificMessage(const char* message) { + SimDriverStationData->SetGameSpecificMessage(message); +} + +void HALSIM_SetEventName(const char* name) { + SimDriverStationData->SetEventName(name); +} + +void HALSIM_SetMatchType(HAL_MatchType type) { + SimDriverStationData->SetMatchType(type); +} + +void HALSIM_SetMatchNumber(int32_t matchNumber) { + SimDriverStationData->SetMatchNumber(matchNumber); +} + +void HALSIM_SetReplayNumber(int32_t replayNumber) { + SimDriverStationData->SetReplayNumber(replayNumber); +} + #define REGISTER(NAME) \ SimDriverStationData->NAME.RegisterCallback(callback, param, initialNotify) diff --git a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h index 7838d67145..69ba28a4ed 100644 --- a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h +++ b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h @@ -58,6 +58,25 @@ class DriverStationData { void NotifyNewData(); + 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 SetJoystickButtons(int32_t stick, uint32_t buttons); + void SetJoystickAxisCount(int32_t stick, int32_t count); + void SetJoystickPOVCount(int32_t stick, int32_t count); + void SetJoystickButtonCount(int32_t stick, int32_t count); + + void SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox); + void SetJoystickType(int32_t stick, int32_t type); + void SetJoystickName(int32_t stick, const char* name); + void SetJoystickAxisType(int32_t stick, int32_t axis, int32_t type); + + void SetGameSpecificMessage(const char* message); + void SetEventName(const char* name); + void SetMatchType(HAL_MatchType type); + void SetMatchNumber(int32_t matchNumber); + void SetReplayNumber(int32_t replayNumber); + SimDataValue enabled{false}; SimDataValue autonomous{false}; SimDataValue test{false}; diff --git a/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h b/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h index c57281a7ca..942e8973af 100644 --- a/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h +++ b/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h @@ -11,8 +11,10 @@ #include #include +#include #include "CallbackStore.h" +#include "frc/DriverStation.h" namespace frc { namespace sim { @@ -108,7 +110,261 @@ class DriverStationSim { HALSIM_SetDriverStationDsAttached(dsAttached); } - static void NotifyNewData() { HALSIM_NotifyDriverStationNewData(); } + static std::unique_ptr RegisterAllianceStationIdCallback( + NotifyCallback callback, bool initialNotify) { + auto store = std::make_unique( + -1, callback, &HALSIM_CancelDriverStationAllianceStationIdCallback); + store->SetUid(HALSIM_RegisterDriverStationAllianceStationIdCallback( + &CallbackStoreThunk, store.get(), initialNotify)); + return store; + } + + static HAL_AllianceStationID GetAllianceStationId() { + return HALSIM_GetDriverStationAllianceStationId(); + } + + static void SetAllianceStationId(HAL_AllianceStationID allianceStationId) { + HALSIM_SetDriverStationAllianceStationId(allianceStationId); + } + + static std::unique_ptr RegisterMatchTimeCallback( + NotifyCallback callback, bool initialNotify) { + auto store = std::make_unique( + -1, callback, &HALSIM_CancelDriverStationMatchTimeCallback); + store->SetUid(HALSIM_RegisterDriverStationMatchTimeCallback( + &CallbackStoreThunk, store.get(), initialNotify)); + return store; + } + + static double GetMatchTime() { return HALSIM_GetDriverStationMatchTime(); } + + static void SetMatchTime(double matchTime) { + HALSIM_SetDriverStationMatchTime(matchTime); + } + + /** + * Updates DriverStation data so that new values are visible to the user + * program. + */ + static void NotifyNewData() { + HALSIM_NotifyDriverStationNewData(); + DriverStation::GetInstance().WaitForData(); + } + + /** + * Sets suppression of DriverStation::ReportError and ReportWarning messages. + * + * @param shouldSend If false then messages will be suppressed. + */ + static void SetSendError(bool shouldSend) { + if (shouldSend) { + HALSIM_SetSendError(nullptr); + } else { + HALSIM_SetSendError([](HAL_Bool isError, int32_t errorCode, + HAL_Bool isLVCode, const char* details, + const char* location, const char* callStack, + HAL_Bool printMsg) { return 0; }); + } + } + + /** + * Sets suppression of DriverStation::SendConsoleLine messages. + * + * @param shouldSend If false then messages will be suppressed. + */ + static void SetSendConsoleLine(bool shouldSend) { + if (shouldSend) { + HALSIM_SetSendConsoleLine(nullptr); + } else { + HALSIM_SetSendConsoleLine([](const char* line) { return 0; }); + } + } + + /** + * Gets the joystick outputs. + * + * @param stick The joystick number + * @return The joystick outputs + */ + static int64_t GetJoystickOutputs(int stick) { + int64_t outputs = 0; + int32_t leftRumble; + int32_t rightRumble; + HALSIM_GetJoystickOutputs(stick, &outputs, &leftRumble, &rightRumble); + return outputs; + } + + /** + * Gets the joystick rumble. + * + * @param stick The joystick number + * @param rumbleNum Rumble to get (0=left, 1=right) + * @return The joystick rumble value + */ + static int GetJoystickRumble(int stick, int rumbleNum) { + int64_t outputs; + int32_t leftRumble = 0; + int32_t rightRumble = 0; + HALSIM_GetJoystickOutputs(stick, &outputs, &leftRumble, &rightRumble); + return rumbleNum == 0 ? leftRumble : rightRumble; + } + + /** + * Sets the state of one joystick button. Button indexes begin at 1. + * + * @param stick The joystick number + * @param button The button index, beginning at 1 + * @param state The state of the joystick button + */ + static void SetJoystickButton(int stick, int button, bool state) { + HALSIM_SetJoystickButton(stick, button, state); + } + + /** + * Gets the value of the axis on a joystick. + * + * @param stick The joystick number + * @param axis The analog axis number + * @param value The value of the axis on the joystick + */ + static void SetJoystickAxis(int stick, int axis, double value) { + HALSIM_SetJoystickAxis(stick, axis, value); + } + + /** + * Gets the state of a POV on a joystick. + * + * @param stick The joystick number + * @param pov The POV number + * @param value the angle of the POV in degrees, or -1 for not pressed + */ + static void SetJoystickPOV(int stick, int pov, int value) { + HALSIM_SetJoystickPOV(stick, pov, value); + } + + /** + * Sets the state of all the buttons on a joystick. + * + * @param stick The joystick number + * @param buttons The bitmap state of the buttons on the joystick + */ + static void SetJoystickButtons(int stick, uint32_t buttons) { + HALSIM_SetJoystickButtonsValue(stick, buttons); + } + + /** + * Sets the number of axes for a joystick. + * + * @param stick The joystick number + * @param count The number of axes on the indicated joystick + */ + static void SetJoystickAxisCount(int stick, int count) { + HALSIM_SetJoystickAxisCount(stick, count); + } + + /** + * Sets the number of POVs for a joystick. + * + * @param stick The joystick number + * @param count The number of POVs on the indicated joystick + */ + static void SetJoystickPOVCount(int stick, int count) { + HALSIM_SetJoystickPOVCount(stick, count); + } + + /** + * Sets the number of buttons for a joystick. + * + * @param stick The joystick number + * @param count The number of buttons on the indicated joystick + */ + static void SetJoystickButtonCount(int stick, int count) { + HALSIM_SetJoystickButtonCount(stick, count); + } + + /** + * Sets the value of isXbox for a joystick. + * + * @param stick The joystick number + * @param isXbox The value of isXbox + */ + static void SetJoystickIsXbox(int stick, bool isXbox) { + HALSIM_SetJoystickIsXbox(stick, isXbox); + } + + /** + * Sets the value of type for a joystick. + * + * @param stick The joystick number + * @param type The value of type + */ + static void SetJoystickType(int stick, int type) { + HALSIM_SetJoystickType(stick, type); + } + + /** + * Sets the name of a joystick. + * + * @param stick The joystick number + * @param name The value of name + */ + static void SetJoystickName(int stick, const char* name) { + HALSIM_SetJoystickName(stick, name); + } + + /** + * Sets the types of Axes for a joystick. + * + * @param stick The joystick number + * @param axis The target axis + * @param type The type of axis + */ + static void SetJoystickAxisType(int stick, int axis, int type) { + HALSIM_SetJoystickAxisType(stick, axis, type); + } + + /** + * Sets the game specific message. + * + * @param message the game specific message + */ + static void SetGameSpecificMessage(const char* message) { + HALSIM_SetGameSpecificMessage(message); + } + + /** + * Sets the event name. + * + * @param name the event name + */ + static void SetEventName(const char* name) { HALSIM_SetEventName(name); } + + /** + * Sets the match type. + * + * @param type the match type + */ + static void SetMatchType(DriverStation::MatchType type) { + HALSIM_SetMatchType(static_cast(static_cast(type))); + } + + /** + * Sets the match number. + * + * @param matchNumber the match number + */ + static void SetMatchNumber(int matchNumber) { + HALSIM_SetMatchNumber(matchNumber); + } + + /** + * Sets the replay number. + * + * @param replayNumber the replay number + */ + static void SetReplayNumber(int replayNumber) { + HALSIM_SetReplayNumber(replayNumber); + } static void ResetData() { HALSIM_ResetDriverStationData(); } }; diff --git a/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h b/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h new file mode 100644 index 0000000000..402f5db3ed --- /dev/null +++ b/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h @@ -0,0 +1,97 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#pragma once + +#include "frc/GenericHID.h" +#include "frc/simulation/DriverStationSim.h" + +namespace frc { +namespace sim { + +/** + * Class to control a simulated generic joystick. + */ +class GenericHIDSim { + public: + /** + * Constructs from a GenericHID object. + * + * @param joystick joystick to simulate + */ + explicit GenericHIDSim(const GenericHID& joystick) + : m_port{joystick.GetPort()} {} + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + explicit GenericHIDSim(int port) : m_port{port} {} + + /** + * Updates joystick data so that new values are visible to the user program. + */ + void NotifyNewData() { DriverStationSim::NotifyNewData(); } + + void SetRawButton(int button, bool value) { + DriverStationSim::SetJoystickButton(m_port, button, value); + } + + void SetRawAxis(int axis, double value) { + DriverStationSim::SetJoystickAxis(m_port, axis, value); + } + + void SetPOV(int pov, int value) { + DriverStationSim::SetJoystickPOV(m_port, pov, value); + } + + void SetPOV(int value) { SetPOV(0, value); } + + void SetAxisCount(int count) { + DriverStationSim::SetJoystickAxisCount(m_port, count); + } + + void SetPOVCount(int count) { + DriverStationSim::SetJoystickPOVCount(m_port, count); + } + + void SetButtonCount(int count) { + DriverStationSim::SetJoystickButtonCount(m_port, count); + } + + void SetType(GenericHID::HIDType type) { + DriverStationSim::SetJoystickType(m_port, type); + } + + void SetName(const char* name) { + DriverStationSim::SetJoystickName(m_port, name); + } + + void SetAxisType(int axis, int type) { + DriverStationSim::SetJoystickAxisType(m_port, axis, type); + } + + bool GetOutput(int outputNumber) { + int64_t outputs = GetOutputs(); + return (outputs & (static_cast(1) << (outputNumber - 1))) != 0; + } + + int64_t GetOutputs() { return DriverStationSim::GetJoystickOutputs(m_port); } + + double GetRumble(GenericHID::RumbleType type) { + int value = DriverStationSim::GetJoystickRumble( + m_port, type == GenericHID::kLeftRumble ? 0 : 1); + return value / 65535.0; + } + + protected: + int m_port; +}; + +} // namespace sim +} // namespace frc diff --git a/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h b/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h new file mode 100644 index 0000000000..f0d07f99e1 --- /dev/null +++ b/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h @@ -0,0 +1,85 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#pragma once + +#include "frc/Joystick.h" +#include "frc/simulation/GenericHIDSim.h" + +namespace frc { +namespace sim { + +/** + * Class to control a simulated joystick. + */ +class JoystickSim : public GenericHIDSim { + public: + /** + * Constructs from a Joystick object. + * + * @param joystick joystick to simulate + */ + explicit JoystickSim(const Joystick& joystick) + : GenericHIDSim{joystick}, m_joystick{&joystick} { + // default to a reasonable joystick configuration + SetAxisCount(5); + SetButtonCount(12); + SetPOVCount(1); + } + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + explicit JoystickSim(int port) : GenericHIDSim{port} { + // default to a reasonable joystick configuration + SetAxisCount(5); + SetButtonCount(12); + SetPOVCount(1); + } + + void SetX(double value) { + SetRawAxis( + m_joystick ? m_joystick->GetXChannel() : Joystick::kDefaultXChannel, + value); + } + + void SetY(double value) { + SetRawAxis( + m_joystick ? m_joystick->GetYChannel() : Joystick::kDefaultYChannel, + value); + } + + void SetZ(double value) { + SetRawAxis( + m_joystick ? m_joystick->GetZChannel() : Joystick::kDefaultZChannel, + value); + } + + void SetTwist(double value) { + SetRawAxis(m_joystick ? m_joystick->GetTwistChannel() + : Joystick::kDefaultTwistChannel, + value); + } + + void SetThrottle(double value) { + SetRawAxis(m_joystick ? m_joystick->GetThrottleChannel() + : Joystick::kDefaultThrottleChannel, + value); + } + + void SetTrigger(bool state) { SetRawButton(1, state); } + + void SetTop(bool state) { SetRawButton(2, state); } + + private: + const Joystick* m_joystick = nullptr; +}; + +} // namespace sim +} // namespace frc diff --git a/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h b/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h new file mode 100644 index 0000000000..3aff21505c --- /dev/null +++ b/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h @@ -0,0 +1,111 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#pragma once + +#include "frc/XboxController.h" +#include "frc/simulation/GenericHIDSim.h" + +namespace frc { +namespace sim { + +/** + * Class to control a simulated Xbox 360 or Xbox One controller. + */ +class XboxControllerSim : public GenericHIDSim { + public: + /** + * Constructs from a XboxController object. + * + * @param joystick controller to simulate + */ + explicit XboxControllerSim(const XboxController& joystick) + : GenericHIDSim{joystick} { + SetAxisCount(6); + SetButtonCount(10); + } + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + explicit XboxControllerSim(int port) : GenericHIDSim{port} { + SetAxisCount(6); + SetButtonCount(10); + } + + void SetX(GenericHID::JoystickHand hand, double value) { + if (hand == GenericHID::kLeftHand) { + SetRawAxis(static_cast(XboxController::Axis::kLeftX), value); + } else { + SetRawAxis(static_cast(XboxController::Axis::kRightX), value); + } + } + + void SetY(GenericHID::JoystickHand hand, double value) { + if (hand == GenericHID::kLeftHand) { + SetRawAxis(static_cast(XboxController::Axis::kLeftY), value); + } else { + SetRawAxis(static_cast(XboxController::Axis::kRightY), value); + } + } + + void SetTriggerAxis(GenericHID::JoystickHand hand, double value) { + if (hand == GenericHID::kLeftHand) { + SetRawAxis(static_cast(XboxController::Axis::kLeftTrigger), value); + } else { + SetRawAxis(static_cast(XboxController::Axis::kRightTrigger), value); + } + } + + void SetBumper(GenericHID::JoystickHand hand, bool state) { + if (hand == GenericHID::kLeftHand) { + SetRawButton(static_cast(XboxController::Button::kBumperLeft), + state); + } else { + SetRawButton(static_cast(XboxController::Button::kBumperRight), + state); + } + } + + void SetStickButton(GenericHID::JoystickHand hand, bool state) { + if (hand == GenericHID::kLeftHand) { + SetRawButton(static_cast(XboxController::Button::kStickLeft), state); + } else { + SetRawButton(static_cast(XboxController::Button::kStickRight), + state); + } + } + + void SetAButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kA), state); + } + + void SetBButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kB), state); + } + + void SetXButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kX), state); + } + + void SetYButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kY), state); + } + + void SetBackButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kBack), state); + } + + void SetStartButton(bool state) { + SetRawButton(static_cast(XboxController::Button::kStart), state); + } +}; + +} // namespace sim +} // namespace frc diff --git a/wpilibc/src/test/native/cpp/JoystickTest.cpp b/wpilibc/src/test/native/cpp/JoystickTest.cpp new file mode 100644 index 0000000000..0480b76ecf --- /dev/null +++ b/wpilibc/src/test/native/cpp/JoystickTest.cpp @@ -0,0 +1,39 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "frc/Joystick.h" // NOLINT(build/include_order) + +#include "frc/simulation/JoystickSim.h" +#include "gtest/gtest.h" + +using namespace frc; + +TEST(JoystickTests, GetX) { + Joystick joy{1}; + sim::JoystickSim joysim{joy}; + + joysim.SetX(0.25); + joysim.NotifyNewData(); + ASSERT_NEAR(joy.GetX(), 0.25, 0.001); + + joysim.SetX(0); + joysim.NotifyNewData(); + ASSERT_NEAR(joy.GetX(), 0, 0.001); +} + +TEST(JoystickTests, GetY) { + Joystick joy{1}; + sim::JoystickSim joysim{joy}; + + joysim.SetY(0.25); + joysim.NotifyNewData(); + ASSERT_NEAR(joy.GetY(), 0.25, 0.001); + + joysim.SetY(0); + joysim.NotifyNewData(); + ASSERT_NEAR(joy.GetY(), 0, 0.001); +} diff --git a/wpilibc/src/test/native/cpp/XboxControllerTest.cpp b/wpilibc/src/test/native/cpp/XboxControllerTest.cpp new file mode 100644 index 0000000000..66ccfcd297 --- /dev/null +++ b/wpilibc/src/test/native/cpp/XboxControllerTest.cpp @@ -0,0 +1,74 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "frc/XboxController.h" // NOLINT(build/include_order) + +#include "frc/simulation/XboxControllerSim.h" +#include "gtest/gtest.h" + +using namespace frc; + +TEST(XboxControllerTests, GetX) { + XboxController joy{2}; + sim::XboxControllerSim joysim{joy}; + + joysim.SetX(XboxController::kLeftHand, 0.35); + joysim.SetX(XboxController::kRightHand, 0.45); + joysim.NotifyNewData(); + ASSERT_NEAR(joy.GetX(XboxController::kLeftHand), 0.35, 0.001); + ASSERT_NEAR(joy.GetX(XboxController::kRightHand), 0.45, 0.001); +} + +TEST(XboxControllerTests, GetBumper) { + XboxController joy{1}; + sim::XboxControllerSim joysim{joy}; + + joysim.SetBumper(XboxController::kLeftHand, false); + joysim.SetBumper(XboxController::kRightHand, true); + joysim.NotifyNewData(); + ASSERT_FALSE(joy.GetBumper(XboxController::kLeftHand)); + ASSERT_TRUE(joy.GetBumper(XboxController::kRightHand)); + // need to call pressed and released to clear flags + joy.GetBumperPressed(XboxController::kLeftHand); + joy.GetBumperReleased(XboxController::kLeftHand); + joy.GetBumperPressed(XboxController::kRightHand); + joy.GetBumperReleased(XboxController::kRightHand); + + joysim.SetBumper(XboxController::kLeftHand, true); + joysim.SetBumper(XboxController::kRightHand, false); + joysim.NotifyNewData(); + ASSERT_TRUE(joy.GetBumper(XboxController::kLeftHand)); + ASSERT_TRUE(joy.GetBumperPressed(XboxController::kLeftHand)); + ASSERT_FALSE(joy.GetBumperReleased(XboxController::kLeftHand)); + ASSERT_FALSE(joy.GetBumper(XboxController::kRightHand)); + ASSERT_FALSE(joy.GetBumperPressed(XboxController::kRightHand)); + ASSERT_TRUE(joy.GetBumperReleased(XboxController::kRightHand)); +} + +TEST(XboxControllerTests, GetAButton) { + XboxController joy{1}; + sim::XboxControllerSim joysim{joy}; + + joysim.SetAButton(false); + joysim.NotifyNewData(); + ASSERT_FALSE(joy.GetAButton()); + // need to call pressed and released to clear flags + joy.GetAButtonPressed(); + joy.GetAButtonReleased(); + + joysim.SetAButton(true); + joysim.NotifyNewData(); + ASSERT_TRUE(joy.GetAButton()); + ASSERT_TRUE(joy.GetAButtonPressed()); + ASSERT_FALSE(joy.GetAButtonReleased()); + + joysim.SetAButton(false); + joysim.NotifyNewData(); + ASSERT_FALSE(joy.GetAButton()); + ASSERT_FALSE(joy.GetAButtonPressed()); + ASSERT_TRUE(joy.GetAButtonReleased()); +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java index 60a60bbd73..a83a34631b 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------*/ -/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */ +/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ @@ -18,11 +18,11 @@ import edu.wpi.first.hal.HAL; * and the mapping of ports to hardware buttons depends on the code in the Driver Station. */ public class Joystick extends GenericHID { - static final byte kDefaultXChannel = 0; - static final byte kDefaultYChannel = 1; - static final byte kDefaultZChannel = 2; - static final byte kDefaultTwistChannel = 2; - static final byte kDefaultThrottleChannel = 3; + public static final byte kDefaultXChannel = 0; + public static final byte kDefaultYChannel = 1; + public static final byte kDefaultZChannel = 2; + public static final byte kDefaultTwistChannel = 2; + public static final byte kDefaultThrottleChannel = 3; /** * Represents an analog axis on a joystick. diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java index 8d6e6573b8..40b1017905 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java @@ -7,13 +7,15 @@ package edu.wpi.first.wpilibj.simulation; +import edu.wpi.first.hal.AllianceStationID; import edu.wpi.first.hal.simulation.DriverStationDataJNI; import edu.wpi.first.hal.simulation.NotifyCallback; +import edu.wpi.first.wpilibj.DriverStation; /** * Class to control a simulated driver station. */ -@SuppressWarnings("PMD.UseUtilityClass") +@SuppressWarnings({"PMD.UseUtilityClass", "PMD.GodClass", "PMD.ExcessivePublicCount"}) public class DriverStationSim { public static CallbackStore registerEnabledCallback(NotifyCallback callback, boolean initialNotify) { int uid = DriverStationDataJNI.registerEnabledCallback(callback, initialNotify); @@ -80,19 +82,291 @@ public class DriverStationSim { public static void setDsAttached(boolean dsAttached) { DriverStationDataJNI.setDsAttached(dsAttached); } - public static void notifyNewData() { - DriverStationDataJNI.notifyNewData(); + + public static CallbackStore registerAllianceStationIdCallback(NotifyCallback callback, boolean initialNotify) { + int uid = DriverStationDataJNI.registerAllianceStationIdCallback(callback, initialNotify); + return new CallbackStore(uid, DriverStationDataJNI::cancelAllianceStationIdCallback); + } + public static AllianceStationID getAllianceStationId() { + switch (DriverStationDataJNI.getAllianceStationId()) { + case 0: + return AllianceStationID.Red1; + case 1: + return AllianceStationID.Red2; + case 2: + return AllianceStationID.Red3; + case 3: + return AllianceStationID.Blue1; + case 4: + return AllianceStationID.Blue2; + case 5: + return AllianceStationID.Blue3; + default: + return null; + } + } + public static void setAllianceStationId(AllianceStationID allianceStationId) { + int allianceStation; + switch (allianceStationId) { + case Red1: + allianceStation = 0; + break; + case Red2: + allianceStation = 1; + break; + case Red3: + allianceStation = 2; + break; + case Blue1: + allianceStation = 3; + break; + case Blue2: + allianceStation = 4; + break; + case Blue3: + allianceStation = 5; + break; + default: + return; + } + DriverStationDataJNI.setAllianceStationId(allianceStation); + } + + public static CallbackStore registerMatchTimeCallback(NotifyCallback callback, boolean initialNotify) { + int uid = DriverStationDataJNI.registerMatchTimeCallback(callback, initialNotify); + return new CallbackStore(uid, DriverStationDataJNI::cancelMatchTimeCallback); + } + public static double getMatchTime() { + return DriverStationDataJNI.getMatchTime(); + } + public static void setMatchTime(double matchTime) { + DriverStationDataJNI.setMatchTime(matchTime); } /** - * Toggles suppression of DriverStation.reportError and reportWarning messages. + * Updates DriverStation data so that new values are visible to the user + * program. + */ + public static void notifyNewData() { + DriverStationDataJNI.notifyNewData(); + DriverStation.getInstance().waitForData(); + } + + /** + * Sets suppression of DriverStation.reportError and reportWarning messages. * - * @param shouldSend If false then messages will will be suppressed. + * @param shouldSend If false then messages will be suppressed. */ public static void setSendError(boolean shouldSend) { DriverStationDataJNI.setSendError(shouldSend); } + /** + * Sets suppression of DriverStation.sendConsoleLine messages. + * + * @param shouldSend If false then messages will be suppressed. + */ + public static void setSendConsoleLine(boolean shouldSend) { + DriverStationDataJNI.setSendConsoleLine(shouldSend); + } + + /** + * Gets the joystick outputs. + * + * @param stick The joystick number + * @return The joystick outputs + */ + public static long getJoystickOutputs(int stick) { + return DriverStationDataJNI.getJoystickOutputs(stick); + } + + /** + * Gets the joystick rumble. + * + * @param stick The joystick number + * @param rumbleNum Rumble to get (0=left, 1=right) + * @return The joystick rumble value + */ + public static int getJoystickRumble(int stick, int rumbleNum) { + return DriverStationDataJNI.getJoystickRumble(stick, rumbleNum); + } + + /** + * Sets the state of one joystick button. Button indexes begin at 1. + * + * @param stick The joystick number + * @param button The button index, beginning at 1 + * @param state The state of the joystick button + */ + public static void setJoystickButton(int stick, int button, boolean state) { + DriverStationDataJNI.setJoystickButton(stick, button, state); + } + + /** + * Gets the value of the axis on a joystick. + * + * @param stick The joystick number + * @param axis The analog axis number + * @param value The value of the axis on the joystick + */ + public static void setJoystickAxis(int stick, int axis, double value) { + DriverStationDataJNI.setJoystickAxis(stick, axis, value); + } + + /** + * Gets the state of a POV on a joystick. + * + * @param stick The joystick number + * @param pov The POV number + * @param value the angle of the POV in degrees, or -1 for not pressed + */ + public static void setJoystickPOV(int stick, int pov, int value) { + DriverStationDataJNI.setJoystickPOV(stick, pov, value); + } + + /** + * Sets the state of all the buttons on a joystick. + * + * @param stick The joystick number + * @param buttons The bitmap state of the buttons on the joystick + */ + public static void setJoystickButtons(int stick, int buttons) { + DriverStationDataJNI.setJoystickButtonsValue(stick, buttons); + } + + /** + * Sets the number of axes for a joystick. + * + * @param stick The joystick number + * @param count The number of axes on the indicated joystick + */ + public static void setJoystickAxisCount(int stick, int count) { + DriverStationDataJNI.setJoystickAxisCount(stick, count); + } + + /** + * Sets the number of POVs for a joystick. + * + * @param stick The joystick number + * @param count The number of POVs on the indicated joystick + */ + public static void setJoystickPOVCount(int stick, int count) { + DriverStationDataJNI.setJoystickPOVCount(stick, count); + } + + /** + * Sets the number of buttons for a joystick. + * + * @param stick The joystick number + * @param count The number of buttons on the indicated joystick + */ + public static void setJoystickButtonCount(int stick, int count) { + DriverStationDataJNI.setJoystickButtonCount(stick, count); + } + + /** + * Sets the value of isXbox for a joystick. + * + * @param stick The joystick number + * @param isXbox The value of isXbox + */ + public static void setJoystickIsXbox(int stick, boolean isXbox) { + DriverStationDataJNI.setJoystickIsXbox(stick, isXbox); + } + + /** + * Sets the value of type for a joystick. + * + * @param stick The joystick number + * @param type The value of type + */ + public static void setJoystickType(int stick, int type) { + DriverStationDataJNI.setJoystickType(stick, type); + } + + /** + * Sets the name of a joystick. + * + * @param stick The joystick number + * @param name The value of name + */ + public static void setJoystickName(int stick, String name) { + DriverStationDataJNI.setJoystickName(stick, name); + } + + /** + * Sets the types of Axes for a joystick. + * + * @param stick The joystick number + * @param axis The target axis + * @param type The type of axis + */ + public static void setJoystickAxisType(int stick, int axis, int type) { + DriverStationDataJNI.setJoystickAxisType(stick, axis, type); + } + + /** + * Sets the game specific message. + * + * @param message the game specific message + */ + public static void setGameSpecificMessage(String message) { + DriverStationDataJNI.setGameSpecificMessage(message); + } + + /** + * Sets the event name. + * + * @param name the event name + */ + public static void setEventName(String name) { + DriverStationDataJNI.setEventName(name); + } + + /** + * Sets the match type. + * + * @param type the match type + */ + public static void setMatchType(DriverStation.MatchType type) { + int matchType; + switch (type) { + case Practice: + matchType = 1; + break; + case Qualification: + matchType = 2; + break; + case Elimination: + matchType = 3; + break; + case None: + matchType = 0; + break; + default: + return; + } + DriverStationDataJNI.setMatchType(matchType); + } + + /** + * Sets the match number. + * + * @param matchNumber the match number + */ + public static void setMatchNumber(int matchNumber) { + DriverStationDataJNI.setMatchNumber(matchNumber); + } + + /** + * Sets the replay number. + * + * @param replayNumber the replay number + */ + public static void setReplayNumber(int replayNumber) { + DriverStationDataJNI.setReplayNumber(replayNumber); + } + public static void resetData() { DriverStationDataJNI.resetData(); } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java new file mode 100644 index 0000000000..506be521b3 --- /dev/null +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java @@ -0,0 +1,97 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj.simulation; + +import edu.wpi.first.wpilibj.GenericHID; + +/** + * Class to control a simulated generic joystick. + */ +public class GenericHIDSim { + protected final int m_port; + + /** + * Constructs from a GenericHID object. + * + * @param joystick joystick to simulate + */ + public GenericHIDSim(GenericHID joystick) { + m_port = joystick.getPort(); + } + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + public GenericHIDSim(int port) { + m_port = port; + } + + /** + * Updates joystick data so that new values are visible to the user program. + */ + public void notifyNewData() { + DriverStationSim.notifyNewData(); + } + + public void setRawButton(int button, boolean value) { + DriverStationSim.setJoystickButton(m_port, button, value); + } + + public void setRawAxis(int axis, double value) { + DriverStationSim.setJoystickAxis(m_port, axis, value); + } + + public void setPOV(int pov, int value) { + DriverStationSim.setJoystickPOV(m_port, pov, value); + } + + public void setPOV(int value) { + setPOV(0, value); + } + + public void setAxisCount(int count) { + DriverStationSim.setJoystickAxisCount(m_port, count); + } + + public void setPOVCount(int count) { + DriverStationSim.setJoystickPOVCount(m_port, count); + } + + public void setButtonCount(int count) { + DriverStationSim.setJoystickButtonCount(m_port, count); + } + + public void setType(GenericHID.HIDType type) { + DriverStationSim.setJoystickType(m_port, type.value); + } + + public void setName(String name) { + DriverStationSim.setJoystickName(m_port, name); + } + + public void setAxisType(int axis, int type) { + DriverStationSim.setJoystickAxisType(m_port, axis, type); + } + + public boolean getOutput(int outputNumber) { + long outputs = getOutputs(); + return (outputs & (1 << (outputNumber - 1))) != 0; + } + + public long getOutputs() { + return DriverStationSim.getJoystickOutputs(m_port); + } + + public double getRumble(GenericHID.RumbleType type) { + int value = DriverStationSim.getJoystickRumble( + m_port, type == GenericHID.RumbleType.kLeftRumble ? 0 : 1); + return value / 65535.0; + } +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java new file mode 100644 index 0000000000..d1d710053d --- /dev/null +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java @@ -0,0 +1,76 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj.simulation; + +import edu.wpi.first.wpilibj.Joystick; + +/** + * Class to control a simulated joystick. + */ +public class JoystickSim extends GenericHIDSim { + private Joystick m_joystick; + + /** + * Constructs from a Joystick object. + * + * @param joystick joystick to simulate + */ + public JoystickSim(Joystick joystick) { + super(joystick); + m_joystick = joystick; + // default to a reasonable joystick configuration + setAxisCount(5); + setButtonCount(12); + setPOVCount(1); + } + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + public JoystickSim(int port) { + super(port); + // default to a reasonable joystick configuration + setAxisCount(5); + setButtonCount(12); + setPOVCount(1); + } + + public void setX(double value) { + setRawAxis(m_joystick != null ? m_joystick.getXChannel() : Joystick.kDefaultXChannel, value); + } + + public void setY(double value) { + setRawAxis(m_joystick != null ? m_joystick.getYChannel() : Joystick.kDefaultYChannel, value); + } + + public void setZ(double value) { + setRawAxis(m_joystick != null ? m_joystick.getZChannel() : Joystick.kDefaultZChannel, value); + } + + public void setTwist(double value) { + setRawAxis( + m_joystick != null ? m_joystick.getTwistChannel() : Joystick.kDefaultTwistChannel, + value); + } + + public void setThrottle(double value) { + setRawAxis( + m_joystick != null ? m_joystick.getThrottleChannel() : Joystick.kDefaultThrottleChannel, + value); + } + + public void setTrigger(boolean state) { + setRawButton(1, state); + } + + public void setTop(boolean state) { + setRawButton(2, state); + } +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java new file mode 100644 index 0000000000..40a02bf61b --- /dev/null +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java @@ -0,0 +1,102 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj.simulation; + +import edu.wpi.first.wpilibj.GenericHID; +import edu.wpi.first.wpilibj.XboxController; + +/** + * Class to control a simulated Xbox 360 or Xbox One controller. + */ +public class XboxControllerSim extends GenericHIDSim { + /** + * Constructs from a XboxController object. + * + * @param joystick controller to simulate + */ + public XboxControllerSim(XboxController joystick) { + super(joystick); + setAxisCount(6); + setButtonCount(10); + } + + /** + * Constructs from a joystick port number. + * + * @param port port number + */ + public XboxControllerSim(int port) { + super(port); + setAxisCount(6); + setButtonCount(10); + } + + public void setX(GenericHID.Hand hand, double value) { + if (hand.equals(GenericHID.Hand.kLeft)) { + setRawAxis(XboxController.Axis.kLeftX.value, value); + } else { + setRawAxis(XboxController.Axis.kRightX.value, value); + } + } + + public void setY(GenericHID.Hand hand, double value) { + if (hand.equals(GenericHID.Hand.kLeft)) { + setRawAxis(XboxController.Axis.kLeftY.value, value); + } else { + setRawAxis(XboxController.Axis.kRightY.value, value); + } + } + + public void setTriggerAxis(GenericHID.Hand hand, double value) { + if (hand.equals(GenericHID.Hand.kLeft)) { + setRawAxis(XboxController.Axis.kLeftTrigger.value, value); + } else { + setRawAxis(XboxController.Axis.kRightTrigger.value, value); + } + } + + public void setBumper(GenericHID.Hand hand, boolean state) { + if (hand.equals(GenericHID.Hand.kLeft)) { + setRawButton(XboxController.Button.kBumperLeft.value, state); + } else { + setRawButton(XboxController.Button.kBumperRight.value, state); + } + } + + public void setStickButton(GenericHID.Hand hand, boolean state) { + if (hand.equals(GenericHID.Hand.kLeft)) { + setRawButton(XboxController.Button.kStickLeft.value, state); + } else { + setRawButton(XboxController.Button.kStickRight.value, state); + } + } + + public void setAButton(boolean state) { + setRawButton(XboxController.Button.kA.value, state); + } + + public void setBButton(boolean state) { + setRawButton(XboxController.Button.kB.value, state); + } + + public void setXButton(boolean state) { + setRawButton(XboxController.Button.kX.value, state); + } + + public void setYButton(boolean state) { + setRawButton(XboxController.Button.kY.value, state); + } + + public void setBackButton(boolean state) { + setRawButton(XboxController.Button.kBack.value, state); + } + + public void setStartButton(boolean state) { + setRawButton(XboxController.Button.kStart.value, state); + } +} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java new file mode 100644 index 0000000000..7b1cfbb02f --- /dev/null +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java @@ -0,0 +1,47 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj; + +import org.junit.jupiter.api.Test; + +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.simulation.JoystickSim; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class JoystickTest { + @Test + void testGetX() { + HAL.initialize(500, 0); + Joystick joy = new Joystick(1); + JoystickSim joysim = new JoystickSim(joy); + + joysim.setX(0.25); + joysim.notifyNewData(); + assertEquals(0.25, joy.getX(), 0.001); + + joysim.setX(0); + joysim.notifyNewData(); + assertEquals(0.0, joy.getX(), 0.001); + } + + @Test + void testGetY() { + HAL.initialize(500, 0); + Joystick joy = new Joystick(1); + JoystickSim joysim = new JoystickSim(joy); + + joysim.setY(0.25); + joysim.notifyNewData(); + assertEquals(0.25, joy.getY(), 0.001); + + joysim.setY(0); + joysim.notifyNewData(); + assertEquals(0.0, joy.getY(), 0.001); + } +} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java new file mode 100644 index 0000000000..34fce9a5fd --- /dev/null +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java @@ -0,0 +1,86 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj; + +import org.junit.jupiter.api.Test; + +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.simulation.XboxControllerSim; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class XboxControllerTest { + @Test + void testGetX() { + HAL.initialize(500, 0); + XboxController joy = new XboxController(2); + XboxControllerSim joysim = new XboxControllerSim(joy); + + joysim.setX(XboxController.Hand.kLeft, 0.35); + joysim.setX(XboxController.Hand.kRight, 0.45); + joysim.notifyNewData(); + assertEquals(0.35, joy.getX(XboxController.Hand.kLeft), 0.001); + assertEquals(0.45, joy.getX(XboxController.Hand.kRight), 0.001); + } + + @Test + void testGetBumper() { + HAL.initialize(500, 0); + XboxController joy = new XboxController(2); + XboxControllerSim joysim = new XboxControllerSim(joy); + + joysim.setBumper(XboxController.Hand.kLeft, false); + joysim.setBumper(XboxController.Hand.kRight, true); + joysim.notifyNewData(); + assertFalse(joy.getBumper(XboxController.Hand.kLeft)); + assertTrue(joy.getBumper(XboxController.Hand.kRight)); + // need to call pressed and released to clear flags + joy.getBumperPressed(XboxController.Hand.kLeft); + joy.getBumperReleased(XboxController.Hand.kLeft); + joy.getBumperPressed(XboxController.Hand.kRight); + joy.getBumperReleased(XboxController.Hand.kRight); + + joysim.setBumper(XboxController.Hand.kLeft, true); + joysim.setBumper(XboxController.Hand.kRight, false); + joysim.notifyNewData(); + assertTrue(joy.getBumper(XboxController.Hand.kLeft)); + assertTrue(joy.getBumperPressed(XboxController.Hand.kLeft)); + assertFalse(joy.getBumperReleased(XboxController.Hand.kLeft)); + assertFalse(joy.getBumper(XboxController.Hand.kRight)); + assertFalse(joy.getBumperPressed(XboxController.Hand.kRight)); + assertTrue(joy.getBumperReleased(XboxController.Hand.kRight)); + } + + @Test + void testGetAButton() { + HAL.initialize(500, 0); + XboxController joy = new XboxController(2); + XboxControllerSim joysim = new XboxControllerSim(joy); + + joysim.setAButton(false); + joysim.notifyNewData(); + assertFalse(joy.getAButton()); + // need to call pressed and released to clear flags + joy.getAButtonPressed(); + joy.getAButtonReleased(); + + joysim.setAButton(true); + joysim.notifyNewData(); + assertTrue(joy.getAButton()); + assertTrue(joy.getAButtonPressed()); + assertFalse(joy.getAButtonReleased()); + + joysim.setAButton(false); + joysim.notifyNewData(); + assertFalse(joy.getAButton()); + assertFalse(joy.getAButtonPressed()); + assertTrue(joy.getAButtonReleased()); + } +}