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