// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. package edu.wpi.first.wpilibj; import static edu.wpi.first.units.Units.Seconds; import edu.wpi.first.hal.NotifierJNI; import edu.wpi.first.units.measure.Time; import java.io.Closeable; import java.util.PriorityQueue; import java.util.concurrent.locks.ReentrantLock; /** * A class that's a wrapper around a watchdog timer. * *
When the timer expires, a message is printed to the console and an optional user-provided * callback is invoked. * *
The watchdog is initialized disabled, so the user needs to call enable() before use.
*/
public class Watchdog implements Closeable, Comparable This also enables the timer if it was previously disabled.
*/
public void reset() {
enable();
}
/** Enables the watchdog timer. */
public void enable() {
m_startTime = Timer.getFPGATimestamp();
m_tracer.clearEpochs();
m_queueMutex.lock();
try {
m_isExpired = false;
m_watchdogs.remove(this);
m_expirationTime = m_startTime + m_timeout;
m_watchdogs.add(this);
updateAlarm();
} finally {
m_queueMutex.unlock();
}
}
/** Disables the watchdog timer. */
public void disable() {
m_queueMutex.lock();
try {
m_watchdogs.remove(this);
updateAlarm();
} finally {
m_queueMutex.unlock();
}
}
/**
* Enable or disable suppression of the generic timeout message.
*
* This may be desirable if the user-provided callback already prints a more specific message.
*
* @param suppress Whether to suppress generic timeout message.
*/
public void suppressTimeoutMessage(boolean suppress) {
m_suppressTimeoutMessage = suppress;
}
@SuppressWarnings("resource")
private static void updateAlarm() {
if (m_watchdogs.isEmpty()) {
NotifierJNI.cancelNotifierAlarm(m_notifier);
} else {
NotifierJNI.updateNotifierAlarm(
m_notifier, (long) (m_watchdogs.peek().m_expirationTime * 1e6));
}
}
private static Thread startDaemonThread(Runnable target) {
Thread inst = new Thread(target);
inst.setDaemon(true);
inst.start();
return inst;
}
private static void schedulerFunc() {
while (!Thread.currentThread().isInterrupted()) {
long curTime = NotifierJNI.waitForNotifierAlarm(m_notifier);
if (curTime == 0) {
break;
}
m_queueMutex.lock();
try {
if (m_watchdogs.isEmpty()) {
continue;
}
// If the condition variable timed out, that means a Watchdog timeout
// has occurred, so call its timeout function.
Watchdog watchdog = m_watchdogs.poll();
double now = curTime * 1e-6;
if (now - watchdog.m_lastTimeoutPrint > kMinPrintPeriod) {
watchdog.m_lastTimeoutPrint = now;
if (!watchdog.m_suppressTimeoutMessage) {
DriverStation.reportWarning(
String.format("Watchdog not fed within %.6fs\n", watchdog.m_timeout), false);
}
}
// Set expiration flag before calling the callback so any
// manipulation of the flag in the callback (e.g., calling
// Disable()) isn't clobbered.
watchdog.m_isExpired = true;
m_queueMutex.unlock();
watchdog.m_callback.run();
m_queueMutex.lock();
updateAlarm();
} finally {
m_queueMutex.unlock();
}
}
}
}