5package org.wpilib.framework;
7import java.util.HashMap;
9import java.util.concurrent.atomic.AtomicInteger;
10import java.util.concurrent.locks.ReentrantLock;
11import java.util.function.BiConsumer;
12import java.util.function.Consumer;
13import java.util.function.Supplier;
14import org.wpilib.backend.NetworkTablesTelemetryBackend;
15import org.wpilib.backend.NetworkTablesTunableBackend;
16import org.wpilib.driverstation.DriverStationErrors;
17import org.wpilib.driverstation.RobotState;
18import org.wpilib.driverstation.internal.DriverStationBackend;
19import org.wpilib.hardware.hal.HAL;
20import org.wpilib.hardware.hal.HALUtil;
21import org.wpilib.internal.UnitTelemetry;
22import org.wpilib.math.util.MathShared;
23import org.wpilib.math.util.MathSharedStore;
24import org.wpilib.networktables.IntegerPublisher;
25import org.wpilib.networktables.MultiSubscriber;
26import org.wpilib.networktables.NetworkTableEvent;
27import org.wpilib.networktables.NetworkTableInstance;
28import org.wpilib.networktables.PubSubOption;
29import org.wpilib.networktables.StringPublisher;
30import org.wpilib.system.RuntimeType;
31import org.wpilib.system.Timer;
32import org.wpilib.system.WPILibVersion;
33import org.wpilib.telemetry.TelemetryRegistry;
34import org.wpilib.tunable.Tunable;
35import org.wpilib.tunable.TunableConfig;
36import org.wpilib.tunable.TunableDouble;
37import org.wpilib.tunable.TunableRegistry;
38import org.wpilib.units.Measure;
39import org.wpilib.units.Unit;
40import org.wpilib.util.Alert;
41import org.wpilib.util.UsageReporting;
42import org.wpilib.util.WPIUtilJNI;
53public abstract class RobotBase implements AutoCloseable {
54 private static final String PROGRAM_START_TIME_TOPIC =
"/Robot/ProgramStartTime";
55 private static final String WPILIB_VERSION_TOPIC =
"/Robot/WPILibVersion";
56 private static final AtomicInteger s_nextWarningReporterId =
new AtomicInteger();
60 private static long m_threadId = -1;
65 private final Map<String, Alert> m_telemetryWarningAlerts =
new HashMap<>();
66 private final Map<String, Alert> m_tunableWarningAlerts =
new HashMap<>();
67 private final BiConsumer<String, String> m_telemetryWarningReporter =
68 this::reportTelemetryWarning;
69 private final Consumer<String> m_tunableWarningReporter = this::reportTunableWarning;
70 private final String m_warningAlertIdPrefix =
71 "warning" + s_nextWarningReporterId.getAndIncrement() +
"_";
72 private final AtomicInteger m_nextWarningAlertId =
new AtomicInteger();
74 private final int m_connListenerHandle;
76 private static void setupMathShared() {
80 public void reportError(String error, StackTraceElement[] stackTrace) {
85 public double getTimestamp() {
91 private void reportTelemetryWarning(String path, String msg) {
93 m_telemetryWarningAlerts,
96 "Telemetry '" + path +
"': warning: " + msg);
99 private void reportTunableWarning(String msg) {
100 reportWarningAlert(m_tunableWarningAlerts,
"Tunables", msg,
"Tunable warning: " + msg);
103 private void reportWarningAlert(
104 Map<String, Alert> alerts, String group, String key, String text) {
105 synchronized (alerts) {
106 Alert alert = alerts.get(key);
111 m_warningAlertIdPrefix + m_nextWarningAlertId.getAndIncrement(),
114 alerts.put(key, alert);
122 private static void closeWarningAlerts(Map<String, Alert> alerts) {
123 synchronized (alerts) {
124 for (
Alert alert : alerts.values()) {
131 @SuppressWarnings(
"rawtypes")
132 private static class TunableMeasure
extends Tunable<Measure> implements
Tunable.CustomTunable {
135 m_unit = initialValue.
unit();
137 m_value = initialValue;
141 public void set(
double value) {
147 public double get() {
154 public void set(
Measure value) {
155 if (!m_baseUnit.
equivalent(value.unit().getBaseUnit())) {
156 throw new IllegalArgumentException(
157 "Measure unit " + value.unit() +
" is not compatible with " + m_unit);
159 m_magnitudeTunable.
set(value.baseUnitMagnitude());
175 return m_magnitudeTunable;
198 private final Unit m_unit;
199 private final Unit m_baseUnit;
212 @SuppressWarnings(
"this-escape")
215 m_threadId = Thread.currentThread().threadId();
220 inst.
startServer(
"/home/systemcore/networktables.json",
"",
"robot");
222 inst.
startServer(
"networktables.json",
"",
"robot");
230 (table, name, value) -> {
231 UnitTelemetry.log(table, name, value);
239 (initialValue, config) -> {
240 if (config == null) {
241 config = new TunableConfig();
243 return new TunableMeasure(
256 throw new InterruptedException();
259 }
catch (InterruptedException ex) {
260 System.err.println(
"timed out while waiting for NT server to start");
263 m_programStartTimePublisher = inst.getIntegerTopic(PROGRAM_START_TIME_TOPIC).publish();
264 m_programStartTimePublisher.set(WPIUtilJNI.getProgramStartTime());
266 m_wpilibVersionPublisher = inst.getStringTopic(WPILIB_VERSION_TOPIC).publish();
267 m_wpilibVersionPublisher.set(WPILibVersion.Version);
269 m_connListenerHandle =
270 inst.addConnectionListener(
273 if (event.is(NetworkTableEvent.Kind.CONNECTED)) {
274 UsageReporting.reportUsage(
"NT/" + event.connInfo.remoteId,
"");
289 @SuppressWarnings(
"PMD.CompareObjectsWithEquals")
290 public
void close() {
292 TelemetryRegistry.setReportWarning(null);
295 TunableRegistry.setReportWarning(null);
297 closeWarningAlerts(m_telemetryWarningAlerts);
298 closeWarningAlerts(m_tunableWarningAlerts);
300 m_programStartTimePublisher.close();
301 m_wpilibVersionPublisher.close();
440 private static final ReentrantLock m_runMutex =
new ReentrantLock();
442 private static boolean m_suppressExitWarning;
452 for (
int i = elements.length - 1; i >= 0; i--) {
453 StackTraceElement element = elements[i];
456 if (
RobotBase.class.equals(Class.forName(element.getClassName()))) {
459 if (
RobotBase.class.isAssignableFrom(Class.forName(element.getClassName()))) {
460 return element.getClassName();
462 }
catch (ClassNotFoundException e) {
470 @SuppressWarnings(
"PMD.AvoidCatchingGenericException")
471 private static <T extends
RobotBase>
void runRobot(Supplier<T> robotConstructor) {
472 System.out.println(
"********** Robot program starting **********");
476 robot = robotConstructor.get();
477 }
catch (Throwable throwable) {
478 Throwable cause = throwable.getCause();
482 StackTraceElement[] elements = throwable.getStackTrace();
483 String robotName = getRobotName(elements);
484 DriverStationErrors.reportError(
485 "Unhandled exception instantiating robot " + robotName +
" " + throwable, elements);
486 DriverStationErrors.reportError(
487 "The robot program quit unexpectedly."
488 +
" This is usually due to a code error.\n"
489 +
" The above stacktrace can help determine where the error occurred.\n"
490 +
" See https://wpilib.org/stacktrace for more information.\n",
492 DriverStationErrors.reportError(
"Could not instantiate robot " + robotName +
"!",
false);
493 DriverStationErrors.reportCrash(
"Could not instantiate robot " + robotName +
"!", elements);
501 boolean errorOnExit =
false;
503 robot.startCompetition();
504 }
catch (Throwable throwable) {
505 Throwable cause = throwable.getCause();
510 "Unhandled exception: " + throwable, throwable.getStackTrace());
512 "Unhandled exception: " + throwable, throwable.getStackTrace());
516 boolean suppressExitWarning = m_suppressExitWarning;
518 if (!suppressExitWarning) {
521 "The robot program quit unexpectedly."
522 +
" This is usually due to a code error.\n"
523 +
" The above stacktrace can help determine where the error occurred.\n"
524 +
" See https://wpilib.org/stacktrace for more information.",
528 "The startCompetition() method (or methods called by it) should have "
529 +
"handled the exception above.",
533 "Unexpected return from startCompetition() method.",
false);
546 m_suppressExitWarning = value;
556 public static <T extends RobotBase>
void startRobot(Supplier<T> robotConstructor) {
560 if (!
HAL.initialize()) {
561 throw new IllegalStateException(
"Failed to initialize. Terminating");
576 runRobot(robotConstructor);
580 thread.setDaemon(
true);
592 }
catch (InterruptedException ex) {
593 Thread.currentThread().interrupt();
596 runRobot(robotConstructor);
static void reportCrash(String details, StackTraceElement[] stackTrace)
static void reportWarning(String warning, boolean printTrace)
static void reportError(String error, boolean printTrace)
static boolean isAutonomousEnabled()
static long getOpModeId()
static boolean isTeleop()
static boolean isUtilityEnabled()
static boolean isUtility()
static boolean isEnabled()
static boolean isAutonomous()
static boolean isTeleopEnabled()
static boolean isDisabled()
static String getOpMode()
static void refreshData()
static boolean isEnabled()
static boolean isTeleopEnabled()
static boolean isUtility()
static String getOpMode()
static boolean isDisabled()
static< T extends RobotBase > void startRobot(Supplier< T > robotConstructor)
static void suppressExitWarning(boolean value)
static boolean isUtilityEnabled()
static boolean isAutonomous()
static boolean isTeleop()
abstract void startCompetition()
static RuntimeType getRuntimeType()
static boolean isAutonomousEnabled()
static boolean isSimulation()
abstract void endCompetition()
static long getOpModeId()
static long getMainThreadId()
static String getRobotName(StackTraceElement[] elements)
static String getUnitMetadata(Unit unit)
static synchronized void setMathShared(MathShared shared)
MultiSubscriber(NetworkTableInstance inst, String[] prefixes, PubSubOption... options)
void removeListener(int listener)
static synchronized NetworkTableInstance getDefault()
static double getTimestamp()
static final String Version
static void registerBackend(String prefix, TelemetryBackend backend)
static< T > void registerTypeHandler(Class< T > cls, TypeHandler< T > handler)
static void setReportWarning(BiConsumer< String, String > func)
static BiConsumer< String, String > getReportWarning()
boolean supportsChangeNotification()
abstract void set(double value)
TunableDouble(TunableConfig config)
abstract Class< T > getTypeClass()
static void registerBackend(String prefix, TunableBackend backend)
static< T > void registerTypeHandler(Class< T > cls, TypeHandler< T > handler)
static Consumer< String > getReportWarning()
static void setReportWarning(Consumer< String > func)
boolean equivalent(Unit other)
abstract Measure<?> ofBaseUnits(double baseUnitMagnitude)
Alert(String id, String text, Level level)
void setText(String text)
static synchronized void setReportUsageImpl(BiConsumer< String, String > func)
static void reportUsage(String resource, String data)
static RuntimeType getValue(int type)
PubSubOption DISABLE_SIGNAL
TunableBase getInnerTunable()
double baseUnitMagnitude()