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