blob: 36122bf61418c6c6886cffaddfea45ad9685f894 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2017-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 "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);
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080085 SimEncoderData[index].digitalChannelB = getHandleIndex(digitalSourceHandleB);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080086 SimEncoderData[index].initialized = true;
87 SimEncoderData[index].reverseDirection = reverseDirection;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080088 SimEncoderData[index].simDevice = 0;
Brian Silverman41cdd3e2019-01-19 19:48:58 -080089 // TODO: Add encoding type to Sim data
90 encoder->index = index;
91 encoder->nativeHandle = nativeHandle;
92 encoder->encodingType = encodingType;
93 encoder->distancePerPulse = 1.0;
94 return handle;
95}
96
97void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
98 auto encoder = encoderHandles->Get(encoderHandle);
99 encoderHandles->Free(encoderHandle);
100 if (encoder == nullptr) return;
101 if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::FPGAEncoder)) {
102 fpgaEncoderHandles->Free(encoder->nativeHandle);
103 } else if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::Counter)) {
104 counterHandles->Free(encoder->nativeHandle);
105 }
106 SimEncoderData[encoder->index].initialized = false;
107}
108
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800109void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
110 HAL_SimDeviceHandle device) {
111 auto encoder = encoderHandles->Get(handle);
112 if (encoder == nullptr) return;
113 SimEncoderData[encoder->index].simDevice = device;
114}
115
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800116static inline int EncodingScaleFactor(Encoder* encoder) {
117 switch (encoder->encodingType) {
118 case HAL_Encoder_k1X:
119 return 1;
120 case HAL_Encoder_k2X:
121 return 2;
122 case HAL_Encoder_k4X:
123 return 4;
124 default:
125 return 0;
126 }
127}
128
129static inline double DecodingScaleFactor(Encoder* encoder) {
130 switch (encoder->encodingType) {
131 case HAL_Encoder_k1X:
132 return 1.0;
133 case HAL_Encoder_k2X:
134 return 0.5;
135 case HAL_Encoder_k4X:
136 return 0.25;
137 default:
138 return 0.0;
139 }
140}
141
142int32_t HAL_GetEncoder(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}
151int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
152 auto encoder = encoderHandles->Get(encoderHandle);
153 if (encoder == nullptr) {
154 *status = HAL_HANDLE_ERROR;
155 return 0;
156 }
157
158 return SimEncoderData[encoder->index].count /
159 DecodingScaleFactor(encoder.get());
160}
161int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
162 int32_t* status) {
163 auto encoder = encoderHandles->Get(encoderHandle);
164 if (encoder == nullptr) {
165 *status = HAL_HANDLE_ERROR;
166 return 0;
167 }
168
169 return EncodingScaleFactor(encoder.get());
170}
171void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
172 auto encoder = encoderHandles->Get(encoderHandle);
173 if (encoder == nullptr) {
174 *status = HAL_HANDLE_ERROR;
175 return;
176 }
177
178 SimEncoderData[encoder->index].count = 0;
179 SimEncoderData[encoder->index].period = std::numeric_limits<double>::max();
180 SimEncoderData[encoder->index].reset = true;
181}
182double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
183 auto encoder = encoderHandles->Get(encoderHandle);
184 if (encoder == nullptr) {
185 *status = HAL_HANDLE_ERROR;
186 return 0;
187 }
188
189 return SimEncoderData[encoder->index].period;
190}
191void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
192 int32_t* status) {
193 auto encoder = encoderHandles->Get(encoderHandle);
194 if (encoder == nullptr) {
195 *status = HAL_HANDLE_ERROR;
196 return;
197 }
198
199 SimEncoderData[encoder->index].maxPeriod = maxPeriod;
200}
201HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
202 int32_t* status) {
203 auto encoder = encoderHandles->Get(encoderHandle);
204 if (encoder == nullptr) {
205 *status = HAL_HANDLE_ERROR;
206 return 0;
207 }
208
209 return SimEncoderData[encoder->index].period >
210 SimEncoderData[encoder->index].maxPeriod;
211}
212HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
213 int32_t* status) {
214 auto encoder = encoderHandles->Get(encoderHandle);
215 if (encoder == nullptr) {
216 *status = HAL_HANDLE_ERROR;
217 return 0;
218 }
219
220 return SimEncoderData[encoder->index].direction;
221}
222double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
223 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 SimEncoderData[encoder->index].count * encoder->distancePerPulse;
231}
232double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
233 auto encoder = encoderHandles->Get(encoderHandle);
234 if (encoder == nullptr) {
235 *status = HAL_HANDLE_ERROR;
236 return 0;
237 }
238
239 return encoder->distancePerPulse / SimEncoderData[encoder->index].period;
240}
241void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
242 int32_t* status) {
243 auto encoder = encoderHandles->Get(encoderHandle);
244 if (encoder == nullptr) {
245 *status = HAL_HANDLE_ERROR;
246 return;
247 }
248
249 if (minRate == 0.0) {
250 *status = PARAMETER_OUT_OF_RANGE;
251 return;
252 }
253
254 SimEncoderData[encoder->index].maxPeriod =
255 encoder->distancePerPulse / minRate;
256}
257void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
258 double distancePerPulse, int32_t* status) {
259 auto encoder = encoderHandles->Get(encoderHandle);
260 if (encoder == nullptr) {
261 *status = HAL_HANDLE_ERROR;
262 return;
263 }
264
265 if (distancePerPulse == 0.0) {
266 *status = PARAMETER_OUT_OF_RANGE;
267 return;
268 }
269 encoder->distancePerPulse = distancePerPulse;
270 SimEncoderData[encoder->index].distancePerPulse = distancePerPulse;
271}
272void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
273 HAL_Bool reverseDirection,
274 int32_t* status) {
275 auto encoder = encoderHandles->Get(encoderHandle);
276 if (encoder == nullptr) {
277 *status = HAL_HANDLE_ERROR;
278 return;
279 }
280
281 SimEncoderData[encoder->index].reverseDirection = reverseDirection;
282}
283void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
284 int32_t samplesToAverage, int32_t* status) {
285 auto encoder = encoderHandles->Get(encoderHandle);
286 if (encoder == nullptr) {
287 *status = HAL_HANDLE_ERROR;
288 return;
289 }
290
291 SimEncoderData[encoder->index].samplesToAverage = samplesToAverage;
292}
293int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
294 int32_t* status) {
295 auto encoder = encoderHandles->Get(encoderHandle);
296 if (encoder == nullptr) {
297 *status = HAL_HANDLE_ERROR;
298 return 0;
299 }
300
301 return SimEncoderData[encoder->index].samplesToAverage;
302}
303
304void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
305 HAL_Handle digitalSourceHandle,
306 HAL_AnalogTriggerType analogTriggerType,
307 HAL_EncoderIndexingType type, int32_t* status) {
308 // Not implemented yet
309}
310
311int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
312 int32_t* status) {
313 auto encoder = encoderHandles->Get(encoderHandle);
314 if (encoder == nullptr) {
315 *status = HAL_HANDLE_ERROR;
316 return 0;
317 }
318
319 return encoder->index;
320}
321
322double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
323 int32_t* status) {
324 auto encoder = encoderHandles->Get(encoderHandle);
325 if (encoder == nullptr) {
326 *status = HAL_HANDLE_ERROR;
327 return 0.0;
328 }
329
330 return DecodingScaleFactor(encoder.get());
331}
332
333double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
334 int32_t* status) {
335 auto encoder = encoderHandles->Get(encoderHandle);
336 if (encoder == nullptr) {
337 *status = HAL_HANDLE_ERROR;
338 return 0.0;
339 }
340
341 return encoder->distancePerPulse;
342}
343
344HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
345 HAL_EncoderHandle encoderHandle, int32_t* status) {
346 auto encoder = encoderHandles->Get(encoderHandle);
347 if (encoder == nullptr) {
348 *status = HAL_HANDLE_ERROR;
349 return HAL_Encoder_k4X; // default to k4x
350 }
351
352 return encoder->encodingType;
353}
354} // extern "C"