blob: 6d881706a43b8f7df31bcd6e8c396b44a0e19f9c [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
Austin Schuhc5e36082015-10-31 13:30:46 -07009#include "DigitalInput.h"
Brian Silvermanff7b3472015-01-26 17:53:04 -050010#include "Encoder.h"
11#include "AnalogInput.h"
12#include "Utility.h"
13#include "dma.h"
Austin Schuh5c25ab72015-11-01 13:17:11 -080014#undef ERROR
Brian Silvermanff7b3472015-01-26 17:53:04 -050015
16namespace frc971 {
17namespace wpilib {
18
19// Generic interface for classes that do something with DMA samples and also
20// poll current sensor values.
21class DMASampleHandlerInterface {
22 public:
23 virtual ~DMASampleHandlerInterface() {}
24
25 // Updates values based on a new DMA sample.
26 virtual void UpdateFromSample(const DMASample &sample) = 0;
27
28 // Polls the current values and saves them for later reference.
29 virtual void UpdatePolledValue() = 0;
30
31 // Fills in the "polled" values from sample.
32 // This is only called when a DMA event happens right as we're polling values.
33 virtual void PollFromSample(const DMASample &sample) = 0;
34
35 // Adds readings and triggers appropriate to this object to dma.
36 virtual void AddToDMA(DMA *dma) = 0;
37};
38
39// Counts edges on a sensor using DMA data and latches encoder values
40// corresponding to those edges.
41class DMAEdgeCounter : public DMASampleHandlerInterface {
42 public:
Austin Schuhc5e36082015-10-31 13:30:46 -070043 DMAEdgeCounter(Encoder *encoder, DigitalInput *input)
Brian Silverman03a00cf2015-08-29 19:26:54 -070044 : encoder_(encoder), input_(input) {}
Brian Silvermanff7b3472015-01-26 17:53:04 -050045
Brian Silverman552350b2015-08-02 18:23:34 -070046 int positive_count() const { return pos_edge_count_; }
47 int negative_count() const { return neg_edge_count_; }
48 int last_positive_encoder_value() const { return pos_last_encoder_; }
49 int last_negative_encoder_value() const { return neg_last_encoder_; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050050
51 // Returns the value of the sensor in the last-read DMA sample.
Brian Silverman552350b2015-08-02 18:23:34 -070052 bool last_value() const { return ExtractValue(prev_sample_); }
Brian Silvermanff7b3472015-01-26 17:53:04 -050053 // Returns the most recent polled value of the sensor.
54 bool polled_value() const { return polled_value_; }
55 // Returns the most recent polled reading from the encoder.
56 int polled_encoder() const { return polled_encoder_; }
57
58 private:
Brian Silverman552350b2015-08-02 18:23:34 -070059 void UpdateFromSample(const DMASample &sample) override;
60 void UpdatePolledValue() override {
61 polled_value_ = input_->Get();
62 polled_encoder_ = encoder_->GetRaw();
63 }
64 void PollFromSample(const DMASample &sample) override {
65 polled_value_ = ExtractValue(sample);
66 polled_encoder_ = sample.GetRaw(encoder_);
67 }
68 void AddToDMA(DMA *dma) override {
69 dma->Add(encoder_);
70 dma->Add(input_);
Brian Silverman03a00cf2015-08-29 19:26:54 -070071 dma->SetExternalTrigger(input_, true, true);
Brian Silverman552350b2015-08-02 18:23:34 -070072 }
73
74 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -050075
76 Encoder *const encoder_;
Austin Schuhc5e36082015-10-31 13:30:46 -070077 DigitalInput *const input_;
Brian Silvermanff7b3472015-01-26 17:53:04 -050078
79 // The last DMA reading we got.
80 DMASample prev_sample_;
81 // Whether or not we actually have anything in prev_sample_.
82 bool have_prev_sample_ = false;
83
84 // Values related to the positive edge.
85 int pos_edge_count_ = 0;
86 double pos_edge_time_ = 0.0;
87 int pos_last_encoder_ = 0;
88
89 // Values related to the negative edge.
90 int neg_edge_count_ = 0;
91 double neg_edge_time_ = 0.0;
92 int neg_last_encoder_ = 0;
93
94 bool polled_value_ = false;
95 int polled_encoder_ = 0;
96
97 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
98};
99
Brian Silverman552350b2015-08-02 18:23:34 -0700100// Reads a hall effect in sync with DMA samples.
101class DMADigitalReader : public DMASampleHandlerInterface {
102 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700103 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700104
105 bool value() const { return value_; }
106
107 private:
108 void UpdateFromSample(const DMASample & /*sample*/) override {}
109 void UpdatePolledValue() override { value_ = input_->Get(); }
110 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700111 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700112 }
113 void AddToDMA(DMA *dma) override {
114 dma->Add(input_);
115 }
116
Austin Schuhc5e36082015-10-31 13:30:46 -0700117 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700118
119 bool value_;
120
121 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
122};
123
Austin Schuh89f1e092015-11-22 22:30:39 -0800124// Reads an analog sensor in sync with DMA samples.
125class DMAAnalogReader : public DMASampleHandlerInterface {
126 public:
127 DMAAnalogReader(AnalogInput *input) : input_(input) {}
128
129 double value() const { return value_; }
130
131 private:
132 void UpdateFromSample(const DMASample & /*sample*/) override {}
133 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
134 void PollFromSample(const DMASample &sample) override {
135 value_ = sample.GetVoltage(input_);
136 }
137 void AddToDMA(DMA *dma) override {
138 dma->Add(input_);
139 }
140
141 AnalogInput *const input_;
142
143 double value_;
144
145 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
146};
147
Brian Silvermanff7b3472015-01-26 17:53:04 -0500148// This class handles updating the sampled data on multiple
149// DMASampleHandlerInterfaces. The caller should create an instance and then
150// periodically call RunIteration, retrieving whatever data from the
151// DMASampleHandlerInterfaces after each iteration.
152class DMASynchronizer {
153 public:
154 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
155
156 // Adds a new handler to this object. This method must not be called after
157 // Start().
158 void Add(DMASampleHandlerInterface *handler) {
159 handler->AddToDMA(dma_.get());
160 handlers_.emplace_back(handler);
161 }
162
163 // Actually starts watching for DMA samples.
164 // Add may not be called any more after this.
165 void Start() {
166 dma_->Start(1024);
167 }
168
169 // Updates all sensor values.
170 void RunIteration() {
171 SampleSensors();
172 CheckDMA();
173 }
174
175 private:
176 // Reads the state of all the sensors and records it as the polled values of
177 // all the inputs.
178 void SampleSensors() {
179 sample_time_ = GetFPGATime();
180 for (auto &c : handlers_) {
181 c->UpdatePolledValue();
182 }
183 }
184
185 // Gets called by the DMA handler to update edge counts.
186 void CheckDMA();
187
188 const ::std::unique_ptr<DMA> dma_;
189 ::std::vector<DMASampleHandlerInterface *> handlers_;
190
191 // The time at which we most recently read the sensor values.
Austin Schuh8f314a92015-11-22 21:35:40 -0800192 uint32_t sample_time_ = 0.0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500193
194 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
195};
196
197} // namespace wpilib
198} // namespace frc971
199
200#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_