blob: b2c6ecb8375c792494bd1b2c3278a24170cb1c31 [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul41fa78a2019-12-14 20:53:14 -08002/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
Parker Schuhd3b7a8872018-02-19 16:42:27 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#pragma once
9
10#include <memory>
11#include <string>
12
Austin Schuhf6b94632019-02-02 22:11:27 -080013#include "hal/Counter.h"
14#include "hal/Types.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080015#include "frc971/wpilib/ahal/AnalogTrigger.h"
16#include "frc971/wpilib/ahal/CounterBase.h"
17#include "frc971/wpilib/ahal/SensorBase.h"
18
19namespace frc {
20
21class DigitalGlitchFilter;
22
23/**
24 * Class for counting the number of ticks on a digital input channel.
25 * This is a general purpose class for counting repetitive events. It can return
26 * the number of counts, the period of the most recent cycle, and detect when
27 * the signal being counted has stopped by supplying a maximum cycle time.
28 *
29 * All counters will immediately start counting - Reset() them if you need them
30 * to be zeroed before use.
31 */
32class Counter : public CounterBase {
James Kuszmaul41fa78a2019-12-14 20:53:14 -080033 friend class DMA;
34 friend class DMASample;
35
Parker Schuhd3b7a8872018-02-19 16:42:27 -080036 public:
37 enum Mode {
38 kTwoPulse = 0,
39 kSemiperiod = 1,
40 kPulseLength = 2,
41 kExternalDirection = 3
42 };
James Kuszmaul41fa78a2019-12-14 20:53:14 -080043
44 /**
45 * Create an instance of a counter where no sources are selected.
46 *
47 * They all must be selected by calling functions to specify the upsource and
48 * the downsource independently.
49 *
50 * This creates a ChipObject counter and initializes status variables
51 * appropriately.
52 *
53 * The counter will start counting immediately.
54 *
55 * @param mode The counter mode
56 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080057 explicit Counter(Mode mode = kTwoPulse);
James Kuszmaul41fa78a2019-12-14 20:53:14 -080058
59 /**
60 * Create an instance of a Counter object.
61 *
62 * Create an up-Counter instance given a channel.
63 *
64 * The counter will start counting immediately.
65 *
66 * @param channel The DIO channel to use as the up source. 0-9 are on-board,
67 * 10-25 are on the MXP
68 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080069 explicit Counter(int channel);
James Kuszmaul41fa78a2019-12-14 20:53:14 -080070
71 /**
72 * Create an instance of a counter from a Digital Source (such as a Digital
73 * Input).
74 *
75 * This is used if an existing digital input is to be shared by multiple other
76 * objects such as encoders or if the Digital Source is not a Digital Input
77 * channel (such as an Analog Trigger).
78 *
79 * The counter will start counting immediately.
80 * @param source A pointer to the existing DigitalSource object. It will be
81 * set as the Up Source.
82 */
83 explicit Counter(DigitalSource* source);
84
85 /**
86 * Create an instance of a counter from a Digital Source (such as a Digital
87 * Input).
88 *
89 * This is used if an existing digital input is to be shared by multiple other
90 * objects such as encoders or if the Digital Source is not a Digital Input
91 * channel (such as an Analog Trigger).
92 *
93 * The counter will start counting immediately.
94 *
95 * @param source A pointer to the existing DigitalSource object. It will be
96 * set as the Up Source.
97 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -080098 explicit Counter(std::shared_ptr<DigitalSource> source);
James Kuszmaul41fa78a2019-12-14 20:53:14 -080099
100 /**
101 * Create an instance of a Counter object.
102 *
103 * Create an instance of a simple up-Counter given an analog trigger.
104 * Use the trigger state output from the analog trigger.
105 *
106 * The counter will start counting immediately.
107 *
108 * @param trigger The reference to the existing AnalogTrigger object.
109 */
110 explicit Counter(const AnalogTrigger& trigger);
111
112 /**
113 * Create an instance of a Counter object.
114 *
115 * Creates a full up-down counter given two Digital Sources.
116 *
117 * @param encodingType The quadrature decoding mode (1x or 2x)
118 * @param upSource The pointer to the DigitalSource to set as the up
119 * source
120 * @param downSource The pointer to the DigitalSource to set as the down
121 * source
122 * @param inverted True to invert the output (reverse the direction)
123 */
124 Counter(EncodingType encodingType, DigitalSource* upSource,
125 DigitalSource* downSource, bool inverted);
126
127 /**
128 * Create an instance of a Counter object.
129 *
130 * Creates a full up-down counter given two Digital Sources.
131 *
132 * @param encodingType The quadrature decoding mode (1x or 2x)
133 * @param upSource The pointer to the DigitalSource to set as the up
134 * source
135 * @param downSource The pointer to the DigitalSource to set as the down
136 * source
137 * @param inverted True to invert the output (reverse the direction)
138 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800139 Counter(EncodingType encodingType, std::shared_ptr<DigitalSource> upSource,
140 std::shared_ptr<DigitalSource> downSource, bool inverted);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800141
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800142 ~Counter() override;
143
144 Counter(Counter&&) = default;
145 Counter& operator=(Counter&&) = default;
146
147 /**
148 * Set the upsource for the counter as a digital input channel.
149 *
150 * @param channel The DIO channel to use as the up source. 0-9 are on-board,
151 * 10-25 are on the MXP
152 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800153 void SetUpSource(int channel);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800154
155 /**
156 * Set the up counting source to be an analog trigger.
157 *
158 * @param analogTrigger The analog trigger object that is used for the Up
159 * Source
160 * @param triggerType The analog trigger output that will trigger the
161 * counter.
162 */
163 void SetUpSource(AnalogTrigger* analogTrigger, AnalogTriggerType triggerType);
164
165 /**
166 * Set the up counting source to be an analog trigger.
167 *
168 * @param analogTrigger The analog trigger object that is used for the Up
169 * Source
170 * @param triggerType The analog trigger output that will trigger the
171 * counter.
172 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800173 void SetUpSource(std::shared_ptr<AnalogTrigger> analogTrigger,
174 AnalogTriggerType triggerType);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800175
176 void SetUpSource(DigitalSource* source);
177
178 /**
179 * Set the source object that causes the counter to count up.
180 *
181 * Set the up counting DigitalSource.
182 *
183 * @param source Pointer to the DigitalSource object to set as the up source
184 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800185 void SetUpSource(std::shared_ptr<DigitalSource> source);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800186
187 /**
188 * Set the source object that causes the counter to count up.
189 *
190 * Set the up counting DigitalSource.
191 *
192 * @param source Reference to the DigitalSource object to set as the up source
193 */
194 void SetUpSource(DigitalSource& source);
195
196 /**
197 * Set the edge sensitivity on an up counting source.
198 *
199 * Set the up source to either detect rising edges or falling edges or both.
200 *
201 * @param risingEdge True to trigger on rising edges
202 * @param fallingEdge True to trigger on falling edges
203 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800204 void SetUpSourceEdge(bool risingEdge, bool fallingEdge);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800205
206 /**
207 * Disable the up counting source to the counter.
208 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800209 void ClearUpSource();
210
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800211 /**
212 * Set the down counting source to be a digital input channel.
213 *
214 * @param channel The DIO channel to use as the up source. 0-9 are on-board,
215 * 10-25 are on the MXP
216 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800217 void SetDownSource(int channel);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800218
219 /**
220 * Set the down counting source to be an analog trigger.
221 *
222 * @param analogTrigger The analog trigger object that is used for the Down
223 * Source
224 * @param triggerType The analog trigger output that will trigger the
225 * counter.
226 */
227 void SetDownSource(AnalogTrigger* analogTrigger,
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800228 AnalogTriggerType triggerType);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800229
230 /**
231 * Set the down counting source to be an analog trigger.
232 *
233 * @param analogTrigger The analog trigger object that is used for the Down
234 * Source
235 * @param triggerType The analog trigger output that will trigger the
236 * counter.
237 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800238 void SetDownSource(std::shared_ptr<AnalogTrigger> analogTrigger,
239 AnalogTriggerType triggerType);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800240
241 /**
242 * Set the source object that causes the counter to count down.
243 *
244 * Set the down counting DigitalSource.
245 *
246 * @param source Pointer to the DigitalSource object to set as the down source
247 */
248 void SetDownSource(DigitalSource* source);
249
250 /**
251 * Set the source object that causes the counter to count down.
252 *
253 * Set the down counting DigitalSource.
254 *
255 * @param source Reference to the DigitalSource object to set as the down
256 * source
257 */
258 void SetDownSource(DigitalSource& source);
259
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800260 void SetDownSource(std::shared_ptr<DigitalSource> source);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800261
262 /**
263 * Set the edge sensitivity on a down counting source.
264 *
265 * Set the down source to either detect rising edges or falling edges.
266 *
267 * @param risingEdge True to trigger on rising edges
268 * @param fallingEdge True to trigger on falling edges
269 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800270 void SetDownSourceEdge(bool risingEdge, bool fallingEdge);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800271
272 /**
273 * Disable the down counting source to the counter.
274 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800275 void ClearDownSource();
276
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800277 /**
278 * Set standard up / down counting mode on this counter.
279 *
280 * Up and down counts are sourced independently from two inputs.
281 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800282 void SetUpDownCounterMode();
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800283
284 /**
285 * Set external direction mode on this counter.
286 *
287 * Counts are sourced on the Up counter input.
288 * The Down counter input represents the direction to count.
289 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800290 void SetExternalDirectionMode();
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800291
292 /**
293 * Set Semi-period mode on this counter.
294 *
295 * Counts up on both rising and falling edges.
296 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800297 void SetSemiPeriodMode(bool highSemiPeriod);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800298
299 /**
300 * Configure the counter to count in up or down based on the length of the
301 * input pulse.
302 *
303 * This mode is most useful for direction sensitive gear tooth sensors.
304 *
305 * @param threshold The pulse length beyond which the counter counts the
306 * opposite direction. Units are seconds.
307 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800308 void SetPulseLengthMode(double threshold);
309
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800310 /**
311 * Set the Counter to return reversed sensing on the direction.
312 *
313 * This allows counters to change the direction they are counting in the case
314 * of 1X and 2X quadrature encoding only. Any other counter mode isn't
315 * supported.
316 *
317 * @param reverseDirection true if the value counted should be negated.
318 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800319 void SetReverseDirection(bool reverseDirection);
320
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800321 /**
322 * Set the Samples to Average which specifies the number of samples of the
323 * timer to average when calculating the period. Perform averaging to account
324 * for mechanical imperfections or as oversampling to increase resolution.
325 *
326 * @param samplesToAverage The number of samples to average from 1 to 127.
327 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800328 void SetSamplesToAverage(int samplesToAverage);
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800329
330 /**
331 * Get the Samples to Average which specifies the number of samples of the
332 * timer to average when calculating the period.
333 *
334 * Perform averaging to account for mechanical imperfections or as
335 * oversampling to increase resolution.
336 *
337 * @return The number of samples being averaged (from 1 to 127)
338 */
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800339 int GetSamplesToAverage() const;
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800340
341 int GetFPGAIndex() const;
342
343 // CounterBase interface
344 /**
345 * Read the current counter value.
346 *
347 * Read the value at this instant. It may still be running, so it reflects the
348 * current value. Next time it is read, it might have a different value.
349 */
350 int Get() const override;
351
352 /**
353 * Reset the Counter to zero.
354 *
355 * Set the counter value to zero. This doesn't effect the running state of the
356 * counter, just sets the current value to zero.
357 */
358 void Reset() override;
359
360 /**
361 * Get the Period of the most recent count.
362 *
363 * Returns the time interval of the most recent count. This can be used for
364 * velocity calculations to determine shaft speed.
365 *
366 * @returns The period between the last two pulses in units of seconds.
367 */
368 double GetPeriod() const override;
369
370 /**
371 * Set the maximum period where the device is still considered "moving".
372 *
373 * Sets the maximum period where the device is considered moving. This value
374 * is used to determine the "stopped" state of the counter using the
375 * GetStopped method.
376 *
377 * @param maxPeriod The maximum period where the counted device is considered
378 * moving in seconds.
379 */
380 void SetMaxPeriod(double maxPeriod) override;
381
382 /**
383 * Select whether you want to continue updating the event timer output when
384 * there are no samples captured.
385 *
386 * The output of the event timer has a buffer of periods that are averaged and
387 * posted to a register on the FPGA. When the timer detects that the event
388 * source has stopped (based on the MaxPeriod) the buffer of samples to be
389 * averaged is emptied. If you enable the update when empty, you will be
390 * notified of the stopped source and the event time will report 0 samples.
391 * If you disable update when empty, the most recent average will remain on
392 * the output until a new sample is acquired. You will never see 0 samples
393 * output (except when there have been no events since an FPGA reset) and you
394 * will likely not see the stopped bit become true (since it is updated at the
395 * end of an average and there are no samples to average).
396 *
397 * @param enabled True to enable update when empty
398 */
399 void SetUpdateWhenEmpty(bool enabled);
400
401 /**
402 * Determine if the clock is stopped.
403 *
404 * Determine if the clocked input is stopped based on the MaxPeriod value set
405 * using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
406 * device (and counter) are assumed to be stopped and it returns true.
407 *
408 * @return Returns true if the most recent counter period exceeds the
409 * MaxPeriod value set by SetMaxPeriod.
410 */
411 bool GetStopped() const override;
412
413 /**
414 * The last direction the counter value changed.
415 *
416 * @return The last direction the counter value changed.
417 */
418 bool GetDirection() const override;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800419
420 protected:
421 // Makes the counter count up.
422 std::shared_ptr<DigitalSource> m_upSource;
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800423
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800424 // Makes the counter count down.
425 std::shared_ptr<DigitalSource> m_downSource;
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800426
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800427 // The FPGA counter object
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800428 hal::Handle<HAL_CounterHandle> m_counter;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800429
430 private:
James Kuszmaul41fa78a2019-12-14 20:53:14 -0800431 int m_index = 0; // The index of this counter.
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800432
433 friend class DigitalGlitchFilter;
434};
435
436} // namespace frc