blob: 939dc5e0d8a740c0cfd064970c232454688c3f7d [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
9#include "frc971/wpilib/hall_effect.h"
10
11#include "DigitalSource.h"
12#include "Encoder.h"
13#include "AnalogInput.h"
14#include "Utility.h"
15#include "dma.h"
16
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:
44 DMAEdgeCounter(Encoder *encoder, DigitalSource *input)
45 : encoder_(encoder), input_(input), inverted_(false) {}
46 DMAEdgeCounter(Encoder *encoder, HallEffect *input)
47 : encoder_(encoder), input_(input), inverted_(true) {}
48
Brian Silverman552350b2015-08-02 18:23:34 -070049 int positive_count() const { return pos_edge_count_; }
50 int negative_count() const { return neg_edge_count_; }
51 int last_positive_encoder_value() const { return pos_last_encoder_; }
52 int last_negative_encoder_value() const { return neg_last_encoder_; }
Brian Silvermanff7b3472015-01-26 17:53:04 -050053
54 // Returns the value of the sensor in the last-read DMA sample.
Brian Silverman552350b2015-08-02 18:23:34 -070055 bool last_value() const { return ExtractValue(prev_sample_); }
Brian Silvermanff7b3472015-01-26 17:53:04 -050056 // Returns the most recent polled value of the sensor.
57 bool polled_value() const { return polled_value_; }
58 // Returns the most recent polled reading from the encoder.
59 int polled_encoder() const { return polled_encoder_; }
60
61 private:
Brian Silverman552350b2015-08-02 18:23:34 -070062 void UpdateFromSample(const DMASample &sample) override;
63 void UpdatePolledValue() override {
64 polled_value_ = input_->Get();
65 polled_encoder_ = encoder_->GetRaw();
66 }
67 void PollFromSample(const DMASample &sample) override {
68 polled_value_ = ExtractValue(sample);
69 polled_encoder_ = sample.GetRaw(encoder_);
70 }
71 void AddToDMA(DMA *dma) override {
72 dma->Add(encoder_);
73 dma->Add(input_);
74 }
75
76 bool ExtractValue(const DMASample &sample) const;
Brian Silvermanff7b3472015-01-26 17:53:04 -050077
78 Encoder *const encoder_;
79 DigitalSource *const input_;
80 const bool inverted_;
81
82 // The last DMA reading we got.
83 DMASample prev_sample_;
84 // Whether or not we actually have anything in prev_sample_.
85 bool have_prev_sample_ = false;
86
87 // Values related to the positive edge.
88 int pos_edge_count_ = 0;
89 double pos_edge_time_ = 0.0;
90 int pos_last_encoder_ = 0;
91
92 // Values related to the negative edge.
93 int neg_edge_count_ = 0;
94 double neg_edge_time_ = 0.0;
95 int neg_last_encoder_ = 0;
96
97 bool polled_value_ = false;
98 int polled_encoder_ = 0;
99
100 DISALLOW_COPY_AND_ASSIGN(DMAEdgeCounter);
101};
102
Brian Silverman552350b2015-08-02 18:23:34 -0700103// Reads a hall effect in sync with DMA samples.
104class DMADigitalReader : public DMASampleHandlerInterface {
105 public:
106 DMADigitalReader(DigitalSource *input) : input_(input), inverted_(false) {}
107 DMADigitalReader(HallEffect *input) : input_(input), inverted_(true) {}
108
109 bool value() const { return value_; }
110
111 private:
112 void UpdateFromSample(const DMASample & /*sample*/) override {}
113 void UpdatePolledValue() override { value_ = input_->Get(); }
114 void PollFromSample(const DMASample &sample) override {
115 if (inverted_) {
116 value_ = !sample.Get(input_);
117 } else {
118 value_ = sample.Get(input_);
119 }
120 }
121 void AddToDMA(DMA *dma) override {
122 dma->Add(input_);
123 }
124
125 DigitalSource *const input_;
126 const bool inverted_;
127
128 bool value_;
129
130 DISALLOW_COPY_AND_ASSIGN(DMADigitalReader);
131};
132
Brian Silvermanff7b3472015-01-26 17:53:04 -0500133// This class handles updating the sampled data on multiple
134// DMASampleHandlerInterfaces. The caller should create an instance and then
135// periodically call RunIteration, retrieving whatever data from the
136// DMASampleHandlerInterfaces after each iteration.
137class DMASynchronizer {
138 public:
139 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
140
141 // Adds a new handler to this object. This method must not be called after
142 // Start().
143 void Add(DMASampleHandlerInterface *handler) {
144 handler->AddToDMA(dma_.get());
145 handlers_.emplace_back(handler);
146 }
147
148 // Actually starts watching for DMA samples.
149 // Add may not be called any more after this.
150 void Start() {
151 dma_->Start(1024);
152 }
153
154 // Updates all sensor values.
155 void RunIteration() {
156 SampleSensors();
157 CheckDMA();
158 }
159
160 private:
161 // Reads the state of all the sensors and records it as the polled values of
162 // all the inputs.
163 void SampleSensors() {
164 sample_time_ = GetFPGATime();
165 for (auto &c : handlers_) {
166 c->UpdatePolledValue();
167 }
168 }
169
170 // Gets called by the DMA handler to update edge counts.
171 void CheckDMA();
172
173 const ::std::unique_ptr<DMA> dma_;
174 ::std::vector<DMASampleHandlerInterface *> handlers_;
175
176 // The time at which we most recently read the sensor values.
177 double sample_time_ = 0.0;
178
179 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
180};
181
182} // namespace wpilib
183} // namespace frc971
184
185#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_