blob: 9862918ef9fdf34899ce38c08afb41ab08654778 [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
4#include <optional>
5#include <chrono>
6
7#include "aos/time/time.h"
8#include "glog/logging.h"
9#include "hal/cpp/fpga_clock.h"
10
11namespace frc971 {
12namespace wpilib {
13
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
53} // namespace wpilib
54} // namespace frc971
55
56#endif // FRC971_WPILIB_FPGA_TIME_CONVERSION_H_