blob: 42fb86b0d78f4491f202445fe8bd4e70ea73cf7e [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"
Brian Silverman4da58072015-01-26 20:18:52 -050010
Parker Schuhd3b7a8872018-02-19 16:42:27 -080011#include "frc971/wpilib/ahal/AnalogInput.h"
12#include "frc971/wpilib/ahal/Counter.h"
13#include "frc971/wpilib/ahal/DigitalSource.h"
14#include "frc971/wpilib/ahal/Encoder.h"
Brian Silverman4da58072015-01-26 20:18:52 -050015
Brian Silvermanb5b46ca2016-03-13 01:14:17 -050016#include "frc971/wpilib/dma.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080017#include "frc971/wpilib/dma_edge_counting.h"
Brian Silverman4da58072015-01-26 20:18:52 -050018
19namespace frc971 {
20namespace wpilib {
21
22// Latches values from an encoder and potentiometer on positive edges from
23// another input using an interrupt.
24class InterruptEncoderAndPotentiometer {
25 public:
26 // priority is the priority the thread will run at.
27 InterruptEncoderAndPotentiometer(int priority) : priority_(priority) {}
28
29 // Starts the thread running so it can receive interrupts.
30 void Start();
31
32 // Tells the thread to stop running and then waits for it to finish.
33 void Stop() {
34 run_ = false;
35 thread_.join();
36 }
37
38 // Loops until Stop() is called, reading interrupts.
39 // Designed to be called by ::std::thread internally.
40 void operator()();
41
42 // Returns the mutex which must be held while calling index_posedge_count(),
43 // last_encoder_value(), and last_potentiometer_voltage().
44 // Holding this mutex will increase the handling latency.
45 ::aos::Mutex *mutex() { return &mutex_; }
46
Parker Schuhd3b7a8872018-02-19 16:42:27 -080047 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Brian Silverman4da58072015-01-26 20:18:52 -050048 encoder_ = ::std::move(encoder);
49 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080050 frc::Encoder *encoder() const { return encoder_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050051
Parker Schuhd3b7a8872018-02-19 16:42:27 -080052 void set_index(::std::unique_ptr<frc::DigitalSource> index) {
Brian Silverman4da58072015-01-26 20:18:52 -050053 index_ = ::std::move(index);
54 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080055 frc::DigitalSource *index() const { return index_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050056
Parker Schuhd3b7a8872018-02-19 16:42:27 -080057 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Brian Silverman4da58072015-01-26 20:18:52 -050058 potentiometer_ = ::std::move(potentiometer);
59 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -080060 frc::AnalogInput *potentiometer() const { return potentiometer_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -050061
62 // Returns the number of poseges that have happened on the index input.
63 // mutex() must be held while calling this.
64 uint32_t index_posedge_count() const { return index_posedge_count_; }
65 // Returns the value of the encoder at the last index posedge.
66 // mutex() must be held while calling this.
67 int32_t last_encoder_value() const { return last_encoder_value_; }
68 // Returns the voltage of the potentiometer at the last index posedge.
69 // mutex() must be held while calling this.
70 float last_potentiometer_voltage() const {
71 return last_potentiometer_voltage_;
72 }
73
74 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -080075 ::std::unique_ptr<frc::Encoder> encoder_;
76 ::std::unique_ptr<frc::DigitalSource> index_;
77 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Brian Silverman4da58072015-01-26 20:18:52 -050078
79 int32_t last_encoder_value_{0};
80 float last_potentiometer_voltage_{0.0f};
81 uint32_t index_posedge_count_{0};
82
83 ::aos::Mutex mutex_;
84
85 const int priority_;
86
87 ::std::atomic<bool> run_{true};
88 ::std::thread thread_;
89
90 DISALLOW_COPY_AND_ASSIGN(InterruptEncoderAndPotentiometer);
91};
92
Brian Silverman7cce2d32017-02-19 21:48:48 -080093// Latches values from an encoder on positive edges from another input using
94// DMA.
95class DMAEncoder : public DMASampleHandlerInterface {
Brian Silverman4da58072015-01-26 20:18:52 -050096 public:
Brian Silverman7cce2d32017-02-19 21:48:48 -080097 DMAEncoder() {}
Brian Silverman4da58072015-01-26 20:18:52 -050098
Parker Schuhd3b7a8872018-02-19 16:42:27 -080099 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Brian Silverman4da58072015-01-26 20:18:52 -0500100 encoder_ = ::std::move(encoder);
101 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800102 frc::Encoder *encoder() const { return encoder_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -0500103
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800104 void set_index(::std::unique_ptr<frc::DigitalSource> index) {
Brian Silverman4da58072015-01-26 20:18:52 -0500105 index_ = ::std::move(index);
106 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800107 frc::DigitalSource *index() const { return index_.get(); }
Brian Silverman4da58072015-01-26 20:18:52 -0500108
Brian Silverman4da58072015-01-26 20:18:52 -0500109 // Returns the most recent polled value of the encoder.
110 uint32_t polled_encoder_value() const { return polled_encoder_value_; }
Brian Silverman4da58072015-01-26 20:18:52 -0500111
112 // Returns the number of poseges that have happened on the index input.
113 uint32_t index_posedge_count() const { return index_posedge_count_; }
114 // Returns the value of the encoder at the last index posedge.
115 int32_t last_encoder_value() const { return last_encoder_value_; }
Brian Silverman7cce2d32017-02-19 21:48:48 -0800116
117 void UpdateFromSample(const DMASample &sample) override {
118 DoUpdateFromSample(sample);
Brian Silverman4da58072015-01-26 20:18:52 -0500119 }
120
Brian Silverman7cce2d32017-02-19 21:48:48 -0800121 void PollFromSample(const DMASample &sample) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500122 polled_encoder_value_ = sample.GetRaw(encoder_.get());
Brian Silverman4da58072015-01-26 20:18:52 -0500123 }
124
Brian Silverman7cce2d32017-02-19 21:48:48 -0800125 void UpdatePolledValue() override {
Brian Silverman4da58072015-01-26 20:18:52 -0500126 polled_encoder_value_ = encoder_->GetRaw();
Brian Silverman4da58072015-01-26 20:18:52 -0500127 }
128
Brian Silverman7cce2d32017-02-19 21:48:48 -0800129 void AddToDMA(DMA *dma) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500130 dma->Add(encoder_.get());
131 dma->Add(index_.get());
Austin Schuhc6cc4102015-02-15 23:19:53 -0800132 dma->SetExternalTrigger(index_.get(), true, true);
Brian Silverman4da58072015-01-26 20:18:52 -0500133 }
134
Brian Silverman7cce2d32017-02-19 21:48:48 -0800135 protected:
136 // The same as UpdateFromSample except also returns true if this sample is a
137 // new edge on the index.
138 bool DoUpdateFromSample(const DMASample &sample);
139
Brian Silverman4da58072015-01-26 20:18:52 -0500140 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800141 ::std::unique_ptr<frc::Encoder> encoder_;
142 ::std::unique_ptr<frc::DigitalSource> index_;
Brian Silverman4da58072015-01-26 20:18:52 -0500143
144 int32_t polled_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500145
146 int32_t last_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500147
148 uint32_t index_posedge_count_ = 0;
149
150 // Whether or not it was triggered in the last sample.
151 bool index_last_value_ = false;
152
Brian Silverman7cce2d32017-02-19 21:48:48 -0800153 DISALLOW_COPY_AND_ASSIGN(DMAEncoder);
154};
155
156// Latches values from an encoder and potentiometer on positive edges from
157// another input using DMA.
158class DMAEncoderAndPotentiometer : public DMAEncoder {
159 public:
160 DMAEncoderAndPotentiometer() {}
161
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800162 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Brian Silverman7cce2d32017-02-19 21:48:48 -0800163 potentiometer_ = ::std::move(potentiometer);
164 }
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800165 frc::AnalogInput *potentiometer() const { return potentiometer_.get(); }
Brian Silverman7cce2d32017-02-19 21:48:48 -0800166
167 // Returns the most recent polled voltage of the potentiometer.
168 float polled_potentiometer_voltage() const {
169 return polled_potentiometer_voltage_;
170 }
171
172 // Returns the voltage of the potentiometer at the last index posedge.
173 float last_potentiometer_voltage() const {
174 return last_potentiometer_voltage_;
175 }
176
177 void UpdateFromSample(const DMASample &sample) override {
178 if (DMAEncoder::DoUpdateFromSample(sample)) {
179 last_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
180 }
181 }
182
183 void PollFromSample(const DMASample &sample) override {
184 polled_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
185 DMAEncoder::PollFromSample(sample);
186 }
187
188 void UpdatePolledValue() override {
189 polled_potentiometer_voltage_ = potentiometer_->GetVoltage();
190 DMAEncoder::UpdatePolledValue();
191 }
192
193 void AddToDMA(DMA *dma) override {
194 dma->Add(potentiometer_.get());
195 DMAEncoder::AddToDMA(dma);
196 }
197
198 private:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800199 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Brian Silverman7cce2d32017-02-19 21:48:48 -0800200
201 float polled_potentiometer_voltage_ = 0.0f;
202
203 float last_potentiometer_voltage_ = 0.0f;
204
Brian Silverman4da58072015-01-26 20:18:52 -0500205 DISALLOW_COPY_AND_ASSIGN(DMAEncoderAndPotentiometer);
206};
207
Austin Schuh2a3e0632018-02-19 16:24:49 -0800208// Class to read duty cycle of an input. This is tuned for the CTRE encoder's
209// absolute position output.
210class DutyCycleReader {
211 public:
212 // Configure the reader to use the provided digital input.
213 void set_input(::std::unique_ptr<::frc::DigitalInput> input) {
214 high_counter_.reset(new ::frc::Counter(input.get()));
215 high_counter_->SetMaxPeriod(kMaxPeriod);
216 high_counter_->SetSemiPeriodMode(true);
217
218 period_length_counter_.reset(new ::frc::Counter(input.get()));
219 period_length_counter_->SetMaxPeriod(kMaxPeriod);
220 period_length_counter_->SetUpSourceEdge(true, false);
221
222 input_ = ::std::move(input);
223 }
224
225 // Returns the last duty cycle or nan if the signal is stale.
226 double Read() const {
227 const double high_time = high_counter_->GetPeriod();
228 const double period_length = period_length_counter_->GetPeriod();
229 if (!::std::isfinite(high_time) || !::std::isfinite(period_length)) {
230 return ::std::numeric_limits<double>::quiet_NaN();
231 }
232 return high_time / period_length;
233 }
234
235 private:
236 static constexpr ::std::chrono::nanoseconds kNominalPeriod =
237 ::std::chrono::microseconds(4096);
238 static constexpr double kMaxPeriod =
239 (::std::chrono::duration_cast<::std::chrono::duration<double>>(
240 kNominalPeriod) *
241 2).count();
242
243 ::std::unique_ptr<::frc::Counter> high_counter_, period_length_counter_;
244 ::std::unique_ptr<::frc::DigitalInput> input_;
245};
246
247// Class to hold a CTRE encoder with absolute angle pwm and potentiometer pair.
248class AbsoluteEncoderAndPotentiometer {
249 public:
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800250 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800251 duty_cycle_.set_input(::std::move(input));
252 }
253
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800254 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800255 encoder_ = ::std::move(encoder);
256 }
257
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800258 void set_potentiometer(::std::unique_ptr<frc::AnalogInput> potentiometer) {
Austin Schuh2a3e0632018-02-19 16:24:49 -0800259 potentiometer_ = ::std::move(potentiometer);
260 }
261
262 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
263 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
264 double ReadPotentiometerVoltage() const {
265 return potentiometer_->GetVoltage();
266 }
267
268 private:
269 DutyCycleReader duty_cycle_;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800270 ::std::unique_ptr<frc::Encoder> encoder_;
271 ::std::unique_ptr<frc::AnalogInput> potentiometer_;
Austin Schuh2a3e0632018-02-19 16:24:49 -0800272};
273
Sabina Davis8d8ac0a2019-02-06 23:51:07 -0800274class AbsoluteEncoder {
275 public:
276 void set_absolute_pwm(::std::unique_ptr<frc::DigitalInput> input) {
277 duty_cycle_.set_input(::std::move(input));
278 }
279
280 void set_encoder(::std::unique_ptr<frc::Encoder> encoder) {
281 encoder_ = ::std::move(encoder);
282 }
283
284 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
285 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
286
287 private:
288 DutyCycleReader duty_cycle_;
289 ::std::unique_ptr<frc::Encoder> encoder_;
290};
291
Brian Silverman4da58072015-01-26 20:18:52 -0500292} // namespace wpilib
293} // namespace frc971
294
295#endif // FRC971_ENCODER_AND_POTENTIOMETER_H_