blob: 9862918ef9fdf34899ce38c08afb41ab08654778 [file] [log] [blame]
#ifndef FRC971_WPILIB_FPGA_TIME_CONVERSION_H_
#define FRC971_WPILIB_FPGA_TIME_CONVERSION_H_
#include <optional>
#include <chrono>
#include "aos/time/time.h"
#include "glog/logging.h"
#include "hal/cpp/fpga_clock.h"
namespace frc971 {
namespace wpilib {
// Returns the offset from the monotonic clock to the FPGA time. This is defined
// as `fpga_time - monotonic_time`.
// Returns nullopt if sampling the time once failed.
std::optional<std::chrono::nanoseconds> CalculateFpgaOffset();
class FpgaTimeConverter {
public:
aos::monotonic_clock::time_point FpgaToMonotonic(
hal::fpga_clock::time_point fpga_time) {
UpdateOffset();
return aos::monotonic_clock::epoch() +
(fpga_time.time_since_epoch() + offset_);
}
hal::fpga_clock::time_point MonotonicToFpga(
aos::monotonic_clock::time_point monotonic_time) {
UpdateOffset();
return hal::fpga_clock::epoch() +
std::chrono::duration_cast<hal::fpga_clock::duration>(
monotonic_time.time_since_epoch() - offset_);
}
private:
void UpdateOffset() {
for (int i = 0; i < 10; ++i) {
const auto new_offset = CalculateFpgaOffset();
if (new_offset) {
offset_ = *new_offset;
return;
} else if (offset_ != offset_.min()) {
return;
}
}
LOG(FATAL) << "Failed to calculate FPGA offset";
}
std::chrono::nanoseconds offset_ = std::chrono::nanoseconds::min();
};
} // namespace wpilib
} // namespace frc971
#endif // FRC971_WPILIB_FPGA_TIME_CONVERSION_H_