blob: c8a00eaf8c522e9c95e77118741f34828a496592 [file] [log] [blame]
Brian Silvermanff7b3472015-01-26 17:53:04 -05001#ifndef FRC971_WPILIB_DMA_EDGE_COUNTING_H_
2#define FRC971_WPILIB_DMA_EDGE_COUNTING_H_
3
4#include <memory>
5#include <vector>
6
7#include "aos/common/macros.h"
8
Brian Silvermanb5b46ca2016-03-13 01:14:17 -05009#include "frc971/wpilib/dma.h"
10
Austin Schuhc5e36082015-10-31 13:30:46 -070011#include "DigitalInput.h"
Brian Silvermanff7b3472015-01-26 17:53:04 -050012#include "Encoder.h"
13#include "AnalogInput.h"
14#include "Utility.h"
Austin Schuh5c25ab72015-11-01 13:17:11 -080015#undef ERROR
Brian Silvermanff7b3472015-01-26 17:53:04 -050016
17namespace frc971 {
18namespace wpilib {
19
20// Generic interface for classes that do something with DMA samples and also
21// poll current sensor values.
22class DMASampleHandlerInterface {
23 public:
24 virtual ~DMASampleHandlerInterface() {}
25
26 // Updates values based on a new DMA sample.
27 virtual void UpdateFromSample(const DMASample &sample) = 0;
28
29 // Polls the current values and saves them for later reference.
30 virtual void UpdatePolledValue() = 0;
31
32 // Fills in the "polled" values from sample.
33 // This is only called when a DMA event happens right as we're polling values.
34 virtual void PollFromSample(const DMASample &sample) = 0;
35
36 // Adds readings and triggers appropriate to this object to dma.
37 virtual void AddToDMA(DMA *dma) = 0;
38};
39
Austin Schuh8e5950d2018-03-21 20:29:40 -070040// TODO(brian): Timeout old data.
41class DMAPulseWidthReader : public DMASampleHandlerInterface {
42 public:
43 DMAPulseWidthReader(DigitalInput *input) : input_(input) {}
44 DMAPulseWidthReader() = default;
45
46 void set_input(DigitalInput *input) { input_ = input; }
47
48 double last_width() const { return last_width_; }
49
50 private:
51 void UpdateFromSample(const DMASample & /*sample*/) override;
52 void UpdatePolledValue() override {}
53
54 void PollFromSample(const DMASample & /*sample*/) override {}
55 void AddToDMA(DMA *dma) override {
56 dma->Add(input_);
57 dma->SetExternalTrigger(input_, true, true);
58 }
59
60 DigitalInput *input_ = nullptr;
61
62 // The last DMA reading we got.
63 DMASample prev_sample_;
64 // Whether or not we actually have anything in prev_sample_.
65 bool have_prev_sample_ = false;
66
67 double last_width_ = ::std::numeric_limits<double>::quiet_NaN();
68
69 DISALLOW_COPY_AND_ASSIGN(DMAPulseWidthReader);
70};
71
Brian Silvermanff7b3472015-01-26 17:53:04 -050072// Counts edges on a sensor using DMA data and latches encoder values
73// corresponding to those edges.
74class DMAEdgeCounter : public DMASampleHandlerInterface {
75 public:
Austin Schuhc5e36082015-10-31 13:30:46 -070076 DMAEdgeCounter(Encoder *encoder, DigitalInput *input)
Brian Silverman03a00cf2015-08-29 19:26:54 -070077 : encoder_(encoder), input_(input) {}
Brianef030df2017-03-05 15:06:04 -080078 DMAEdgeCounter() = default;
79
80 void set_encoder(Encoder *encoder) { encoder_ = encoder; }
81 void set_input(DigitalInput *input) { input_ = input; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050082
Brian Silverman552350b2015-08-02 18:23:34 -070083 int positive_count() const { return pos_edge_count_; }
84 int negative_count() const { return neg_edge_count_; }
85 int last_positive_encoder_value() const { return pos_last_encoder_; }
86 int last_negative_encoder_value() const { return neg_last_encoder_; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050087
88 // Returns the value of the sensor in the last-read DMA sample.
Brian Silverman552350b2015-08-02 18:23:34 -070089 bool last_value() const { return ExtractValue(prev_sample_); }
Brian Silvermanff7b3472015-01-26 17:53:04 -050090 // Returns the most recent polled value of the sensor.
91 bool polled_value() const { return polled_value_; }
92 // Returns the most recent polled reading from the encoder.
93 int polled_encoder() const { return polled_encoder_; }
94
95 private:
Brian Silverman552350b2015-08-02 18:23:34 -070096 void UpdateFromSample(const DMASample &sample) override;
97 void UpdatePolledValue() override {
Austin Schuhf83da152017-03-05 22:28:45 -080098 previous_polled_value_ = polled_value_;
Brian Silverman552350b2015-08-02 18:23:34 -070099 polled_value_ = input_->Get();
100 polled_encoder_ = encoder_->GetRaw();
101 }
102 void PollFromSample(const DMASample &sample) override {
Austin Schuhf83da152017-03-05 22:28:45 -0800103 previous_polled_value_ = polled_value_;
Brian Silverman552350b2015-08-02 18:23:34 -0700104 polled_value_ = ExtractValue(sample);
105 polled_encoder_ = sample.GetRaw(encoder_);
106 }
107 void AddToDMA(DMA *dma) override {
108 dma->Add(encoder_);
109 dma->Add(input_);
Brian Silverman03a00cf2015-08-29 19:26:54 -0700110 dma->SetExternalTrigger(input_, true, true);
Brian Silverman552350b2015-08-02 18:23:34 -0700111 }
112
113 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500114
Brianef030df2017-03-05 15:06:04 -0800115 Encoder *encoder_ = nullptr;
116 DigitalInput *input_ = nullptr;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500117
118 // The last DMA reading we got.
119 DMASample prev_sample_;
120 // Whether or not we actually have anything in prev_sample_.
121 bool have_prev_sample_ = false;
122
123 // Values related to the positive edge.
124 int pos_edge_count_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500125 int pos_last_encoder_ = 0;
126
127 // Values related to the negative edge.
128 int neg_edge_count_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500129 int neg_last_encoder_ = 0;
130
131 bool polled_value_ = false;
Austin Schuhf83da152017-03-05 22:28:45 -0800132 bool previous_polled_value_ = false;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500133 int polled_encoder_ = 0;
134
135 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
136};
137
Brian Silverman552350b2015-08-02 18:23:34 -0700138// Reads a hall effect in sync with DMA samples.
139class DMADigitalReader : public DMASampleHandlerInterface {
140 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700141 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700142
143 bool value() const { return value_; }
144
145 private:
146 void UpdateFromSample(const DMASample & /*sample*/) override {}
147 void UpdatePolledValue() override { value_ = input_->Get(); }
148 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700149 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700150 }
151 void AddToDMA(DMA *dma) override {
152 dma->Add(input_);
153 }
154
Austin Schuhc5e36082015-10-31 13:30:46 -0700155 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700156
157 bool value_;
158
159 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
160};
161
Austin Schuh89f1e092015-11-22 22:30:39 -0800162// Reads an analog sensor in sync with DMA samples.
163class DMAAnalogReader : public DMASampleHandlerInterface {
164 public:
165 DMAAnalogReader(AnalogInput *input) : input_(input) {}
166
167 double value() const { return value_; }
168
169 private:
170 void UpdateFromSample(const DMASample & /*sample*/) override {}
171 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
172 void PollFromSample(const DMASample &sample) override {
173 value_ = sample.GetVoltage(input_);
174 }
175 void AddToDMA(DMA *dma) override {
176 dma->Add(input_);
177 }
178
179 AnalogInput *const input_;
180
181 double value_;
182
183 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
184};
185
Brian Silvermanff7b3472015-01-26 17:53:04 -0500186// This class handles updating the sampled data on multiple
187// DMASampleHandlerInterfaces. The caller should create an instance and then
188// periodically call RunIteration, retrieving whatever data from the
189// DMASampleHandlerInterfaces after each iteration.
190class DMASynchronizer {
191 public:
192 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
193
194 // Adds a new handler to this object. This method must not be called after
195 // Start().
196 void Add(DMASampleHandlerInterface *handler) {
197 handler->AddToDMA(dma_.get());
198 handlers_.emplace_back(handler);
199 }
200
201 // Actually starts watching for DMA samples.
202 // Add may not be called any more after this.
203 void Start() {
204 dma_->Start(1024);
205 }
206
207 // Updates all sensor values.
208 void RunIteration() {
209 SampleSensors();
210 CheckDMA();
211 }
212
213 private:
214 // Reads the state of all the sensors and records it as the polled values of
215 // all the inputs.
216 void SampleSensors() {
217 sample_time_ = GetFPGATime();
218 for (auto &c : handlers_) {
219 c->UpdatePolledValue();
220 }
221 }
222
223 // Gets called by the DMA handler to update edge counts.
224 void CheckDMA();
225
226 const ::std::unique_ptr<DMA> dma_;
227 ::std::vector<DMASampleHandlerInterface *> handlers_;
228
229 // The time at which we most recently read the sensor values.
Austin Schuhf853bde2017-11-23 13:23:27 -0800230 int64_t sample_time_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500231
232 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
233};
234
235} // namespace wpilib
236} // namespace frc971
237
238#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_