blob: 78aa28123c4dae61c800506a756bb96ccb33e3b5 [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/Encoder.h"
6
7#include "CounterInternal.h"
8#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -07009#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include "PortsInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080011#include "hal/Errors.h"
12#include "hal/handles/HandlesInternal.h"
13#include "hal/handles/LimitedHandleResource.h"
14#include "mockdata/EncoderDataInternal.h"
15
16using namespace hal;
17
18namespace {
19struct Encoder {
20 HAL_Handle nativeHandle;
Austin Schuh812d0d12021-11-04 20:16:48 -070021 HAL_FPGAEncoderHandle fpgaHandle;
22 HAL_CounterHandle counterHandle;
Brian Silverman8fce7482020-01-05 13:18:21 -080023 HAL_EncoderEncodingType encodingType;
24 double distancePerPulse;
25 uint8_t index;
26};
27struct Empty {};
28} // namespace
29
30static LimitedHandleResource<HAL_EncoderHandle, Encoder,
31 kNumEncoders + kNumCounters,
32 HAL_HandleEnum::Encoder>* encoderHandles;
33
34static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
35 HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
36
Austin Schuh812d0d12021-11-04 20:16:48 -070037namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080038void InitializeEncoder() {
39 static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
40 HAL_HandleEnum::FPGAEncoder>
41 feH;
42 fpgaEncoderHandles = &feH;
43 static LimitedHandleResource<HAL_EncoderHandle, Encoder,
44 kNumEncoders + kNumCounters,
45 HAL_HandleEnum::Encoder>
46 eH;
47 encoderHandles = &eH;
48}
Austin Schuh812d0d12021-11-04 20:16:48 -070049} // namespace hal::init
50
51namespace hal {
52bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
53 HAL_FPGAEncoderHandle* fpgaHandle,
54 HAL_CounterHandle* counterHandle) {
55 auto encoder = encoderHandles->Get(handle);
56 if (!handle) {
57 return false;
58 }
59
60 *fpgaHandle = encoder->fpgaHandle;
61 *counterHandle = encoder->counterHandle;
62 return true;
63}
Brian Silverman8fce7482020-01-05 13:18:21 -080064} // namespace hal
65
66extern "C" {
67HAL_EncoderHandle HAL_InitializeEncoder(
68 HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
69 HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
70 HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
71 int32_t* status) {
72 hal::init::CheckInit();
73 HAL_Handle nativeHandle = HAL_kInvalidHandle;
74 if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
75 // k4x, allocate encoder
76 nativeHandle = fpgaEncoderHandles->Allocate();
77 } else {
78 // k2x or k1x, allocate counter
79 nativeHandle = counterHandles->Allocate();
80 }
81 if (nativeHandle == HAL_kInvalidHandle) {
82 *status = NO_AVAILABLE_RESOURCES;
83 return HAL_kInvalidHandle;
84 }
85 auto handle = encoderHandles->Allocate();
86 if (handle == HAL_kInvalidHandle) {
87 *status = NO_AVAILABLE_RESOURCES;
88 return HAL_kInvalidHandle;
89 }
90 auto encoder = encoderHandles->Get(handle);
91 if (encoder == nullptr) { // would only occur on thread issue
92 *status = HAL_HANDLE_ERROR;
93 return HAL_kInvalidHandle;
94 }
95 int16_t index = getHandleIndex(handle);
96 SimEncoderData[index].digitalChannelA = getHandleIndex(digitalSourceHandleA);
97 SimEncoderData[index].digitalChannelB = getHandleIndex(digitalSourceHandleB);
98 SimEncoderData[index].initialized = true;
99 SimEncoderData[index].reverseDirection = reverseDirection;
100 SimEncoderData[index].simDevice = 0;
101 // TODO: Add encoding type to Sim data
102 encoder->index = index;
103 encoder->nativeHandle = nativeHandle;
104 encoder->encodingType = encodingType;
105 encoder->distancePerPulse = 1.0;
Austin Schuh812d0d12021-11-04 20:16:48 -0700106 if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
107 encoder->fpgaHandle = nativeHandle;
108 encoder->counterHandle = HAL_kInvalidHandle;
109 } else {
110 encoder->fpgaHandle = HAL_kInvalidHandle;
111 encoder->counterHandle = nativeHandle;
112 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800113 return handle;
114}
115
116void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
117 auto encoder = encoderHandles->Get(encoderHandle);
118 encoderHandles->Free(encoderHandle);
Austin Schuh812d0d12021-11-04 20:16:48 -0700119 if (encoder == nullptr) {
120 return;
121 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800122 if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::FPGAEncoder)) {
123 fpgaEncoderHandles->Free(encoder->nativeHandle);
124 } else if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::Counter)) {
125 counterHandles->Free(encoder->nativeHandle);
126 }
127 SimEncoderData[encoder->index].initialized = false;
128}
129
130void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
131 HAL_SimDeviceHandle device) {
132 auto encoder = encoderHandles->Get(handle);
Austin Schuh812d0d12021-11-04 20:16:48 -0700133 if (encoder == nullptr) {
134 return;
135 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800136 SimEncoderData[encoder->index].simDevice = device;
137}
138
139static inline int EncodingScaleFactor(Encoder* encoder) {
140 switch (encoder->encodingType) {
141 case HAL_Encoder_k1X:
142 return 1;
143 case HAL_Encoder_k2X:
144 return 2;
145 case HAL_Encoder_k4X:
146 return 4;
147 default:
148 return 0;
149 }
150}
151
152static inline double DecodingScaleFactor(Encoder* encoder) {
153 switch (encoder->encodingType) {
154 case HAL_Encoder_k1X:
155 return 1.0;
156 case HAL_Encoder_k2X:
157 return 0.5;
158 case HAL_Encoder_k4X:
159 return 0.25;
160 default:
161 return 0.0;
162 }
163}
164
165int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
166 auto encoder = encoderHandles->Get(encoderHandle);
167 if (encoder == nullptr) {
168 *status = HAL_HANDLE_ERROR;
169 return 0;
170 }
171
172 return SimEncoderData[encoder->index].count;
173}
174int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
175 auto encoder = encoderHandles->Get(encoderHandle);
176 if (encoder == nullptr) {
177 *status = HAL_HANDLE_ERROR;
178 return 0;
179 }
180
181 return SimEncoderData[encoder->index].count /
182 DecodingScaleFactor(encoder.get());
183}
184int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
185 int32_t* status) {
186 auto encoder = encoderHandles->Get(encoderHandle);
187 if (encoder == nullptr) {
188 *status = HAL_HANDLE_ERROR;
189 return 0;
190 }
191
192 return EncodingScaleFactor(encoder.get());
193}
194void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
195 auto encoder = encoderHandles->Get(encoderHandle);
196 if (encoder == nullptr) {
197 *status = HAL_HANDLE_ERROR;
198 return;
199 }
200
Austin Schuh812d0d12021-11-04 20:16:48 -0700201 SimEncoderData[encoder->index].reset = true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800202 SimEncoderData[encoder->index].count = 0;
203 SimEncoderData[encoder->index].period = std::numeric_limits<double>::max();
Brian Silverman8fce7482020-01-05 13:18:21 -0800204}
205double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
206 auto encoder = encoderHandles->Get(encoderHandle);
207 if (encoder == nullptr) {
208 *status = HAL_HANDLE_ERROR;
209 return 0;
210 }
211
212 return SimEncoderData[encoder->index].period;
213}
214void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
215 int32_t* status) {
216 auto encoder = encoderHandles->Get(encoderHandle);
217 if (encoder == nullptr) {
218 *status = HAL_HANDLE_ERROR;
219 return;
220 }
221
222 SimEncoderData[encoder->index].maxPeriod = maxPeriod;
223}
224HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
225 int32_t* status) {
226 auto encoder = encoderHandles->Get(encoderHandle);
227 if (encoder == nullptr) {
228 *status = HAL_HANDLE_ERROR;
229 return 0;
230 }
231
232 return SimEncoderData[encoder->index].period >
233 SimEncoderData[encoder->index].maxPeriod;
234}
235HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
236 int32_t* status) {
237 auto encoder = encoderHandles->Get(encoderHandle);
238 if (encoder == nullptr) {
239 *status = HAL_HANDLE_ERROR;
240 return 0;
241 }
242
243 return SimEncoderData[encoder->index].direction;
244}
245double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
246 int32_t* status) {
247 auto encoder = encoderHandles->Get(encoderHandle);
248 if (encoder == nullptr) {
249 *status = HAL_HANDLE_ERROR;
250 return 0;
251 }
252
253 return SimEncoderData[encoder->index].count * encoder->distancePerPulse;
254}
255double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
256 auto encoder = encoderHandles->Get(encoderHandle);
257 if (encoder == nullptr) {
258 *status = HAL_HANDLE_ERROR;
259 return 0;
260 }
261
262 return encoder->distancePerPulse / SimEncoderData[encoder->index].period;
263}
264void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
265 int32_t* status) {
266 auto encoder = encoderHandles->Get(encoderHandle);
267 if (encoder == nullptr) {
268 *status = HAL_HANDLE_ERROR;
269 return;
270 }
271
272 if (minRate == 0.0) {
273 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700274 hal::SetLastError(status, "minRate must not be 0");
Brian Silverman8fce7482020-01-05 13:18:21 -0800275 return;
276 }
277
278 SimEncoderData[encoder->index].maxPeriod =
279 encoder->distancePerPulse / minRate;
280}
281void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
282 double distancePerPulse, int32_t* status) {
283 auto encoder = encoderHandles->Get(encoderHandle);
284 if (encoder == nullptr) {
285 *status = HAL_HANDLE_ERROR;
286 return;
287 }
288
289 if (distancePerPulse == 0.0) {
290 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700291 hal::SetLastError(status, "distancePerPulse must not be 0");
Brian Silverman8fce7482020-01-05 13:18:21 -0800292 return;
293 }
294 encoder->distancePerPulse = distancePerPulse;
295 SimEncoderData[encoder->index].distancePerPulse = distancePerPulse;
296}
297void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
298 HAL_Bool reverseDirection,
299 int32_t* status) {
300 auto encoder = encoderHandles->Get(encoderHandle);
301 if (encoder == nullptr) {
302 *status = HAL_HANDLE_ERROR;
303 return;
304 }
305
306 SimEncoderData[encoder->index].reverseDirection = reverseDirection;
307}
308void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
309 int32_t samplesToAverage, int32_t* status) {
310 auto encoder = encoderHandles->Get(encoderHandle);
311 if (encoder == nullptr) {
312 *status = HAL_HANDLE_ERROR;
313 return;
314 }
315
316 SimEncoderData[encoder->index].samplesToAverage = samplesToAverage;
317}
318int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
319 int32_t* status) {
320 auto encoder = encoderHandles->Get(encoderHandle);
321 if (encoder == nullptr) {
322 *status = HAL_HANDLE_ERROR;
323 return 0;
324 }
325
326 return SimEncoderData[encoder->index].samplesToAverage;
327}
328
329void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
330 HAL_Handle digitalSourceHandle,
331 HAL_AnalogTriggerType analogTriggerType,
332 HAL_EncoderIndexingType type, int32_t* status) {
333 // Not implemented yet
334}
335
336int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
337 int32_t* status) {
338 auto encoder = encoderHandles->Get(encoderHandle);
339 if (encoder == nullptr) {
340 *status = HAL_HANDLE_ERROR;
341 return 0;
342 }
343
344 return encoder->index;
345}
346
347double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
348 int32_t* status) {
349 auto encoder = encoderHandles->Get(encoderHandle);
350 if (encoder == nullptr) {
351 *status = HAL_HANDLE_ERROR;
352 return 0.0;
353 }
354
355 return DecodingScaleFactor(encoder.get());
356}
357
358double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
359 int32_t* status) {
360 auto encoder = encoderHandles->Get(encoderHandle);
361 if (encoder == nullptr) {
362 *status = HAL_HANDLE_ERROR;
363 return 0.0;
364 }
365
366 return encoder->distancePerPulse;
367}
368
369HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
370 HAL_EncoderHandle encoderHandle, int32_t* status) {
371 auto encoder = encoderHandles->Get(encoderHandle);
372 if (encoder == nullptr) {
373 *status = HAL_HANDLE_ERROR;
374 return HAL_Encoder_k4X; // default to k4x
375 }
376
377 return encoder->encodingType;
378}
379} // extern "C"