blob: 6edfea3e1e0ee97e6dcf4359efa4b6ee1862c730 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/Encoder.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <fmt/format.h>
8
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include "EncoderInternal.h"
10#include "FPGAEncoder.h"
11#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070012#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080013#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(0.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;
Austin Schuh812d0d12021-11-04 20:16:48 -070052 hal::SetLastError(status, fmt::format("Encoding type {} invalid.",
53 static_cast<int>(encodingType)));
Brian Silverman8fce7482020-01-05 13:18:21 -080054 return;
55 }
56}
57
58void Encoder::SetupCounter(HAL_Handle digitalSourceHandleA,
59 HAL_AnalogTriggerType analogTriggerTypeA,
60 HAL_Handle digitalSourceHandleB,
61 HAL_AnalogTriggerType analogTriggerTypeB,
62 bool reverseDirection,
63 HAL_EncoderEncodingType encodingType,
64 int32_t* status) {
65 m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
66 m_counter =
67 HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status);
Austin Schuh812d0d12021-11-04 20:16:48 -070068 if (*status != 0) {
69 return;
70 }
Brian Silverman8fce7482020-01-05 13:18:21 -080071 HAL_SetCounterMaxPeriod(m_counter, 0.5, status);
Austin Schuh812d0d12021-11-04 20:16:48 -070072 if (*status != 0) {
73 return;
74 }
Brian Silverman8fce7482020-01-05 13:18:21 -080075 HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA,
76 status);
Austin Schuh812d0d12021-11-04 20:16:48 -070077 if (*status != 0) {
78 return;
79 }
Brian Silverman8fce7482020-01-05 13:18:21 -080080 HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB,
81 status);
Austin Schuh812d0d12021-11-04 20:16:48 -070082 if (*status != 0) {
83 return;
84 }
Brian Silverman8fce7482020-01-05 13:18:21 -080085 if (encodingType == HAL_Encoder_k1X) {
86 HAL_SetCounterUpSourceEdge(m_counter, true, false, status);
87 HAL_SetCounterAverageSize(m_counter, 1, status);
88 } else {
89 HAL_SetCounterUpSourceEdge(m_counter, true, true, status);
90 HAL_SetCounterAverageSize(m_counter, 2, status);
91 }
92 HAL_SetCounterDownSourceEdge(m_counter, reverseDirection, true, status);
93}
94
95Encoder::~Encoder() {
96 if (m_counter != HAL_kInvalidHandle) {
97 int32_t status = 0;
98 HAL_FreeCounter(m_counter, &status);
99 } else {
100 int32_t status = 0;
101 HAL_FreeFPGAEncoder(m_encoder, &status);
102 }
103}
104
105// CounterBase interface
106int32_t Encoder::Get(int32_t* status) const {
107 return static_cast<int32_t>(GetRaw(status) * DecodingScaleFactor());
108}
109
110int32_t Encoder::GetRaw(int32_t* status) const {
111 if (m_counter) {
112 return HAL_GetCounter(m_counter, status);
113 } else {
114 return HAL_GetFPGAEncoder(m_encoder, status);
115 }
116}
117
118int32_t Encoder::GetEncodingScale(int32_t* status) const {
119 return m_encodingScale;
120}
121
122void Encoder::Reset(int32_t* status) {
123 if (m_counter) {
124 HAL_ResetCounter(m_counter, status);
125 } else {
126 HAL_ResetFPGAEncoder(m_encoder, status);
127 }
128}
129
130double Encoder::GetPeriod(int32_t* status) const {
131 if (m_counter) {
132 return HAL_GetCounterPeriod(m_counter, status) / DecodingScaleFactor();
133 } else {
134 return HAL_GetFPGAEncoderPeriod(m_encoder, status);
135 }
136}
137
138void Encoder::SetMaxPeriod(double maxPeriod, int32_t* status) {
139 if (m_counter) {
140 HAL_SetCounterMaxPeriod(m_counter, maxPeriod, status);
141 } else {
142 HAL_SetFPGAEncoderMaxPeriod(m_encoder, maxPeriod, status);
143 }
144}
145
146bool Encoder::GetStopped(int32_t* status) const {
147 if (m_counter) {
148 return HAL_GetCounterStopped(m_counter, status);
149 } else {
150 return HAL_GetFPGAEncoderStopped(m_encoder, status);
151 }
152}
153
154bool Encoder::GetDirection(int32_t* status) const {
155 if (m_counter) {
156 return HAL_GetCounterDirection(m_counter, status);
157 } else {
158 return HAL_GetFPGAEncoderDirection(m_encoder, status);
159 }
160}
161
162double Encoder::GetDistance(int32_t* status) const {
163 return GetRaw(status) * DecodingScaleFactor() * m_distancePerPulse;
164}
165
166double Encoder::GetRate(int32_t* status) const {
167 return m_distancePerPulse / GetPeriod(status);
168}
169
170void Encoder::SetMinRate(double minRate, int32_t* status) {
171 SetMaxPeriod(m_distancePerPulse / minRate, status);
172}
173
174void Encoder::SetDistancePerPulse(double distancePerPulse, int32_t* status) {
175 m_distancePerPulse = distancePerPulse;
176}
177
178void Encoder::SetReverseDirection(bool reverseDirection, int32_t* status) {
179 if (m_counter) {
180 HAL_SetCounterReverseDirection(m_counter, reverseDirection, status);
181 } else {
182 HAL_SetFPGAEncoderReverseDirection(m_encoder, reverseDirection, status);
183 }
184}
185
186void Encoder::SetSamplesToAverage(int32_t samplesToAverage, int32_t* status) {
187 if (samplesToAverage < 1 || samplesToAverage > 127) {
188 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700189 hal::SetLastError(status, fmt::format("Samples to average must be between "
190 "1 and 127 inclusive. Requested {}",
191 samplesToAverage));
Brian Silverman8fce7482020-01-05 13:18:21 -0800192 return;
193 }
194 if (m_counter) {
195 HAL_SetCounterSamplesToAverage(m_counter, samplesToAverage, status);
196 } else {
197 HAL_SetFPGAEncoderSamplesToAverage(m_encoder, samplesToAverage, status);
198 }
199}
200
201int32_t Encoder::GetSamplesToAverage(int32_t* status) const {
202 if (m_counter) {
203 return HAL_GetCounterSamplesToAverage(m_counter, status);
204 } else {
205 return HAL_GetFPGAEncoderSamplesToAverage(m_encoder, status);
206 }
207}
208
209void Encoder::SetIndexSource(HAL_Handle digitalSourceHandle,
210 HAL_AnalogTriggerType analogTriggerType,
211 HAL_EncoderIndexingType type, int32_t* status) {
212 if (m_counter) {
213 *status = HAL_COUNTER_NOT_SUPPORTED;
214 return;
215 }
216 bool activeHigh =
217 (type == HAL_kResetWhileHigh) || (type == HAL_kResetOnRisingEdge);
218 bool edgeSensitive =
219 (type == HAL_kResetOnFallingEdge) || (type == HAL_kResetOnRisingEdge);
220 HAL_SetFPGAEncoderIndexSource(m_encoder, digitalSourceHandle,
221 analogTriggerType, activeHigh, edgeSensitive,
222 status);
223}
224
225double Encoder::DecodingScaleFactor() const {
226 switch (m_encodingType) {
227 case HAL_Encoder_k1X:
228 return 1.0;
229 case HAL_Encoder_k2X:
230 return 0.5;
231 case HAL_Encoder_k4X:
232 return 0.25;
233 default:
234 return 0.0;
235 }
236}
237
238static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
239 kNumEncoders + kNumCounters,
240 HAL_HandleEnum::Encoder>* encoderHandles;
241
Austin Schuh812d0d12021-11-04 20:16:48 -0700242namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -0800243void InitializeEncoder() {
244 static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
245 kNumEncoders + kNumCounters,
246 HAL_HandleEnum::Encoder>
247 eH;
248 encoderHandles = &eH;
249}
Austin Schuh812d0d12021-11-04 20:16:48 -0700250} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800251
252namespace hal {
253bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
254 HAL_FPGAEncoderHandle* fpgaHandle,
255 HAL_CounterHandle* counterHandle) {
256 auto encoder = encoderHandles->Get(handle);
Austin Schuh812d0d12021-11-04 20:16:48 -0700257 if (!encoder) {
258 return false;
259 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800260
261 *fpgaHandle = encoder->m_encoder;
262 *counterHandle = encoder->m_counter;
263 return true;
264}
265} // namespace hal
266
267extern "C" {
268HAL_EncoderHandle HAL_InitializeEncoder(
269 HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
270 HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
271 HAL_Bool reverseDirection, HAL_EncoderEncodingType encodingType,
272 int32_t* status) {
273 hal::init::CheckInit();
274 auto encoder = std::make_shared<Encoder>(
275 digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
276 analogTriggerTypeB, reverseDirection, encodingType, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700277 if (*status != 0) {
278 return HAL_kInvalidHandle; // return in creation error
279 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800280 auto handle = encoderHandles->Allocate(encoder);
281 if (handle == HAL_kInvalidHandle) {
282 *status = NO_AVAILABLE_RESOURCES;
283 return HAL_kInvalidHandle;
284 }
285 return handle;
286}
287
288void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
289 encoderHandles->Free(encoderHandle);
290}
291
292void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
293 HAL_SimDeviceHandle device) {}
294
295int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
296 auto encoder = encoderHandles->Get(encoderHandle);
297 if (encoder == nullptr) {
298 *status = HAL_HANDLE_ERROR;
299 return 0;
300 }
301 return encoder->Get(status);
302}
303
304int32_t HAL_GetEncoderRaw(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->GetRaw(status);
311}
312
313int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
314 int32_t* status) {
315 auto encoder = encoderHandles->Get(encoderHandle);
316 if (encoder == nullptr) {
317 *status = HAL_HANDLE_ERROR;
318 return 0;
319 }
320 return encoder->GetEncodingScale(status);
321}
322
323void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
324 auto encoder = encoderHandles->Get(encoderHandle);
325 if (encoder == nullptr) {
326 *status = HAL_HANDLE_ERROR;
327 return;
328 }
329 encoder->Reset(status);
330}
331
332double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
333 auto encoder = encoderHandles->Get(encoderHandle);
334 if (encoder == nullptr) {
335 *status = HAL_HANDLE_ERROR;
336 return 0;
337 }
338 return encoder->GetPeriod(status);
339}
340
341void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
342 int32_t* status) {
343 auto encoder = encoderHandles->Get(encoderHandle);
344 if (encoder == nullptr) {
345 *status = HAL_HANDLE_ERROR;
346 return;
347 }
348 encoder->SetMaxPeriod(maxPeriod, status);
349}
350
351HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
352 int32_t* status) {
353 auto encoder = encoderHandles->Get(encoderHandle);
354 if (encoder == nullptr) {
355 *status = HAL_HANDLE_ERROR;
356 return 0;
357 }
358 return encoder->GetStopped(status);
359}
360
361HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
362 int32_t* status) {
363 auto encoder = encoderHandles->Get(encoderHandle);
364 if (encoder == nullptr) {
365 *status = HAL_HANDLE_ERROR;
366 return 0;
367 }
368 return encoder->GetDirection(status);
369}
370
371double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle,
372 int32_t* status) {
373 auto encoder = encoderHandles->Get(encoderHandle);
374 if (encoder == nullptr) {
375 *status = HAL_HANDLE_ERROR;
376 return 0;
377 }
378 return encoder->GetDistance(status);
379}
380
381double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status) {
382 auto encoder = encoderHandles->Get(encoderHandle);
383 if (encoder == nullptr) {
384 *status = HAL_HANDLE_ERROR;
385 return 0;
386 }
387 return encoder->GetRate(status);
388}
389
390void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
391 int32_t* status) {
392 auto encoder = encoderHandles->Get(encoderHandle);
393 if (encoder == nullptr) {
394 *status = HAL_HANDLE_ERROR;
395 return;
396 }
397 encoder->SetMinRate(minRate, status);
398}
399
400void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
401 double distancePerPulse, int32_t* status) {
402 auto encoder = encoderHandles->Get(encoderHandle);
403 if (encoder == nullptr) {
404 *status = HAL_HANDLE_ERROR;
405 return;
406 }
407 encoder->SetDistancePerPulse(distancePerPulse, status);
408}
409
410void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
411 HAL_Bool reverseDirection,
412 int32_t* status) {
413 auto encoder = encoderHandles->Get(encoderHandle);
414 if (encoder == nullptr) {
415 *status = HAL_HANDLE_ERROR;
416 return;
417 }
418 encoder->SetReverseDirection(reverseDirection, status);
419}
420
421void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
422 int32_t samplesToAverage, int32_t* status) {
423 auto encoder = encoderHandles->Get(encoderHandle);
424 if (encoder == nullptr) {
425 *status = HAL_HANDLE_ERROR;
426 return;
427 }
428 encoder->SetSamplesToAverage(samplesToAverage, status);
429}
430
431int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
432 int32_t* status) {
433 auto encoder = encoderHandles->Get(encoderHandle);
434 if (encoder == nullptr) {
435 *status = HAL_HANDLE_ERROR;
436 return 0;
437 }
438 return encoder->GetSamplesToAverage(status);
439}
440
441double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
442 int32_t* status) {
443 auto encoder = encoderHandles->Get(encoderHandle);
444 if (encoder == nullptr) {
445 *status = HAL_HANDLE_ERROR;
446 return 0;
447 }
448 return encoder->DecodingScaleFactor();
449}
450
451double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
452 int32_t* status) {
453 auto encoder = encoderHandles->Get(encoderHandle);
454 if (encoder == nullptr) {
455 *status = HAL_HANDLE_ERROR;
456 return 0;
457 }
458 return encoder->GetDistancePerPulse();
459}
460
461HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
462 HAL_EncoderHandle encoderHandle, int32_t* status) {
463 auto encoder = encoderHandles->Get(encoderHandle);
464 if (encoder == nullptr) {
465 *status = HAL_HANDLE_ERROR;
466 return HAL_Encoder_k4X; // default to k4X
467 }
468 return encoder->GetEncodingType();
469}
470
471void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
472 HAL_Handle digitalSourceHandle,
473 HAL_AnalogTriggerType analogTriggerType,
474 HAL_EncoderIndexingType type, int32_t* status) {
475 auto encoder = encoderHandles->Get(encoderHandle);
476 if (encoder == nullptr) {
477 *status = HAL_HANDLE_ERROR;
478 return;
479 }
480 encoder->SetIndexSource(digitalSourceHandle, analogTriggerType, type, status);
481}
482
483int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
484 int32_t* status) {
485 auto encoder = encoderHandles->Get(encoderHandle);
486 if (encoder == nullptr) {
487 *status = HAL_HANDLE_ERROR;
488 return 0;
489 }
490 return encoder->GetFPGAIndex();
491}
492
493} // extern "C"