blob: c279089e31d1fa42889f8f85df42fbf40f1aa26d [file] [log] [blame]
Brian Silverman7be68ba2020-01-08 22:08:40 -08001#ifndef FRC971_WPILIB_FPGA_TIME_CONVERSION_H_
2#define FRC971_WPILIB_FPGA_TIME_CONVERSION_H_
3
Brian Silverman7be68ba2020-01-08 22:08:40 -08004#include <chrono>
Philipp Schrader790cb542023-07-05 21:06:52 -07005#include <optional>
6
7#include "glog/logging.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -08008
9#include "aos/time/time.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -080010#include "hal/cpp/fpga_clock.h"
11
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080012namespace frc971::wpilib {
Brian Silverman7be68ba2020-01-08 22:08:40 -080013
14// Returns the offset from the monotonic clock to the FPGA time. This is defined
15// as `fpga_time - monotonic_time`.
16// Returns nullopt if sampling the time once failed.
17std::optional<std::chrono::nanoseconds> CalculateFpgaOffset();
18
19class FpgaTimeConverter {
20 public:
21 aos::monotonic_clock::time_point FpgaToMonotonic(
22 hal::fpga_clock::time_point fpga_time) {
23 UpdateOffset();
24 return aos::monotonic_clock::epoch() +
25 (fpga_time.time_since_epoch() + offset_);
26 }
27
28 hal::fpga_clock::time_point MonotonicToFpga(
29 aos::monotonic_clock::time_point monotonic_time) {
30 UpdateOffset();
31 return hal::fpga_clock::epoch() +
32 std::chrono::duration_cast<hal::fpga_clock::duration>(
33 monotonic_time.time_since_epoch() - offset_);
34 }
35
36 private:
37 void UpdateOffset() {
38 for (int i = 0; i < 10; ++i) {
39 const auto new_offset = CalculateFpgaOffset();
40 if (new_offset) {
41 offset_ = *new_offset;
42 return;
43 } else if (offset_ != offset_.min()) {
44 return;
45 }
46 }
47 LOG(FATAL) << "Failed to calculate FPGA offset";
48 }
49
50 std::chrono::nanoseconds offset_ = std::chrono::nanoseconds::min();
51};
52
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080053} // namespace frc971::wpilib
Brian Silverman7be68ba2020-01-08 22:08:40 -080054
55#endif // FRC971_WPILIB_FPGA_TIME_CONVERSION_H_