blob: 64722caa057a093ddfe52ecb9f06f940862c3710 [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;
93 double pos_edge_time_ = 0.0;
94 int pos_last_encoder_ = 0;
95
96 // Values related to the negative edge.
97 int neg_edge_count_ = 0;
98 double neg_edge_time_ = 0.0;
99 int neg_last_encoder_ = 0;
100
101 bool polled_value_ = false;
Austin Schuhf83da152017-03-05 22:28:45 -0800102 bool previous_polled_value_ = false;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500103 int polled_encoder_ = 0;
104
105 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
106};
107
Brian Silverman552350b2015-08-02 18:23:34 -0700108// Reads a hall effect in sync with DMA samples.
109class DMADigitalReader : public DMASampleHandlerInterface {
110 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700111 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700112
113 bool value() const { return value_; }
114
115 private:
116 void UpdateFromSample(const DMASample & /*sample*/) override {}
117 void UpdatePolledValue() override { value_ = input_->Get(); }
118 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700119 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700120 }
121 void AddToDMA(DMA *dma) override {
122 dma->Add(input_);
123 }
124
Austin Schuhc5e36082015-10-31 13:30:46 -0700125 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700126
127 bool value_;
128
129 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
130};
131
Austin Schuh89f1e092015-11-22 22:30:39 -0800132// Reads an analog sensor in sync with DMA samples.
133class DMAAnalogReader : public DMASampleHandlerInterface {
134 public:
135 DMAAnalogReader(AnalogInput *input) : input_(input) {}
136
137 double value() const { return value_; }
138
139 private:
140 void UpdateFromSample(const DMASample & /*sample*/) override {}
141 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
142 void PollFromSample(const DMASample &sample) override {
143 value_ = sample.GetVoltage(input_);
144 }
145 void AddToDMA(DMA *dma) override {
146 dma->Add(input_);
147 }
148
149 AnalogInput *const input_;
150
151 double value_;
152
153 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
154};
155
Brian Silvermanff7b3472015-01-26 17:53:04 -0500156// This class handles updating the sampled data on multiple
157// DMASampleHandlerInterfaces. The caller should create an instance and then
158// periodically call RunIteration, retrieving whatever data from the
159// DMASampleHandlerInterfaces after each iteration.
160class DMASynchronizer {
161 public:
162 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
163
164 // Adds a new handler to this object. This method must not be called after
165 // Start().
166 void Add(DMASampleHandlerInterface *handler) {
167 handler->AddToDMA(dma_.get());
168 handlers_.emplace_back(handler);
169 }
170
171 // Actually starts watching for DMA samples.
172 // Add may not be called any more after this.
173 void Start() {
174 dma_->Start(1024);
175 }
176
177 // Updates all sensor values.
178 void RunIteration() {
179 SampleSensors();
180 CheckDMA();
181 }
182
183 private:
184 // Reads the state of all the sensors and records it as the polled values of
185 // all the inputs.
186 void SampleSensors() {
187 sample_time_ = GetFPGATime();
188 for (auto &c : handlers_) {
189 c->UpdatePolledValue();
190 }
191 }
192
193 // Gets called by the DMA handler to update edge counts.
194 void CheckDMA();
195
196 const ::std::unique_ptr<DMA> dma_;
197 ::std::vector<DMASampleHandlerInterface *> handlers_;
198
199 // The time at which we most recently read the sensor values.
Brian Silverman135d0432016-02-20 21:35:19 -0500200 uint32_t sample_time_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500201
202 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
203};
204
205} // namespace wpilib
206} // namespace frc971
207
208#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_