blob: 1751ac03253e4f128953caed0d9fe540196607a1 [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
James Kuszmaulb13e13f2023-11-22 20:44:04 -08007#include <cmath>
Austin Schuh812d0d12021-11-04 20:16:48 -07008#include <string>
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include <thread>
10
Austin Schuh812d0d12021-11-04 20:16:48 -070011#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080012
13#include "AnalogInternal.h"
14#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070015#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080016#include "hal/AnalogAccumulator.h"
17#include "hal/AnalogInput.h"
18#include "hal/handles/IndexedHandleResource.h"
19
20namespace {
21
22struct AnalogGyro {
23 HAL_AnalogInputHandle handle;
24 double voltsPerDegreePerSecond;
25 double offset;
26 int32_t center;
Austin Schuh812d0d12021-11-04 20:16:48 -070027 std::string previousAllocation;
Brian Silverman8fce7482020-01-05 13:18:21 -080028};
29
30} // namespace
31
32static constexpr uint32_t kOversampleBits = 10;
33static constexpr uint32_t kAverageBits = 0;
34static constexpr double kSamplesPerSecond = 50.0;
35static constexpr double kCalibrationSampleTime = 5.0;
36static constexpr double kDefaultVoltsPerDegreePerSecond = 0.007;
37
38using namespace hal;
39
40static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
41 HAL_HandleEnum::AnalogGyro>* analogGyroHandles;
42
Austin Schuh812d0d12021-11-04 20:16:48 -070043namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080044void InitializeAnalogGyro() {
45 static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
46 HAL_HandleEnum::AnalogGyro>
47 agHandles;
48 analogGyroHandles = &agHandles;
49}
Austin Schuh812d0d12021-11-04 20:16:48 -070050} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080051
52static void Wait(double seconds) {
Austin Schuh812d0d12021-11-04 20:16:48 -070053 if (seconds < 0.0) {
54 return;
55 }
Brian Silverman8fce7482020-01-05 13:18:21 -080056 std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
57}
58
59extern "C" {
60
61HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
Austin Schuh812d0d12021-11-04 20:16:48 -070062 const char* allocationLocation,
Brian Silverman8fce7482020-01-05 13:18:21 -080063 int32_t* status) {
64 hal::init::CheckInit();
Austin Schuh812d0d12021-11-04 20:16:48 -070065 // Handle will be type checked by HAL_IsAccumulatorChannel
66 int16_t channel = getHandleIndex(analogHandle);
Brian Silverman8fce7482020-01-05 13:18:21 -080067 if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
68 if (*status == 0) {
69 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
Austin Schuh812d0d12021-11-04 20:16:48 -070070 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
71 0, kNumAccumulators, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080072 }
73 return HAL_kInvalidHandle;
74 }
75
Austin Schuh812d0d12021-11-04 20:16:48 -070076 HAL_GyroHandle handle;
77 auto gyro = analogGyroHandles->Allocate(channel, &handle, status);
Brian Silverman8fce7482020-01-05 13:18:21 -080078
Austin Schuh812d0d12021-11-04 20:16:48 -070079 if (*status != 0) {
80 if (gyro) {
81 hal::SetLastErrorPreviouslyAllocated(status, "Analog Gyro", channel,
82 gyro->previousAllocation);
83 } else {
84 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
85 0, kNumAccumulators, channel);
86 }
Brian Silverman8fce7482020-01-05 13:18:21 -080087 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
Austin Schuh812d0d12021-11-04 20:16:48 -070088 }
Brian Silverman8fce7482020-01-05 13:18:21 -080089
90 // Initialize port structure
Brian Silverman8fce7482020-01-05 13:18:21 -080091
92 gyro->handle = analogHandle;
93 gyro->voltsPerDegreePerSecond = 0;
94 gyro->offset = 0;
95 gyro->center = 0;
96
Austin Schuh812d0d12021-11-04 20:16:48 -070097 gyro->previousAllocation = allocationLocation ? allocationLocation : "";
98
Brian Silverman8fce7482020-01-05 13:18:21 -080099 return handle;
100}
101
102void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
103 auto gyro = analogGyroHandles->Get(handle);
104 if (gyro == nullptr) {
105 *status = HAL_HANDLE_ERROR;
106 return;
107 }
108
109 gyro->voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
110
111 HAL_SetAnalogAverageBits(gyro->handle, kAverageBits, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700112 if (*status != 0) {
113 return;
114 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800115 HAL_SetAnalogOversampleBits(gyro->handle, kOversampleBits, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700116 if (*status != 0) {
117 return;
118 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800119 double sampleRate =
120 kSamplesPerSecond * (1 << (kAverageBits + kOversampleBits));
121 HAL_SetAnalogSampleRate(sampleRate, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700122 if (*status != 0) {
123 return;
124 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800125 Wait(0.1);
126
127 HAL_SetAnalogGyroDeadband(handle, 0.0, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700128 if (*status != 0) {
129 return;
130 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800131}
132
133void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
134 analogGyroHandles->Free(handle);
135}
136
137void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
138 double voltsPerDegreePerSecond, double offset,
139 int32_t center, int32_t* status) {
140 auto gyro = analogGyroHandles->Get(handle);
141 if (gyro == nullptr) {
142 *status = HAL_HANDLE_ERROR;
143 return;
144 }
145
146 gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
147 gyro->offset = offset;
148 gyro->center = center;
149 HAL_SetAccumulatorCenter(gyro->handle, center, status);
150}
151
152void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
153 double voltsPerDegreePerSecond,
154 int32_t* status) {
155 auto gyro = analogGyroHandles->Get(handle);
156 if (gyro == nullptr) {
157 *status = HAL_HANDLE_ERROR;
158 return;
159 }
160
161 gyro->voltsPerDegreePerSecond = voltsPerDegreePerSecond;
162}
163
164void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
165 auto gyro = analogGyroHandles->Get(handle);
166 if (gyro == nullptr) {
167 *status = HAL_HANDLE_ERROR;
168 return;
169 }
170 HAL_ResetAccumulator(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700171 if (*status != 0) {
172 return;
173 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800174
175 const double sampleTime = 1.0 / HAL_GetAnalogSampleRate(status);
176 const double overSamples =
177 1 << HAL_GetAnalogOversampleBits(gyro->handle, status);
178 const double averageSamples =
179 1 << HAL_GetAnalogAverageBits(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700180 if (*status != 0) {
181 return;
182 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800183 Wait(sampleTime * overSamples * averageSamples);
184}
185
186void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
187 auto gyro = analogGyroHandles->Get(handle);
188 if (gyro == nullptr) {
189 *status = HAL_HANDLE_ERROR;
190 return;
191 }
192
193 HAL_InitAccumulator(gyro->handle, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700194 if (*status != 0) {
195 return;
196 }
197 fmt::print("Calibrating analog gyro for {} seconds.\n",
198 kCalibrationSampleTime);
Brian Silverman8fce7482020-01-05 13:18:21 -0800199 Wait(kCalibrationSampleTime);
200
201 int64_t value;
202 int64_t count;
203 HAL_GetAccumulatorOutput(gyro->handle, &value, &count, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700204 if (*status != 0) {
205 return;
206 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800207
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800208 gyro->center =
209 std::round(static_cast<double>(value) / static_cast<double>(count));
Brian Silverman8fce7482020-01-05 13:18:21 -0800210
211 gyro->offset = static_cast<double>(value) / static_cast<double>(count) -
212 static_cast<double>(gyro->center);
213 HAL_SetAccumulatorCenter(gyro->handle, gyro->center, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700214 if (*status != 0) {
215 return;
216 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800217 HAL_ResetAnalogGyro(handle, status);
218}
219
220void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
221 int32_t* status) {
222 auto gyro = analogGyroHandles->Get(handle);
223 if (gyro == nullptr) {
224 *status = HAL_HANDLE_ERROR;
225 return;
226 }
227 int32_t deadband = static_cast<int32_t>(
228 volts * 1e9 / HAL_GetAnalogLSBWeight(gyro->handle, status) *
229 (1 << HAL_GetAnalogOversampleBits(gyro->handle, status)));
Austin Schuh812d0d12021-11-04 20:16:48 -0700230 if (*status != 0) {
231 return;
232 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800233 HAL_SetAccumulatorDeadband(gyro->handle, deadband, status);
234}
235
236double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status) {
237 auto gyro = analogGyroHandles->Get(handle);
238 if (gyro == nullptr) {
239 *status = HAL_HANDLE_ERROR;
240 return 0;
241 }
242 int64_t rawValue = 0;
243 int64_t count = 0;
244 HAL_GetAccumulatorOutput(gyro->handle, &rawValue, &count, status);
245
246 int64_t value = rawValue - static_cast<int64_t>(static_cast<double>(count) *
247 gyro->offset);
248
249 double scaledValue =
250 value * 1e-9 *
251 static_cast<double>(HAL_GetAnalogLSBWeight(gyro->handle, status)) *
252 static_cast<double>(1 << HAL_GetAnalogAverageBits(gyro->handle, status)) /
253 (HAL_GetAnalogSampleRate(status) * gyro->voltsPerDegreePerSecond);
254
255 return scaledValue;
256}
257
258double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status) {
259 auto gyro = analogGyroHandles->Get(handle);
260 if (gyro == nullptr) {
261 *status = HAL_HANDLE_ERROR;
262 return 0;
263 }
264
265 return (HAL_GetAnalogAverageValue(gyro->handle, status) -
266 (static_cast<double>(gyro->center) + gyro->offset)) *
267 1e-9 * HAL_GetAnalogLSBWeight(gyro->handle, status) /
268 ((1 << HAL_GetAnalogOversampleBits(gyro->handle, status)) *
269 gyro->voltsPerDegreePerSecond);
270}
271
272double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status) {
273 auto gyro = analogGyroHandles->Get(handle);
274 if (gyro == nullptr) {
275 *status = HAL_HANDLE_ERROR;
276 return 0;
277 }
278 return gyro->offset;
279}
280
281int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status) {
282 auto gyro = analogGyroHandles->Get(handle);
283 if (gyro == nullptr) {
284 *status = HAL_HANDLE_ERROR;
285 return 0;
286 }
287 return gyro->center;
288}
289
290} // extern "C"