blob: 7f84df88ff98719b2d2a2924d5ead08ea62ea092 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/Counter.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <fmt/format.h>
8
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include "ConstantsInternal.h"
10#include "DigitalInternal.h"
11#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070012#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080013#include "PortsInternal.h"
14#include "hal/HAL.h"
15#include "hal/handles/LimitedHandleResource.h"
16
17using namespace hal;
18
19namespace {
20
21struct Counter {
22 std::unique_ptr<tCounter> counter;
23 uint8_t index;
24};
25
26} // namespace
27
28static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
29 HAL_HandleEnum::Counter>* counterHandles;
30
Austin Schuh812d0d12021-11-04 20:16:48 -070031namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080032void InitializeCounter() {
33 static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
34 HAL_HandleEnum::Counter>
35 ch;
36 counterHandles = &ch;
37}
Austin Schuh812d0d12021-11-04 20:16:48 -070038} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080039
40extern "C" {
41
42HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
43 int32_t* status) {
44 hal::init::CheckInit();
45 auto handle = counterHandles->Allocate();
46 if (handle == HAL_kInvalidHandle) { // out of resources
47 *status = NO_AVAILABLE_RESOURCES;
48 return HAL_kInvalidHandle;
49 }
50 auto counter = counterHandles->Get(handle);
51 if (counter == nullptr) { // would only occur on thread issues
52 *status = HAL_HANDLE_ERROR;
53 return HAL_kInvalidHandle;
54 }
55 counter->index = static_cast<uint8_t>(getHandleIndex(handle));
56 *index = counter->index;
57
58 counter->counter.reset(tCounter::create(counter->index, status));
59 counter->counter->writeConfig_Mode(mode, status);
60 counter->counter->writeTimerConfig_AverageSize(1, status);
61 return handle;
62}
63
64void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status) {
65 counterHandles->Free(counterHandle);
66}
67
68void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
69 int32_t* status) {
70 auto counter = counterHandles->Get(counterHandle);
71 if (counter == nullptr) {
72 *status = HAL_HANDLE_ERROR;
73 return;
74 }
75 counter->counter->writeTimerConfig_AverageSize(size, status);
76}
77
78void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
79 HAL_Handle digitalSourceHandle,
80 HAL_AnalogTriggerType analogTriggerType,
81 int32_t* status) {
82 auto counter = counterHandles->Get(counterHandle);
83 if (counter == nullptr) {
84 *status = HAL_HANDLE_ERROR;
85 return;
86 }
87
88 bool routingAnalogTrigger = false;
89 uint8_t routingChannel = 0;
90 uint8_t routingModule = 0;
91 bool success =
92 remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
93 routingModule, routingAnalogTrigger);
94 if (!success) {
95 *status = HAL_HANDLE_ERROR;
96 return;
97 }
98
99 counter->counter->writeConfig_UpSource_Module(routingModule, status);
100 counter->counter->writeConfig_UpSource_Channel(routingChannel, status);
101 counter->counter->writeConfig_UpSource_AnalogTrigger(routingAnalogTrigger,
102 status);
103
104 if (counter->counter->readConfig_Mode(status) == HAL_Counter_kTwoPulse ||
105 counter->counter->readConfig_Mode(status) ==
106 HAL_Counter_kExternalDirection) {
107 HAL_SetCounterUpSourceEdge(counterHandle, true, false, status);
108 }
109 counter->counter->strobeReset(status);
110}
111
112void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
113 HAL_Bool risingEdge, HAL_Bool fallingEdge,
114 int32_t* status) {
115 auto counter = counterHandles->Get(counterHandle);
116 if (counter == nullptr) {
117 *status = HAL_HANDLE_ERROR;
118 return;
119 }
120 counter->counter->writeConfig_UpRisingEdge(risingEdge, status);
121 counter->counter->writeConfig_UpFallingEdge(fallingEdge, status);
122}
123
124void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle,
125 int32_t* status) {
126 auto counter = counterHandles->Get(counterHandle);
127 if (counter == nullptr) {
128 *status = HAL_HANDLE_ERROR;
129 return;
130 }
131 counter->counter->writeConfig_UpFallingEdge(false, status);
132 counter->counter->writeConfig_UpRisingEdge(false, status);
133 // Index 0 of digital is always 0.
134 counter->counter->writeConfig_UpSource_Channel(0, status);
135 counter->counter->writeConfig_UpSource_AnalogTrigger(false, status);
136}
137
138void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
139 HAL_Handle digitalSourceHandle,
140 HAL_AnalogTriggerType analogTriggerType,
141 int32_t* status) {
142 auto counter = counterHandles->Get(counterHandle);
143 if (counter == nullptr) {
144 *status = HAL_HANDLE_ERROR;
145 return;
146 }
147 uint8_t mode = counter->counter->readConfig_Mode(status);
148 if (mode != HAL_Counter_kTwoPulse && mode != HAL_Counter_kExternalDirection) {
149 // TODO: wpi_setWPIErrorWithContext(ParameterOutOfRange, "Counter only
150 // supports DownSource in TwoPulse and ExternalDirection modes.");
151 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700152 hal::SetLastError(status,
153 "Counter only supports DownSource in TwoPulse and "
154 "ExternalDirection mode.");
Brian Silverman8fce7482020-01-05 13:18:21 -0800155 return;
156 }
157
158 bool routingAnalogTrigger = false;
159 uint8_t routingChannel = 0;
160 uint8_t routingModule = 0;
161 bool success =
162 remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
163 routingModule, routingAnalogTrigger);
164 if (!success) {
165 *status = HAL_HANDLE_ERROR;
166 return;
167 }
168
169 counter->counter->writeConfig_DownSource_Module(routingModule, status);
170 counter->counter->writeConfig_DownSource_Channel(routingChannel, status);
171 counter->counter->writeConfig_DownSource_AnalogTrigger(routingAnalogTrigger,
172 status);
173
174 HAL_SetCounterDownSourceEdge(counterHandle, true, false, status);
175 counter->counter->strobeReset(status);
176}
177
178void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
179 HAL_Bool risingEdge, HAL_Bool fallingEdge,
180 int32_t* status) {
181 auto counter = counterHandles->Get(counterHandle);
182 if (counter == nullptr) {
183 *status = HAL_HANDLE_ERROR;
184 return;
185 }
186 counter->counter->writeConfig_DownRisingEdge(risingEdge, status);
187 counter->counter->writeConfig_DownFallingEdge(fallingEdge, status);
188}
189
190void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
191 int32_t* status) {
192 auto counter = counterHandles->Get(counterHandle);
193 if (counter == nullptr) {
194 *status = HAL_HANDLE_ERROR;
195 return;
196 }
197 counter->counter->writeConfig_DownFallingEdge(false, status);
198 counter->counter->writeConfig_DownRisingEdge(false, status);
199 // Index 0 of digital is always 0.
200 counter->counter->writeConfig_DownSource_Channel(0, status);
201 counter->counter->writeConfig_DownSource_AnalogTrigger(false, status);
202}
203
204void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle,
205 int32_t* status) {
206 auto counter = counterHandles->Get(counterHandle);
207 if (counter == nullptr) {
208 *status = HAL_HANDLE_ERROR;
209 return;
210 }
211 counter->counter->writeConfig_Mode(HAL_Counter_kTwoPulse, status);
212}
213
214void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
215 int32_t* status) {
216 auto counter = counterHandles->Get(counterHandle);
217 if (counter == nullptr) {
218 *status = HAL_HANDLE_ERROR;
219 return;
220 }
221 counter->counter->writeConfig_Mode(HAL_Counter_kExternalDirection, status);
222}
223
224void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
225 HAL_Bool highSemiPeriod, int32_t* status) {
226 auto counter = counterHandles->Get(counterHandle);
227 if (counter == nullptr) {
228 *status = HAL_HANDLE_ERROR;
229 return;
230 }
231 counter->counter->writeConfig_Mode(HAL_Counter_kSemiperiod, status);
232 counter->counter->writeConfig_UpRisingEdge(highSemiPeriod, status);
233 HAL_SetCounterUpdateWhenEmpty(counterHandle, false, status);
234}
235
236void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
237 double threshold, int32_t* status) {
238 auto counter = counterHandles->Get(counterHandle);
239 if (counter == nullptr) {
240 *status = HAL_HANDLE_ERROR;
241 return;
242 }
243 counter->counter->writeConfig_Mode(HAL_Counter_kPulseLength, status);
244 counter->counter->writeConfig_PulseLengthThreshold(
245 static_cast<uint32_t>(threshold * 1.0e6) *
246 kSystemClockTicksPerMicrosecond,
247 status);
248}
249
250int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
251 int32_t* status) {
252 auto counter = counterHandles->Get(counterHandle);
253 if (counter == nullptr) {
254 *status = HAL_HANDLE_ERROR;
255 return 0;
256 }
257 return counter->counter->readTimerConfig_AverageSize(status);
258}
259
260void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
261 int32_t samplesToAverage, int32_t* status) {
262 auto counter = counterHandles->Get(counterHandle);
263 if (counter == nullptr) {
264 *status = HAL_HANDLE_ERROR;
265 return;
266 }
267 if (samplesToAverage < 1 || samplesToAverage > 127) {
268 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700269 hal::SetLastError(status, fmt::format("Samples to average must be between "
270 "1 and 127 inclusive. Requested {}",
271 samplesToAverage));
272 return;
Brian Silverman8fce7482020-01-05 13:18:21 -0800273 }
274 counter->counter->writeTimerConfig_AverageSize(samplesToAverage, status);
275}
276
277void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
278 auto counter = counterHandles->Get(counterHandle);
279 if (counter == nullptr) {
280 *status = HAL_HANDLE_ERROR;
281 return;
282 }
283 counter->counter->strobeReset(status);
284}
285
286int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status) {
287 auto counter = counterHandles->Get(counterHandle);
288 if (counter == nullptr) {
289 *status = HAL_HANDLE_ERROR;
290 return 0;
291 }
292 int32_t value = counter->counter->readOutput_Value(status);
293 return value;
294}
295
296double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status) {
297 auto counter = counterHandles->Get(counterHandle);
298 if (counter == nullptr) {
299 *status = HAL_HANDLE_ERROR;
300 return 0.0;
301 }
302 tCounter::tTimerOutput output = counter->counter->readTimerOutput(status);
303 double period;
304 if (output.Stalled) {
305 // Return infinity
306 double zero = 0.0;
307 period = 1.0 / zero;
308 } else {
309 // output.Period is a fixed point number that counts by 2 (24 bits, 25
310 // integer bits)
311 period = static_cast<double>(output.Period << 1) /
312 static_cast<double>(output.Count);
313 }
314 return static_cast<double>(period *
315 2.5e-8); // result * timebase (currently 25ns)
316}
317
318void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
319 int32_t* status) {
320 auto counter = counterHandles->Get(counterHandle);
321 if (counter == nullptr) {
322 *status = HAL_HANDLE_ERROR;
323 return;
324 }
325 counter->counter->writeTimerConfig_StallPeriod(
326 static_cast<uint32_t>(maxPeriod * 4.0e8), status);
327}
328
329void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
330 HAL_Bool enabled, int32_t* status) {
331 auto counter = counterHandles->Get(counterHandle);
332 if (counter == nullptr) {
333 *status = HAL_HANDLE_ERROR;
334 return;
335 }
336 counter->counter->writeTimerConfig_UpdateWhenEmpty(enabled, status);
337}
338
339HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
340 int32_t* status) {
341 auto counter = counterHandles->Get(counterHandle);
342 if (counter == nullptr) {
343 *status = HAL_HANDLE_ERROR;
344 return false;
345 }
346 return counter->counter->readTimerOutput_Stalled(status);
347}
348
349HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
350 int32_t* status) {
351 auto counter = counterHandles->Get(counterHandle);
352 if (counter == nullptr) {
353 *status = HAL_HANDLE_ERROR;
354 return false;
355 }
356 bool value = counter->counter->readOutput_Direction(status);
357 return value;
358}
359
360void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
361 HAL_Bool reverseDirection,
362 int32_t* status) {
363 auto counter = counterHandles->Get(counterHandle);
364 if (counter == nullptr) {
365 *status = HAL_HANDLE_ERROR;
366 return;
367 }
368 if (counter->counter->readConfig_Mode(status) ==
369 HAL_Counter_kExternalDirection) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700370 if (reverseDirection) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800371 HAL_SetCounterDownSourceEdge(counterHandle, true, true, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700372 } else {
Brian Silverman8fce7482020-01-05 13:18:21 -0800373 HAL_SetCounterDownSourceEdge(counterHandle, false, true, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700374 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800375 }
376}
377
378} // extern "C"