blob: adf70ed6cedb38310ba230b965252772432d7d86 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2016-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 "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
264int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
265 auto encoder = encoderHandles->Get(encoderHandle);
266 if (encoder == nullptr) {
267 *status = HAL_HANDLE_ERROR;
268 return 0;
269 }
270 return encoder->Get(status);
271}
272
273int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status) {
274 auto encoder = encoderHandles->Get(encoderHandle);
275 if (encoder == nullptr) {
276 *status = HAL_HANDLE_ERROR;
277 return 0;
278 }
279 return encoder->GetRaw(status);
280}
281
282int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
283 int32_t* status) {
284 auto encoder = encoderHandles->Get(encoderHandle);
285 if (encoder == nullptr) {
286 *status = HAL_HANDLE_ERROR;
287 return 0;
288 }
289 return encoder->GetEncodingScale(status);
290}
291
292void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
293 auto encoder = encoderHandles->Get(encoderHandle);
294 if (encoder == nullptr) {
295 *status = HAL_HANDLE_ERROR;
296 return;
297 }
298 encoder->Reset(status);
299}
300
301double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
302 auto encoder = encoderHandles->Get(encoderHandle);
303 if (encoder == nullptr) {
304 *status = HAL_HANDLE_ERROR;
305 return 0;
306 }
307 return encoder->GetPeriod(status);
308}
309
310void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
311 int32_t* status) {
312 auto encoder = encoderHandles->Get(encoderHandle);
313 if (encoder == nullptr) {
314 *status = HAL_HANDLE_ERROR;
315 return;
316 }
317 encoder->SetMaxPeriod(maxPeriod, status);
318}
319
320HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
321 int32_t* status) {
322 auto encoder = encoderHandles->Get(encoderHandle);
323 if (encoder == nullptr) {
324 *status = HAL_HANDLE_ERROR;
325 return 0;
326 }
327 return encoder->GetStopped(status);
328}
329
330HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
331 int32_t* status) {
332 auto encoder = encoderHandles->Get(encoderHandle);
333 if (encoder == nullptr) {
334 *status = HAL_HANDLE_ERROR;
335 return 0;
336 }
337 return encoder->GetDirection(status);
338}
339
340double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
341 int32_t* status) {
342 auto encoder = encoderHandles->Get(encoderHandle);
343 if (encoder == nullptr) {
344 *status = HAL_HANDLE_ERROR;
345 return 0;
346 }
347 return encoder->GetDistance(status);
348}
349
350double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
351 auto encoder = encoderHandles->Get(encoderHandle);
352 if (encoder == nullptr) {
353 *status = HAL_HANDLE_ERROR;
354 return 0;
355 }
356 return encoder->GetRate(status);
357}
358
359void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
360 int32_t* status) {
361 auto encoder = encoderHandles->Get(encoderHandle);
362 if (encoder == nullptr) {
363 *status = HAL_HANDLE_ERROR;
364 return;
365 }
366 encoder->SetMinRate(minRate, status);
367}
368
369void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
370 double distancePerPulse, int32_t* status) {
371 auto encoder = encoderHandles->Get(encoderHandle);
372 if (encoder == nullptr) {
373 *status = HAL_HANDLE_ERROR;
374 return;
375 }
376 encoder->SetDistancePerPulse(distancePerPulse, status);
377}
378
379void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
380 HAL_Bool reverseDirection,
381 int32_t* status) {
382 auto encoder = encoderHandles->Get(encoderHandle);
383 if (encoder == nullptr) {
384 *status = HAL_HANDLE_ERROR;
385 return;
386 }
387 encoder->SetReverseDirection(reverseDirection, status);
388}
389
390void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
391 int32_t samplesToAverage, int32_t* status) {
392 auto encoder = encoderHandles->Get(encoderHandle);
393 if (encoder == nullptr) {
394 *status = HAL_HANDLE_ERROR;
395 return;
396 }
397 encoder->SetSamplesToAverage(samplesToAverage, status);
398}
399
400int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
401 int32_t* status) {
402 auto encoder = encoderHandles->Get(encoderHandle);
403 if (encoder == nullptr) {
404 *status = HAL_HANDLE_ERROR;
405 return 0;
406 }
407 return encoder->GetSamplesToAverage(status);
408}
409
410double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
411 int32_t* status) {
412 auto encoder = encoderHandles->Get(encoderHandle);
413 if (encoder == nullptr) {
414 *status = HAL_HANDLE_ERROR;
415 return 0;
416 }
417 return encoder->DecodingScaleFactor();
418}
419
420double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
421 int32_t* status) {
422 auto encoder = encoderHandles->Get(encoderHandle);
423 if (encoder == nullptr) {
424 *status = HAL_HANDLE_ERROR;
425 return 0;
426 }
427 return encoder->GetDistancePerPulse();
428}
429
430HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
431 HAL_EncoderHandle encoderHandle, int32_t* status) {
432 auto encoder = encoderHandles->Get(encoderHandle);
433 if (encoder == nullptr) {
434 *status = HAL_HANDLE_ERROR;
435 return HAL_Encoder_k4X; // default to k4X
436 }
437 return encoder->GetEncodingType();
438}
439
440void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
441 HAL_Handle digitalSourceHandle,
442 HAL_AnalogTriggerType analogTriggerType,
443 HAL_EncoderIndexingType type, int32_t* status) {
444 auto encoder = encoderHandles->Get(encoderHandle);
445 if (encoder == nullptr) {
446 *status = HAL_HANDLE_ERROR;
447 return;
448 }
449 encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
450}
451
452int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
453 int32_t* status) {
454 auto encoder = encoderHandles->Get(encoderHandle);
455 if (encoder == nullptr) {
456 *status = HAL_HANDLE_ERROR;
457 return 0;
458 }
459 return encoder->GetFPGAIndex();
460}
461
462} // extern "C"