blob: 5d6808dc28cd5386c4a40131419268cc9033a437 [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
49 virtual void UpdateFromSample(const DMASample &sample) override;
50 virtual void UpdatePolledValue() override {
51 polled_value_ = input_->Get();
52 polled_encoder_ = encoder_->GetRaw();
53 }
54 virtual void PollFromSample(const DMASample &sample) override {
55 polled_value_ = ExtractValue(sample);
56 polled_encoder_ = sample.GetRaw(encoder_);
57 }
58 virtual void AddToDMA(DMA *dma) override {
59 dma->Add(encoder_);
60 dma->Add(input_);
61 }
62
63 int positive_count() { return pos_edge_count_; }
64 int negative_count() { return neg_edge_count_; }
65 int last_positive_encoder_value() { return pos_last_encoder_; }
66 int last_negative_encoder_value() { return neg_last_encoder_; }
67
68 // Returns the value of the sensor in the last-read DMA sample.
69 bool last_value() { return ExtractValue(prev_sample_); }
70 // Returns the most recent polled value of the sensor.
71 bool polled_value() const { return polled_value_; }
72 // Returns the most recent polled reading from the encoder.
73 int polled_encoder() const { return polled_encoder_; }
74
75 private:
76 bool ExtractValue(const DMASample &sample);
77
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
103// This class handles updating the sampled data on multiple
104// DMASampleHandlerInterfaces. The caller should create an instance and then
105// periodically call RunIteration, retrieving whatever data from the
106// DMASampleHandlerInterfaces after each iteration.
107class DMASynchronizer {
108 public:
109 DMASynchronizer(::std::unique_ptr<DMA> dma) : dma_(::std::move(dma)) {}
110
111 // Adds a new handler to this object. This method must not be called after
112 // Start().
113 void Add(DMASampleHandlerInterface *handler) {
114 handler->AddToDMA(dma_.get());
115 handlers_.emplace_back(handler);
116 }
117
118 // Actually starts watching for DMA samples.
119 // Add may not be called any more after this.
120 void Start() {
121 dma_->Start(1024);
122 }
123
124 // Updates all sensor values.
125 void RunIteration() {
126 SampleSensors();
127 CheckDMA();
128 }
129
130 private:
131 // Reads the state of all the sensors and records it as the polled values of
132 // all the inputs.
133 void SampleSensors() {
134 sample_time_ = GetFPGATime();
135 for (auto &c : handlers_) {
136 c->UpdatePolledValue();
137 }
138 }
139
140 // Gets called by the DMA handler to update edge counts.
141 void CheckDMA();
142
143 const ::std::unique_ptr<DMA> dma_;
144 ::std::vector<DMASampleHandlerInterface *> handlers_;
145
146 // The time at which we most recently read the sensor values.
147 double sample_time_ = 0.0;
148
149 DISALLOW_COPY_AND_ASSIGN(DMASynchronizer);
150};
151
152} // namespace wpilib
153} // namespace frc971
154
155#endif // FRC971_WPILIB_DMA_EDGE_COUNTING_H_