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