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