blob: 3cce77dc369d8175b323ace9a43047adf5310154 [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>
5#include <thread>
6
7#include "aos/common/macros.h"
8#include "aos/common/mutex.h"
9
10#include "Encoder.h"
11#include "DigitalSource.h"
12#include "AnalogInput.h"
Brian Silverman4da58072015-01-26 20:18:52 -050013
14#include "frc971/wpilib/dma_edge_counting.h"
Brian Silvermanb5b46ca2016-03-13 01:14:17 -050015#include "frc971/wpilib/dma.h"
Brian Silverman4da58072015-01-26 20:18:52 -050016
17namespace frc971 {
18namespace wpilib {
19
20// Latches values from an encoder and potentiometer on positive edges from
21// another input using an interrupt.
22class InterruptEncoderAndPotentiometer {
23 public:
24 // priority is the priority the thread will run at.
25 InterruptEncoderAndPotentiometer(int priority) : priority_(priority) {}
26
27 // Starts the thread running so it can receive interrupts.
28 void Start();
29
30 // Tells the thread to stop running and then waits for it to finish.
31 void Stop() {
32 run_ = false;
33 thread_.join();
34 }
35
36 // Loops until Stop() is called, reading interrupts.
37 // Designed to be called by ::std::thread internally.
38 void operator()();
39
40 // Returns the mutex which must be held while calling index_posedge_count(),
41 // last_encoder_value(), and last_potentiometer_voltage().
42 // Holding this mutex will increase the handling latency.
43 ::aos::Mutex *mutex() { return &mutex_; }
44
45 void set_encoder(::std::unique_ptr<Encoder> encoder) {
46 encoder_ = ::std::move(encoder);
47 }
48 Encoder *encoder() const { return encoder_.get(); }
49
50 void set_index(::std::unique_ptr<DigitalSource> index) {
51 index_ = ::std::move(index);
52 }
53 DigitalSource *index() const { return index_.get(); }
54
55 void set_potentiometer(::std::unique_ptr<AnalogInput> potentiometer) {
56 potentiometer_ = ::std::move(potentiometer);
57 }
58 AnalogInput *potentiometer() const { return potentiometer_.get(); }
59
60 // Returns the number of poseges that have happened on the index input.
61 // mutex() must be held while calling this.
62 uint32_t index_posedge_count() const { return index_posedge_count_; }
63 // Returns the value of the encoder at the last index posedge.
64 // mutex() must be held while calling this.
65 int32_t last_encoder_value() const { return last_encoder_value_; }
66 // Returns the voltage of the potentiometer at the last index posedge.
67 // mutex() must be held while calling this.
68 float last_potentiometer_voltage() const {
69 return last_potentiometer_voltage_;
70 }
71
72 private:
73 ::std::unique_ptr<Encoder> encoder_;
74 ::std::unique_ptr<DigitalSource> index_;
75 ::std::unique_ptr<AnalogInput> potentiometer_;
76
77 int32_t last_encoder_value_{0};
78 float last_potentiometer_voltage_{0.0f};
79 uint32_t index_posedge_count_{0};
80
81 ::aos::Mutex mutex_;
82
83 const int priority_;
84
85 ::std::atomic<bool> run_{true};
86 ::std::thread thread_;
87
88 DISALLOW_COPY_AND_ASSIGN(InterruptEncoderAndPotentiometer);
89};
90
Brian Silverman7cce2d32017-02-19 21:48:48 -080091// Latches values from an encoder on positive edges from another input using
92// DMA.
93class DMAEncoder : public DMASampleHandlerInterface {
Brian Silverman4da58072015-01-26 20:18:52 -050094 public:
Brian Silverman7cce2d32017-02-19 21:48:48 -080095 DMAEncoder() {}
Brian Silverman4da58072015-01-26 20:18:52 -050096
97 void set_encoder(::std::unique_ptr<Encoder> encoder) {
98 encoder_ = ::std::move(encoder);
99 }
100 Encoder *encoder() const { return encoder_.get(); }
101
102 void set_index(::std::unique_ptr<DigitalSource> index) {
103 index_ = ::std::move(index);
104 }
105 DigitalSource *index() const { return index_.get(); }
106
Brian Silverman4da58072015-01-26 20:18:52 -0500107 // Returns the most recent polled value of the encoder.
108 uint32_t polled_encoder_value() const { return polled_encoder_value_; }
Brian Silverman4da58072015-01-26 20:18:52 -0500109
110 // Returns the number of poseges that have happened on the index input.
111 uint32_t index_posedge_count() const { return index_posedge_count_; }
112 // Returns the value of the encoder at the last index posedge.
113 int32_t last_encoder_value() const { return last_encoder_value_; }
Brian Silverman7cce2d32017-02-19 21:48:48 -0800114
115 void UpdateFromSample(const DMASample &sample) override {
116 DoUpdateFromSample(sample);
Brian Silverman4da58072015-01-26 20:18:52 -0500117 }
118
Brian Silverman7cce2d32017-02-19 21:48:48 -0800119 void PollFromSample(const DMASample &sample) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500120 polled_encoder_value_ = sample.GetRaw(encoder_.get());
Brian Silverman4da58072015-01-26 20:18:52 -0500121 }
122
Brian Silverman7cce2d32017-02-19 21:48:48 -0800123 void UpdatePolledValue() override {
Brian Silverman4da58072015-01-26 20:18:52 -0500124 polled_encoder_value_ = encoder_->GetRaw();
Brian Silverman4da58072015-01-26 20:18:52 -0500125 }
126
Brian Silverman7cce2d32017-02-19 21:48:48 -0800127 void AddToDMA(DMA *dma) override {
Brian Silverman4da58072015-01-26 20:18:52 -0500128 dma->Add(encoder_.get());
129 dma->Add(index_.get());
Austin Schuhc6cc4102015-02-15 23:19:53 -0800130 dma->SetExternalTrigger(index_.get(), true, true);
Brian Silverman4da58072015-01-26 20:18:52 -0500131 }
132
Brian Silverman7cce2d32017-02-19 21:48:48 -0800133 protected:
134 // The same as UpdateFromSample except also returns true if this sample is a
135 // new edge on the index.
136 bool DoUpdateFromSample(const DMASample &sample);
137
Brian Silverman4da58072015-01-26 20:18:52 -0500138 private:
139 ::std::unique_ptr<Encoder> encoder_;
140 ::std::unique_ptr<DigitalSource> index_;
Brian Silverman4da58072015-01-26 20:18:52 -0500141
142 int32_t polled_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500143
144 int32_t last_encoder_value_ = 0;
Brian Silverman4da58072015-01-26 20:18:52 -0500145
146 uint32_t index_posedge_count_ = 0;
147
148 // Whether or not it was triggered in the last sample.
149 bool index_last_value_ = false;
150
Brian Silverman7cce2d32017-02-19 21:48:48 -0800151 DISALLOW_COPY_AND_ASSIGN(DMAEncoder);
152};
153
154// Latches values from an encoder and potentiometer on positive edges from
155// another input using DMA.
156class DMAEncoderAndPotentiometer : public DMAEncoder {
157 public:
158 DMAEncoderAndPotentiometer() {}
159
160 void set_potentiometer(::std::unique_ptr<AnalogInput> potentiometer) {
161 potentiometer_ = ::std::move(potentiometer);
162 }
163 AnalogInput *potentiometer() const { return potentiometer_.get(); }
164
165 // Returns the most recent polled voltage of the potentiometer.
166 float polled_potentiometer_voltage() const {
167 return polled_potentiometer_voltage_;
168 }
169
170 // Returns the voltage of the potentiometer at the last index posedge.
171 float last_potentiometer_voltage() const {
172 return last_potentiometer_voltage_;
173 }
174
175 void UpdateFromSample(const DMASample &sample) override {
176 if (DMAEncoder::DoUpdateFromSample(sample)) {
177 last_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
178 }
179 }
180
181 void PollFromSample(const DMASample &sample) override {
182 polled_potentiometer_voltage_ = sample.GetVoltage(potentiometer_.get());
183 DMAEncoder::PollFromSample(sample);
184 }
185
186 void UpdatePolledValue() override {
187 polled_potentiometer_voltage_ = potentiometer_->GetVoltage();
188 DMAEncoder::UpdatePolledValue();
189 }
190
191 void AddToDMA(DMA *dma) override {
192 dma->Add(potentiometer_.get());
193 DMAEncoder::AddToDMA(dma);
194 }
195
196 private:
197 ::std::unique_ptr<AnalogInput> potentiometer_;
198
199 float polled_potentiometer_voltage_ = 0.0f;
200
201 float last_potentiometer_voltage_ = 0.0f;
202
Brian Silverman4da58072015-01-26 20:18:52 -0500203 DISALLOW_COPY_AND_ASSIGN(DMAEncoderAndPotentiometer);
204};
205
Austin Schuh2a3e0632018-02-19 16:24:49 -0800206// Class to read duty cycle of an input. This is tuned for the CTRE encoder's
207// absolute position output.
208class DutyCycleReader {
209 public:
210 // Configure the reader to use the provided digital input.
211 void set_input(::std::unique_ptr<::frc::DigitalInput> input) {
212 high_counter_.reset(new ::frc::Counter(input.get()));
213 high_counter_->SetMaxPeriod(kMaxPeriod);
214 high_counter_->SetSemiPeriodMode(true);
215
216 period_length_counter_.reset(new ::frc::Counter(input.get()));
217 period_length_counter_->SetMaxPeriod(kMaxPeriod);
218 period_length_counter_->SetUpSourceEdge(true, false);
219
220 input_ = ::std::move(input);
221 }
222
223 // Returns the last duty cycle or nan if the signal is stale.
224 double Read() const {
225 const double high_time = high_counter_->GetPeriod();
226 const double period_length = period_length_counter_->GetPeriod();
227 if (!::std::isfinite(high_time) || !::std::isfinite(period_length)) {
228 return ::std::numeric_limits<double>::quiet_NaN();
229 }
230 return high_time / period_length;
231 }
232
233 private:
234 static constexpr ::std::chrono::nanoseconds kNominalPeriod =
235 ::std::chrono::microseconds(4096);
236 static constexpr double kMaxPeriod =
237 (::std::chrono::duration_cast<::std::chrono::duration<double>>(
238 kNominalPeriod) *
239 2).count();
240
241 ::std::unique_ptr<::frc::Counter> high_counter_, period_length_counter_;
242 ::std::unique_ptr<::frc::DigitalInput> input_;
243};
244
245// Class to hold a CTRE encoder with absolute angle pwm and potentiometer pair.
246class AbsoluteEncoderAndPotentiometer {
247 public:
248 void set_absolute_pwm(::std::unique_ptr<DigitalInput> input) {
249 duty_cycle_.set_input(::std::move(input));
250 }
251
252 void set_encoder(::std::unique_ptr<Encoder> encoder) {
253 encoder_ = ::std::move(encoder);
254 }
255
256 void set_potentiometer(::std::unique_ptr<AnalogInput> potentiometer) {
257 potentiometer_ = ::std::move(potentiometer);
258 }
259
260 double ReadAbsoluteEncoder() const { return duty_cycle_.Read(); }
261 int32_t ReadRelativeEncoder() const { return encoder_->GetRaw(); }
262 double ReadPotentiometerVoltage() const {
263 return potentiometer_->GetVoltage();
264 }
265
266 private:
267 DutyCycleReader duty_cycle_;
268 ::std::unique_ptr<Encoder> encoder_;
269 ::std::unique_ptr<AnalogInput> potentiometer_;
270};
271
Brian Silverman4da58072015-01-26 20:18:52 -0500272} // namespace wpilib
273} // namespace frc971
274
275#endif // FRC971_ENCODER_AND_POTENTIOMETER_H_