50public final class DriverStationBackend {
54 private static final long[] m_metadataCache =
new long[7];
55 private static final float[] m_touchpadFingersCache =
new float[8];
57 private static int availableToCount(
long available) {
66 while ((available & 0x1) != 0) {
73 private static final class HALJoystickTouchpadFinger {
79 private static class HALJoystickTouchpad {
80 final HALJoystickTouchpadFinger[] m_fingers =
84 HALJoystickTouchpad() {
85 for (
int i = 0; i < m_fingers.length; i++) {
86 m_fingers[i] =
new HALJoystickTouchpadFinger();
91 private static class HALJoystickTouchpads {
92 final HALJoystickTouchpad[] m_touchpads =
93 new HALJoystickTouchpad[DriverStationJNI.MAX_JOYSTICK_TOUCHPADS];
96 HALJoystickTouchpads() {
97 for (
int i = 0; i < m_touchpads.length; i++) {
98 m_touchpads[i] =
new HALJoystickTouchpad();
103 private static final class HALJoystickButtons {
108 private static class HALJoystickAxes {
109 final float[] m_axes;
112 HALJoystickAxes(
int count) {
113 m_axes =
new float[count];
117 private static class HALJoystickAxesRaw {
118 final short[] m_axes;
120 @SuppressWarnings(
"unused")
123 HALJoystickAxesRaw(
int count) {
124 m_axes =
new short[count];
128 private static class HALJoystickPOVs {
132 HALJoystickPOVs(
int count) {
133 m_povs =
new byte[count];
134 for (
int i = 0; i < count; i++) {
140 private static String opModeToString(
long id) {
144 m_opModesMutex.lock();
146 OpModeOption option = m_opModes.get(
id);
147 if (option !=
null) {
151 m_opModesMutex.unlock();
153 return "<" +
id +
">";
156 private static class MatchDataSender {
157 private static final String SMART_DASHBOARD_TYPE =
"DriverStation";
159 final StringPublisher gameData;
160 final StringPublisher eventName;
161 final IntegerPublisher matchNumber;
162 final IntegerPublisher replayNumber;
163 final IntegerPublisher matchType;
164 final BooleanPublisher alliance;
165 final IntegerPublisher station;
166 final IntegerPublisher allianceStation;
167 final StructPublisher<ControlWord> controlWord;
168 final StringPublisher opMode;
169 String oldEventName =
"";
170 String oldGameData =
"";
174 boolean oldIsRedAlliance =
true;
175 int oldStationNumber = 1;
176 int oldAllianceStation = 0;
177 final ControlWord oldControlWord =
new ControlWord();
178 final ControlWord currentControlWord =
new ControlWord();
181 var table = NetworkTableInstance.getDefault().getTable(
"DriverStation");
183 .getStringTopic(
".type")
185 StringTopic.TYPE_STRING,
"{\"SmartDashboard\":\"" + SMART_DASHBOARD_TYPE +
"\"}")
186 .set(SMART_DASHBOARD_TYPE);
187 gameData = table.getStringTopic(
"GameData").publish();
189 eventName = table.getStringTopic(
"EventName").publish();
191 matchNumber = table.getIntegerTopic(
"MatchNumber").publish();
193 replayNumber = table.getIntegerTopic(
"ReplayNumber").publish();
195 matchType = table.getIntegerTopic(
"MatchType").publish();
197 alliance = table.getBooleanTopic(
"IsRedAlliance").publish();
199 station = table.getIntegerTopic(
"StationNumber").publish();
201 allianceStation = table.getIntegerTopic(
"AllianceStationID").publish();
202 allianceStation.set(0);
203 controlWord = table.getStructTopic(
"ControlWord", ControlWord.struct).publish();
204 controlWord.set(oldControlWord);
205 opMode = table.getStringTopic(
"OpMode").publish();
209 @SuppressWarnings(
"VariableDeclarationUsageDistance")
210 private
void sendMatchData() {
211 AllianceStationID allianceID = DriverStationJNI.getAllianceStation();
212 final int stationNumber =
213 switch (allianceID) {
214 case BLUE_1, RED_1 -> 1;
215 case BLUE_2, RED_2 -> 2;
216 case BLUE_3, RED_3 -> 3;
219 final boolean isRedAlliance =
220 switch (allianceID) {
221 case BLUE_1, BLUE_2, BLUE_3 ->
false;
222 case RED_1, RED_2, RED_3, UNKNOWN ->
true;
225 String currentEventName;
226 String currentGameData;
227 int currentMatchNumber;
228 int currentReplayNumber;
229 int currentMatchType;
230 m_cacheDataMutex.lock();
232 currentEventName = DriverStationBackend.m_matchInfo.eventName;
233 currentGameData = DriverStationBackend.m_gameData;
234 currentMatchNumber = DriverStationBackend.m_matchInfo.matchNumber;
235 currentReplayNumber = DriverStationBackend.m_matchInfo.replayNumber;
236 currentMatchType = DriverStationBackend.m_matchInfo.matchType;
238 m_cacheDataMutex.unlock();
240 DriverStationJNI.getControlWord(currentControlWord);
242 if (oldIsRedAlliance != isRedAlliance) {
243 alliance.set(isRedAlliance);
244 oldIsRedAlliance = isRedAlliance;
246 if (oldStationNumber != stationNumber) {
247 station.set(stationNumber);
248 oldStationNumber = stationNumber;
250 if (oldAllianceStation != allianceID.ordinal()) {
251 allianceStation.set(allianceID.ordinal());
252 oldAllianceStation = allianceID.ordinal();
254 if (!oldEventName.equals(currentEventName)) {
255 eventName.set(currentEventName);
256 oldEventName = currentEventName;
258 if (!oldGameData.equals(currentGameData)) {
259 gameData.set(currentGameData);
260 oldGameData = currentGameData;
262 if (currentMatchNumber != oldMatchNumber) {
263 matchNumber.set(currentMatchNumber);
264 oldMatchNumber = currentMatchNumber;
266 if (currentReplayNumber != oldReplayNumber) {
267 replayNumber.set(currentReplayNumber);
268 oldReplayNumber = currentReplayNumber;
270 if (currentMatchType != oldMatchType) {
271 matchType.set(currentMatchType);
272 oldMatchType = currentMatchType;
274 if (!currentControlWord.equals(oldControlWord)) {
275 long currentOpModeId = currentControlWord.getOpModeId();
276 if (currentOpModeId != oldControlWord.getOpModeId()) {
277 opMode.set(opModeToString(currentOpModeId));
279 controlWord.set(currentControlWord);
280 oldControlWord.update(currentControlWord);
285 private static class JoystickLogSender {
286 JoystickLogSender(DataLog log,
int stick,
long timestamp) {
289 m_logButtons =
new BooleanArrayLogEntry(log,
"DS:joystick" + stick +
"/buttons", timestamp);
290 m_logAxes =
new FloatArrayLogEntry(log,
"DS:joystick" + stick +
"/axes", timestamp);
291 m_logPOVs =
new IntegerArrayLogEntry(log,
"DS:joystick" + stick +
"/povs", timestamp);
293 appendButtons(m_joystickButtons[m_stick], timestamp);
294 appendAxes(m_joystickAxes[m_stick], timestamp);
295 appendPOVs(m_joystickPOVs[m_stick], timestamp);
298 public void send(
long timestamp) {
299 HALJoystickButtons buttons = m_joystickButtons[m_stick];
300 if (buttons.m_available != m_prevButtons.m_available
301 || buttons.m_buttons != m_prevButtons.m_buttons) {
302 appendButtons(buttons, timestamp);
305 HALJoystickAxes axes = m_joystickAxes[m_stick];
306 int available = axes.m_available;
307 boolean needToLog =
false;
308 if (available != m_prevAxes.m_available) {
311 for (
int i = 0; i < m_prevAxes.m_axes.length; i++) {
312 if (axes.m_axes[i] != m_prevAxes.m_axes[i]) {
319 appendAxes(axes, timestamp);
322 HALJoystickPOVs povs = m_joystickPOVs[m_stick];
323 available = m_joystickPOVs[m_stick].m_available;
325 if (available != m_prevPOVs.m_available) {
328 for (
int i = 0; i < m_prevPOVs.m_povs.length; i++) {
329 if (povs.m_povs[i] != m_prevPOVs.m_povs[i]) {
336 appendPOVs(povs, timestamp);
340 void appendButtons(HALJoystickButtons buttons,
long timestamp) {
341 int count = availableToCount(buttons.m_available);
342 if (m_sizedButtons ==
null || m_sizedButtons.length != count) {
343 m_sizedButtons =
new boolean[count];
345 long buttonsValue = buttons.m_buttons;
346 for (
int i = 0; i < count; i++) {
347 m_sizedButtons[i] = (buttonsValue & (1L << i)) != 0;
349 m_logButtons.append(m_sizedButtons, timestamp);
350 m_prevButtons.m_available = buttons.m_available;
351 m_prevButtons.m_buttons = buttons.m_buttons;
354 void appendAxes(HALJoystickAxes axes,
long timestamp) {
355 int count = availableToCount(axes.m_available);
356 if (m_sizedAxes ==
null || m_sizedAxes.length != count) {
357 m_sizedAxes =
new float[count];
359 System.arraycopy(axes.m_axes, 0, m_sizedAxes, 0, count);
360 m_logAxes.append(m_sizedAxes, timestamp);
361 m_prevAxes.m_available = axes.m_available;
362 System.arraycopy(axes.m_axes, 0, m_prevAxes.m_axes, 0, count);
365 void appendPOVs(HALJoystickPOVs povs,
long timestamp) {
366 int count = availableToCount(povs.m_available);
367 if (m_sizedPOVs ==
null || m_sizedPOVs.length != count) {
368 m_sizedPOVs =
new long[count];
370 for (
int i = 0; i < count; i++) {
371 m_sizedPOVs[i] = povs.m_povs[i];
373 m_logPOVs.append(m_sizedPOVs, timestamp);
374 m_prevPOVs.m_available = povs.m_available;
375 System.arraycopy(povs.m_povs, 0, m_prevPOVs.m_povs, 0, count);
379 boolean[] m_sizedButtons;
382 final HALJoystickButtons m_prevButtons =
new HALJoystickButtons();
383 final HALJoystickAxes m_prevAxes =
new HALJoystickAxes(DriverStationJNI.MAX_JOYSTICK_AXES);
384 final HALJoystickPOVs m_prevPOVs =
new HALJoystickPOVs(DriverStationJNI.MAX_JOYSTICK_POVS);
385 final BooleanArrayLogEntry m_logButtons;
386 final FloatArrayLogEntry m_logAxes;
387 final IntegerArrayLogEntry m_logPOVs;
390 private static class DataLogSender {
391 DataLogSender(DataLog log,
boolean logJoysticks,
long timestamp) {
393 StructLogEntry.create(log,
"DS:controlWord", ControlWord.struct, timestamp);
396 m_logControlWord.append(m_controlWordCache, timestamp);
397 m_oldControlWord.update(m_controlWordCache);
400 m_logOpMode =
new StringLogEntry(log,
"DS:opMode", timestamp);
401 m_logOpMode.append(m_opModeCache, timestamp);
404 m_joysticks =
new JoystickLogSender[JOYSTICK_PORTS];
405 for (
int i = 0; i < JOYSTICK_PORTS; i++) {
406 m_joysticks[i] =
new JoystickLogSender(log, i, timestamp);
409 m_joysticks =
new JoystickLogSender[0];
413 public void send(
long timestamp) {
415 if (!m_controlWordCache.equals(m_oldControlWord)) {
417 long opModeId = m_controlWordCache.getOpModeId();
418 if (opModeId != m_oldControlWord.getOpModeId()) {
419 m_logOpMode.append(m_opModeCache, timestamp);
422 m_logControlWord.append(m_controlWordCache, timestamp);
423 m_oldControlWord.update(m_controlWordCache);
427 for (JoystickLogSender joystick : m_joysticks) {
428 joystick.send(timestamp);
432 final ControlWord m_oldControlWord =
new ControlWord();
433 final StructLogEntry<ControlWord> m_logControlWord;
434 final StringLogEntry m_logOpMode;
436 final JoystickLogSender[] m_joysticks;
440 private static HALJoystickAxes[] m_joystickAxes =
new HALJoystickAxes[JOYSTICK_PORTS];
441 private static HALJoystickAxesRaw[] m_joystickAxesRaw =
new HALJoystickAxesRaw[JOYSTICK_PORTS];
442 private static HALJoystickPOVs[] m_joystickPOVs =
new HALJoystickPOVs[JOYSTICK_PORTS];
443 private static HALJoystickButtons[] m_joystickButtons =
new HALJoystickButtons[JOYSTICK_PORTS];
444 private static HALJoystickTouchpads[] m_joystickTouchpads =
445 new HALJoystickTouchpads[JOYSTICK_PORTS];
447 private static String m_gameData =
"";
449 private static String m_opMode =
"";
453 private static HALJoystickAxes[] m_joystickAxesCache =
new HALJoystickAxes[JOYSTICK_PORTS];
454 private static HALJoystickAxesRaw[] m_joystickAxesRawCache =
455 new HALJoystickAxesRaw[JOYSTICK_PORTS];
456 private static HALJoystickPOVs[] m_joystickPOVsCache =
new HALJoystickPOVs[JOYSTICK_PORTS];
457 private static HALJoystickButtons[] m_joystickButtonsCache =
458 new HALJoystickButtons[JOYSTICK_PORTS];
459 private static HALJoystickTouchpads[] m_joystickTouchpadsCache =
460 new HALJoystickTouchpads[JOYSTICK_PORTS];
462 private static String m_gameDataCache =
"";
465 private static String m_opModeCache =
"";
468 private static long[] m_joystickButtonsPressed =
new long[JOYSTICK_PORTS];
469 private static long[] m_joystickButtonsReleased =
new long[JOYSTICK_PORTS];
471 private static final MatchDataSender m_matchDataSender;
472 private static DataLogSender m_dataLogSender;
474 private static final ReentrantLock m_cacheDataMutex =
new ReentrantLock();
476 private enum JoystickResourceAlert {
477 BUTTON(
"ButtonUnavailable",
"Button"),
478 AXIS(
"AxisUnavailable",
"axis"),
479 POV(
"POVUnavailable",
"POV");
481 final String idSuffix;
484 JoystickResourceAlert(String idSuffix, String label) {
485 this.idSuffix = idSuffix;
489 boolean isAvailable(
int stick,
int resource) {
490 return switch (
this) {
497 String getText(
int stick,
int resource) {
498 return "Joystick " + label +
" " + resource +
" on port " + stick +
" not available";
505 private static final class JoystickAlertState {
510 private static final class JoystickAlerts {
512 final String connectionText;
513 final JoystickAlertState connectionAlert =
new JoystickAlertState();
514 final JoystickAlertState[] resourceAlerts =
515 new JoystickAlertState[JOYSTICK_RESOURCE_ALERTS.length];
516 final JoystickAlertState touchpadFingerAlert =
new JoystickAlertState();
517 final int[] resourceAlertValues =
new int[JOYSTICK_RESOURCE_ALERTS.length];
518 int touchpadFingerAlertTouchpad;
519 int touchpadFingerAlertFinger;
522 JoystickAlerts(
int stick) {
525 "Joystick on port " + stick +
" not available, check if controller is plugged in";
526 for (
int i = 0; i < resourceAlerts.length; i++) {
527 resourceAlerts[i] =
new JoystickAlertState();
532 boolean initializeAlerts() {
535 Alert newConnectionAlert =
null;
536 Alert[] newResourceAlerts =
new Alert[JOYSTICK_RESOURCE_ALERTS.length];
537 Alert newTouchpadFingerAlert =
null;
543 "joystick" + stick +
"Disconnected",
546 for (JoystickResourceAlert resourceAlert : JOYSTICK_RESOURCE_ALERTS) {
547 newResourceAlerts[resourceAlert.ordinal()] =
550 "joystick" + stick + resourceAlert.idSuffix,
554 newTouchpadFingerAlert =
557 "joystick" + stick +
"TouchpadFingerUnavailable",
560 }
catch (AlertException ex) {
561 closeAlert(newConnectionAlert);
562 for (Alert alert : newResourceAlerts) {
565 closeAlert(newTouchpadFingerAlert);
570 connectionAlert.alert = newConnectionAlert;
571 for (JoystickResourceAlert resourceAlert : JOYSTICK_RESOURCE_ALERTS) {
572 resourceAlerts[resourceAlert.ordinal()].alert = newResourceAlerts[resourceAlert.ordinal()];
574 touchpadFingerAlert.alert = newTouchpadFingerAlert;
580 closeAlert(connectionAlert);
581 for (JoystickAlertState alertState : resourceAlerts) {
582 closeAlert(alertState);
584 closeAlert(touchpadFingerAlert);
588 static void closeAlert(JoystickAlertState alertState) {
589 closeAlert(alertState.alert);
590 alertState.alert =
null;
591 alertState.active =
false;
594 static void closeAlert(Alert alert) {
601 }
catch (AlertException ex) {
606 boolean prepareForReport() {
607 if (isJoystickConnected(stick)) {
608 setAlert(connectionAlert,
false, connectionText,
true);
612 clearResourceAlerts();
613 setAlert(connectionAlert,
true, connectionText,
true);
618 if (!isJoystickConnected(stick)) {
619 clearResourceAlerts();
623 if (connectionAlert.active) {
624 setAlert(connectionAlert,
false, connectionText,
true);
627 for (JoystickResourceAlert resourceAlert : JOYSTICK_RESOURCE_ALERTS) {
628 refreshResourceAlert(resourceAlert);
631 if (touchpadFingerAlert.active
632 && getStickTouchpadFingerAvailable(
633 stick, touchpadFingerAlertTouchpad, touchpadFingerAlertFinger)) {
634 setAlert(touchpadFingerAlert,
false);
638 void clearAllAlerts() {
639 setAlert(connectionAlert,
false, connectionText,
true);
640 clearResourceAlerts();
643 void clearResourceAlerts() {
644 for (JoystickAlertState alertState : resourceAlerts) {
645 setAlert(alertState,
false);
647 setAlert(touchpadFingerAlert,
false);
650 void refreshResourceAlert(JoystickResourceAlert resourceAlert) {
651 int alertIndex = resourceAlert.ordinal();
652 JoystickAlertState alertState = resourceAlerts[alertIndex];
653 if (alertState.active && resourceAlert.isAvailable(stick, resourceAlertValues[alertIndex])) {
654 setAlert(alertState,
false);
658 void reportResourceWarning(JoystickResourceAlert resourceAlert,
int resource) {
659 int alertIndex = resourceAlert.ordinal();
660 resourceAlertValues[alertIndex] = resource;
661 setAlert(resourceAlerts[alertIndex],
true, resourceAlert.getText(stick, resource),
false);
664 void reportTouchpadFingerWarning(
int touchpad,
int finger) {
666 "Joystick touchpad finger "
673 touchpadFingerAlertTouchpad = touchpad;
674 touchpadFingerAlertFinger = finger;
675 setAlert(touchpadFingerAlert,
true, text,
false);
679 JoystickAlertState alertState,
boolean active, String text,
boolean verifyActive) {
680 if (alertState.alert ==
null) {
685 if (active && !text.isEmpty()) {
686 alertState.alert.setText(text);
688 alertState.alert.set(active);
689 return !active || !verifyActive || alertState.alert.get();
690 }
catch (AlertException ex) {
695 boolean setAlert(JoystickAlertState alertState,
boolean active) {
696 return setAlert(alertState, active,
"",
false);
700 JoystickAlertState alertState,
boolean active, String text,
boolean verifyActive) {
701 if (!active && !alertState.active) {
705 if (active && !initialized && !initializeAlerts()) {
709 if (!applyAlert(alertState, active, text, verifyActive)) {
711 alertState.active =
false;
714 if (!initializeAlerts()) {
717 if (!applyAlert(alertState, active, text, verifyActive)) {
721 alertState.active = active;
726 private static final ReentrantLock m_joystickAlertMutex =
new ReentrantLock();
727 private static boolean m_silenceJoystickAlerts;
728 private static final JoystickAlerts[] m_joystickAlerts =
new JoystickAlerts[JOYSTICK_PORTS];
730 private static volatile boolean m_userProgramStarted =
false;
731 private static final Map<Long, OpModeOption> m_opModes =
new HashMap<>();
732 private static final ReentrantLock m_opModesMutex =
new ReentrantLock();
745 for (
int i = 0; i < JOYSTICK_PORTS; i++) {
746 m_joystickButtons[i] =
new HALJoystickButtons();
750 m_joystickTouchpads[i] =
new HALJoystickTouchpads();
752 m_joystickButtonsCache[i] =
new HALJoystickButtons();
756 m_joystickTouchpadsCache[i] =
new HALJoystickTouchpads();
759 m_matchDataSender =
new MatchDataSender();
768 public static void reportError(String error,
boolean printTrace) {
769 reportErrorImpl(
true, 1, error, printTrace);
778 public static void reportError(String error, StackTraceElement[] stackTrace) {
779 reportErrorImpl(
true, 1, error, stackTrace);
789 reportErrorImpl(
false, 1, warning, printTrace);
798 public static void reportWarning(String warning, StackTraceElement[] stackTrace) {
799 reportErrorImpl(
false, 1, warning, stackTrace);
802 private static void reportErrorImpl(
boolean isError,
int code, String error,
boolean printTrace) {
803 reportErrorImpl(isError, code, error, printTrace, Thread.currentThread().getStackTrace(), 3);
806 private static void reportErrorImpl(
807 boolean isError,
int code, String error, StackTraceElement[] stackTrace) {
808 reportErrorImpl(isError, code, error,
true, stackTrace, 0);
811 private static void reportErrorImpl(
816 StackTraceElement[] stackTrace,
817 int stackTraceFirst) {
819 if (stackTrace.length >= stackTraceFirst + 1) {
820 locString = stackTrace[stackTraceFirst].toString();
824 StringBuilder traceString =
new StringBuilder();
826 boolean haveLoc =
false;
827 for (
int i = stackTraceFirst; i < stackTrace.length; i++) {
828 String loc = stackTrace[i].toString();
829 traceString.append(
"\tat ").append(loc).append(
'\n');
831 if (!haveLoc && !loc.startsWith(
"org.wpilib")) {
837 DriverStationJNI.sendError(isError, code, error, locString, traceString.toString(),
true);
846 public static void reportCrash(String error, StackTraceElement[] stackTrace) {
847 reportCrashImpl(error, stackTrace, 0);
850 private static void reportCrashImpl(
851 String error, StackTraceElement[] stackTrace,
int stackTraceFirst) {
853 if (stackTrace.length >= stackTraceFirst + 1) {
854 locString = stackTrace[stackTraceFirst].toString();
858 StringBuilder traceString =
new StringBuilder();
859 boolean haveLoc =
false;
860 for (
int i = stackTraceFirst; i < stackTrace.length; i++) {
861 String loc = stackTrace[i].toString();
862 traceString.append(
"\tat ").append(loc).append(
'\n');
864 if (!haveLoc && !loc.startsWith(
"org.wpilib")) {
869 DriverStationJNI.sendProgramCrash(error, locString, traceString.toString());
873 }
catch (InterruptedException e) {
874 Thread.currentThread().interrupt();
887 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
890 throw new IllegalArgumentException(
"Joystick Button is out of range");
893 long mask = 1L << button;
895 m_cacheDataMutex.lock();
897 if ((m_joystickButtons[stick].m_available & mask) != 0) {
898 return (m_joystickButtons[stick].m_buttons & mask) != 0;
901 m_cacheDataMutex.unlock();
917 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
920 throw new IllegalArgumentException(
"Joystick Button is out of range");
923 long mask = 1L << button;
925 m_cacheDataMutex.lock();
927 if ((m_joystickButtons[stick].m_available & mask) != 0) {
928 return Optional.of((m_joystickButtons[stick].m_buttons & mask) != 0);
931 m_cacheDataMutex.unlock();
933 return Optional.empty();
945 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
948 throw new IllegalArgumentException(
"Joystick Button is out of range");
951 long mask = 1L << button;
953 m_cacheDataMutex.lock();
955 if ((m_joystickButtons[stick].m_available & mask) != 0) {
957 if ((m_joystickButtonsPressed[stick] & mask) != 0) {
958 m_joystickButtonsPressed[stick] &= ~mask;
965 m_cacheDataMutex.unlock();
981 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
984 throw new IllegalArgumentException(
"Joystick Button is out of range");
987 long mask = 1L << button;
989 m_cacheDataMutex.lock();
991 if ((m_joystickButtons[stick].m_available & mask) != 0) {
993 if ((m_joystickButtonsReleased[stick] & mask) != 0) {
994 m_joystickButtonsReleased[stick] &= ~mask;
1001 m_cacheDataMutex.unlock();
1018 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1021 throw new IllegalArgumentException(
"Joystick axis is out of range");
1024 int mask = 1 << axis;
1026 m_cacheDataMutex.lock();
1028 if ((m_joystickAxes[stick].m_available & mask) != 0) {
1029 return m_joystickAxes[stick].m_axes[axis];
1032 m_cacheDataMutex.unlock();
1049 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1052 throw new IllegalArgumentException(
"Joystick touchpad is out of range");
1055 throw new IllegalArgumentException(
"Joystick touchpad finger is out of range");
1059 m_cacheDataMutex.lock();
1061 touchpadCount = m_joystickTouchpads[stick].m_count;
1062 if (touchpad < touchpadCount) {
1063 HALJoystickTouchpad tp = m_joystickTouchpads[stick].m_touchpads[touchpad];
1064 if (finger < tp.m_count) {
1066 tp.m_fingers[finger].m_down, tp.m_fingers[finger].m_x, tp.m_fingers[finger].m_y);
1070 m_cacheDataMutex.unlock();
1073 reportJoystickTouchpadFingerWarning(stick, touchpad, finger);
1087 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1090 throw new IllegalArgumentException(
"Joystick touchpad is out of range");
1093 throw new IllegalArgumentException(
"Joystick touchpad finger is out of range");
1097 m_cacheDataMutex.lock();
1099 touchpadCount = m_joystickTouchpads[stick].m_count;
1100 if (touchpad < touchpadCount) {
1101 HALJoystickTouchpad tp = m_joystickTouchpads[stick].m_touchpads[touchpad];
1102 if (finger < tp.m_count) {
1107 m_cacheDataMutex.unlock();
1123 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1126 throw new IllegalArgumentException(
"Joystick axis is out of range");
1129 int mask = 1 << axis;
1131 m_cacheDataMutex.lock();
1133 if ((m_joystickAxes[stick].m_available & mask) != 0) {
1134 return OptionalDouble.of(m_joystickAxes[stick].m_axes[axis]);
1137 m_cacheDataMutex.unlock();
1140 return OptionalDouble.empty();
1152 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1155 throw new IllegalArgumentException(
"Joystick POV is out of range");
1158 int mask = 1 << pov;
1160 m_cacheDataMutex.lock();
1162 if ((m_joystickPOVs[stick].m_available & mask) != 0) {
1166 m_cacheDataMutex.unlock();
1181 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1184 m_cacheDataMutex.lock();
1186 return m_joystickButtons[stick].m_buttons;
1188 m_cacheDataMutex.unlock();
1210 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1213 m_cacheDataMutex.lock();
1215 return m_joystickAxes[stick].m_available;
1217 m_cacheDataMutex.unlock();
1239 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1242 m_cacheDataMutex.lock();
1244 return m_joystickPOVs[stick].m_available;
1246 m_cacheDataMutex.unlock();
1268 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1271 m_cacheDataMutex.lock();
1273 return m_joystickButtons[stick].m_available;
1275 m_cacheDataMutex.unlock();
1287 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1301 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1315 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1329 throw new IllegalArgumentException(
"Joystick index is out of range, should be 0-5");
1356 m_cacheDataMutex.lock();
1358 return m_controlWord.isEnabled() && m_controlWord.isDSAttached();
1360 m_cacheDataMutex.unlock();
1379 m_cacheDataMutex.lock();
1381 return m_controlWord.isEStopped();
1383 m_cacheDataMutex.unlock();
1400 if (!m_userProgramStarted) {
1404 m_cacheDataMutex.lock();
1406 return m_controlWord.getRobotMode();
1408 m_cacheDataMutex.unlock();
1439 m_cacheDataMutex.lock();
1443 m_cacheDataMutex.unlock();
1474 m_cacheDataMutex.lock();
1478 m_cacheDataMutex.unlock();
1509 m_cacheDataMutex.lock();
1513 m_cacheDataMutex.unlock();
1517 private static int convertColorToInt(
Color color) {
1518 if (color ==
null) {
1521 return (((
int) (color.
red * 255) & 0xff) << 16)
1522 | (((int) (color.green * 255) & 0xff) << 8)
1523 | ((
int) (color.
blue * 255) & 0xff);
1540 @SuppressWarnings(
"PMD.UseStringBufferForStringAppends")
1547 Color backgroundColor) {
1548 if (name.isBlank()) {
1549 throw new IllegalArgumentException(
"OpMode name must be non-blank");
1552 m_opModesMutex.lock();
1554 String nameCopy = name;
1556 long id = OpModeOption.makeId(mode, nameCopy.hashCode());
1557 OpModeOption existing = m_opModes.get(id);
1558 if (existing == null) {
1566 convertColorToInt(textColor),
1567 convertColorToInt(backgroundColor)));
1570 if (existing.getMode() == mode && existing.name.equals(name)) {
1572 throw new IllegalArgumentException(
"OpMode " + name +
" already exists for mode " + mode);
1578 m_opModesMutex.unlock();
1595 return addOpMode(mode, name, group, description,
null,
null);
1610 return addOpMode(mode, name, group,
"");
1636 if (name.isBlank()) {
1639 m_opModesMutex.lock();
1644 if (opMode.getMode() == mode && opMode.name.equals(name)) {
1645 m_opModes.remove(opMode.id);
1650 m_opModesMutex.unlock();
1657 m_opModesMutex.lock();
1662 m_opModesMutex.unlock();
1666 m_opModes.values().stream()
1671 "OpMode/" + mode, String.valueOf(modeCounts.getOrDefault(mode, 0L)));
1677 m_opModesMutex.lock();
1682 m_opModesMutex.unlock();
1704 m_userProgramStarted =
true;
1720 "DriverStationBackend.clearUserProgramStarted() was called! "
1721 +
"This method exists solely for internal WPILib unit tests "
1722 +
"and does nothing in team code.",
1727 m_userProgramStarted =
false;
1745 if (!m_userProgramStarted) {
1749 m_cacheDataMutex.lock();
1751 return m_controlWord.getOpModeId();
1753 m_cacheDataMutex.unlock();
1772 if (!m_userProgramStarted) {
1776 m_cacheDataMutex.lock();
1780 m_cacheDataMutex.unlock();
1812 m_cacheDataMutex.lock();
1814 return m_controlWord.isDSAttached();
1816 m_cacheDataMutex.unlock();
1826 m_cacheDataMutex.lock();
1828 return m_controlWord.isFMSAttached();
1830 m_cacheDataMutex.unlock();
1842 m_cacheDataMutex.lock();
1844 if (m_gameData ==
null || m_gameData.isEmpty()) {
1845 return Optional.empty();
1847 return Optional.of(m_gameData);
1849 m_cacheDataMutex.unlock();
1859 m_cacheDataMutex.lock();
1861 return m_matchInfo.eventName;
1863 m_cacheDataMutex.unlock();
1874 m_cacheDataMutex.lock();
1876 matchType = m_matchInfo.matchType;
1878 m_cacheDataMutex.unlock();
1880 return switch (matchType) {
1894 m_cacheDataMutex.lock();
1896 return m_matchInfo.matchNumber;
1898 m_cacheDataMutex.unlock();
1908 m_cacheDataMutex.lock();
1910 return m_matchInfo.replayNumber;
1912 m_cacheDataMutex.unlock();
1916 private static Map<AllianceStationID, Optional<Alliance>> m_allianceMap =
1926 private static Map<AllianceStationID, OptionalInt> m_stationMap =
1945 if (allianceStationID ==
null) {
1949 return m_allianceMap.get(allianceStationID);
1961 if (allianceStationID ==
null) {
1965 return m_stationMap.get(allianceStationID);
2008 m_joystickAlertMutex.lock();
2010 m_silenceJoystickAlerts = silence;
2012 clearJoystickAlertsLocked();
2015 m_joystickAlertMutex.unlock();
2026 m_joystickAlertMutex.lock();
2030 m_joystickAlertMutex.unlock();
2040 m_cacheDataMutex.lock();
2042 word.
update(m_controlWord);
2044 m_cacheDataMutex.unlock();
2059 m_joystickAxesCache[stick].m_axes,
2060 m_joystickAxesRawCache[stick].m_axes,
2061 m_joystickPOVsCache[stick].m_povs,
2062 m_touchpadFingersCache,
2064 m_joystickAxesCache[stick].m_available = (int) m_metadataCache[0];
2065 m_joystickAxesRawCache[stick].m_available = (int) m_metadataCache[0];
2066 m_joystickPOVsCache[stick].m_available = (int) m_metadataCache[1];
2067 m_joystickButtonsCache[stick].m_available = m_metadataCache[2];
2068 m_joystickButtonsCache[stick].m_buttons = m_metadataCache[3];
2069 m_joystickTouchpadsCache[stick].m_count = (int) m_metadataCache[4];
2070 for (
int i = 0; i < m_joystickTouchpadsCache[stick].m_count; i++) {
2071 long metadata = m_metadataCache[5 + i];
2072 m_joystickTouchpadsCache[stick].m_touchpads[i].m_fingers[0].m_down = (metadata & 0x1) != 0;
2073 m_joystickTouchpadsCache[stick].m_touchpads[i].m_fingers[1].m_down = (metadata & 0x2) != 0;
2074 m_joystickTouchpadsCache[stick].m_touchpads[i].m_count = (int) (metadata >> 2 & 0x3);
2075 for (
int j = 0; j < m_joystickTouchpadsCache[stick].m_touchpads[i].m_count; j++) {
2076 m_joystickTouchpadsCache[stick].m_touchpads[i].m_fingers[j].m_x =
2077 m_touchpadFingersCache[i * 4 + j * 2 + 0];
2078 m_joystickTouchpadsCache[stick].m_touchpads[i].m_fingers[j].m_y =
2079 m_touchpadFingersCache[i * 4 + j * 2 + 1];
2092 m_opModeCache = opModeToString(m_controlWordCache.getOpModeId());
2094 DataLogSender dataLogSender;
2096 m_cacheDataMutex.lock();
2100 m_joystickButtonsPressed[i] |=
2101 ~m_joystickButtons[i].m_buttons & m_joystickButtonsCache[i].m_buttons;
2104 m_joystickButtonsReleased[i] |=
2105 m_joystickButtons[i].m_buttons & ~m_joystickButtonsCache[i].m_buttons;
2109 HALJoystickAxes[] currentAxes = m_joystickAxes;
2110 m_joystickAxes = m_joystickAxesCache;
2111 m_joystickAxesCache = currentAxes;
2113 HALJoystickAxesRaw[] currentAxesRaw = m_joystickAxesRaw;
2114 m_joystickAxesRaw = m_joystickAxesRawCache;
2115 m_joystickAxesRawCache = currentAxesRaw;
2117 HALJoystickButtons[] currentButtons = m_joystickButtons;
2118 m_joystickButtons = m_joystickButtonsCache;
2119 m_joystickButtonsCache = currentButtons;
2121 HALJoystickPOVs[] currentPOVs = m_joystickPOVs;
2122 m_joystickPOVs = m_joystickPOVsCache;
2123 m_joystickPOVsCache = currentPOVs;
2125 HALJoystickTouchpads[] currentTouchpads = m_joystickTouchpads;
2126 m_joystickTouchpads = m_joystickTouchpadsCache;
2127 m_joystickTouchpadsCache = currentTouchpads;
2130 m_matchInfo = m_matchInfoCache;
2131 m_matchInfoCache = currentInfo;
2133 m_gameData = m_gameDataCache;
2136 m_controlWord = m_controlWordCache;
2137 m_controlWordCache = currentWord;
2139 String currentOpMode = m_opMode;
2140 m_opMode = m_opModeCache;
2141 m_opModeCache = currentOpMode;
2143 dataLogSender = m_dataLogSender;
2145 m_cacheDataMutex.unlock();
2148 clearJoystickAlerts();
2150 m_refreshEvents.wakeup();
2152 m_matchDataSender.sendMatchData();
2153 if (dataLogSender !=
null) {
2164 m_refreshEvents.add(handle);
2173 m_refreshEvents.remove(handle);
2176 private static JoystickAlerts getJoystickAlertsLocked(
int stick) {
2177 JoystickAlerts alerts = m_joystickAlerts[stick];
2178 if (alerts ==
null) {
2179 alerts =
new JoystickAlerts(stick);
2180 m_joystickAlerts[stick] = alerts;
2185 private static void reportJoystickResourceWarning(
2186 int stick, JoystickResourceAlert resourceAlert,
int resource) {
2187 m_joystickAlertMutex.lock();
2189 if (!isFMSAttached() && m_silenceJoystickAlerts) {
2193 JoystickAlerts alerts = getJoystickAlertsLocked(stick);
2194 if (!alerts.prepareForReport()) {
2198 alerts.reportResourceWarning(resourceAlert, resource);
2200 m_joystickAlertMutex.unlock();
2204 private static void reportJoystickTouchpadFingerWarning(
int stick,
int touchpad,
int finger) {
2205 m_joystickAlertMutex.lock();
2207 if (!isFMSAttached() && m_silenceJoystickAlerts) {
2211 JoystickAlerts alerts = getJoystickAlertsLocked(stick);
2212 if (!alerts.prepareForReport()) {
2216 alerts.reportTouchpadFingerWarning(touchpad, finger);
2218 m_joystickAlertMutex.unlock();
2222 private static void clearJoystickAlerts() {
2223 m_joystickAlertMutex.lock();
2225 clearJoystickAlertsLocked();
2227 m_joystickAlertMutex.unlock();
2231 private static void clearJoystickAlertsLocked() {
2232 if (!isFMSAttached() && m_silenceJoystickAlerts) {
2233 for (JoystickAlerts alerts : m_joystickAlerts) {
2234 if (alerts !=
null) {
2235 alerts.clearAllAlerts();
2241 for (JoystickAlerts alerts : m_joystickAlerts) {
2242 if (alerts !=
null) {
2254 @SuppressWarnings(
"PMD.NonThreadSafeSingleton")
2256 m_cacheDataMutex.lock();
2258 if (m_dataLogSender ==
null) {
2259 m_dataLogSender =
new DataLogSender(log, logJoysticks,
WPIUtilJNI.now());
2262 m_cacheDataMutex.unlock();