/*
* Strongback
* Copyright 2015, Strongback and individual contributors by the @authors tag.
* See the COPYRIGHT.txt in the distribution for a full listing of individual
* contributors.
*
* Licensed under the MIT License; you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.strongback.components;
import org.strongback.StrongbackRequirementException;
import edu.wpi.first.wpilibj.Utility;
/**
* The system that provides information about match time.
*
* @author Randall Hauch
*/
@FunctionalInterface
public interface Clock {
/**
* Return the current time, in microseconds.
*
* @return the elapsed time, in microseconds
*/
public long currentTimeInMicros();
/**
* Return the current time, in nanoseconds.
*
* @return the elapsed time, in nanoseconds
*/
default public long currentTimeInNanos() {
return currentTimeInMicros() * 1000;
}
/**
* Return the current time, in milliseconds.
*
* @return the elapsed time, in milliseconds
*/
default public long currentTimeInMillis() {
return (long) (currentTimeInMicros() / 1000.0);
}
/**
* Create a new time system that uses the FPGA clock. At this time, the precision of the resulting clock has not been
* verified or tested.
*
* @return the FPGA-based clock; never null
* @throws StrongbackRequirementException if the FPGA hardware is not available
*/
public static Clock fpga() {
try {
Utility.getFPGATime();
// If we're here, then the method did not throw an exception and there is FPGA hardware on this platform ...
return Utility::getFPGATime;
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
throw new StrongbackRequirementException("Missing FPGA hardware or software", e);
}
}
/**
* Create a new time system that uses the FPGA clock if it is available, or the {@link #system() JRE's time system} if not.
*
* @return the FPGA-based clock or (if that is not available) the system clock; never null
*/
public static Clock fpgaOrSystem() {
try {
return fpga();
} catch (StrongbackRequirementException e) {
return system();
}
}
/**
* Create a new time system that uses the JRE's System clock. The performance and precision of the JVM clock depends upon
* the accuracy and precision of the underlying platform's mechanism for returning absolute and relative time. Absolute time
* can be obtained via {@link #currentTimeInMillis()}, although precision on some platforms may be as low as 10 or 20
* milliseconds. Relative time that can be compared within a single process can be obtained via
* {@link #currentTimeInNanos()} and {@link #currentTimeInMicros()}, although again the precision may be at best around 10
* or 20 microseconds.
* <p>
* Additionally, care must be taken when using relative time on multi-core systems. Because relative time often uses the
* CPU's clock, relative time obtained from different CPUs might not be comparable. This is possible even if using a single
* thread, since the same thread might be scheduled on a different CPU after switching thread contexts.
*
* @return the system clock; never null
*/
public static Clock system() {
return new Clock() {
@Override
public long currentTimeInMicros() {
return (long) (currentTimeInNanos() / 1000.0);
}
@Override
public long currentTimeInNanos() {
return System.nanoTime();
}
@Override
public long currentTimeInMillis() {
return System.currentTimeMillis();
}
};
}
}