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