blob: c97bbc5a0506222fcec76b77af59657585c24113 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
3/* 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#include "frc/Counter.h"
9
10#include <utility>
11
12#include <hal/HAL.h>
13
14#include "frc/AnalogTrigger.h"
15#include "frc/DigitalInput.h"
16#include "frc/WPIErrors.h"
17#include "frc/smartdashboard/SendableBuilder.h"
18
19using namespace frc;
20
21Counter::Counter(Mode mode) {
22 int32_t status = 0;
23 m_counter = HAL_InitializeCounter((HAL_Counter_Mode)mode, &m_index, &status);
24 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
25
26 SetMaxPeriod(.5);
27
28 HAL_Report(HALUsageReporting::kResourceType_Counter, m_index, mode);
29 SetName("Counter", m_index);
30}
31
32Counter::Counter(int channel) : Counter(kTwoPulse) {
33 SetUpSource(channel);
34 ClearDownSource();
35}
36
37Counter::Counter(DigitalSource* source) : Counter(kTwoPulse) {
38 SetUpSource(source);
39 ClearDownSource();
40}
41
42Counter::Counter(std::shared_ptr<DigitalSource> source) : Counter(kTwoPulse) {
43 SetUpSource(source);
44 ClearDownSource();
45}
46
47Counter::Counter(const AnalogTrigger& trigger) : Counter(kTwoPulse) {
48 SetUpSource(trigger.CreateOutput(AnalogTriggerType::kState));
49 ClearDownSource();
50}
51
52Counter::Counter(EncodingType encodingType, DigitalSource* upSource,
53 DigitalSource* downSource, bool inverted)
54 : Counter(encodingType,
55 std::shared_ptr<DigitalSource>(upSource,
56 NullDeleter<DigitalSource>()),
57 std::shared_ptr<DigitalSource>(downSource,
58 NullDeleter<DigitalSource>()),
59 inverted) {}
60
61Counter::Counter(EncodingType encodingType,
62 std::shared_ptr<DigitalSource> upSource,
63 std::shared_ptr<DigitalSource> downSource, bool inverted)
64 : Counter(kExternalDirection) {
65 if (encodingType != k1X && encodingType != k2X) {
66 wpi_setWPIErrorWithContext(
67 ParameterOutOfRange,
68 "Counter only supports 1X and 2X quadrature decoding.");
69 return;
70 }
71 SetUpSource(upSource);
72 SetDownSource(downSource);
73 int32_t status = 0;
74
75 if (encodingType == k1X) {
76 SetUpSourceEdge(true, false);
77 HAL_SetCounterAverageSize(m_counter, 1, &status);
78 } else {
79 SetUpSourceEdge(true, true);
80 HAL_SetCounterAverageSize(m_counter, 2, &status);
81 }
82
83 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
84 SetDownSourceEdge(inverted, true);
85}
86
87Counter::~Counter() {
88 SetUpdateWhenEmpty(true);
89
90 int32_t status = 0;
91 HAL_FreeCounter(m_counter, &status);
92 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
93 m_counter = HAL_kInvalidHandle;
94}
95
96Counter::Counter(Counter&& rhs)
97 : ErrorBase(std::move(rhs)),
98 SendableBase(std::move(rhs)),
99 CounterBase(std::move(rhs)),
100 m_upSource(std::move(rhs.m_upSource)),
101 m_downSource(std::move(rhs.m_downSource)),
102 m_index(std::move(rhs.m_index)) {
103 std::swap(m_counter, rhs.m_counter);
104}
105
106Counter& Counter::operator=(Counter&& rhs) {
107 ErrorBase::operator=(std::move(rhs));
108 SendableBase::operator=(std::move(rhs));
109 CounterBase::operator=(std::move(rhs));
110
111 m_upSource = std::move(rhs.m_upSource);
112 m_downSource = std::move(rhs.m_downSource);
113 std::swap(m_counter, rhs.m_counter);
114 m_index = std::move(rhs.m_index);
115
116 return *this;
117}
118
119void Counter::SetUpSource(int channel) {
120 if (StatusIsFatal()) return;
121 SetUpSource(std::make_shared<DigitalInput>(channel));
122 AddChild(m_upSource);
123}
124
125void Counter::SetUpSource(AnalogTrigger* analogTrigger,
126 AnalogTriggerType triggerType) {
127 SetUpSource(std::shared_ptr<AnalogTrigger>(analogTrigger,
128 NullDeleter<AnalogTrigger>()),
129 triggerType);
130}
131
132void Counter::SetUpSource(std::shared_ptr<AnalogTrigger> analogTrigger,
133 AnalogTriggerType triggerType) {
134 if (StatusIsFatal()) return;
135 SetUpSource(analogTrigger->CreateOutput(triggerType));
136}
137
138void Counter::SetUpSource(DigitalSource* source) {
139 SetUpSource(
140 std::shared_ptr<DigitalSource>(source, NullDeleter<DigitalSource>()));
141}
142
143void Counter::SetUpSource(std::shared_ptr<DigitalSource> source) {
144 if (StatusIsFatal()) return;
145 m_upSource = source;
146 if (m_upSource->StatusIsFatal()) {
147 CloneError(*m_upSource);
148 } else {
149 int32_t status = 0;
150 HAL_SetCounterUpSource(
151 m_counter, source->GetPortHandleForRouting(),
152 (HAL_AnalogTriggerType)source->GetAnalogTriggerTypeForRouting(),
153 &status);
154 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
155 }
156}
157
158void Counter::SetUpSource(DigitalSource& source) {
159 SetUpSource(
160 std::shared_ptr<DigitalSource>(&source, NullDeleter<DigitalSource>()));
161}
162
163void Counter::SetUpSourceEdge(bool risingEdge, bool fallingEdge) {
164 if (StatusIsFatal()) return;
165 if (m_upSource == nullptr) {
166 wpi_setWPIErrorWithContext(
167 NullParameter,
168 "Must set non-nullptr UpSource before setting UpSourceEdge");
169 }
170 int32_t status = 0;
171 HAL_SetCounterUpSourceEdge(m_counter, risingEdge, fallingEdge, &status);
172 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
173}
174
175void Counter::ClearUpSource() {
176 if (StatusIsFatal()) return;
177 m_upSource.reset();
178 int32_t status = 0;
179 HAL_ClearCounterUpSource(m_counter, &status);
180 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
181}
182
183void Counter::SetDownSource(int channel) {
184 if (StatusIsFatal()) return;
185 SetDownSource(std::make_shared<DigitalInput>(channel));
186 AddChild(m_downSource);
187}
188
189void Counter::SetDownSource(AnalogTrigger* analogTrigger,
190 AnalogTriggerType triggerType) {
191 SetDownSource(std::shared_ptr<AnalogTrigger>(analogTrigger,
192 NullDeleter<AnalogTrigger>()),
193 triggerType);
194}
195
196void Counter::SetDownSource(std::shared_ptr<AnalogTrigger> analogTrigger,
197 AnalogTriggerType triggerType) {
198 if (StatusIsFatal()) return;
199 SetDownSource(analogTrigger->CreateOutput(triggerType));
200}
201
202void Counter::SetDownSource(DigitalSource* source) {
203 SetDownSource(
204 std::shared_ptr<DigitalSource>(source, NullDeleter<DigitalSource>()));
205}
206
207void Counter::SetDownSource(DigitalSource& source) {
208 SetDownSource(
209 std::shared_ptr<DigitalSource>(&source, NullDeleter<DigitalSource>()));
210}
211
212void Counter::SetDownSource(std::shared_ptr<DigitalSource> source) {
213 if (StatusIsFatal()) return;
214 m_downSource = source;
215 if (m_downSource->StatusIsFatal()) {
216 CloneError(*m_downSource);
217 } else {
218 int32_t status = 0;
219 HAL_SetCounterDownSource(
220 m_counter, source->GetPortHandleForRouting(),
221 (HAL_AnalogTriggerType)source->GetAnalogTriggerTypeForRouting(),
222 &status);
223 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
224 }
225}
226
227void Counter::SetDownSourceEdge(bool risingEdge, bool fallingEdge) {
228 if (StatusIsFatal()) return;
229 if (m_downSource == nullptr) {
230 wpi_setWPIErrorWithContext(
231 NullParameter,
232 "Must set non-nullptr DownSource before setting DownSourceEdge");
233 }
234 int32_t status = 0;
235 HAL_SetCounterDownSourceEdge(m_counter, risingEdge, fallingEdge, &status);
236 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
237}
238
239void Counter::ClearDownSource() {
240 if (StatusIsFatal()) return;
241 m_downSource.reset();
242 int32_t status = 0;
243 HAL_ClearCounterDownSource(m_counter, &status);
244 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
245}
246
247void Counter::SetUpDownCounterMode() {
248 if (StatusIsFatal()) return;
249 int32_t status = 0;
250 HAL_SetCounterUpDownMode(m_counter, &status);
251 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
252}
253
254void Counter::SetExternalDirectionMode() {
255 if (StatusIsFatal()) return;
256 int32_t status = 0;
257 HAL_SetCounterExternalDirectionMode(m_counter, &status);
258 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
259}
260
261void Counter::SetSemiPeriodMode(bool highSemiPeriod) {
262 if (StatusIsFatal()) return;
263 int32_t status = 0;
264 HAL_SetCounterSemiPeriodMode(m_counter, highSemiPeriod, &status);
265 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
266}
267
268void Counter::SetPulseLengthMode(double threshold) {
269 if (StatusIsFatal()) return;
270 int32_t status = 0;
271 HAL_SetCounterPulseLengthMode(m_counter, threshold, &status);
272 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
273}
274
275void Counter::SetReverseDirection(bool reverseDirection) {
276 if (StatusIsFatal()) return;
277 int32_t status = 0;
278 HAL_SetCounterReverseDirection(m_counter, reverseDirection, &status);
279 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
280}
281
282void Counter::SetSamplesToAverage(int samplesToAverage) {
283 if (samplesToAverage < 1 || samplesToAverage > 127) {
284 wpi_setWPIErrorWithContext(
285 ParameterOutOfRange,
286 "Average counter values must be between 1 and 127");
287 }
288 int32_t status = 0;
289 HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, &status);
290 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
291}
292
293int Counter::GetSamplesToAverage() const {
294 int32_t status = 0;
295 int samples = HAL_GetCounterSamplesToAverage(m_counter, &status);
296 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
297 return samples;
298}
299
300int Counter::GetFPGAIndex() const { return m_index; }
301
302int Counter::Get() const {
303 if (StatusIsFatal()) return 0;
304 int32_t status = 0;
305 int value = HAL_GetCounter(m_counter, &status);
306 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
307 return value;
308}
309
310void Counter::Reset() {
311 if (StatusIsFatal()) return;
312 int32_t status = 0;
313 HAL_ResetCounter(m_counter, &status);
314 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
315}
316
317double Counter::GetPeriod() const {
318 if (StatusIsFatal()) return 0.0;
319 int32_t status = 0;
320 double value = HAL_GetCounterPeriod(m_counter, &status);
321 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
322 return value;
323}
324
325void Counter::SetMaxPeriod(double maxPeriod) {
326 if (StatusIsFatal()) return;
327 int32_t status = 0;
328 HAL_SetCounterMaxPeriod(m_counter, maxPeriod, &status);
329 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
330}
331
332void Counter::SetUpdateWhenEmpty(bool enabled) {
333 if (StatusIsFatal()) return;
334 int32_t status = 0;
335 HAL_SetCounterUpdateWhenEmpty(m_counter, enabled, &status);
336 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
337}
338
339bool Counter::GetStopped() const {
340 if (StatusIsFatal()) return false;
341 int32_t status = 0;
342 bool value = HAL_GetCounterStopped(m_counter, &status);
343 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
344 return value;
345}
346
347bool Counter::GetDirection() const {
348 if (StatusIsFatal()) return false;
349 int32_t status = 0;
350 bool value = HAL_GetCounterDirection(m_counter, &status);
351 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
352 return value;
353}
354
355void Counter::InitSendable(SendableBuilder& builder) {
356 builder.SetSmartDashboardType("Counter");
357 builder.AddDoubleProperty("Value", [=]() { return Get(); }, nullptr);
358}