blob: 7f2e107b706b8436950208a557ad6a022d3a52ae [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 "FPGAEncoder.h"
9
10#include <memory>
11
12#include "DigitalInternal.h"
13#include "HALInitializer.h"
14#include "PortsInternal.h"
15#include "hal/handles/LimitedHandleResource.h"
16
17using namespace hal;
18
19namespace {
20
21struct Encoder {
22 std::unique_ptr<tEncoder> encoder;
23 uint8_t index;
24};
25
26} // namespace
27
28static constexpr double DECODING_SCALING_FACTOR = 0.25;
29
30static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
31 HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
32
33namespace hal {
34namespace init {
35void InitializeFPGAEncoder() {
36 static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
37 HAL_HandleEnum::FPGAEncoder>
38 feH;
39 fpgaEncoderHandles = &feH;
40}
41} // namespace init
42} // namespace hal
43
44extern "C" {
45
46HAL_FPGAEncoderHandle HAL_InitializeFPGAEncoder(
47 HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
48 HAL_Handle digitalSourceHandleB, HAL_AnalogTriggerType analogTriggerTypeB,
49 HAL_Bool reverseDirection, int32_t* index, int32_t* status) {
50 hal::init::CheckInit();
51 bool routingAnalogTriggerA = false;
52 uint8_t routingChannelA = 0;
53 uint8_t routingModuleA = 0;
54 bool successA = remapDigitalSource(digitalSourceHandleA, analogTriggerTypeA,
55 routingChannelA, routingModuleA,
56 routingAnalogTriggerA);
57 bool routingAnalogTriggerB = false;
58 uint8_t routingChannelB = 0;
59 uint8_t routingModuleB = 0;
60 bool successB = remapDigitalSource(digitalSourceHandleB, analogTriggerTypeB,
61 routingChannelB, routingModuleB,
62 routingAnalogTriggerB);
63
64 if (!successA || !successB) {
65 *status = HAL_HANDLE_ERROR;
66 return HAL_kInvalidHandle;
67 }
68
69 auto handle = fpgaEncoderHandles->Allocate();
70 if (handle == HAL_kInvalidHandle) { // out of resources
71 *status = NO_AVAILABLE_RESOURCES;
72 return HAL_kInvalidHandle;
73 }
74
75 auto encoder = fpgaEncoderHandles->Get(handle);
76 if (encoder == nullptr) { // will only error on thread issue
77 *status = HAL_HANDLE_ERROR;
78 return HAL_kInvalidHandle;
79 }
80
81 encoder->index = static_cast<uint8_t>(getHandleIndex(handle));
82 *index = encoder->index;
83 // TODO: if (index == ~0ul) { CloneError(quadEncoders); return; }
84 encoder->encoder.reset(tEncoder::create(encoder->index, status));
85 encoder->encoder->writeConfig_ASource_Module(routingModuleA, status);
86 encoder->encoder->writeConfig_ASource_Channel(routingChannelA, status);
87 encoder->encoder->writeConfig_ASource_AnalogTrigger(routingAnalogTriggerA,
88 status);
89 encoder->encoder->writeConfig_BSource_Module(routingModuleB, status);
90 encoder->encoder->writeConfig_BSource_Channel(routingChannelB, status);
91 encoder->encoder->writeConfig_BSource_AnalogTrigger(routingAnalogTriggerB,
92 status);
93 encoder->encoder->strobeReset(status);
94 encoder->encoder->writeConfig_Reverse(reverseDirection, status);
95 encoder->encoder->writeTimerConfig_AverageSize(4, status);
96
97 return handle;
98}
99
100void HAL_FreeFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
101 int32_t* status) {
102 fpgaEncoderHandles->Free(fpgaEncoderHandle);
103}
104
105void HAL_ResetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
106 int32_t* status) {
107 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
108 if (encoder == nullptr) {
109 *status = HAL_HANDLE_ERROR;
110 return;
111 }
112 encoder->encoder->strobeReset(status);
113}
114
115int32_t HAL_GetFPGAEncoder(HAL_FPGAEncoderHandle fpgaEncoderHandle,
116 int32_t* status) {
117 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
118 if (encoder == nullptr) {
119 *status = HAL_HANDLE_ERROR;
120 return 0;
121 }
122 return encoder->encoder->readOutput_Value(status);
123}
124
125double HAL_GetFPGAEncoderPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
126 int32_t* status) {
127 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
128 if (encoder == nullptr) {
129 *status = HAL_HANDLE_ERROR;
130 return 0.0;
131 }
132 tEncoder::tTimerOutput output = encoder->encoder->readTimerOutput(status);
133 double value;
134 if (output.Stalled) {
135 // Return infinity
136 double zero = 0.0;
137 value = 1.0 / zero;
138 } else {
139 // output.Period is a fixed point number that counts by 2 (24 bits, 25
140 // integer bits)
141 value = static_cast<double>(output.Period << 1) /
142 static_cast<double>(output.Count);
143 }
144 double measuredPeriod = value * 2.5e-8;
145 return measuredPeriod / DECODING_SCALING_FACTOR;
146}
147
148void HAL_SetFPGAEncoderMaxPeriod(HAL_FPGAEncoderHandle fpgaEncoderHandle,
149 double maxPeriod, int32_t* status) {
150 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
151 if (encoder == nullptr) {
152 *status = HAL_HANDLE_ERROR;
153 return;
154 }
155 encoder->encoder->writeTimerConfig_StallPeriod(
156 static_cast<uint32_t>(maxPeriod * 4.0e8 * DECODING_SCALING_FACTOR),
157 status);
158}
159
160HAL_Bool HAL_GetFPGAEncoderStopped(HAL_FPGAEncoderHandle fpgaEncoderHandle,
161 int32_t* status) {
162 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
163 if (encoder == nullptr) {
164 *status = HAL_HANDLE_ERROR;
165 return false;
166 }
167 return encoder->encoder->readTimerOutput_Stalled(status) != 0;
168}
169
170HAL_Bool HAL_GetFPGAEncoderDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
171 int32_t* status) {
172 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
173 if (encoder == nullptr) {
174 *status = HAL_HANDLE_ERROR;
175 return false;
176 }
177 return encoder->encoder->readOutput_Direction(status);
178}
179
180void HAL_SetFPGAEncoderReverseDirection(HAL_FPGAEncoderHandle fpgaEncoderHandle,
181 HAL_Bool reverseDirection,
182 int32_t* status) {
183 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
184 if (encoder == nullptr) {
185 *status = HAL_HANDLE_ERROR;
186 return;
187 }
188 encoder->encoder->writeConfig_Reverse(reverseDirection, status);
189}
190
191void HAL_SetFPGAEncoderSamplesToAverage(HAL_FPGAEncoderHandle fpgaEncoderHandle,
192 int32_t samplesToAverage,
193 int32_t* status) {
194 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
195 if (encoder == nullptr) {
196 *status = HAL_HANDLE_ERROR;
197 return;
198 }
199 if (samplesToAverage < 1 || samplesToAverage > 127) {
200 *status = PARAMETER_OUT_OF_RANGE;
201 }
202 encoder->encoder->writeTimerConfig_AverageSize(samplesToAverage, status);
203}
204
205int32_t HAL_GetFPGAEncoderSamplesToAverage(
206 HAL_FPGAEncoderHandle fpgaEncoderHandle, int32_t* status) {
207 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
208 if (encoder == nullptr) {
209 *status = HAL_HANDLE_ERROR;
210 return 0;
211 }
212 return encoder->encoder->readTimerConfig_AverageSize(status);
213}
214
215void HAL_SetFPGAEncoderIndexSource(HAL_FPGAEncoderHandle fpgaEncoderHandle,
216 HAL_Handle digitalSourceHandle,
217 HAL_AnalogTriggerType analogTriggerType,
218 HAL_Bool activeHigh, HAL_Bool edgeSensitive,
219 int32_t* status) {
220 auto encoder = fpgaEncoderHandles->Get(fpgaEncoderHandle);
221 if (encoder == nullptr) {
222 *status = HAL_HANDLE_ERROR;
223 return;
224 }
225
226 bool routingAnalogTrigger = false;
227 uint8_t routingChannel = 0;
228 uint8_t routingModule = 0;
229 bool success =
230 remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
231 routingModule, routingAnalogTrigger);
232 if (!success) {
233 *status = HAL_HANDLE_ERROR;
234 return;
235 }
236
237 encoder->encoder->writeConfig_IndexSource_Channel(routingChannel, status);
238 encoder->encoder->writeConfig_IndexSource_Module(routingModule, status);
239 encoder->encoder->writeConfig_IndexSource_AnalogTrigger(routingAnalogTrigger,
240 status);
241 encoder->encoder->writeConfig_IndexActiveHigh(activeHigh, status);
242 encoder->encoder->writeConfig_IndexEdgeSensitive(edgeSensitive, status);
243}
244
245} // extern "C"