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