blob: 813f59c5086deb124f8b727b05fbf40c29a5dec6 [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
40// Counts edges on a sensor using DMA data and latches encoder values
41// corresponding to those edges.
42class DMAEdgeCounter : public DMASampleHandlerInterface {
43 public:
Austin Schuhc5e36082015-10-31 13:30:46 -070044 DMAEdgeCounter(Encoder *encoder, DigitalInput *input)
Brian Silverman03a00cf2015-08-29 19:26:54 -070045 : encoder_(encoder), input_(input) {}
Brianef030df2017-03-05 15:06:04 -080046 DMAEdgeCounter() = default;
47
48 void set_encoder(Encoder *encoder) { encoder_ = encoder; }
49 void set_input(DigitalInput *input) { input_ = input; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050050
Brian Silverman552350b2015-08-02 18:23:34 -070051 int positive_count() const { return pos_edge_count_; }
52 int negative_count() const { return neg_edge_count_; }
53 int last_positive_encoder_value() const { return pos_last_encoder_; }
54 int last_negative_encoder_value() const { return neg_last_encoder_; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050055
56 // Returns the value of the sensor in the last-read DMA sample.
Brian Silverman552350b2015-08-02 18:23:34 -070057 bool last_value() const { return ExtractValue(prev_sample_); }
Brian Silvermanff7b3472015-01-26 17:53:04 -050058 // Returns the most recent polled value of the sensor.
59 bool polled_value() const { return polled_value_; }
60 // Returns the most recent polled reading from the encoder.
61 int polled_encoder() const { return polled_encoder_; }
62
63 private:
Brian Silverman552350b2015-08-02 18:23:34 -070064 void UpdateFromSample(const DMASample &sample) override;
65 void UpdatePolledValue() override {
Austin Schuhf83da152017-03-05 22:28:45 -080066 previous_polled_value_ = polled_value_;
Brian Silverman552350b2015-08-02 18:23:34 -070067 polled_value_ = input_->Get();
68 polled_encoder_ = encoder_->GetRaw();
69 }
70 void PollFromSample(const DMASample &sample) override {
Austin Schuhf83da152017-03-05 22:28:45 -080071 previous_polled_value_ = polled_value_;
Brian Silverman552350b2015-08-02 18:23:34 -070072 polled_value_ = ExtractValue(sample);
73 polled_encoder_ = sample.GetRaw(encoder_);
74 }
75 void AddToDMA(DMA *dma) override {
76 dma->Add(encoder_);
77 dma->Add(input_);
Brian Silverman03a00cf2015-08-29 19:26:54 -070078 dma->SetExternalTrigger(input_, true, true);
Brian Silverman552350b2015-08-02 18:23:34 -070079 }
80
81 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -050082
Brianef030df2017-03-05 15:06:04 -080083 Encoder *encoder_ = nullptr;
84 DigitalInput *input_ = nullptr;
Brian Silvermanff7b3472015-01-26 17:53:04 -050085
86 // The last DMA reading we got.
87 DMASample prev_sample_;
88 // Whether or not we actually have anything in prev_sample_.
89 bool have_prev_sample_ = false;
90
91 // Values related to the positive edge.
92 int pos_edge_count_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -050093 int pos_last_encoder_ = 0;
94
95 // Values related to the negative edge.
96 int neg_edge_count_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -050097 int neg_last_encoder_ = 0;
98
99 bool polled_value_ = false;
Austin Schuhf83da152017-03-05 22:28:45 -0800100 bool previous_polled_value_ = false;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500101 int polled_encoder_ = 0;
102
103 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
104};
105
Brian Silverman552350b2015-08-02 18:23:34 -0700106// Reads a hall effect in sync with DMA samples.
107class DMADigitalReader : public DMASampleHandlerInterface {
108 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700109 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700110
111 bool value() const { return value_; }
112
113 private:
114 void UpdateFromSample(const DMASample & /*sample*/) override {}
115 void UpdatePolledValue() override { value_ = input_->Get(); }
116 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700117 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700118 }
119 void AddToDMA(DMA *dma) override {
120 dma->Add(input_);
121 }
122
Austin Schuhc5e36082015-10-31 13:30:46 -0700123 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700124
125 bool value_;
126
127 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
128};
129
Austin Schuh89f1e092015-11-22 22:30:39 -0800130// Reads an analog sensor in sync with DMA samples.
131class DMAAnalogReader : public DMASampleHandlerInterface {
132 public:
133 DMAAnalogReader(AnalogInput *input) : input_(input) {}
134
135 double value() const { return value_; }
136
137 private:
138 void UpdateFromSample(const DMASample & /*sample*/) override {}
139 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
140 void PollFromSample(const DMASample &sample) override {
141 value_ = sample.GetVoltage(input_);
142 }
143 void AddToDMA(DMA *dma) override {
144 dma->Add(input_);
145 }
146
147 AnalogInput *const input_;
148
149 double value_;
150
151 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
152};
153
Brian Silvermanff7b3472015-01-26 17:53:04 -0500154// This class handles updating the sampled data on multiple
155// DMASampleHandlerInterfaces. The caller should create an instance and then
156// periodically call RunIteration, retrieving whatever data from the
157// DMASampleHandlerInterfaces after each iteration.
158class DMASynchronizer {
159 public:
160 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
161
162 // Adds a new handler to this object. This method must not be called after
163 // Start().
164 void Add(DMASampleHandlerInterface *handler) {
165 handler->AddToDMA(dma_.get());
166 handlers_.emplace_back(handler);
167 }
168
169 // Actually starts watching for DMA samples.
170 // Add may not be called any more after this.
171 void Start() {
172 dma_->Start(1024);
173 }
174
175 // Updates all sensor values.
176 void RunIteration() {
177 SampleSensors();
178 CheckDMA();
179 }
180
181 private:
182 // Reads the state of all the sensors and records it as the polled values of
183 // all the inputs.
184 void SampleSensors() {
185 sample_time_ = GetFPGATime();
186 for (auto &c : handlers_) {
187 c->UpdatePolledValue();
188 }
189 }
190
191 // Gets called by the DMA handler to update edge counts.
192 void CheckDMA();
193
194 const ::std::unique_ptr<DMA> dma_;
195 ::std::vector<DMASampleHandlerInterface *> handlers_;
196
197 // The time at which we most recently read the sensor values.
Austin Schuhf853bde2017-11-23 13:23:27 -0800198 int64_t sample_time_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500199
200 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
201};
202
203} // namespace wpilib
204} // namespace frc971
205
206#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_