diff --git a/wpilibc/Athena/include/DriverStation.h b/wpilibc/Athena/include/DriverStation.h index 0fc2b886fa..3f310a3a09 100644 --- a/wpilibc/Athena/include/DriverStation.h +++ b/wpilibc/Athena/include/DriverStation.h @@ -9,6 +9,7 @@ #include #include +#include #include "HAL/HAL.hpp" #include "HAL/cpp/Semaphore.hpp" #include "HAL/cpp/priority_condition_variable.h" @@ -100,10 +101,17 @@ class DriverStation : public SensorBase, public RobotStateInterface { void ReportJoystickUnpluggedWarning(std::string message); void Run(); - HALJoystickAxes m_joystickAxes[kJoystickPorts]; - HALJoystickPOVs m_joystickPOVs[kJoystickPorts]; - HALJoystickButtons m_joystickButtons[kJoystickPorts]; - HALJoystickDescriptor m_joystickDescriptor[kJoystickPorts]; + std::unique_ptr m_joystickAxes; + std::unique_ptr m_joystickPOVs; + std::unique_ptr m_joystickButtons; + std::unique_ptr m_joystickDescriptor; + + // Cached Data + std::unique_ptr m_joystickAxesCache; + std::unique_ptr m_joystickPOVsCache; + std::unique_ptr m_joystickButtonsCache; + std::unique_ptr m_joystickDescriptorCache; + Task m_task; std::atomic m_isRunning{false}; mutable Semaphore m_newControlData{Semaphore::kEmpty}; @@ -111,6 +119,7 @@ class DriverStation : public SensorBase, public RobotStateInterface { priority_mutex m_packetDataAvailableMutex; std::condition_variable_any m_waitForDataCond; priority_mutex m_waitForDataMutex; + mutable priority_mutex m_joystickDataMutex; bool m_userInDisabled = false; bool m_userInAutonomous = false; bool m_userInTeleop = false; diff --git a/wpilibc/Athena/src/DriverStation.cpp b/wpilibc/Athena/src/DriverStation.cpp index 1d7e003b2c..474dce30bd 100644 --- a/wpilibc/Athena/src/DriverStation.cpp +++ b/wpilibc/Athena/src/DriverStation.cpp @@ -33,6 +33,15 @@ const uint32_t DriverStation::kJoystickPorts; * This is only called once the first time GetInstance() is called */ DriverStation::DriverStation() { + m_joystickAxes = std::make_unique (kJoystickPorts); + m_joystickPOVs = std::make_unique (kJoystickPorts); + m_joystickButtons = std::make_unique (kJoystickPorts); + m_joystickDescriptor = std::make_unique (kJoystickPorts); + m_joystickAxesCache = std::make_unique (kJoystickPorts); + m_joystickPOVsCache = std::make_unique (kJoystickPorts); + m_joystickButtonsCache = std::make_unique (kJoystickPorts); + m_joystickDescriptorCache = std::make_unique (kJoystickPorts); + // All joysticks should default to having zero axes, povs and buttons, so // uninitialized memory doesn't get sent to speed controllers. for (unsigned int i = 0; i < kJoystickPorts; i++) { @@ -42,6 +51,13 @@ DriverStation::DriverStation() { m_joystickDescriptor[i].isXbox = 0; m_joystickDescriptor[i].type = -1; m_joystickDescriptor[i].name[0] = '\0'; + + m_joystickAxesCache[i].count = 0; + m_joystickPOVsCache[i].count = 0; + m_joystickButtonsCache[i].count = 0; + m_joystickDescriptorCache[i].isXbox = 0; + m_joystickDescriptorCache[i].type = -1; + m_joystickDescriptorCache[i].name[0] = '\0'; } // Register that semaphore with the network communications task. // It will signal when new packet data is available. @@ -100,13 +116,21 @@ DriverStation& DriverStation::GetInstance() { * the data will be copied from the DS polling loop. */ void DriverStation::GetData() { - // Get the status of all of the joysticks + // Get the status of all of the joysticks, and save to the cache for (uint8_t stick = 0; stick < kJoystickPorts; stick++) { - HALGetJoystickAxes(stick, &m_joystickAxes[stick]); - HALGetJoystickPOVs(stick, &m_joystickPOVs[stick]); - HALGetJoystickButtons(stick, &m_joystickButtons[stick]); - HALGetJoystickDescriptor(stick, &m_joystickDescriptor[stick]); + HALGetJoystickAxes(stick, &m_joystickAxesCache[stick]); + HALGetJoystickPOVs(stick, &m_joystickPOVsCache[stick]); + HALGetJoystickButtons(stick, &m_joystickButtonsCache[stick]); + HALGetJoystickDescriptor(stick, &m_joystickDescriptorCache[stick]); } + // Obtain a write lock on the data, swap the cached data into the + // main data arrays + std::lock_guard lock(m_joystickDataMutex); + m_joystickAxes.swap(m_joystickAxesCache); + m_joystickPOVs.swap(m_joystickPOVsCache); + m_joystickButtons.swap(m_joystickButtonsCache); + m_joystickDescriptor.swap(m_joystickDescriptorCache); + m_newControlData.give(); } @@ -159,9 +183,8 @@ int DriverStation::GetStickAxisCount(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return 0; } - HALJoystickAxes joystickAxes; - HALGetJoystickAxes(stick, &joystickAxes); - return joystickAxes.count; + std::lock_guard lock(m_joystickDataMutex); + return m_joystickAxes[stick].count; } /** @@ -174,6 +197,7 @@ std::string DriverStation::GetJoystickName(uint32_t stick) const { if (stick >= kJoystickPorts) { wpi_setWPIError(BadJoystickIndex); } + std::lock_guard lock(m_joystickDataMutex); std::string retVal(m_joystickDescriptor[stick].name); return retVal; } @@ -189,6 +213,7 @@ int DriverStation::GetJoystickType(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return -1; } + std::lock_guard lock(m_joystickDataMutex); return (int)m_joystickDescriptor[stick].type; } @@ -203,6 +228,7 @@ bool DriverStation::GetJoystickIsXbox(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return false; } + std::lock_guard lock(m_joystickDataMutex); return (bool)m_joystickDescriptor[stick].isXbox; } @@ -217,6 +243,7 @@ int DriverStation::GetJoystickAxisType(uint32_t stick, uint8_t axis) const { wpi_setWPIError(BadJoystickIndex); return -1; } + std::lock_guard lock(m_joystickDataMutex); return m_joystickDescriptor[stick].axisTypes[axis]; } @@ -231,9 +258,8 @@ int DriverStation::GetStickPOVCount(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return 0; } - HALJoystickPOVs joystickPOVs; - HALGetJoystickPOVs(stick, &joystickPOVs); - return joystickPOVs.count; + std::lock_guard lock(m_joystickDataMutex); + return m_joystickPOVs[stick].count; } /** @@ -247,9 +273,8 @@ int DriverStation::GetStickButtonCount(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return 0; } - HALJoystickButtons joystickButtons; - HALGetJoystickButtons(stick, &joystickButtons); - return joystickButtons.count; + std::lock_guard lock(m_joystickDataMutex); + return m_joystickButtons[stick].count; } /** @@ -266,8 +291,11 @@ float DriverStation::GetStickAxis(uint32_t stick, uint32_t axis) { wpi_setWPIError(BadJoystickIndex); return 0; } - + std::unique_lock lock(m_joystickDataMutex); if (axis >= m_joystickAxes[stick].count) { + // Unlock early so error printing isn't locked. + m_joystickDataMutex.unlock(); + lock.release(); if (axis >= kMaxJoystickAxes) wpi_setWPIError(BadJoystickAxis); else @@ -295,8 +323,10 @@ int DriverStation::GetStickPOV(uint32_t stick, uint32_t pov) { wpi_setWPIError(BadJoystickIndex); return -1; } - + std::unique_lock lock(m_joystickDataMutex); if (pov >= m_joystickPOVs[stick].count) { + // Unlock early so error printing isn't locked. + lock.unlock(); if (pov >= kMaxJoystickPOVs) wpi_setWPIError(BadJoystickAxis); else @@ -319,7 +349,7 @@ uint32_t DriverStation::GetStickButtons(uint32_t stick) const { wpi_setWPIError(BadJoystickIndex); return 0; } - + std::lock_guard lock(m_joystickDataMutex); return m_joystickButtons[stick].buttons; } @@ -335,17 +365,21 @@ bool DriverStation::GetStickButton(uint32_t stick, uint8_t button) { wpi_setWPIError(BadJoystickIndex); return false; } - - if (button > m_joystickButtons[stick].count) { - ReportJoystickUnpluggedWarning( - "Joystick Button missing, check if all controllers are plugged in"); - return false; - } if (button == 0) { ReportJoystickUnpluggedError( - "Button indexes begin at 1 in WPILib for C++ and Java"); + "ERROR: Button indexes begin at 1 in WPILib for C++ and Java"); return false; } + std::unique_lock lock(m_joystickDataMutex); + if (button > m_joystickButtons[stick].count) { + // Unlock early so error printing isn't locked. + lock.unlock(); + ReportJoystickUnpluggedWarning( + "Joystick Button missing, check if all controllers are " + "plugged in"); + return false; + } + return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0; } diff --git a/wpilibj/src/athena/cpp/lib/FRCNetworkCommunicationsLibrary.cpp b/wpilibj/src/athena/cpp/lib/FRCNetworkCommunicationsLibrary.cpp index 6e3bb0cf6f..4c403f1a67 100644 --- a/wpilibj/src/athena/cpp/lib/FRCNetworkCommunicationsLibrary.cpp +++ b/wpilibj/src/athena/cpp/lib/FRCNetworkCommunicationsLibrary.cpp @@ -142,37 +142,47 @@ Java_edu_wpi_first_wpilibj_communication_FRCNetworkCommunicationsLibrary_NativeH /* * Class: edu_wpi_first_wpilibj_communication_FRCNetworkCommunicationsLibrary * Method: HALGetJoystickAxes - * Signature: (B)[S + * Signature: (B[S)B */ -JNIEXPORT jshortArray JNICALL +JNIEXPORT jbyte JNICALL Java_edu_wpi_first_wpilibj_communication_FRCNetworkCommunicationsLibrary_HALGetJoystickAxes( - JNIEnv *env, jclass, jbyte joystickNum) { + JNIEnv * env, jclass, jbyte joystickNum, jshortArray axesArray) { NETCOMM_LOG(logDEBUG) << "Calling HALJoystickAxes"; HALJoystickAxes axes; HALGetJoystickAxes(joystickNum, &axes); - jshortArray axesArray = env->NewShortArray(axes.count); + jsize javaSize = env->GetArrayLength(axesArray); + if (axes.count > javaSize) + { + ThrowIllegalArgumentException(env, "Native array size larger then passed in java array size"); + } + env->SetShortArrayRegion(axesArray, 0, axes.count, axes.axes); - return axesArray; + return axes.count; } /* * Class: edu_wpi_first_wpilibj_communication_FRCNetworkCommunicationsLibrary * Method: HALGetJoystickPOVs - * Signature: (B)[S + * Signature: (B[S)B */ -JNIEXPORT jshortArray JNICALL +JNIEXPORT jbyte JNICALL Java_edu_wpi_first_wpilibj_communication_FRCNetworkCommunicationsLibrary_HALGetJoystickPOVs( - JNIEnv *env, jclass, jbyte joystickNum) { + JNIEnv * env, jclass, jbyte joystickNum, jshortArray povsArray) { NETCOMM_LOG(logDEBUG) << "Calling HALJoystickPOVs"; HALJoystickPOVs povs; HALGetJoystickPOVs(joystickNum, &povs); - jshortArray povsArray = env->NewShortArray(povs.count); + jsize javaSize = env->GetArrayLength(povsArray); + if (povs.count > javaSize) + { + ThrowIllegalArgumentException(env, "Native array size larger then passed in java array size"); + } + env->SetShortArrayRegion(povsArray, 0, povs.count, povs.povs); - return povsArray; + return povs.count; } /* diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/DriverStation.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/DriverStation.java index 7f95b5d738..530066c4a5 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/DriverStation.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/DriverStation.java @@ -30,6 +30,24 @@ public class DriverStation implements RobotState.Interface { public byte m_count; } + private class HALJoystickAxes { + public short[] m_axes; + public byte m_count; + + public HALJoystickAxes(int count) { + m_axes = new short[count]; + } + } + + private class HALJoystickPOVs { + public short[] m_povs; + public byte m_count; + + public HALJoystickPOVs(int count) { + m_povs = new short[count]; + } + } + /** * The robot alliance that the robot is a part of. */ @@ -55,11 +73,16 @@ public class DriverStation implements RobotState.Interface { private static DriverStation instance = new DriverStation(); - private short[][] m_joystickAxes = - new short[kJoystickPorts][FRCNetworkCommunicationsLibrary.kMaxJoystickAxes]; - private short[][] m_joystickPOVs = - new short[kJoystickPorts][FRCNetworkCommunicationsLibrary.kMaxJoystickPOVs]; + private HALJoystickAxes[] m_joystickAxes = new HALJoystickAxes[kJoystickPorts]; + private HALJoystickPOVs[] m_joystickPOVs = new HALJoystickPOVs[kJoystickPorts]; private HALJoystickButtons[] m_joystickButtons = new HALJoystickButtons[kJoystickPorts]; + + private HALJoystickAxes[] m_joystickAxesCache = new HALJoystickAxes[kJoystickPorts]; + private HALJoystickPOVs[] m_joystickPOVsCache = new HALJoystickPOVs[kJoystickPorts]; + private HALJoystickButtons[] m_joystickButtonsCache = new HALJoystickButtons[kJoystickPorts]; + // preallocated byte buffer for button count + private ByteBuffer m_buttonCountBuffer = ByteBuffer.allocateDirect(1); + private int[] m_joystickIsXbox = new int[kJoystickPorts]; private int[] m_joystickType = new int[kJoystickPorts]; private String[] m_joystickName = new String[kJoystickPorts]; @@ -68,7 +91,10 @@ public class DriverStation implements RobotState.Interface { private Thread m_thread; private final Object m_dataSem; + private final Object m_newControlDataMutex; + private final Object m_joystickMutex; private volatile boolean m_threadKeepAlive = true; + private boolean m_userInDisabled = false; private boolean m_userInAutonomous = false; private boolean m_userInTeleop = false; @@ -94,8 +120,18 @@ public class DriverStation implements RobotState.Interface { */ protected DriverStation() { m_dataSem = new Object(); + m_joystickMutex = new Object(); + m_newControlDataMutex = new Object(); for (int i = 0; i < kJoystickPorts; i++) { m_joystickButtons[i] = new HALJoystickButtons(); + m_joystickAxes[i] = new HALJoystickAxes(FRCNetworkCommunicationsLibrary.kMaxJoystickAxes); + m_joystickPOVs[i] = new HALJoystickPOVs(FRCNetworkCommunicationsLibrary.kMaxJoystickPOVs); + + m_joystickButtonsCache[i] = new HALJoystickButtons(); + m_joystickAxesCache[i] = + new HALJoystickAxes(FRCNetworkCommunicationsLibrary.kMaxJoystickAxes); + m_joystickPOVsCache[i] = + new HALJoystickPOVs(FRCNetworkCommunicationsLibrary.kMaxJoystickPOVs); } m_packetDataAvailableMutex = HALUtil.initializeMutexNormal(); @@ -122,9 +158,7 @@ public class DriverStation implements RobotState.Interface { int safetyCounter = 0; while (m_threadKeepAlive) { HALUtil.takeMultiWait(m_packetDataAvailableSem, m_packetDataAvailableMutex); - synchronized (this) { - getData(); - } + getData(); synchronized (m_dataSem) { m_dataSem.notifyAll(); } @@ -174,19 +208,38 @@ public class DriverStation implements RobotState.Interface { * Copy data from the DS task for the user. If no new data exists, it will just be returned, * otherwise the data will be copied from the DS polling loop. */ - protected synchronized void getData() { - + protected void getData() { // Get the status of all of the joysticks for (byte stick = 0; stick < kJoystickPorts; stick++) { - m_joystickAxes[stick] = FRCNetworkCommunicationsLibrary.HALGetJoystickAxes(stick); - m_joystickPOVs[stick] = FRCNetworkCommunicationsLibrary.HALGetJoystickPOVs(stick); - ByteBuffer countBuffer = ByteBuffer.allocateDirect(1); - m_joystickButtons[stick].m_buttons = - FRCNetworkCommunicationsLibrary.HALGetJoystickButtons(stick, countBuffer); - m_joystickButtons[stick].m_count = countBuffer.get(); + m_joystickAxesCache[stick].m_count = + FRCNetworkCommunicationsLibrary.HALGetJoystickAxes(stick, + m_joystickAxesCache[stick].m_axes); + m_joystickPOVsCache[stick].m_count = + FRCNetworkCommunicationsLibrary.HALGetJoystickPOVs(stick, + m_joystickPOVsCache[stick].m_povs); + m_joystickButtonsCache[stick].m_buttons = + FRCNetworkCommunicationsLibrary.HALGetJoystickButtons(stick, m_buttonCountBuffer); + m_joystickButtonsCache[stick].m_count = m_buttonCountBuffer.get(0); } + // lock joystick mutex to swap cache data + synchronized (m_joystickMutex) { + // move cache to actual data + HALJoystickAxes[] currentAxes = m_joystickAxes; + m_joystickAxes = m_joystickAxesCache; + m_joystickAxesCache = currentAxes; - m_newControlData = true; + HALJoystickButtons[] currentButtons = m_joystickButtons; + m_joystickButtons = m_joystickButtonsCache; + m_joystickButtonsCache = currentButtons; + + HALJoystickPOVs[] currentPOVs = m_joystickPOVs; + m_joystickPOVs = m_joystickPOVsCache; + m_joystickPOVsCache = currentPOVs; + } + //Lock new control data mutex and set new control data. + synchronized (m_newControlDataMutex) { + m_newControlData = true; + } } /** @@ -230,28 +283,30 @@ public class DriverStation implements RobotState.Interface { * @param axis The analog axis value to read from the joystick. * @return The value of the axis on the joystick. */ - public synchronized double getStickAxis(int stick, int axis) { + public double getStickAxis(int stick, int axis) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - if (axis < 0 || axis >= FRCNetworkCommunicationsLibrary.kMaxJoystickAxes) { throw new RuntimeException("Joystick axis is out of range"); } - - if (axis >= m_joystickAxes[stick].length) { + + boolean error = false; + double retVal = 0.0; + synchronized (m_joystickMutex) { + if (axis >= m_joystickAxes[stick].m_count) { + // set error + error = true; + retVal = 0.0; + } else { + retVal = m_joystickAxes[stick].m_axes[axis]; + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick axis " + axis + " on port " + stick + " not available, check if controller is plugged in"); - return 0.0; - } - - byte value = (byte) m_joystickAxes[stick][axis]; - - if (value < 0) { - return value / 128.0; - } else { - return value / 127.0; } + return retVal; } /** @@ -260,13 +315,13 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return The number of axes on the indicated joystick */ - public synchronized int getStickAxisCount(int stick) { - + public int getStickAxisCount(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - - return m_joystickAxes[stick].length; + synchronized (m_joystickMutex) { + return m_joystickAxes[stick].m_count; + } } /** @@ -274,22 +329,28 @@ public class DriverStation implements RobotState.Interface { * * @return the angle of the POV in degrees, or -1 if the POV is not pressed. */ - public synchronized int getStickPOV(int stick, int pov) { + public int getStickPOV(int stick, int pov) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - if (pov < 0 || pov >= FRCNetworkCommunicationsLibrary.kMaxJoystickPOVs) { throw new RuntimeException("Joystick POV is out of range"); } - - if (pov >= m_joystickPOVs[stick].length) { + boolean error = false; + int retVal = -1; + synchronized (m_joystickMutex) { + if (pov >= m_joystickPOVs[stick].m_count) { + error = true; + retVal = -1; + } else { + retVal = m_joystickPOVs[stick].m_povs[pov]; + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick POV " + pov + " on port " + stick + " not available, check if controller is plugged in"); - return -1; } - - return m_joystickPOVs[stick][pov]; + return retVal; } /** @@ -298,13 +359,13 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return The number of POVs on the indicated joystick */ - public synchronized int getStickPOVCount(int stick) { - + public int getStickPOVCount(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - - return m_joystickPOVs[stick].length; + synchronized (m_joystickMutex) { + return m_joystickPOVs[stick].m_count; + } } /** @@ -313,12 +374,13 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick to read. * @return The state of the buttons on the joystick. */ - public synchronized int getStickButtons(final int stick) { + public int getStickButtons(final int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-3"); } - - return m_joystickButtons[stick].m_buttons; + synchronized (m_joystickMutex) { + return m_joystickButtons[stick].m_buttons; + } } /** @@ -328,22 +390,29 @@ public class DriverStation implements RobotState.Interface { * @param button The button index, beginning at 1. * @return The state of the joystick button. */ - public synchronized boolean getStickButton(final int stick, byte button) { + public boolean getStickButton(final int stick, byte button) { + if (button <= 0) { + reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n"); + return false; + } if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-3"); } - - - if (button > m_joystickButtons[stick].m_count) { + boolean error = false; + boolean retVal = false; + synchronized (m_joystickMutex) { + if (button > m_joystickButtons[stick].m_count) { + error = true; + retVal = false; + } else { + retVal = ((0x1 << (button - 1)) & m_joystickButtons[stick].m_buttons) != 0; + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick Button " + button + " on port " + stick + " not available, check if controller is plugged in"); - return false; } - if (button <= 0) { - reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java"); - return false; - } - return ((0x1 << (button - 1)) & m_joystickButtons[stick].m_buttons) != 0; + return retVal; } /** @@ -352,14 +421,13 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return The number of buttons on the indicated joystick */ - public synchronized int getStickButtonCount(int stick) { - + public int getStickButtonCount(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - - - return m_joystickButtons[stick].m_count; + synchronized (m_joystickMutex) { + return m_joystickButtons[stick].m_count; + } } /** @@ -368,21 +436,25 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return A boolean that returns the value of isXbox */ - public synchronized boolean getJoystickIsXbox(int stick) { - + public boolean getJoystickIsXbox(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - // TODO: Remove this when calling for descriptor on empty stick no longer - // crashes - if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].length) { + boolean error = false; + boolean retVal = false; + synchronized (m_joystickMutex) { + // TODO: Remove this when calling for descriptor on empty stick no longer + // crashes + if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) { + error = true; + retVal = false; + } else if (FRCNetworkCommunicationsLibrary.HALGetJoystickIsXbox((byte) stick) == 1) { + retVal = true; + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick on port " + stick + " not available, check if controller is plugged in"); - return false; - } - boolean retVal = false; - if (FRCNetworkCommunicationsLibrary.HALGetJoystickIsXbox((byte) stick) == 1) { - retVal = true; } return retVal; } @@ -393,19 +465,27 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return The value of type */ - public synchronized int getJoystickType(int stick) { - + public int getJoystickType(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - // TODO: Remove this when calling for descriptor on empty stick no longer - // crashes - if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].length) { + boolean error = false; + int retVal = -1; + synchronized (m_joystickMutex) { + // TODO: Remove this when calling for descriptor on empty stick no longer + // crashes + if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) { + error = true; + retVal = -1; + } else { + retVal = FRCNetworkCommunicationsLibrary.HALGetJoystickType((byte) stick); + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick on port " + stick + " not available, check if controller is plugged in"); - return -1; } - return FRCNetworkCommunicationsLibrary.HALGetJoystickType((byte) stick); + return retVal; } /** @@ -414,19 +494,27 @@ public class DriverStation implements RobotState.Interface { * @param stick The joystick port number * @return The value of name */ - public synchronized String getJoystickName(int stick) { - + public String getJoystickName(int stick) { if (stick < 0 || stick >= kJoystickPorts) { throw new RuntimeException("Joystick index is out of range, should be 0-5"); } - // TODO: Remove this when calling for descriptor on empty stick no longer - // crashes - if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].length) { + boolean error = false; + String retVal = ""; + synchronized (m_joystickMutex) { + // TODO: Remove this when calling for descriptor on empty stick no longer + // crashes + if (1 > m_joystickButtons[stick].m_count && 1 > m_joystickAxes[stick].m_count) { + error = true; + retVal = ""; + } else { + retVal = FRCNetworkCommunicationsLibrary.HALGetJoystickName((byte) stick); + } + } + if (error) { reportJoystickUnpluggedWarning("Joystick on port " + stick + " not available, check if controller is plugged in"); - return ""; } - return FRCNetworkCommunicationsLibrary.HALGetJoystickName((byte) stick); + return retVal; } /** @@ -505,10 +593,12 @@ public class DriverStation implements RobotState.Interface { * * @return True if the control data has been updated since the last call. */ - public synchronized boolean isNewControlData() { - boolean result = m_newControlData; - m_newControlData = false; - return result; + public boolean isNewControlData() { + synchronized (m_newControlDataMutex) { + boolean result = m_newControlData; + m_newControlData = false; + return result; + } } /** diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary.java index c5e88a1d78..cb821efef8 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary.java @@ -224,10 +224,10 @@ public class FRCNetworkCommunicationsLibrary extends JNIWrapper { public static int kMaxJoystickAxes = 12; public static int kMaxJoystickPOVs = 12; + + public static native byte HALGetJoystickAxes(byte joystickNum, short[] axesArray); - public static native short[] HALGetJoystickAxes(byte joystickNum); - - public static native short[] HALGetJoystickPOVs(byte joystickNum); + public static native byte HALGetJoystickPOVs(byte joystickNum, short[] povsArray); public static native int HALGetJoystickButtons(byte joystickNum, ByteBuffer count);