blob: 698769fede7c691522c127f0e38e2b5606702bee [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/PWM.h"
6
7#include "ConstantsInternal.h"
8#include "DigitalInternal.h"
9#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070010#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080011#include "PortsInternal.h"
12#include "hal/handles/HandlesInternal.h"
13#include "mockdata/PWMDataInternal.h"
14
15using namespace hal;
16
Austin Schuh812d0d12021-11-04 20:16:48 -070017namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080018void InitializePWM() {}
Austin Schuh812d0d12021-11-04 20:16:48 -070019} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080020
21extern "C" {
22
23HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
Austin Schuh812d0d12021-11-04 20:16:48 -070024 const char* allocationLocation,
Brian Silverman8fce7482020-01-05 13:18:21 -080025 int32_t* status) {
26 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -080027
28 int16_t channel = getPortHandleChannel(portHandle);
29 if (channel == InvalidHandleIndex) {
Austin Schuh812d0d12021-11-04 20:16:48 -070030 *status = RESOURCE_OUT_OF_RANGE;
31 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
32 kNumPWMChannels, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080033 return HAL_kInvalidHandle;
34 }
35
36 uint8_t origChannel = static_cast<uint8_t>(channel);
37
38 if (origChannel < kNumPWMHeaders) {
39 channel += kNumDigitalChannels; // remap Headers to end of allocations
40 } else {
41 channel = remapMXPPWMChannel(channel) + 10; // remap MXP to proper channel
42 }
43
Austin Schuh812d0d12021-11-04 20:16:48 -070044 HAL_DigitalHandle handle;
Brian Silverman8fce7482020-01-05 13:18:21 -080045
Austin Schuh812d0d12021-11-04 20:16:48 -070046 auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM,
47 &handle, status);
48
49 if (*status != 0) {
50 if (port) {
51 hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
52 port->previousAllocation);
53 } else {
54 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
55 kNumPWMChannels, channel);
56 }
Brian Silverman8fce7482020-01-05 13:18:21 -080057 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
Brian Silverman8fce7482020-01-05 13:18:21 -080058 }
59
60 port->channel = origChannel;
61
62 SimPWMData[origChannel].initialized = true;
63
64 // Defaults to allow an always valid config.
65 HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status);
66
Austin Schuh812d0d12021-11-04 20:16:48 -070067 port->previousAllocation = allocationLocation ? allocationLocation : "";
68
Brian Silverman8fce7482020-01-05 13:18:21 -080069 return handle;
70}
71void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
72 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
73 if (port == nullptr) {
74 *status = HAL_HANDLE_ERROR;
75 return;
76 }
77
78 SimPWMData[port->channel].initialized = false;
79
80 digitalChannelHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
81}
82
83HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
84 return channel < kNumPWMChannels && channel >= 0;
85}
86
87void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double max,
88 double deadbandMax, double center, double deadbandMin,
89 double min, int32_t* status) {
90 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
91 if (port == nullptr) {
92 *status = HAL_HANDLE_ERROR;
93 return;
94 }
95
96 // calculate the loop time in milliseconds
97 double loopTime =
98 HAL_GetPWMLoopTiming(status) / (kSystemClockTicksPerMicrosecond * 1e3);
Austin Schuh812d0d12021-11-04 20:16:48 -070099 if (*status != 0) {
100 return;
101 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800102
103 int32_t maxPwm = static_cast<int32_t>((max - kDefaultPwmCenter) / loopTime +
104 kDefaultPwmStepsDown - 1);
105 int32_t deadbandMaxPwm = static_cast<int32_t>(
106 (deadbandMax - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
107 int32_t centerPwm = static_cast<int32_t>(
108 (center - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
109 int32_t deadbandMinPwm = static_cast<int32_t>(
110 (deadbandMin - kDefaultPwmCenter) / loopTime + kDefaultPwmStepsDown - 1);
111 int32_t minPwm = static_cast<int32_t>((min - kDefaultPwmCenter) / loopTime +
112 kDefaultPwmStepsDown - 1);
113
114 port->maxPwm = maxPwm;
115 port->deadbandMaxPwm = deadbandMaxPwm;
116 port->deadbandMinPwm = deadbandMinPwm;
117 port->centerPwm = centerPwm;
118 port->minPwm = minPwm;
119 port->configSet = true;
120}
121
122void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
123 int32_t deadbandMaxPwm, int32_t centerPwm,
124 int32_t deadbandMinPwm, int32_t minPwm,
125 int32_t* status) {
126 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
127 if (port == nullptr) {
128 *status = HAL_HANDLE_ERROR;
129 return;
130 }
131
132 port->maxPwm = maxPwm;
133 port->deadbandMaxPwm = deadbandMaxPwm;
134 port->deadbandMinPwm = deadbandMinPwm;
135 port->centerPwm = centerPwm;
136 port->minPwm = minPwm;
137}
138
139void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
140 int32_t* deadbandMaxPwm, int32_t* centerPwm,
141 int32_t* deadbandMinPwm, int32_t* minPwm,
142 int32_t* status) {
143 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
144 if (port == nullptr) {
145 *status = HAL_HANDLE_ERROR;
146 return;
147 }
148 *maxPwm = port->maxPwm;
149 *deadbandMaxPwm = port->deadbandMaxPwm;
150 *deadbandMinPwm = port->deadbandMinPwm;
151 *centerPwm = port->centerPwm;
152 *minPwm = port->minPwm;
153}
154
155void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
156 HAL_Bool eliminateDeadband, int32_t* status) {
157 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
158 if (port == nullptr) {
159 *status = HAL_HANDLE_ERROR;
160 return;
161 }
162 port->eliminateDeadband = eliminateDeadband;
163}
164
165HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
166 int32_t* status) {
167 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
168 if (port == nullptr) {
169 *status = HAL_HANDLE_ERROR;
170 return false;
171 }
172 return port->eliminateDeadband;
173}
174
175void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
176 int32_t* status) {
177 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
178 if (port == nullptr) {
179 *status = HAL_HANDLE_ERROR;
180 return;
181 }
182
183 SimPWMData[port->channel].rawValue = value;
184}
185
186void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
187 int32_t* status) {
188 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
189 if (port == nullptr) {
190 *status = HAL_HANDLE_ERROR;
191 return;
192 }
193 if (!port->configSet) {
194 *status = INCOMPATIBLE_STATE;
195 return;
196 }
197
198 if (speed < -1.0) {
199 speed = -1.0;
200 } else if (speed > 1.0) {
201 speed = 1.0;
202 }
203
204 SimPWMData[port->channel].speed = speed;
205}
206
207void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
208 int32_t* status) {
209 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
210 if (port == nullptr) {
211 *status = HAL_HANDLE_ERROR;
212 return;
213 }
214 if (!port->configSet) {
215 *status = INCOMPATIBLE_STATE;
216 return;
217 }
218
219 if (pos < 0.0) {
220 pos = 0.0;
221 } else if (pos > 1.0) {
222 pos = 1.0;
223 }
224
225 SimPWMData[port->channel].position = pos;
226}
227
228void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
229 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
230 if (port == nullptr) {
231 *status = HAL_HANDLE_ERROR;
232 return;
233 }
234 SimPWMData[port->channel].rawValue = 0;
235 SimPWMData[port->channel].position = 0;
236 SimPWMData[port->channel].speed = 0;
237}
238
239int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
240 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
241 if (port == nullptr) {
242 *status = HAL_HANDLE_ERROR;
243 return 0;
244 }
245
246 return SimPWMData[port->channel].rawValue;
247}
248
249double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
250 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
251 if (port == nullptr) {
252 *status = HAL_HANDLE_ERROR;
253 return 0;
254 }
255 if (!port->configSet) {
256 *status = INCOMPATIBLE_STATE;
257 return 0;
258 }
259
260 double speed = SimPWMData[port->channel].speed;
Austin Schuh812d0d12021-11-04 20:16:48 -0700261 if (speed > 1) {
262 speed = 1;
263 }
264 if (speed < -1) {
265 speed = -1;
266 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800267 return speed;
268}
269
270double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
271 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
272 if (port == nullptr) {
273 *status = HAL_HANDLE_ERROR;
274 return 0;
275 }
276 if (!port->configSet) {
277 *status = INCOMPATIBLE_STATE;
278 return 0;
279 }
280
281 double position = SimPWMData[port->channel].position;
Austin Schuh812d0d12021-11-04 20:16:48 -0700282 if (position > 1) {
283 position = 1;
284 }
285 if (position < 0) {
286 position = 0;
287 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800288 return position;
289}
290
291void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
292 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
293 if (port == nullptr) {
294 *status = HAL_HANDLE_ERROR;
295 return;
296 }
297
298 SimPWMData[port->channel].zeroLatch = true;
299 SimPWMData[port->channel].zeroLatch = false;
300}
301
302void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
303 int32_t* status) {
304 auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
305 if (port == nullptr) {
306 *status = HAL_HANDLE_ERROR;
307 return;
308 }
309
310 SimPWMData[port->channel].periodScale = squelchMask;
311}
312
Austin Schuh812d0d12021-11-04 20:16:48 -0700313int32_t HAL_GetPWMLoopTiming(int32_t* status) {
314 return kExpectedLoopTiming;
315}
Brian Silverman8fce7482020-01-05 13:18:21 -0800316
Austin Schuh812d0d12021-11-04 20:16:48 -0700317uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
318 return 0;
319}
Brian Silverman8fce7482020-01-05 13:18:21 -0800320} // extern "C"