[hal,wpilib] Rename FPGA clock to monotonic clock (#8672)

- Remove status return from HAL level (clock getting should never fail)
- Remove 32-bit timestamp expand function
- Make monotonic_clock.hpp (formerly fpga_clock.hpp) header-only and
move to root hal include directory
This commit is contained in:
Peter Johnson
2026-03-15 15:08:41 -07:00
committed by GitHub
parent 1a5b023235
commit e944ae9aca
59 changed files with 233 additions and 358 deletions

View File

@@ -44,7 +44,7 @@ public class TimedRobot extends IterativeRobotBase {
startTime
+ offset
+ this.period
+ (RobotController.getFPGATime() - startTime) / this.period * this.period;
+ (RobotController.getMonotonicTime() - startTime) / this.period * this.period;
}
@Override
@@ -89,7 +89,7 @@ public class TimedRobot extends IterativeRobotBase {
*/
protected TimedRobot(double period) {
super(period);
m_startTimeUs = RobotController.getFPGATime();
m_startTimeUs = RobotController.getMonotonicTime();
addPeriodic(this::loopFunc, period);
NotifierJNI.setNotifierName(m_notifier, "TimedRobot");
@@ -146,7 +146,7 @@ public class TimedRobot extends IterativeRobotBase {
break;
}
long currentTime = RobotController.getFPGATime();
long currentTime = RobotController.getMonotonicTime();
m_loopStartTimeUs = currentTime;
callback.func.run();
@@ -182,7 +182,7 @@ public class TimedRobot extends IterativeRobotBase {
/**
* Return the system clock time in microseconds for the start of the current periodic loop. This
* is in the same time base as Timer.getFPGATimestamp(), but is stable through a loop. It is
* is in the same time base as Timer.getMonotonicTimestamp(), but is stable through a loop. It is
* updated at the beginning of every periodic callback (including the normal periodic loop).
*
* @return Robot running time in microseconds, as of the start of the current periodic function.

View File

@@ -25,7 +25,7 @@ public abstract class MotorSafety {
private double m_expiration = kDefaultSafetyExpiration;
private boolean m_enabled;
private double m_stopTime = Timer.getFPGATimestamp();
private double m_stopTime = Timer.getMonotonicTimestamp();
private final Object m_thisMutex = new Object();
private static final Set<MotorSafety> m_instanceList = new LinkedHashSet<>();
private static final Object m_listMutex = new Object();
@@ -83,7 +83,7 @@ public abstract class MotorSafety {
*/
public void feed() {
synchronized (m_thisMutex) {
m_stopTime = Timer.getFPGATimestamp() + m_expiration;
m_stopTime = Timer.getMonotonicTimestamp() + m_expiration;
}
}
@@ -116,7 +116,7 @@ public abstract class MotorSafety {
*/
public boolean isAlive() {
synchronized (m_thisMutex) {
return !m_enabled || m_stopTime > Timer.getFPGATimestamp();
return !m_enabled || m_stopTime > Timer.getMonotonicTimestamp();
}
}
@@ -138,7 +138,7 @@ public abstract class MotorSafety {
return;
}
if (stopTime < Timer.getFPGATimestamp()) {
if (stopTime < Timer.getMonotonicTimestamp()) {
DriverStation.reportError(
getDescription()
+ "... Output not updated often enough. See https://docs.wpilib.org/motorsafety for more information.",

View File

@@ -66,7 +66,7 @@ public abstract class PeriodicOpMode implements OpMode {
startTime
+ offset
+ this.period
+ (RobotController.getFPGATime() - startTime) / this.period * this.period;
+ (RobotController.getMonotonicTime() - startTime) / this.period * this.period;
}
@Override
@@ -120,7 +120,7 @@ public abstract class PeriodicOpMode implements OpMode {
* @param period period (in seconds) for callbacks to the periodic() function
*/
protected PeriodicOpMode(double period) {
m_startTimeUs = RobotController.getFPGATime();
m_startTimeUs = RobotController.getMonotonicTime();
m_period = period;
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
@@ -157,8 +157,8 @@ public abstract class PeriodicOpMode implements OpMode {
/**
* Return the system clock time in micrseconds for the start of the current periodic loop. This is
* in the same time base as Timer.getFPGATimestamp(), but is stable through a loop. It is updated
* at the beginning of every periodic callback (including the normal periodic loop).
* in the same time base as Timer.getMonotonicTimestamp(), but is stable through a loop. It is
* updated at the beginning of every periodic callback (including the normal periodic loop).
*
* @return Robot running time in microseconds, as of the start of the current periodic function.
*/
@@ -290,8 +290,8 @@ public abstract class PeriodicOpMode implements OpMode {
break;
}
long currentTime = RobotController.getFPGATime();
m_loopStartTimeUs = RobotController.getFPGATime();
long currentTime = RobotController.getMonotonicTime();
m_loopStartTimeUs = RobotController.getMonotonicTime();
callback.func.run();

View File

@@ -22,7 +22,7 @@ import org.wpilib.units.measure.Voltage;
/** Contains functions for roboRIO functionality. */
public final class RobotController {
private static LongSupplier m_timeSource = RobotController::getFPGATime;
private static LongSupplier m_timeSource = RobotController::getMonotonicTime;
private RobotController() {
throw new UnsupportedOperationException("This is a utility class!");
@@ -69,9 +69,9 @@ public final class RobotController {
}
/**
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
* microseconds since the FPGA started. However, the return value of this method may be modified
* to use any time base, including non-monotonic and non-continuous time bases.
* Read the microsecond timestamp. By default, the time is based on the monotonic clock. However,
* the return value of this method may be modified to use any time base, including non-monotonic
* and non-continuous time bases.
*
* @return The current time in microseconds.
*/
@@ -80,9 +80,9 @@ public final class RobotController {
}
/**
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
* microseconds since the FPGA started. However, the return value of this method may be modified
* to use any time base, including non-monotonic and non-continuous time bases.
* Read the microsecond timestamp. By default, the time is based on the monotonic clock. However,
* the return value of this method may be modified to use any time base, including non-monotonic
* and non-continuous time bases.
*
* @return The current time in a measure.
*/
@@ -91,21 +91,21 @@ public final class RobotController {
}
/**
* Read the microsecond timer from the FPGA.
* Read the microsecond monotonic timer.
*
* @return The current time in microseconds according to the FPGA.
* @return The current monotonic time in microseconds.
*/
public static long getFPGATime() {
return HALUtil.getFPGATime();
public static long getMonotonicTime() {
return HALUtil.getMonotonicTime();
}
/**
* Read the microsecond timer in a measure from the FPGA.
* Read the microsecond monotonic timer in a measure.
*
* @return The current time according to the FPGA in a measure.
* @return The current monotonic time in a measure.
*/
public static Time getMeasureFPGATime() {
return Microseconds.of(HALUtil.getFPGATime());
public static Time getMeasureMonotonicTime() {
return Microseconds.of(HALUtil.getMonotonicTime());
}
/**

View File

@@ -17,9 +17,9 @@ import org.wpilib.units.measure.Time;
*/
public class Timer {
/**
* Return the clock time in seconds. By default, the time is based on the FPGA hardware clock in
* seconds since the FPGA started. However, the return value of this method may be modified to use
* any time base, including non-monotonic time bases.
* Return the clock time in seconds. By default, the time is the time returned by
* getMonotonicTimestamp(). However, the return value of this method may be modified to use any
* time base, including non-monotonic time bases.
*
* @return Robot running time in seconds.
*/
@@ -28,13 +28,12 @@ public class Timer {
}
/**
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
* seconds since the FPGA started.
* Return the monotonic clock time in seconds.
*
* @return Robot running time in seconds.
* @return Monotonic time in seconds.
*/
public static double getFPGATimestamp() {
return RobotController.getFPGATime() / 1000000.0;
public static double getMonotonicTimestamp() {
return RobotController.getMonotonicTime() / 1000000.0;
}
/**

View File

@@ -38,7 +38,7 @@ public class Tracer {
/** Restarts the epoch timer. */
public final void resetTimer() {
m_startTime = RobotController.getFPGATime();
m_startTime = RobotController.getMonotonicTime();
}
/**
@@ -53,7 +53,7 @@ public class Tracer {
* @param epochName The name to associate with the epoch.
*/
public void addEpoch(String epochName) {
long currentTime = RobotController.getFPGATime();
long currentTime = RobotController.getMonotonicTime();
m_epochs.put(epochName, currentTime - m_startTime);
m_startTime = currentTime;
}
@@ -71,7 +71,7 @@ public class Tracer {
* @param output the stream that the output is sent to
*/
public void printEpochs(Consumer<String> output) {
long now = RobotController.getFPGATime();
long now = RobotController.getMonotonicTime();
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
StringBuilder sb = new StringBuilder();
m_lastEpochsPrintTime = now;

View File

@@ -100,7 +100,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
* @return The time in seconds since the watchdog was last fed.
*/
public double getTime() {
return Timer.getFPGATimestamp() - m_startTime;
return Timer.getMonotonicTimestamp() - m_startTime;
}
/**
@@ -109,7 +109,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
* @param timeout The watchdog's timeout in seconds with microsecond resolution.
*/
public void setTimeout(double timeout) {
m_startTime = Timer.getFPGATimestamp();
m_startTime = Timer.getMonotonicTimestamp();
m_tracer.clearEpochs();
m_queueMutex.lock();
@@ -184,7 +184,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
/** Enables the watchdog timer. */
public void enable() {
m_startTime = Timer.getFPGATimestamp();
m_startTime = Timer.getMonotonicTimestamp();
m_tracer.clearEpochs();
m_queueMutex.lock();
@@ -247,7 +247,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
Thread.currentThread().interrupt();
break;
}
long curTime = HALUtil.getFPGATime();
long curTime = HALUtil.getMonotonicTime();
m_queueMutex.lock();
try {