blob: 19f26ddd7b9f76a8ae15862c34c238d83a2c9022 [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/AnalogGyro.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <string>
Brian Silverman8fce7482020-01-05 13:18:21 -08008#include <thread>
9
Austin Schuh812d0d12021-11-04 20:16:48 -070010#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080011
12#include "AnalogInternal.h"
13#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070014#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080015#include "hal/AnalogAccumulator.h"
16#include "hal/AnalogInput.h"
17#include "hal/handles/IndexedHandleResource.h"
18
19namespace {
20
21struct AnalogGyro {
22 HAL_AnalogInputHandle handle;
23 double voltsPerDegreePerSecond;
24 double offset;
25 int32_t center;
Austin Schuh812d0d12021-11-04 20:16:48 -070026 std::string previousAllocation;
Brian Silverman8fce7482020-01-05 13:18:21 -080027};
28
29} // namespace
30
31static constexpr uint32_t kOversampleBits = 10;
32static constexpr uint32_t kAverageBits = 0;
33static constexpr double kSamplesPerSecond = 50.0;
34static constexpr double kCalibrationSampleTime = 5.0;
35static constexpr double kDefaultVoltsPerDegreePerSecond = 0.007;
36
37using namespace hal;
38
39static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
40 HAL_HandleEnum::AnalogGyro>* analogGyroHandles;
41
Austin Schuh812d0d12021-11-04 20:16:48 -070042namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080043void InitializeAnalogGyro() {
44 static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
45 HAL_HandleEnum::AnalogGyro>
46 agHandles;
47 analogGyroHandles = &agHandles;
48}
Austin Schuh812d0d12021-11-04 20:16:48 -070049} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080050
51static void Wait(double seconds) {
Austin Schuh812d0d12021-11-04 20:16:48 -070052 if (seconds < 0.0) {
53 return;
54 }
Brian Silverman8fce7482020-01-05 13:18:21 -080055 std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
56}
57
58extern "C" {
59
60HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
Austin Schuh812d0d12021-11-04 20:16:48 -070061 const char* allocationLocation,
Brian Silverman8fce7482020-01-05 13:18:21 -080062 int32_t* status) {
63 hal::init::CheckInit();
Austin Schuh812d0d12021-11-04 20:16:48 -070064 // Handle will be type checked by HAL_IsAccumulatorChannel
65 int16_t channel = getHandleIndex(analogHandle);
Brian Silverman8fce7482020-01-05 13:18:21 -080066 if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
67 if (*status == 0) {
68 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
Austin Schuh812d0d12021-11-04 20:16:48 -070069 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
70 0, kNumAccumulators, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080071 }
72 return HAL_kInvalidHandle;
73 }
74
Austin Schuh812d0d12021-11-04 20:16:48 -070075 HAL_GyroHandle handle;
76 auto gyro = analogGyroHandles->Allocate(channel, &handle, status);
Brian Silverman8fce7482020-01-05 13:18:21 -080077
Austin Schuh812d0d12021-11-04 20:16:48 -070078 if (*status != 0) {
79 if (gyro) {
80 hal::SetLastErrorPreviouslyAllocated(status, "Analog Gyro", channel,
81 gyro->previousAllocation);
82 } else {
83 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
84 0, kNumAccumulators, channel);
85 }
Brian Silverman8fce7482020-01-05 13:18:21 -080086 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
Austin Schuh812d0d12021-11-04 20:16:48 -070087 }
Brian Silverman8fce7482020-01-05 13:18:21 -080088
89 // Initialize port structure
Brian Silverman8fce7482020-01-05 13:18:21 -080090
91 gyro->handle = analogHandle;
92 gyro->voltsPerDegreePerSecond = 0;
93 gyro->offset = 0;
94 gyro->center = 0;
95
Austin Schuh812d0d12021-11-04 20:16:48 -070096 gyro->previousAllocation = allocationLocation ? allocationLocation : "";
97
Brian Silverman8fce7482020-01-05 13:18:21 -080098 return handle;
99}
100
101void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
102 auto gyro = analogGyroHandles->Get(handle);
103 if (gyro == nullptr) {
104 *status = HAL_HANDLE_ERROR;
105 return;
106 }
107
108 gyro->voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
109
110 HAL_SetAnalogAverageBits(gyro->handle, kAverageBits, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700111 if (*status != 0) {
112 return;
113 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800114 HAL_SetAnalogOversampleBits(gyro->handle, kOversampleBits, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700115 if (*status != 0) {
116 return;
117 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800118 double sampleRate =
119 kSamplesPerSecond * (1 << (kAverageBits + kOversampleBits));
120 HAL_SetAnalogSampleRate(sampleRate, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700121 if (*status != 0) {
122 return;
123 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800124 Wait(0.1);
125
126 HAL_SetAnalogGyroDeadband(handle, 0.0, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700127 if (*status != 0) {
128 return;
129 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800130}
131
132void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
133 analogGyroHandles->Free(handle);
134}
135
136void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
137 double voltsPerDegreePerSecond, double offset,
138 int32_t center, int32_t* status) {
139 auto gyro = analogGyroHandles->Get(handle);
140 if (gyro == nullptr) {
141 *status = HAL_HANDLE_ERROR;
142 return;
143 }
144
145 gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
146 gyro->offset = offset;
147 gyro->center = center;
148 HAL_SetAccumulatorCenter(gyro->handle, center, status);
149}
150
151void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
152 double voltsPerDegreePerSecond,
153 int32_t* status) {
154 auto gyro = analogGyroHandles->Get(handle);
155 if (gyro == nullptr) {
156 *status = HAL_HANDLE_ERROR;
157 return;
158 }
159
160 gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
161}
162
163void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
164 auto gyro = analogGyroHandles->Get(handle);
165 if (gyro == nullptr) {
166 *status = HAL_HANDLE_ERROR;
167 return;
168 }
169 HAL_ResetAccumulator(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700170 if (*status != 0) {
171 return;
172 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800173
174 const double sampleTime = 1.0 / HAL_GetAnalogSampleRate(status);
175 const double overSamples =
176 1 << HAL_GetAnalogOversampleBits(gyro->handle, status);
177 const double averageSamples =
178 1 << HAL_GetAnalogAverageBits(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700179 if (*status != 0) {
180 return;
181 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800182 Wait(sampleTime * overSamples * averageSamples);
183}
184
185void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
186 auto gyro = analogGyroHandles->Get(handle);
187 if (gyro == nullptr) {
188 *status = HAL_HANDLE_ERROR;
189 return;
190 }
191
192 HAL_InitAccumulator(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700193 if (*status != 0) {
194 return;
195 }
196 fmt::print("Calibrating analog gyro for {} seconds.\n",
197 kCalibrationSampleTime);
Brian Silverman8fce7482020-01-05 13:18:21 -0800198 Wait(kCalibrationSampleTime);
199
200 int64_t value;
201 int64_t count;
202 HAL_GetAccumulatorOutput(gyro->handle, &value, &count, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700203 if (*status != 0) {
204 return;
205 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800206
207 gyro->center = static_cast<int32_t>(
208 static_cast<double>(value) / static_cast<double>(count) + 0.5);
209
210 gyro->offset = static_cast<double>(value) / static_cast<double>(count) -
211 static_cast<double>(gyro->center);
212 HAL_SetAccumulatorCenter(gyro->handle, gyro->center, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700213 if (*status != 0) {
214 return;
215 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800216 HAL_ResetAnalogGyro(handle, status);
217}
218
219void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
220 int32_t* status) {
221 auto gyro = analogGyroHandles->Get(handle);
222 if (gyro == nullptr) {
223 *status = HAL_HANDLE_ERROR;
224 return;
225 }
226 int32_t deadband = static_cast<int32_t>(
227 volts * 1e9 / HAL_GetAnalogLSBWeight(gyro->handle, status) *
228 (1 << HAL_GetAnalogOversampleBits(gyro->handle, status)));
Austin Schuh812d0d12021-11-04 20:16:48 -0700229 if (*status != 0) {
230 return;
231 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800232 HAL_SetAccumulatorDeadband(gyro->handle, deadband, status);
233}
234
235double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status) {
236 auto gyro = analogGyroHandles->Get(handle);
237 if (gyro == nullptr) {
238 *status = HAL_HANDLE_ERROR;
239 return 0;
240 }
241 int64_t rawValue = 0;
242 int64_t count = 0;
243 HAL_GetAccumulatorOutput(gyro->handle, &rawValue, &count, status);
244
245 int64_t value = rawValue - static_cast<int64_t>(static_cast<double>(count) *
246 gyro->offset);
247
248 double scaledValue =
249 value * 1e-9 *
250 static_cast<double>(HAL_GetAnalogLSBWeight(gyro->handle, status)) *
251 static_cast<double>(1 << HAL_GetAnalogAverageBits(gyro->handle, status)) /
252 (HAL_GetAnalogSampleRate(status) * gyro->voltsPerDegreePerSecond);
253
254 return scaledValue;
255}
256
257double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status) {
258 auto gyro = analogGyroHandles->Get(handle);
259 if (gyro == nullptr) {
260 *status = HAL_HANDLE_ERROR;
261 return 0;
262 }
263
264 return (HAL_GetAnalogAverageValue(gyro->handle, status) -
265 (static_cast<double>(gyro->center) + gyro->offset)) *
266 1e-9 * HAL_GetAnalogLSBWeight(gyro->handle, status) /
267 ((1 << HAL_GetAnalogOversampleBits(gyro->handle, status)) *
268 gyro->voltsPerDegreePerSecond);
269}
270
271double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status) {
272 auto gyro = analogGyroHandles->Get(handle);
273 if (gyro == nullptr) {
274 *status = HAL_HANDLE_ERROR;
275 return 0;
276 }
277 return gyro->offset;
278}
279
280int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status) {
281 auto gyro = analogGyroHandles->Get(handle);
282 if (gyro == nullptr) {
283 *status = HAL_HANDLE_ERROR;
284 return 0;
285 }
286 return gyro->center;
287}
288
289} // extern "C"