001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package org.wpilib.simulation;
006
007import java.util.function.BiConsumer;
008import org.wpilib.driverstation.MatchType;
009import org.wpilib.driverstation.POVDirection;
010import org.wpilib.driverstation.internal.DriverStationBackend;
011import org.wpilib.hardware.hal.AllianceStationID;
012import org.wpilib.hardware.hal.DriverStationJNI;
013import org.wpilib.hardware.hal.OpModeOption;
014import org.wpilib.hardware.hal.RobotMode;
015import org.wpilib.hardware.hal.simulation.DriverStationDataJNI;
016import org.wpilib.hardware.hal.simulation.NotifyCallback;
017import org.wpilib.util.WPIUtilJNI;
018
019/** Class to control a simulated driver station. */
020public final class DriverStationSim {
021  private DriverStationSim() {
022    throw new UnsupportedOperationException("This is a utility class!");
023  }
024
025  /**
026   * Register a callback on whether the DS is enabled.
027   *
028   * @param callback the callback that will be called whenever the enabled state is changed
029   * @param initialNotify if true, the callback will be run on the initial value
030   * @return the {@link CallbackStore} object associated with this callback.
031   */
032  public static CallbackStore registerEnabledCallback(
033      NotifyCallback callback, boolean initialNotify) {
034    int uid = DriverStationDataJNI.registerEnabledCallback(callback, initialNotify);
035    return new CallbackStore(uid, DriverStationDataJNI::cancelEnabledCallback);
036  }
037
038  /**
039   * Check if the DS is enabled.
040   *
041   * @return true if enabled
042   */
043  public static boolean getEnabled() {
044    return DriverStationDataJNI.getEnabled();
045  }
046
047  /**
048   * Change whether the DS is enabled.
049   *
050   * @param enabled the new value
051   */
052  public static void setEnabled(boolean enabled) {
053    DriverStationDataJNI.setEnabled(enabled);
054  }
055
056  /**
057   * Register a callback on DS robot mode changes.
058   *
059   * @param callback the callback that will be called when the robot mode changes
060   * @param initialNotify if true, the callback will be run on the initial value
061   * @return the {@link CallbackStore} object associated with this callback.
062   */
063  public static CallbackStore registerRobotModeCallback(
064      NotifyCallback callback, boolean initialNotify) {
065    int uid = DriverStationDataJNI.registerRobotModeCallback(callback, initialNotify);
066    return new CallbackStore(uid, DriverStationDataJNI::cancelRobotModeCallback);
067  }
068
069  /**
070   * Gets the robot mode set by the DS.
071   *
072   * @return robot mode
073   */
074  public static RobotMode getRobotMode() {
075    return DriverStationDataJNI.getRobotMode();
076  }
077
078  /**
079   * Change the robot mode set by the DS.
080   *
081   * @param mode the new value
082   */
083  public static void setRobotMode(RobotMode mode) {
084    DriverStationDataJNI.setRobotMode(mode);
085  }
086
087  /**
088   * Register a callback on the eStop state.
089   *
090   * @param callback the callback that will be called whenever the eStop state changes
091   * @param initialNotify if true, the callback will be run on the initial value
092   * @return the {@link CallbackStore} object associated with this callback.
093   */
094  public static CallbackStore registerEStopCallback(
095      NotifyCallback callback, boolean initialNotify) {
096    int uid = DriverStationDataJNI.registerEStopCallback(callback, initialNotify);
097    return new CallbackStore(uid, DriverStationDataJNI::cancelEStopCallback);
098  }
099
100  /**
101   * Check if eStop has been activated.
102   *
103   * @return true if eStopped
104   */
105  public static boolean getEStop() {
106    return DriverStationDataJNI.getEStop();
107  }
108
109  /**
110   * Set whether eStop is active.
111   *
112   * @param eStop true to activate
113   */
114  public static void setEStop(boolean eStop) {
115    DriverStationDataJNI.setEStop(eStop);
116  }
117
118  /**
119   * Register a callback on whether the FMS is connected.
120   *
121   * @param callback the callback that will be called whenever the FMS connection changes
122   * @param initialNotify if true, the callback will be run on the initial value
123   * @return the {@link CallbackStore} object associated with this callback.
124   */
125  public static CallbackStore registerFmsAttachedCallback(
126      NotifyCallback callback, boolean initialNotify) {
127    int uid = DriverStationDataJNI.registerFmsAttachedCallback(callback, initialNotify);
128    return new CallbackStore(uid, DriverStationDataJNI::cancelFmsAttachedCallback);
129  }
130
131  /**
132   * Check if the FMS is connected.
133   *
134   * @return true if FMS is connected
135   */
136  public static boolean getFmsAttached() {
137    return DriverStationDataJNI.getFmsAttached();
138  }
139
140  /**
141   * Change whether the FMS is connected.
142   *
143   * @param fmsAttached the new value
144   */
145  public static void setFmsAttached(boolean fmsAttached) {
146    DriverStationDataJNI.setFmsAttached(fmsAttached);
147  }
148
149  /**
150   * Register a callback on whether the DS is connected.
151   *
152   * @param callback the callback that will be called whenever the DS connection changes
153   * @param initialNotify if true, the callback will be run on the initial value
154   * @return the {@link CallbackStore} object associated with this callback.
155   */
156  public static CallbackStore registerDsAttachedCallback(
157      NotifyCallback callback, boolean initialNotify) {
158    int uid = DriverStationDataJNI.registerDsAttachedCallback(callback, initialNotify);
159    return new CallbackStore(uid, DriverStationDataJNI::cancelDsAttachedCallback);
160  }
161
162  /**
163   * Check if the DS is attached.
164   *
165   * @return true if attached
166   */
167  public static boolean getDsAttached() {
168    return DriverStationDataJNI.getDsAttached();
169  }
170
171  /**
172   * Change whether the DS is attached.
173   *
174   * @param dsAttached the new value
175   */
176  public static void setDsAttached(boolean dsAttached) {
177    DriverStationDataJNI.setDsAttached(dsAttached);
178  }
179
180  /**
181   * Register a callback on the alliance station ID.
182   *
183   * @param callback the callback that will be called whenever the alliance station changes
184   * @param initialNotify if true, the callback will be run on the initial value
185   * @return the {@link CallbackStore} object associated with this callback.
186   */
187  public static CallbackStore registerAllianceStationIdCallback(
188      NotifyCallback callback, boolean initialNotify) {
189    int uid = DriverStationDataJNI.registerAllianceStationIdCallback(callback, initialNotify);
190    return new CallbackStore(uid, DriverStationDataJNI::cancelAllianceStationIdCallback);
191  }
192
193  /**
194   * Get the alliance station ID (color + number).
195   *
196   * @return the alliance station color and number
197   */
198  public static AllianceStationID getAllianceStationId() {
199    return switch (DriverStationDataJNI.getAllianceStationId()) {
200      case DriverStationJNI.ALLIANCE_STATION_UNKNOWN -> AllianceStationID.UNKNOWN;
201      case DriverStationJNI.ALLIANCE_STATION_RED_1 -> AllianceStationID.RED_1;
202      case DriverStationJNI.ALLIANCE_STATION_RED_2 -> AllianceStationID.RED_2;
203      case DriverStationJNI.ALLIANCE_STATION_RED_3 -> AllianceStationID.RED_3;
204      case DriverStationJNI.ALLIANCE_STATION_BLUE_1 -> AllianceStationID.BLUE_1;
205      case DriverStationJNI.ALLIANCE_STATION_BLUE_2 -> AllianceStationID.BLUE_2;
206      case DriverStationJNI.ALLIANCE_STATION_BLUE_3 -> AllianceStationID.BLUE_3;
207      default -> AllianceStationID.UNKNOWN;
208    };
209  }
210
211  /**
212   * Change the alliance station.
213   *
214   * @param allianceStationId the new alliance station
215   */
216  public static void setAllianceStationId(AllianceStationID allianceStationId) {
217    int allianceStation =
218        switch (allianceStationId) {
219          case UNKNOWN -> DriverStationJNI.ALLIANCE_STATION_UNKNOWN;
220          case RED_1 -> DriverStationJNI.ALLIANCE_STATION_RED_1;
221          case RED_2 -> DriverStationJNI.ALLIANCE_STATION_RED_2;
222          case RED_3 -> DriverStationJNI.ALLIANCE_STATION_RED_3;
223          case BLUE_1 -> DriverStationJNI.ALLIANCE_STATION_BLUE_1;
224          case BLUE_2 -> DriverStationJNI.ALLIANCE_STATION_BLUE_2;
225          case BLUE_3 -> DriverStationJNI.ALLIANCE_STATION_BLUE_3;
226        };
227    DriverStationDataJNI.setAllianceStationId(allianceStation);
228  }
229
230  /**
231   * Register a callback on match time.
232   *
233   * @param callback the callback that will be called whenever match time changes
234   * @param initialNotify if true, the callback will be run on the initial value
235   * @return the {@link CallbackStore} object associated with this callback.
236   */
237  public static CallbackStore registerMatchTimeCallback(
238      NotifyCallback callback, boolean initialNotify) {
239    int uid = DriverStationDataJNI.registerMatchTimeCallback(callback, initialNotify);
240    return new CallbackStore(uid, DriverStationDataJNI::cancelMatchTimeCallback);
241  }
242
243  /**
244   * Get the current value of the match timer.
245   *
246   * @return the current match time
247   */
248  public static double getMatchTime() {
249    return DriverStationDataJNI.getMatchTime();
250  }
251
252  /**
253   * Sets the match timer.
254   *
255   * @param matchTime the new match time
256   */
257  public static void setMatchTime(double matchTime) {
258    DriverStationDataJNI.setMatchTime(matchTime);
259  }
260
261  /**
262   * Register a callback on opmode changes.
263   *
264   * @param callback the callback that will be called when the opmode changes
265   * @param initialNotify if true, the callback will be run on the initial value
266   * @return the {@link CallbackStore} object associated with this callback.
267   */
268  public static CallbackStore registerOpModeCallback(
269      NotifyCallback callback, boolean initialNotify) {
270    int uid = DriverStationDataJNI.registerOpModeCallback(callback, initialNotify);
271    return new CallbackStore(uid, DriverStationDataJNI::cancelOpModeCallback);
272  }
273
274  /**
275   * Gets the opmode.
276   *
277   * @return opmode
278   */
279  public static long getOpMode() {
280    return DriverStationDataJNI.getOpMode();
281  }
282
283  /**
284   * Change the opmode.
285   *
286   * @param opmode the new value
287   */
288  public static void setOpMode(long opmode) {
289    DriverStationDataJNI.setOpMode(opmode);
290  }
291
292  /**
293   * Register a callback on opmode options changes.
294   *
295   * @param callback the callback that will be called when the list of opmodes changes
296   * @param initialNotify if true, the callback will be run on the initial value
297   * @return the {@link CallbackStore} object associated with this callback.
298   */
299  public static CallbackStore registerOpModeOptionsCallback(
300      BiConsumer<String, OpModeOption[]> callback, boolean initialNotify) {
301    int uid = DriverStationDataJNI.registerOpModeOptionsCallback(callback, initialNotify);
302    return new CallbackStore(uid, DriverStationDataJNI::cancelOpModeOptionsCallback);
303  }
304
305  /**
306   * Gets the list of opmode options.
307   *
308   * @return opmodes list
309   */
310  public static OpModeOption[] getOpModeOptions() {
311    return DriverStationDataJNI.getOpModeOptions();
312  }
313
314  /** Updates DriverStation data so that new values are visible to the user program. */
315  public static void notifyNewData() {
316    int handle = WPIUtilJNI.makeEvent(false, false);
317    DriverStationJNI.provideNewDataEventHandle(handle);
318    DriverStationDataJNI.notifyNewData();
319    try {
320      WPIUtilJNI.waitForObject(handle);
321    } catch (InterruptedException e) {
322      e.printStackTrace();
323    }
324    DriverStationJNI.removeNewDataEventHandle(handle);
325    WPIUtilJNI.destroyEvent(handle);
326    DriverStationBackend.refreshData();
327  }
328
329  /**
330   * Sets suppression of DriverStation.reportError and reportWarning messages.
331   *
332   * @param shouldSend If false then messages will be suppressed.
333   */
334  public static void setSendError(boolean shouldSend) {
335    DriverStationDataJNI.setSendError(shouldSend);
336  }
337
338  /**
339   * Sets suppression of DriverStation.sendConsoleLine messages.
340   *
341   * @param shouldSend If false then messages will be suppressed.
342   */
343  public static void setSendConsoleLine(boolean shouldSend) {
344    DriverStationDataJNI.setSendConsoleLine(shouldSend);
345  }
346
347  /**
348   * Gets the joystick outputs.
349   *
350   * @param stick The joystick number
351   * @return The joystick outputs
352   */
353  public static int getJoystickLeds(int stick) {
354    return DriverStationDataJNI.getJoystickLeds(stick);
355  }
356
357  /**
358   * Gets the joystick rumble.
359   *
360   * @param stick The joystick number
361   * @param rumbleNum Rumble to get (0=left, 1=right, 2=left trigger, 3=right trigger)
362   * @return The joystick rumble value
363   */
364  public static int getJoystickRumble(int stick, int rumbleNum) {
365    return DriverStationDataJNI.getJoystickRumble(stick, rumbleNum);
366  }
367
368  /**
369   * Sets the state of one joystick button. Button indexes begin at 0.
370   *
371   * @param stick The joystick number
372   * @param button The button index, beginning at 0
373   * @param state The state of the joystick button
374   */
375  public static void setJoystickButton(int stick, int button, boolean state) {
376    DriverStationDataJNI.setJoystickButton(stick, button, state);
377  }
378
379  /**
380   * Gets the value of the axis on a joystick.
381   *
382   * @param stick The joystick number
383   * @param axis The analog axis number
384   * @param value The value of the axis on the joystick
385   */
386  public static void setJoystickAxis(int stick, int axis, double value) {
387    DriverStationDataJNI.setJoystickAxis(stick, axis, value);
388  }
389
390  /**
391   * Gets the state of a POV on a joystick.
392   *
393   * @param stick The joystick number
394   * @param pov The POV number
395   * @param value the angle of the POV
396   */
397  public static void setJoystickPOV(int stick, int pov, POVDirection value) {
398    DriverStationDataJNI.setJoystickPOV(stick, pov, value.value);
399  }
400
401  /**
402   * Sets the maximum index that an axis is available at.
403   *
404   * @param stick The joystick number
405   * @param maximumIndex The maximum index an axis is available at.
406   */
407  public static void setJoystickAxesMaximumIndex(int stick, int maximumIndex) {
408    setJoystickAxesAvailable(stick, (1 << maximumIndex) - 1);
409  }
410
411  /**
412   * Sets the number of axes for a joystick.
413   *
414   * @param stick The joystick number
415   * @param count The number of axes on the indicated joystick
416   */
417  public static void setJoystickAxesAvailable(int stick, int count) {
418    DriverStationDataJNI.setJoystickAxesAvailable(stick, count);
419  }
420
421  /**
422   * Sets the maximum index that a pov is available at.
423   *
424   * @param stick The joystick number
425   * @param maximumIndex The maximum index a pov is available at.
426   */
427  public static void setJoystickPOVsMaximumIndex(int stick, int maximumIndex) {
428    setJoystickPOVsAvailable(stick, (1 << maximumIndex) - 1);
429  }
430
431  /**
432   * Sets the number of POVs for a joystick.
433   *
434   * @param stick The joystick number
435   * @param count The number of POVs on the indicated joystick
436   */
437  public static void setJoystickPOVsAvailable(int stick, int count) {
438    DriverStationDataJNI.setJoystickPOVsAvailable(stick, count);
439  }
440
441  /**
442   * Sets the maximum index that a button is available at.
443   *
444   * @param stick The joystick number
445   * @param maximumIndex The maximum index a button is available at.
446   */
447  public static void setJoystickButtonsMaximumIndex(int stick, int maximumIndex) {
448    if (maximumIndex >= 64) {
449      setJoystickButtonsAvailable(stick, 0xFFFFFFFFFFFFFFFFL);
450    } else {
451      setJoystickButtonsAvailable(stick, (1L << maximumIndex) - 1);
452    }
453  }
454
455  /**
456   * Sets the number of buttons for a joystick.
457   *
458   * @param stick The joystick number
459   * @param count The number of buttons on the indicated joystick
460   */
461  public static void setJoystickButtonsAvailable(int stick, long count) {
462    DriverStationDataJNI.setJoystickButtonsAvailable(stick, count);
463  }
464
465  /**
466   * Sets the value of isGamepad for a joystick.
467   *
468   * @param stick The joystick number
469   * @param isGamepad The value of isGamepad
470   */
471  public static void setJoystickIsGamepad(int stick, boolean isGamepad) {
472    DriverStationDataJNI.setJoystickIsGamepad(stick, isGamepad);
473  }
474
475  /**
476   * Sets the value of type for a joystick.
477   *
478   * @param stick The joystick number
479   * @param type The value of type
480   */
481  public static void setJoystickGamepadType(int stick, int type) {
482    DriverStationDataJNI.setJoystickGamepadType(stick, type);
483  }
484
485  /**
486   * Sets the value of supported outputs for a joystick.
487   *
488   * @param stick The joystick number
489   * @param supportedOutputs The value of supported outputs
490   */
491  public static void setJoystickSupportedOutputs(int stick, int supportedOutputs) {
492    DriverStationDataJNI.setJoystickSupportedOutputs(stick, supportedOutputs);
493  }
494
495  /**
496   * Sets the name of a joystick.
497   *
498   * @param stick The joystick number
499   * @param name The value of name
500   */
501  public static void setJoystickName(int stick, String name) {
502    DriverStationDataJNI.setJoystickName(stick, name);
503  }
504
505  /**
506   * Sets the game specific message.
507   *
508   * @param message the game specific message
509   */
510  public static void setGameData(String message) {
511    DriverStationDataJNI.setGameData(message);
512  }
513
514  /**
515   * Sets the event name.
516   *
517   * @param name the event name
518   */
519  public static void setEventName(String name) {
520    DriverStationDataJNI.setEventName(name);
521  }
522
523  /**
524   * Sets the match type.
525   *
526   * @param type the match type
527   */
528  public static void setMatchType(MatchType type) {
529    int matchType =
530        switch (type) {
531          case PRACTICE -> 1;
532          case QUALIFICATION -> 2;
533          case ELIMINATION -> 3;
534          case NONE -> 0;
535        };
536    DriverStationDataJNI.setMatchType(matchType);
537  }
538
539  /**
540   * Sets the match number.
541   *
542   * @param matchNumber the match number
543   */
544  public static void setMatchNumber(int matchNumber) {
545    DriverStationDataJNI.setMatchNumber(matchNumber);
546  }
547
548  /**
549   * Sets the replay number.
550   *
551   * @param replayNumber the replay number
552   */
553  public static void setReplayNumber(int replayNumber) {
554    DriverStationDataJNI.setReplayNumber(replayNumber);
555  }
556
557  /** Reset all simulation data for the Driver Station. */
558  public static void resetData() {
559    DriverStationDataJNI.resetData();
560  }
561}