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