blob: bf3a273e896f12b29f1263689d6097b5ee17ed05 [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;
38 SetMaxPeriod(.5, status);
39 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
241extern "C" {
242HAL_EncoderHandle HAL_InitializeEncoder(
243 HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
244 HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
245 HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
246 int32_t* status) {
247 hal::init::CheckInit();
248 auto encoder = std::make_shared<Encoder>(
249 digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
250 analogTriggerTypeB, reverseDirection, encodingType, status);
251 if (*status != 0) return HAL_kInvalidHandle; // return in creation error
252 auto handle = encoderHandles->Allocate(encoder);
253 if (handle == HAL_kInvalidHandle) {
254 *status = NO_AVAILABLE_RESOURCES;
255 return HAL_kInvalidHandle;
256 }
257 return handle;
258}
259
260void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
261 encoderHandles->Free(encoderHandle);
262}
263
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800264void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
265 HAL_SimDeviceHandle device) {}
266
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800267int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
268 auto encoder = encoderHandles->Get(encoderHandle);
269 if (encoder == nullptr) {
270 *status = HAL_HANDLE_ERROR;
271 return 0;
272 }
273 return encoder->Get(status);
274}
275
276int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
277 auto encoder = encoderHandles->Get(encoderHandle);
278 if (encoder == nullptr) {
279 *status = HAL_HANDLE_ERROR;
280 return 0;
281 }
282 return encoder->GetRaw(status);
283}
284
285int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
286 int32_t* status) {
287 auto encoder = encoderHandles->Get(encoderHandle);
288 if (encoder == nullptr) {
289 *status = HAL_HANDLE_ERROR;
290 return 0;
291 }
292 return encoder->GetEncodingScale(status);
293}
294
295void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
296 auto encoder = encoderHandles->Get(encoderHandle);
297 if (encoder == nullptr) {
298 *status = HAL_HANDLE_ERROR;
299 return;
300 }
301 encoder->Reset(status);
302}
303
304double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
305 auto encoder = encoderHandles->Get(encoderHandle);
306 if (encoder == nullptr) {
307 *status = HAL_HANDLE_ERROR;
308 return 0;
309 }
310 return encoder->GetPeriod(status);
311}
312
313void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
314 int32_t* status) {
315 auto encoder = encoderHandles->Get(encoderHandle);
316 if (encoder == nullptr) {
317 *status = HAL_HANDLE_ERROR;
318 return;
319 }
320 encoder->SetMaxPeriod(maxPeriod, status);
321}
322
323HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
324 int32_t* status) {
325 auto encoder = encoderHandles->Get(encoderHandle);
326 if (encoder == nullptr) {
327 *status = HAL_HANDLE_ERROR;
328 return 0;
329 }
330 return encoder->GetStopped(status);
331}
332
333HAL_Bool HAL_GetEncoderDirection(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;
339 }
340 return encoder->GetDirection(status);
341}
342
343double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
344 int32_t* status) {
345 auto encoder = encoderHandles->Get(encoderHandle);
346 if (encoder == nullptr) {
347 *status = HAL_HANDLE_ERROR;
348 return 0;
349 }
350 return encoder->GetDistance(status);
351}
352
353double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
354 auto encoder = encoderHandles->Get(encoderHandle);
355 if (encoder == nullptr) {
356 *status = HAL_HANDLE_ERROR;
357 return 0;
358 }
359 return encoder->GetRate(status);
360}
361
362void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
363 int32_t* status) {
364 auto encoder = encoderHandles->Get(encoderHandle);
365 if (encoder == nullptr) {
366 *status = HAL_HANDLE_ERROR;
367 return;
368 }
369 encoder->SetMinRate(minRate, status);
370}
371
372void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
373 double distancePerPulse, int32_t* status) {
374 auto encoder = encoderHandles->Get(encoderHandle);
375 if (encoder == nullptr) {
376 *status = HAL_HANDLE_ERROR;
377 return;
378 }
379 encoder->SetDistancePerPulse(distancePerPulse, status);
380}
381
382void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
383 HAL_Bool reverseDirection,
384 int32_t* status) {
385 auto encoder = encoderHandles->Get(encoderHandle);
386 if (encoder == nullptr) {
387 *status = HAL_HANDLE_ERROR;
388 return;
389 }
390 encoder->SetReverseDirection(reverseDirection, status);
391}
392
393void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
394 int32_t samplesToAverage, int32_t* status) {
395 auto encoder = encoderHandles->Get(encoderHandle);
396 if (encoder == nullptr) {
397 *status = HAL_HANDLE_ERROR;
398 return;
399 }
400 encoder->SetSamplesToAverage(samplesToAverage, status);
401}
402
403int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
404 int32_t* status) {
405 auto encoder = encoderHandles->Get(encoderHandle);
406 if (encoder == nullptr) {
407 *status = HAL_HANDLE_ERROR;
408 return 0;
409 }
410 return encoder->GetSamplesToAverage(status);
411}
412
413double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
414 int32_t* status) {
415 auto encoder = encoderHandles->Get(encoderHandle);
416 if (encoder == nullptr) {
417 *status = HAL_HANDLE_ERROR;
418 return 0;
419 }
420 return encoder->DecodingScaleFactor();
421}
422
423double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
424 int32_t* status) {
425 auto encoder = encoderHandles->Get(encoderHandle);
426 if (encoder == nullptr) {
427 *status = HAL_HANDLE_ERROR;
428 return 0;
429 }
430 return encoder->GetDistancePerPulse();
431}
432
433HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
434 HAL_EncoderHandle encoderHandle, int32_t* status) {
435 auto encoder = encoderHandles->Get(encoderHandle);
436 if (encoder == nullptr) {
437 *status = HAL_HANDLE_ERROR;
438 return HAL_Encoder_k4X; // default to k4X
439 }
440 return encoder->GetEncodingType();
441}
442
443void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
444 HAL_Handle digitalSourceHandle,
445 HAL_AnalogTriggerType analogTriggerType,
446 HAL_EncoderIndexingType type, int32_t* status) {
447 auto encoder = encoderHandles->Get(encoderHandle);
448 if (encoder == nullptr) {
449 *status = HAL_HANDLE_ERROR;
450 return;
451 }
452 encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
453}
454
455int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
456 int32_t* status) {
457 auto encoder = encoderHandles->Get(encoderHandle);
458 if (encoder == nullptr) {
459 *status = HAL_HANDLE_ERROR;
460 return 0;
461 }
462 return encoder->GetFPGAIndex();
463}
464
465} // extern "C"