blob: 2f50c4ae3647989c4ef13aaf485ecd361b191383 [file] [log] [blame]
Sabina Davisadc58542019-02-01 22:23:00 -08001#include "frc971/wpilib/sensor_reader.h"
2
Sabina Davis399dbd82019-02-01 23:06:08 -08003#include <inttypes.h>
4#include <unistd.h>
5
Sabina Davisadc58542019-02-01 22:23:00 -08006#include "aos/init.h"
7#include "aos/util/compiler_memory_barrier.h"
Sabina Davis399dbd82019-02-01 23:06:08 -08008#include "aos/util/phased_loop.h"
Sabina Davisadc58542019-02-01 22:23:00 -08009#include "frc971/wpilib/ahal/DigitalInput.h"
10#include "frc971/wpilib/ahal/Utility.h"
11
12namespace frc971 {
13namespace wpilib {
14
15SensorReader::SensorReader() {}
16
Sabina Davisb6317b72019-02-01 22:53:23 -080017void SensorReader::set_drivetrain_left_encoder(
18 ::std::unique_ptr<frc::Encoder> encoder) {
19 fast_encoder_filter_.Add(encoder.get());
20 drivetrain_left_encoder_ = ::std::move(encoder);
21}
22
23void SensorReader::set_drivetrain_right_encoder(
24 ::std::unique_ptr<frc::Encoder> encoder) {
25 fast_encoder_filter_.Add(encoder.get());
26 drivetrain_right_encoder_ = ::std::move(encoder);
27}
28
29// All of the DMA-related set_* calls must be made before this, and it
30// doesn't hurt to do all of them.
Sabina Davis1ffa4172019-02-01 22:38:33 -080031void SensorReader::set_dma(::std::unique_ptr<DMA> dma) {
32 dma_synchronizer_.reset(
33 new ::frc971::wpilib::DMASynchronizer(::std::move(dma)));
34}
35
Sabina Davisadc58542019-02-01 22:23:00 -080036void SensorReader::set_pwm_trigger(
37 ::std::unique_ptr<frc::DigitalInput> pwm_trigger) {
38 medium_encoder_filter_.Add(pwm_trigger.get());
39 pwm_trigger_ = ::std::move(pwm_trigger);
40}
41
42void SensorReader::RunPWMDetecter() {
43 ::aos::SetCurrentThreadRealtimePriority(41);
44
45 pwm_trigger_->RequestInterrupts();
46 // Rising edge only.
47 pwm_trigger_->SetUpSourceEdge(true, false);
48
49 monotonic_clock::time_point last_posedge_monotonic =
50 monotonic_clock::min_time;
51
52 while (run_) {
53 auto ret = pwm_trigger_->WaitForInterrupt(1.0, true);
54 if (ret == frc::InterruptableSensorBase::WaitResult::kRisingEdge) {
55 // Grab all the clocks.
56 const double pwm_fpga_time = pwm_trigger_->ReadRisingTimestamp();
57
58 aos_compiler_memory_barrier();
59 const double fpga_time_before = frc::GetFPGATime() * 1e-6;
60 aos_compiler_memory_barrier();
61 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
62 aos_compiler_memory_barrier();
63 const double fpga_time_after = frc::GetFPGATime() * 1e-6;
64 aos_compiler_memory_barrier();
65
66 const double fpga_offset =
67 (fpga_time_after + fpga_time_before) / 2.0 - pwm_fpga_time;
68
69 // Compute when the edge was.
70 const monotonic_clock::time_point monotonic_edge =
71 monotonic_now - chrono::duration_cast<chrono::nanoseconds>(
72 chrono::duration<double>(fpga_offset));
73
74 LOG(DEBUG, "Got PWM pulse %f spread, %f offset, %lld trigger\n",
75 fpga_time_after - fpga_time_before, fpga_offset,
76 monotonic_edge.time_since_epoch().count());
77
78 // Compute bounds on the timestep and sampling times.
79 const double fpga_sample_length = fpga_time_after - fpga_time_before;
80 const chrono::nanoseconds elapsed_time =
81 monotonic_edge - last_posedge_monotonic;
82
83 last_posedge_monotonic = monotonic_edge;
84
85 // Verify that the values are sane.
86 if (fpga_sample_length > 2e-5 || fpga_sample_length < 0) {
87 continue;
88 }
89 if (fpga_offset < 0 || fpga_offset > 0.00015) {
90 continue;
91 }
92 if (elapsed_time > chrono::microseconds(5050) + chrono::microseconds(4) ||
93 elapsed_time < chrono::microseconds(5050) - chrono::microseconds(4)) {
94 continue;
95 }
96 // Good edge!
97 {
98 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
99 last_tick_time_monotonic_timepoint_ = last_posedge_monotonic;
100 last_period_ = elapsed_time;
101 }
102 } else {
103 LOG(INFO, "PWM triggered %d\n", ret);
104 }
105 }
106 pwm_trigger_->CancelInterrupts();
107}
108
Sabina Davis399dbd82019-02-01 23:06:08 -0800109void SensorReader::operator()() {
110 ::aos::SetCurrentThreadName("SensorReader");
111
112 my_pid_ = getpid();
113
114 dma_synchronizer_->Start();
115
116 ::aos::time::PhasedLoop phased_loop(last_period_,
117 ::std::chrono::milliseconds(3));
118 chrono::nanoseconds filtered_period = last_period_;
119
120 ::std::thread pwm_detecter_thread(
121 ::std::bind(&SensorReader::RunPWMDetecter, this));
122
123 ::aos::SetCurrentThreadRealtimePriority(40);
124 while (run_) {
125 {
126 const int iterations = phased_loop.SleepUntilNext();
127 if (iterations != 1) {
128 LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
129 }
130 }
131 RunIteration();
132
133 monotonic_clock::time_point last_tick_timepoint;
134 chrono::nanoseconds period;
135 {
136 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
137 last_tick_timepoint = last_tick_time_monotonic_timepoint_;
138 period = last_period_;
139 }
140
141 if (last_tick_timepoint == monotonic_clock::min_time) {
142 continue;
143 }
144 chrono::nanoseconds new_offset = phased_loop.OffsetFromIntervalAndTime(
145 period, last_tick_timepoint + chrono::microseconds(2050));
146
147 // TODO(austin): If this is the first edge in a while, skip to it (plus
148 // an offset). Otherwise, slowly drift time to line up.
149
150 phased_loop.set_interval_and_offset(period, new_offset);
151 }
152 pwm_detecter_thread.join();
153}
154
Sabina Davisadc58542019-02-01 22:23:00 -0800155} // namespace wpilib
156} // namespace frc971