blob: c145268d5ddc195462d1082bcb3894b5fa6a1c58 [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
Brian Silvermanff7b3472015-01-26 17:53:04 -0500124// This class handles updating the sampled data on multiple
125// DMASampleHandlerInterfaces. The caller should create an instance and then
126// periodically call RunIteration, retrieving whatever data from the
127// DMASampleHandlerInterfaces after each iteration.
128class DMASynchronizer {
129 public:
130 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
131
132 // Adds a new handler to this object. This method must not be called after
133 // Start().
134 void Add(DMASampleHandlerInterface *handler) {
135 handler->AddToDMA(dma_.get());
136 handlers_.emplace_back(handler);
137 }
138
139 // Actually starts watching for DMA samples.
140 // Add may not be called any more after this.
141 void Start() {
142 dma_->Start(1024);
143 }
144
145 // Updates all sensor values.
146 void RunIteration() {
147 SampleSensors();
148 CheckDMA();
149 }
150
151 private:
152 // Reads the state of all the sensors and records it as the polled values of
153 // all the inputs.
154 void SampleSensors() {
155 sample_time_ = GetFPGATime();
156 for (auto &c : handlers_) {
157 c->UpdatePolledValue();
158 }
159 }
160
161 // Gets called by the DMA handler to update edge counts.
162 void CheckDMA();
163
164 const ::std::unique_ptr<DMA> dma_;
165 ::std::vector<DMASampleHandlerInterface *> handlers_;
166
167 // The time at which we most recently read the sensor values.
168 double sample_time_ = 0.0;
169
170 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
171};
172
173} // namespace wpilib
174} // namespace frc971
175
176#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_