blob: 51cc7a9e834135f5332320e4686e555e64b5b1fb [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
12namespace frc971 {
13namespace wpilib {
14
15// Returns the offset from the monotonic clock to the FPGA time. This is defined
16// as `fpga_time - monotonic_time`.
17// Returns nullopt if sampling the time once failed.
18std::optional<std::chrono::nanoseconds> CalculateFpgaOffset();
19
20class FpgaTimeConverter {
21 public:
22 aos::monotonic_clock::time_point FpgaToMonotonic(
23 hal::fpga_clock::time_point fpga_time) {
24 UpdateOffset();
25 return aos::monotonic_clock::epoch() +
26 (fpga_time.time_since_epoch() + offset_);
27 }
28
29 hal::fpga_clock::time_point MonotonicToFpga(
30 aos::monotonic_clock::time_point monotonic_time) {
31 UpdateOffset();
32 return hal::fpga_clock::epoch() +
33 std::chrono::duration_cast<hal::fpga_clock::duration>(
34 monotonic_time.time_since_epoch() - offset_);
35 }
36
37 private:
38 void UpdateOffset() {
39 for (int i = 0; i < 10; ++i) {
40 const auto new_offset = CalculateFpgaOffset();
41 if (new_offset) {
42 offset_ = *new_offset;
43 return;
44 } else if (offset_ != offset_.min()) {
45 return;
46 }
47 }
48 LOG(FATAL) << "Failed to calculate FPGA offset";
49 }
50
51 std::chrono::nanoseconds offset_ = std::chrono::nanoseconds::min();
52};
53
54} // namespace wpilib
55} // namespace frc971
56
57#endif // FRC971_WPILIB_FPGA_TIME_CONVERSION_H_