blob: eb55664727c43ba20a6113a026a70b194b652201 [file] [log] [blame]
Brian Silverman4da58072015-01-26 20:18:52 -05001#ifndef FRC971_ENCODER_AND_POTENTIOMETER_H_
2#define FRC971_ENCODER_AND_POTENTIOMETER_H_
3
4#include <atomic>
Parker Schuhd3b7a8872018-02-19 16:42:27 -08005#include <cmath>
Brian Silverman4da58072015-01-26 20:18:52 -05006#include <thread>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/macros.h"
9#include "aos/mutex/mutex.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -070010#include "aos/time/time.h"
Brian Silverman4da58072015-01-26 20:18:52 -050011
Parker Schuhd3b7a8872018-02-19 16:42:27 -080012#include "frc971/wpilib/ahal/AnalogInput.h"
13#include "frc971/wpilib/ahal/Counter.h"
14#include "frc971/wpilib/ahal/DigitalSource.h"
15#include "frc971/wpilib/ahal/Encoder.h"
Brian Silverman4da58072015-01-26 20:18:52 -050016
Brian Silvermanb5b46ca2016-03-13 01:14:17 -050017#include "frc971/wpilib/dma.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080018#include "frc971/wpilib/dma_edge_counting.h"
Brian Silverman4da58072015-01-26 20:18:52 -050019
20namespace frc971 {
21namespace wpilib {
22
23// Latches values from an encoder and potentiometer on positive edges from
24// another input using an interrupt.
25class InterruptEncoderAndPotentiometer {
26 public:
27 // priority is the priority the thread will run at.
28 InterruptEncoderAndPotentiometer(int priority) : priority_(priority) {}
29
30 // Starts the thread running so it can receive interrupts.
31 void Start();
32
33 // Tells the thread to stop running and then waits for it to finish.
34 void Stop() {
35 run_ = false;
36 thread_.join();
37 }
38
39 // Loops until Stop() is called, reading interrupts.
40 // Designed to be called by ::std::thread internally.
41 void operator()();
42
43 // Returns the mutex which must be held while calling index_posedge_count(),
44 // last_encoder_value(), and last_potentiometer_voltage().
45 // Holding this mutex will increase the handling latency.
46 ::aos::Mutex *mutex() { return &mutex_; }
47
Parker Schuhd3b7a8872018-02-19 16:42:27 -080048 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Brian Silverman4da58072015-01-26 20:18:52 -050049 encoder_ = ::std::move(encoder);
50 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080051 frc::Encoder *encoder() const { return encoder_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050052
Parker Schuhd3b7a8872018-02-19 16:42:27 -080053 void set_index(::std::unique_ptr<frc::DigitalSource> index) {
Brian Silverman4da58072015-01-26 20:18:52 -050054 index_ = ::std::move(index);
55 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080056 frc::DigitalSource *index() const { return index_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050057
Parker Schuhd3b7a8872018-02-19 16:42:27 -080058 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Brian Silverman4da58072015-01-26 20:18:52 -050059 potentiometer_ = ::std::move(potentiometer);
60 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080061 frc::AnalogInput *potentiometer() const { return potentiometer_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050062
63 // Returns the number of poseges that have happened on the index input.
64 // mutex() must be held while calling this.
65 uint32_t index_posedge_count() const { return index_posedge_count_; }
66 // Returns the value of the encoder at the last index posedge.
67 // mutex() must be held while calling this.
68 int32_t last_encoder_value() const { return last_encoder_value_; }
69 // Returns the voltage of the potentiometer at the last index posedge.
70 // mutex() must be held while calling this.
71 float last_potentiometer_voltage() const {
72 return last_potentiometer_voltage_;
73 }
74
75 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -080076 ::std::unique_ptr<frc::Encoder> encoder_;
77 ::std::unique_ptr<frc::DigitalSource> index_;
78 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Brian Silverman4da58072015-01-26 20:18:52 -050079
80 int32_t last_encoder_value_{0};
81 float last_potentiometer_voltage_{0.0f};
82 uint32_t index_posedge_count_{0};
83
84 ::aos::Mutex mutex_;
85
86 const int priority_;
87
88 ::std::atomic<bool> run_{true};
89 ::std::thread thread_;
90
91 DISALLOW_COPY_AND_ASSIGN(InterruptEncoderAndPotentiometer);
92};
93
Brian Silverman7cce2d32017-02-19 21:48:48 -080094// Latches values from an encoder on positive edges from another input using
95// DMA.
96class DMAEncoder : public DMASampleHandlerInterface {
Brian Silverman4da58072015-01-26 20:18:52 -050097 public:
Brian Silverman7cce2d32017-02-19 21:48:48 -080098 DMAEncoder() {}
Brian Silverman4da58072015-01-26 20:18:52 -050099
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800100 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Brian Silverman4da58072015-01-26 20:18:52 -0500101 encoder_ = ::std::move(encoder);
102 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800103 frc::Encoder *encoder() const { return encoder_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -0500104
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800105 void set_index(::std::unique_ptr<frc::DigitalSource> index) {
Brian Silverman4da58072015-01-26 20:18:52 -0500106 index_ = ::std::move(index);
107 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800108 frc::DigitalSource *index() const { return index_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -0500109
Brian Silverman4da58072015-01-26 20:18:52 -0500110 // Returns the most recent polled value of the encoder.
111 uint32_t polled_encoder_value() const { return polled_encoder_value_; }
Brian Silverman4da58072015-01-26 20:18:52 -0500112
113 // Returns the number of poseges that have happened on the index input.
114 uint32_t index_posedge_count() const { return index_posedge_count_; }
115 // Returns the value of the encoder at the last index posedge.
116 int32_t last_encoder_value() const { return last_encoder_value_; }
Brian Silverman7cce2d32017-02-19 21:48:48 -0800117
118 void UpdateFromSample(const DMASample &sample) override {
119 DoUpdateFromSample(sample);
Brian Silverman4da58072015-01-26 20:18:52 -0500120 }
121
Brian Silverman7cce2d32017-02-19 21:48:48 -0800122 void PollFromSample(const DMASample &sample) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500123 polled_encoder_value_ = sample.GetRaw(encoder_.get());
Brian Silverman4da58072015-01-26 20:18:52 -0500124 }
125
Brian Silverman7cce2d32017-02-19 21:48:48 -0800126 void UpdatePolledValue() override {
Brian Silverman4da58072015-01-26 20:18:52 -0500127 polled_encoder_value_ = encoder_->GetRaw();
Brian Silverman4da58072015-01-26 20:18:52 -0500128 }
129
Brian Silverman7cce2d32017-02-19 21:48:48 -0800130 void AddToDMA(DMA *dma) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500131 dma->Add(encoder_.get());
132 dma->Add(index_.get());
Austin Schuhc6cc4102015-02-15 23:19:53 -0800133 dma->SetExternalTrigger(index_.get(), true, true);
Brian Silverman4da58072015-01-26 20:18:52 -0500134 }
135
Brian Silverman7cce2d32017-02-19 21:48:48 -0800136 protected:
137 // The same as UpdateFromSample except also returns true if this sample is a
138 // new edge on the index.
139 bool DoUpdateFromSample(const DMASample &sample);
140
Brian Silverman4da58072015-01-26 20:18:52 -0500141 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800142 ::std::unique_ptr<frc::Encoder> encoder_;
143 ::std::unique_ptr<frc::DigitalSource> index_;
Brian Silverman4da58072015-01-26 20:18:52 -0500144
145 int32_t polled_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500146
147 int32_t last_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500148
149 uint32_t index_posedge_count_ = 0;
150
151 // Whether or not it was triggered in the last sample.
152 bool index_last_value_ = false;
153
Brian Silverman7cce2d32017-02-19 21:48:48 -0800154 DISALLOW_COPY_AND_ASSIGN(DMAEncoder);
155};
156
157// Latches values from an encoder and potentiometer on positive edges from
158// another input using DMA.
159class DMAEncoderAndPotentiometer : public DMAEncoder {
160 public:
161 DMAEncoderAndPotentiometer() {}
162
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800163 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Brian Silverman7cce2d32017-02-19 21:48:48 -0800164 potentiometer_ = ::std::move(potentiometer);
165 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800166 frc::AnalogInput *potentiometer() const { return potentiometer_.get(); }
Brian Silverman7cce2d32017-02-19 21:48:48 -0800167
168 // Returns the most recent polled voltage of the potentiometer.
169 float polled_potentiometer_voltage() const {
170 return polled_potentiometer_voltage_;
171 }
172
173 // Returns the voltage of the potentiometer at the last index posedge.
174 float last_potentiometer_voltage() const {
175 return last_potentiometer_voltage_;
176 }
177
178 void UpdateFromSample(const DMASample &sample) override {
179 if (DMAEncoder::DoUpdateFromSample(sample)) {
180 last_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
181 }
182 }
183
184 void PollFromSample(const DMASample &sample) override {
185 polled_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
186 DMAEncoder::PollFromSample(sample);
187 }
188
189 void UpdatePolledValue() override {
190 polled_potentiometer_voltage_ = potentiometer_->GetVoltage();
191 DMAEncoder::UpdatePolledValue();
192 }
193
194 void AddToDMA(DMA *dma) override {
195 dma->Add(potentiometer_.get());
196 DMAEncoder::AddToDMA(dma);
197 }
198
199 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800200 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Brian Silverman7cce2d32017-02-19 21:48:48 -0800201
202 float polled_potentiometer_voltage_ = 0.0f;
203
204 float last_potentiometer_voltage_ = 0.0f;
205
Brian Silverman4da58072015-01-26 20:18:52 -0500206 DISALLOW_COPY_AND_ASSIGN(DMAEncoderAndPotentiometer);
207};
208
Austin Schuh2a3e0632018-02-19 16:24:49 -0800209// Class to read duty cycle of an input. This is tuned for the CTRE encoder's
210// absolute position output.
211class DutyCycleReader {
212 public:
213 // Configure the reader to use the provided digital input.
214 void set_input(::std::unique_ptr<::frc::DigitalInput> input) {
215 high_counter_.reset(new ::frc::Counter(input.get()));
216 high_counter_->SetMaxPeriod(kMaxPeriod);
217 high_counter_->SetSemiPeriodMode(true);
218
219 period_length_counter_.reset(new ::frc::Counter(input.get()));
220 period_length_counter_->SetMaxPeriod(kMaxPeriod);
221 period_length_counter_->SetUpSourceEdge(true, false);
222
223 input_ = ::std::move(input);
224 }
225
226 // Returns the last duty cycle or nan if the signal is stale.
227 double Read() const {
228 const double high_time = high_counter_->GetPeriod();
229 const double period_length = period_length_counter_->GetPeriod();
230 if (!::std::isfinite(high_time) || !::std::isfinite(period_length)) {
231 return ::std::numeric_limits<double>::quiet_NaN();
232 }
233 return high_time / period_length;
234 }
235
236 private:
237 static constexpr ::std::chrono::nanoseconds kNominalPeriod =
238 ::std::chrono::microseconds(4096);
239 static constexpr double kMaxPeriod =
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700240 ::aos::time::DurationInSeconds(kNominalPeriod * 2);
Austin Schuh2a3e0632018-02-19 16:24:49 -0800241
242 ::std::unique_ptr<::frc::Counter> high_counter_, period_length_counter_;
243 ::std::unique_ptr<::frc::DigitalInput> input_;
244};
245
246// Class to hold a CTRE encoder with absolute angle pwm and potentiometer pair.
247class AbsoluteEncoderAndPotentiometer {
248 public:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800249 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800250 duty_cycle_.set_input(::std::move(input));
251 }
252
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800253 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800254 encoder_ = ::std::move(encoder);
255 }
256
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800257 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800258 potentiometer_ = ::std::move(potentiometer);
259 }
260
261 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
262 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
263 double ReadPotentiometerVoltage() const {
264 return potentiometer_->GetVoltage();
265 }
266
267 private:
268 DutyCycleReader duty_cycle_;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800269 ::std::unique_ptr<frc::Encoder> encoder_;
270 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Austin Schuh2a3e0632018-02-19 16:24:49 -0800271};
272
Sabina Davis8d8ac0a2019-02-06 23:51:07 -0800273class AbsoluteEncoder {
274 public:
275 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
276 duty_cycle_.set_input(::std::move(input));
277 }
278
279 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
280 encoder_ = ::std::move(encoder);
281 }
282
283 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
284 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
285
286 private:
287 DutyCycleReader duty_cycle_;
288 ::std::unique_ptr<frc::Encoder> encoder_;
289};
290
Brian Silverman4da58072015-01-26 20:18:52 -0500291} // namespace wpilib
292} // namespace frc971
293
294#endif // FRC971_ENCODER_AND_POTENTIOMETER_H_