blob: cdbff1df0ce8b7de84906fe04fe31b8ba5546579 [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) {}
Brian Silvermanff7b3472015-01-26 17:53:04 -050046
Brian Silverman552350b2015-08-02 18:23:34 -070047 int positive_count() const { return pos_edge_count_; }
48 int negative_count() const { return neg_edge_count_; }
49 int last_positive_encoder_value() const { return pos_last_encoder_; }
50 int last_negative_encoder_value() const { return neg_last_encoder_; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050051
52 // Returns the value of the sensor in the last-read DMA sample.
Brian Silverman552350b2015-08-02 18:23:34 -070053 bool last_value() const { return ExtractValue(prev_sample_); }
Brian Silvermanff7b3472015-01-26 17:53:04 -050054 // Returns the most recent polled value of the sensor.
55 bool polled_value() const { return polled_value_; }
56 // Returns the most recent polled reading from the encoder.
57 int polled_encoder() const { return polled_encoder_; }
58
59 private:
Brian Silverman552350b2015-08-02 18:23:34 -070060 void UpdateFromSample(const DMASample &sample) override;
61 void UpdatePolledValue() override {
62 polled_value_ = input_->Get();
63 polled_encoder_ = encoder_->GetRaw();
64 }
65 void PollFromSample(const DMASample &sample) override {
66 polled_value_ = ExtractValue(sample);
67 polled_encoder_ = sample.GetRaw(encoder_);
68 }
69 void AddToDMA(DMA *dma) override {
70 dma->Add(encoder_);
71 dma->Add(input_);
Brian Silverman03a00cf2015-08-29 19:26:54 -070072 dma->SetExternalTrigger(input_, true, true);
Brian Silverman552350b2015-08-02 18:23:34 -070073 }
74
75 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -050076
77 Encoder *const encoder_;
Austin Schuhc5e36082015-10-31 13:30:46 -070078 DigitalInput *const input_;
Brian Silvermanff7b3472015-01-26 17:53:04 -050079
80 // The last DMA reading we got.
81 DMASample prev_sample_;
82 // Whether or not we actually have anything in prev_sample_.
83 bool have_prev_sample_ = false;
84
85 // Values related to the positive edge.
86 int pos_edge_count_ = 0;
87 double pos_edge_time_ = 0.0;
88 int pos_last_encoder_ = 0;
89
90 // Values related to the negative edge.
91 int neg_edge_count_ = 0;
92 double neg_edge_time_ = 0.0;
93 int neg_last_encoder_ = 0;
94
95 bool polled_value_ = false;
96 int polled_encoder_ = 0;
97
98 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
99};
100
Brian Silverman552350b2015-08-02 18:23:34 -0700101// Reads a hall effect in sync with DMA samples.
102class DMADigitalReader : public DMASampleHandlerInterface {
103 public:
Austin Schuhc5e36082015-10-31 13:30:46 -0700104 DMADigitalReader(DigitalInput *input) : input_(input) {}
Brian Silverman552350b2015-08-02 18:23:34 -0700105
106 bool value() const { return value_; }
107
108 private:
109 void UpdateFromSample(const DMASample & /*sample*/) override {}
110 void UpdatePolledValue() override { value_ = input_->Get(); }
111 void PollFromSample(const DMASample &sample) override {
Brian Silverman03a00cf2015-08-29 19:26:54 -0700112 value_ = sample.Get(input_);
Brian Silverman552350b2015-08-02 18:23:34 -0700113 }
114 void AddToDMA(DMA *dma) override {
115 dma->Add(input_);
116 }
117
Austin Schuhc5e36082015-10-31 13:30:46 -0700118 DigitalInput *const input_;
Brian Silverman552350b2015-08-02 18:23:34 -0700119
120 bool value_;
121
122 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
123};
124
Austin Schuh89f1e092015-11-22 22:30:39 -0800125// Reads an analog sensor in sync with DMA samples.
126class DMAAnalogReader : public DMASampleHandlerInterface {
127 public:
128 DMAAnalogReader(AnalogInput *input) : input_(input) {}
129
130 double value() const { return value_; }
131
132 private:
133 void UpdateFromSample(const DMASample & /*sample*/) override {}
134 void UpdatePolledValue() override { value_ = input_->GetVoltage(); }
135 void PollFromSample(const DMASample &sample) override {
136 value_ = sample.GetVoltage(input_);
137 }
138 void AddToDMA(DMA *dma) override {
139 dma->Add(input_);
140 }
141
142 AnalogInput *const input_;
143
144 double value_;
145
146 DISALLOW_COPY_AND_ASSIGN(DMAAnalogReader);
147};
148
Brian Silvermanff7b3472015-01-26 17:53:04 -0500149// This class handles updating the sampled data on multiple
150// DMASampleHandlerInterfaces. The caller should create an instance and then
151// periodically call RunIteration, retrieving whatever data from the
152// DMASampleHandlerInterfaces after each iteration.
153class DMASynchronizer {
154 public:
155 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
156
157 // Adds a new handler to this object. This method must not be called after
158 // Start().
159 void Add(DMASampleHandlerInterface *handler) {
160 handler->AddToDMA(dma_.get());
161 handlers_.emplace_back(handler);
162 }
163
164 // Actually starts watching for DMA samples.
165 // Add may not be called any more after this.
166 void Start() {
167 dma_->Start(1024);
168 }
169
170 // Updates all sensor values.
171 void RunIteration() {
172 SampleSensors();
173 CheckDMA();
174 }
175
176 private:
177 // Reads the state of all the sensors and records it as the polled values of
178 // all the inputs.
179 void SampleSensors() {
180 sample_time_ = GetFPGATime();
181 for (auto &c : handlers_) {
182 c->UpdatePolledValue();
183 }
184 }
185
186 // Gets called by the DMA handler to update edge counts.
187 void CheckDMA();
188
189 const ::std::unique_ptr<DMA> dma_;
190 ::std::vector<DMASampleHandlerInterface *> handlers_;
191
192 // The time at which we most recently read the sensor values.
Brian Silverman135d0432016-02-20 21:35:19 -0500193 uint32_t sample_time_ = 0;
Brian Silvermanff7b3472015-01-26 17:53:04 -0500194
195 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
196};
197
198} // namespace wpilib
199} // namespace frc971
200
201#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_