blob: be8c203e4245f4dda4cccd25436a154ce5d1b95f [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2016-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 "EncoderInternal.h"
11#include "FPGAEncoder.h"
12#include "HALInitializer.h"
13#include "PortsInternal.h"
14#include "hal/ChipObject.h"
15#include "hal/Counter.h"
16#include "hal/Errors.h"
17#include "hal/handles/LimitedClassedHandleResource.h"
18
19using namespace hal;
20
21Encoder::Encoder(HAL_Handle digitalSourceHandleA,
22 HAL_AnalogTriggerType analogTriggerTypeA,
23 HAL_Handle digitalSourceHandleB,
24 HAL_AnalogTriggerType analogTriggerTypeB,
25 bool reverseDirection, HAL_EncoderEncodingType encodingType,
26 int32_t* status) {
27 m_encodingType = encodingType;
28 switch (encodingType) {
29 case HAL_Encoder_k4X: {
30 m_encodingScale = 4;
31 m_encoder = HAL_InitializeFPGAEncoder(
32 digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
33 analogTriggerTypeB, reverseDirection, &m_index, status);
34 if (*status != 0) {
35 return;
36 }
37 m_counter = HAL_kInvalidHandle;
James Kuszmaul4b81d302019-12-14 20:53:14 -080038 SetMaxPeriod(0.5, status);
Brian Silverman41cdd3e2019-01-19 19:48:58 -080039 break;
40 }
41 case HAL_Encoder_k1X:
42 case HAL_Encoder_k2X: {
43 SetupCounter(digitalSourceHandleA, analogTriggerTypeA,
44 digitalSourceHandleB, analogTriggerTypeB, reverseDirection,
45 encodingType, status);
46
47 m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
48 break;
49 }
50 default:
51 *status = PARAMETER_OUT_OF_RANGE;
52 return;
53 }
54}
55
56void Encoder::SetupCounter(HAL_Handle digitalSourceHandleA,
57 HAL_AnalogTriggerType analogTriggerTypeA,
58 HAL_Handle digitalSourceHandleB,
59 HAL_AnalogTriggerType analogTriggerTypeB,
60 bool reverseDirection,
61 HAL_EncoderEncodingType encodingType,
62 int32_t* status) {
63 m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
64 m_counter =
65 HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status);
66 if (*status != 0) return;
67 HAL_SetCounterMaxPeriod(m_counter, 0.5, status);
68 if (*status != 0) return;
69 HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA,
70 status);
71 if (*status != 0) return;
72 HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB,
73 status);
74 if (*status != 0) return;
75 if (encodingType == HAL_Encoder_k1X) {
76 HAL_SetCounterUpSourceEdge(m_counter, true, false, status);
77 HAL_SetCounterAverageSize(m_counter, 1, status);
78 } else {
79 HAL_SetCounterUpSourceEdge(m_counter, true, true, status);
80 HAL_SetCounterAverageSize(m_counter, 2, status);
81 }
82 HAL_SetCounterDownSourceEdge(m_counter, reverseDirection, true, status);
83}
84
85Encoder::~Encoder() {
86 if (m_counter != HAL_kInvalidHandle) {
87 int32_t status = 0;
88 HAL_FreeCounter(m_counter, &status);
89 } else {
90 int32_t status = 0;
91 HAL_FreeFPGAEncoder(m_encoder, &status);
92 }
93}
94
95// CounterBase interface
96int32_t Encoder::Get(int32_t* status) const {
97 return static_cast<int32_t>(GetRaw(status) * DecodingScaleFactor());
98}
99
100int32_t Encoder::GetRaw(int32_t* status) const {
101 if (m_counter) {
102 return HAL_GetCounter(m_counter, status);
103 } else {
104 return HAL_GetFPGAEncoder(m_encoder, status);
105 }
106}
107
108int32_t Encoder::GetEncodingScale(int32_t* status) const {
109 return m_encodingScale;
110}
111
112void Encoder::Reset(int32_t* status) {
113 if (m_counter) {
114 HAL_ResetCounter(m_counter, status);
115 } else {
116 HAL_ResetFPGAEncoder(m_encoder, status);
117 }
118}
119
120double Encoder::GetPeriod(int32_t* status) const {
121 if (m_counter) {
122 return HAL_GetCounterPeriod(m_counter, status) / DecodingScaleFactor();
123 } else {
124 return HAL_GetFPGAEncoderPeriod(m_encoder, status);
125 }
126}
127
128void Encoder::SetMaxPeriod(double maxPeriod, int32_t* status) {
129 if (m_counter) {
130 HAL_SetCounterMaxPeriod(m_counter, maxPeriod, status);
131 } else {
132 HAL_SetFPGAEncoderMaxPeriod(m_encoder, maxPeriod, status);
133 }
134}
135
136bool Encoder::GetStopped(int32_t* status) const {
137 if (m_counter) {
138 return HAL_GetCounterStopped(m_counter, status);
139 } else {
140 return HAL_GetFPGAEncoderStopped(m_encoder, status);
141 }
142}
143
144bool Encoder::GetDirection(int32_t* status) const {
145 if (m_counter) {
146 return HAL_GetCounterDirection(m_counter, status);
147 } else {
148 return HAL_GetFPGAEncoderDirection(m_encoder, status);
149 }
150}
151
152double Encoder::GetDistance(int32_t* status) const {
153 return GetRaw(status) * DecodingScaleFactor() * m_distancePerPulse;
154}
155
156double Encoder::GetRate(int32_t* status) const {
157 return m_distancePerPulse / GetPeriod(status);
158}
159
160void Encoder::SetMinRate(double minRate, int32_t* status) {
161 SetMaxPeriod(m_distancePerPulse / minRate, status);
162}
163
164void Encoder::SetDistancePerPulse(double distancePerPulse, int32_t* status) {
165 m_distancePerPulse = distancePerPulse;
166}
167
168void Encoder::SetReverseDirection(bool reverseDirection, int32_t* status) {
169 if (m_counter) {
170 HAL_SetCounterReverseDirection(m_counter, reverseDirection, status);
171 } else {
172 HAL_SetFPGAEncoderReverseDirection(m_encoder, reverseDirection, status);
173 }
174}
175
176void Encoder::SetSamplesToAverage(int32_t samplesToAverage, int32_t* status) {
177 if (samplesToAverage < 1 || samplesToAverage > 127) {
178 *status = PARAMETER_OUT_OF_RANGE;
179 return;
180 }
181 if (m_counter) {
182 HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, status);
183 } else {
184 HAL_SetFPGAEncoderSamplesToAverage(m_encoder, samplesToAverage, status);
185 }
186}
187
188int32_t Encoder::GetSamplesToAverage(int32_t* status) const {
189 if (m_counter) {
190 return HAL_GetCounterSamplesToAverage(m_counter, status);
191 } else {
192 return HAL_GetFPGAEncoderSamplesToAverage(m_encoder, status);
193 }
194}
195
196void Encoder::SetIndexSource(HAL_Handle digitalSourceHandle,
197 HAL_AnalogTriggerType analogTriggerType,
198 HAL_EncoderIndexingType type, int32_t* status) {
199 if (m_counter) {
200 *status = HAL_COUNTER_NOT_SUPPORTED;
201 return;
202 }
203 bool activeHigh =
204 (type == HAL_kResetWhileHigh) || (type == HAL_kResetOnRisingEdge);
205 bool edgeSensitive =
206 (type == HAL_kResetOnFallingEdge) || (type == HAL_kResetOnRisingEdge);
207 HAL_SetFPGAEncoderIndexSource(m_encoder, digitalSourceHandle,
208 analogTriggerType, activeHigh, edgeSensitive,
209 status);
210}
211
212double Encoder::DecodingScaleFactor() const {
213 switch (m_encodingType) {
214 case HAL_Encoder_k1X:
215 return 1.0;
216 case HAL_Encoder_k2X:
217 return 0.5;
218 case HAL_Encoder_k4X:
219 return 0.25;
220 default:
221 return 0.0;
222 }
223}
224
225static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
226 kNumEncoders + kNumCounters,
227 HAL_HandleEnum::Encoder>* encoderHandles;
228
229namespace hal {
230namespace init {
231void InitializeEncoder() {
232 static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
233 kNumEncoders + kNumCounters,
234 HAL_HandleEnum::Encoder>
235 eH;
236 encoderHandles = &eH;
237}
238} // namespace init
239} // namespace hal
240
James Kuszmaul4b81d302019-12-14 20:53:14 -0800241namespace hal {
242bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
243 HAL_FPGAEncoderHandle* fpgaHandle,
244 HAL_CounterHandle* counterHandle) {
245 auto encoder = encoderHandles->Get(handle);
246 if (!handle) return false;
247
248 *fpgaHandle = encoder->m_encoder;
249 *counterHandle = encoder->m_counter;
250 return true;
251}
252} // namespace hal
253
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800254extern "C" {
255HAL_EncoderHandle HAL_InitializeEncoder(
256 HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
257 HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
258 HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
259 int32_t* status) {
260 hal::init::CheckInit();
261 auto encoder = std::make_shared<Encoder>(
262 digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
263 analogTriggerTypeB, reverseDirection, encodingType, status);
264 if (*status != 0) return HAL_kInvalidHandle; // return in creation error
265 auto handle = encoderHandles->Allocate(encoder);
266 if (handle == HAL_kInvalidHandle) {
267 *status = NO_AVAILABLE_RESOURCES;
268 return HAL_kInvalidHandle;
269 }
270 return handle;
271}
272
273void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
274 encoderHandles->Free(encoderHandle);
275}
276
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800277void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
278 HAL_SimDeviceHandle device) {}
279
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800280int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
281 auto encoder = encoderHandles->Get(encoderHandle);
282 if (encoder == nullptr) {
283 *status = HAL_HANDLE_ERROR;
284 return 0;
285 }
286 return encoder->Get(status);
287}
288
289int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
290 auto encoder = encoderHandles->Get(encoderHandle);
291 if (encoder == nullptr) {
292 *status = HAL_HANDLE_ERROR;
293 return 0;
294 }
295 return encoder->GetRaw(status);
296}
297
298int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
299 int32_t* status) {
300 auto encoder = encoderHandles->Get(encoderHandle);
301 if (encoder == nullptr) {
302 *status = HAL_HANDLE_ERROR;
303 return 0;
304 }
305 return encoder->GetEncodingScale(status);
306}
307
308void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
309 auto encoder = encoderHandles->Get(encoderHandle);
310 if (encoder == nullptr) {
311 *status = HAL_HANDLE_ERROR;
312 return;
313 }
314 encoder->Reset(status);
315}
316
317double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
318 auto encoder = encoderHandles->Get(encoderHandle);
319 if (encoder == nullptr) {
320 *status = HAL_HANDLE_ERROR;
321 return 0;
322 }
323 return encoder->GetPeriod(status);
324}
325
326void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
327 int32_t* status) {
328 auto encoder = encoderHandles->Get(encoderHandle);
329 if (encoder == nullptr) {
330 *status = HAL_HANDLE_ERROR;
331 return;
332 }
333 encoder->SetMaxPeriod(maxPeriod, status);
334}
335
336HAL_Bool HAL_GetEncoderStopped(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 return encoder->GetStopped(status);
344}
345
346HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
347 int32_t* status) {
348 auto encoder = encoderHandles->Get(encoderHandle);
349 if (encoder == nullptr) {
350 *status = HAL_HANDLE_ERROR;
351 return 0;
352 }
353 return encoder->GetDirection(status);
354}
355
356double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
357 int32_t* status) {
358 auto encoder = encoderHandles->Get(encoderHandle);
359 if (encoder == nullptr) {
360 *status = HAL_HANDLE_ERROR;
361 return 0;
362 }
363 return encoder->GetDistance(status);
364}
365
366double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
367 auto encoder = encoderHandles->Get(encoderHandle);
368 if (encoder == nullptr) {
369 *status = HAL_HANDLE_ERROR;
370 return 0;
371 }
372 return encoder->GetRate(status);
373}
374
375void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
376 int32_t* status) {
377 auto encoder = encoderHandles->Get(encoderHandle);
378 if (encoder == nullptr) {
379 *status = HAL_HANDLE_ERROR;
380 return;
381 }
382 encoder->SetMinRate(minRate, status);
383}
384
385void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
386 double distancePerPulse, int32_t* status) {
387 auto encoder = encoderHandles->Get(encoderHandle);
388 if (encoder == nullptr) {
389 *status = HAL_HANDLE_ERROR;
390 return;
391 }
392 encoder->SetDistancePerPulse(distancePerPulse, status);
393}
394
395void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
396 HAL_Bool reverseDirection,
397 int32_t* status) {
398 auto encoder = encoderHandles->Get(encoderHandle);
399 if (encoder == nullptr) {
400 *status = HAL_HANDLE_ERROR;
401 return;
402 }
403 encoder->SetReverseDirection(reverseDirection, status);
404}
405
406void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
407 int32_t samplesToAverage, int32_t* status) {
408 auto encoder = encoderHandles->Get(encoderHandle);
409 if (encoder == nullptr) {
410 *status = HAL_HANDLE_ERROR;
411 return;
412 }
413 encoder->SetSamplesToAverage(samplesToAverage, status);
414}
415
416int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
417 int32_t* status) {
418 auto encoder = encoderHandles->Get(encoderHandle);
419 if (encoder == nullptr) {
420 *status = HAL_HANDLE_ERROR;
421 return 0;
422 }
423 return encoder->GetSamplesToAverage(status);
424}
425
426double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
427 int32_t* status) {
428 auto encoder = encoderHandles->Get(encoderHandle);
429 if (encoder == nullptr) {
430 *status = HAL_HANDLE_ERROR;
431 return 0;
432 }
433 return encoder->DecodingScaleFactor();
434}
435
436double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
437 int32_t* status) {
438 auto encoder = encoderHandles->Get(encoderHandle);
439 if (encoder == nullptr) {
440 *status = HAL_HANDLE_ERROR;
441 return 0;
442 }
443 return encoder->GetDistancePerPulse();
444}
445
446HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
447 HAL_EncoderHandle encoderHandle, int32_t* status) {
448 auto encoder = encoderHandles->Get(encoderHandle);
449 if (encoder == nullptr) {
450 *status = HAL_HANDLE_ERROR;
451 return HAL_Encoder_k4X; // default to k4X
452 }
453 return encoder->GetEncodingType();
454}
455
456void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
457 HAL_Handle digitalSourceHandle,
458 HAL_AnalogTriggerType analogTriggerType,
459 HAL_EncoderIndexingType type, int32_t* status) {
460 auto encoder = encoderHandles->Get(encoderHandle);
461 if (encoder == nullptr) {
462 *status = HAL_HANDLE_ERROR;
463 return;
464 }
465 encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
466}
467
468int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
469 int32_t* status) {
470 auto encoder = encoderHandles->Get(encoderHandle);
471 if (encoder == nullptr) {
472 *status = HAL_HANDLE_ERROR;
473 return 0;
474 }
475 return encoder->GetFPGAIndex();
476}
477
478} // extern "C"