blob: d49b05d44ede34899e3d525fce000109f21c7e85 [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 {
66 polled_value_ = input_->Get();
67 polled_encoder_ = encoder_->GetRaw();
68 }
69 void PollFromSample(const DMASample &sample) override {
70 polled_value_ = ExtractValue(sample);
71 polled_encoder_ = sample.GetRaw(encoder_);
72 }
73 void AddToDMA(DMA *dma) override {
74 dma->Add(encoder_);
75 dma->Add(input_);
Brian Silverman03a00cf2015-08-29 19:26:54 -070076 dma->SetExternalTrigger(input_, true, true);
Brian Silverman552350b2015-08-02 18:23:34 -070077 }
78
79 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -050080
Brianef030df2017-03-05 15:06:04 -080081 Encoder *encoder_ = nullptr;
82 DigitalInput *input_ = nullptr;
Brian Silvermanff7b3472015-01-26 17:53:04 -050083
84 // The last DMA reading we got.
85 DMASample prev_sample_;
86 // Whether or not we actually have anything in prev_sample_.
87 bool have_prev_sample_ = false;
88
89 // Values related to the positive edge.
90 int pos_edge_count_ = 0;
91 double pos_edge_time_ = 0.0;
92 int pos_last_encoder_ = 0;
93
94 // Values related to the negative edge.
95 int neg_edge_count_ = 0;
96 double neg_edge_time_ = 0.0;
97 int neg_last_encoder_ = 0;
98
99 bool polled_value_ = false;
100 int polled_encoder_ = 0;
101
102 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
103};
104
Brian Silverman552350b2015-08-02 18:23:34 -0700105// Reads a hall effect in sync with DMA samples.
106class DMADigitalReader : public DMASampleHandlerInterface {
107 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700108 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700109
110 bool value() const { return value_; }
111
112 private:
113 void UpdateFromSample(const DMASample & /*sample*/) override {}
114 void UpdatePolledValue() override { value_ = input_->Get(); }
115 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700116 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700117 }
118 void AddToDMA(DMA *dma) override {
119 dma->Add(input_);
120 }
121
Austin Schuhc5e36082015-10-31 13:30:46 -0700122 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700123
124 bool value_;
125
126 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
127};
128
Austin Schuh89f1e092015-11-22 22:30:39 -0800129// Reads an analog sensor in sync with DMA samples.
130class DMAAnalogReader : public DMASampleHandlerInterface {
131 public:
132 DMAAnalogReader(AnalogInput *input) : input_(input) {}
133
134 double value() const { return value_; }
135
136 private:
137 void UpdateFromSample(const DMASample & /*sample*/) override {}
138 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
139 void PollFromSample(const DMASample &sample) override {
140 value_ = sample.GetVoltage(input_);
141 }
142 void AddToDMA(DMA *dma) override {
143 dma->Add(input_);
144 }
145
146 AnalogInput *const input_;
147
148 double value_;
149
150 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
151};
152
Brian Silvermanff7b3472015-01-26 17:53:04 -0500153// This class handles updating the sampled data on multiple
154// DMASampleHandlerInterfaces. The caller should create an instance and then
155// periodically call RunIteration, retrieving whatever data from the
156// DMASampleHandlerInterfaces after each iteration.
157class DMASynchronizer {
158 public:
159 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
160
161 // Adds a new handler to this object. This method must not be called after
162 // Start().
163 void Add(DMASampleHandlerInterface *handler) {
164 handler->AddToDMA(dma_.get());
165 handlers_.emplace_back(handler);
166 }
167
168 // Actually starts watching for DMA samples.
169 // Add may not be called any more after this.
170 void Start() {
171 dma_->Start(1024);
172 }
173
174 // Updates all sensor values.
175 void RunIteration() {
176 SampleSensors();
177 CheckDMA();
178 }
179
180 private:
181 // Reads the state of all the sensors and records it as the polled values of
182 // all the inputs.
183 void SampleSensors() {
184 sample_time_ = GetFPGATime();
185 for (auto &c : handlers_) {
186 c->UpdatePolledValue();
187 }
188 }
189
190 // Gets called by the DMA handler to update edge counts.
191 void CheckDMA();
192
193 const ::std::unique_ptr<DMA> dma_;
194 ::std::vector<DMASampleHandlerInterface *> handlers_;
195
196 // The time at which we most recently read the sensor values.
Brian Silverman135d0432016-02-20 21:35:19 -0500197 uint32_t sample_time_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500198
199 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
200};
201
202} // namespace wpilib
203} // namespace frc971
204
205#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_