blob: 3c42bc40c5afbfe2093387c4145dd124b34a7b45 [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. 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
Austin Schuhf6b94632019-02-02 22:11:27 -08008#include "hal/PWM.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -08009
10#include <sstream>
11
Austin Schuh9950f682021-11-06 15:27:58 -070012#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070013
14#include "frc971/wpilib/ahal/PWM.h"
15#include "frc971/wpilib/ahal/WPIErrors.h"
Austin Schuhf6b94632019-02-02 22:11:27 -080016#include "hal/HAL.h"
17#include "hal/Ports.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080018
19using namespace frc;
20
Parker Schuhd3b7a8872018-02-19 16:42:27 -080021/**
22 * Allocate a PWM given a channel number.
23 *
24 * Checks channel value range and allocates the appropriate channel.
25 * The allocation is only done to help users ensure that they don't double
26 * assign channels.
27 *
28 * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the
29 * MXP port
30 */
31PWM::PWM(int channel) {
32 if (!CheckPWMChannel(channel)) {
33 fprintf(stderr, "Channel Index out of range: PWM Channel %d\n", channel);
34 exit(-1);
35 return;
36 }
37
38 int32_t status = 0;
Austin Schuh9950f682021-11-06 15:27:58 -070039 m_handle = HAL_InitializePWMPort(HAL_GetPort(channel), nullptr, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080040 if (status != 0) {
41 // wpi_setErrorWithContextRange(status, 0, HAL_GetNumPWMChannels(),
42 // channel,
43 // HAL_GetErrorMessage(status));
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080044 HAL_CHECK_STATUS(status) << ": Channel " << channel;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080045 m_channel = std::numeric_limits<int>::max();
46 m_handle = HAL_kInvalidHandle;
47 return;
48 }
49
50 m_channel = channel;
51
52 HAL_SetPWMDisabled(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080053 HAL_CHECK_STATUS(status) << ": Channel " << channel;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080054 status = 0;
55 HAL_SetPWMEliminateDeadband(m_handle, false, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080056 HAL_CHECK_STATUS(status) << ": Channel " << channel;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080057
58 HAL_Report(HALUsageReporting::kResourceType_PWM, channel);
59}
60
61/**
62 * Free the PWM channel.
63 *
64 * Free the resource associated with the PWM channel and set the value to 0.
65 */
66PWM::~PWM() {
67 int32_t status = 0;
68
69 HAL_SetPWMDisabled(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080070 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080071
72 HAL_FreePWMPort(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080073 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080074}
75
76/**
77 * Optionally eliminate the deadband from a speed controller.
78 *
79 * @param eliminateDeadband If true, set the motor curve on the Jaguar to
80 * eliminate the deadband in the middle of the range.
81 * Otherwise, keep the full range without modifying
82 * any values.
83 */
84void PWM::EnableDeadbandElimination(bool eliminateDeadband) {
85 int32_t status = 0;
86 HAL_SetPWMEliminateDeadband(m_handle, eliminateDeadband, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -080087 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080088}
89
90/**
91 * Set the bounds on the PWM pulse widths.
92 *
93 * This sets the bounds on the PWM values for a particular type of controller.
94 * The values determine the upper and lower speeds as well as the deadband
95 * bracket.
96 *
97 * @param max The max PWM pulse width in ms
98 * @param deadbandMax The high end of the deadband range pulse width in ms
99 * @param center The center (off) pulse width in ms
100 * @param deadbandMin The low end of the deadband pulse width in ms
101 * @param min The minimum pulse width in ms
102 */
103void PWM::SetBounds(double max, double deadbandMax, double center,
104 double deadbandMin, double min) {
105 int32_t status = 0;
106 HAL_SetPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min,
107 &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800108 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800109}
110
111/**
112 * Set the bounds on the PWM values.
113 *
114 * This sets the bounds on the PWM values for a particular each type of
115 * controller. The values determine the upper and lower speeds as well as the
116 * deadband bracket.
117 *
118 * @param max The Minimum pwm value
119 * @param deadbandMax The high end of the deadband range
120 * @param center The center speed (off)
121 * @param deadbandMin The low end of the deadband range
122 * @param min The minimum pwm value
123 */
124void PWM::SetRawBounds(int max, int deadbandMax, int center, int deadbandMin,
125 int min) {
126 int32_t status = 0;
127 HAL_SetPWMConfigRaw(m_handle, max, deadbandMax, center, deadbandMin, min,
128 &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800129 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800130}
131
132/**
133 * Get the bounds on the PWM values.
134 *
135 * This Gets the bounds on the PWM values for a particular each type of
136 * controller. The values determine the upper and lower speeds as well as the
137 * deadband bracket.
138 *
139 * @param max The Minimum pwm value
140 * @param deadbandMax The high end of the deadband range
141 * @param center The center speed (off)
142 * @param deadbandMin The low end of the deadband range
143 * @param min The minimum pwm value
144 */
145void PWM::GetRawBounds(int *max, int *deadbandMax, int *center,
146 int *deadbandMin, int *min) {
147 int32_t status = 0;
148 HAL_GetPWMConfigRaw(m_handle, max, deadbandMax, center, deadbandMin, min,
149 &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800150 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800151}
152
153/**
154 * Set the PWM value based on a position.
155 *
156 * This is intended to be used by servos.
157 *
158 * @pre SetMaxPositivePwm() called.
159 * @pre SetMinNegativePwm() called.
160 *
161 * @param pos The position to set the servo between 0.0 and 1.0.
162 */
163void PWM::SetPosition(double pos) {
164 int32_t status = 0;
165 HAL_SetPWMPosition(m_handle, pos, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800166 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800167}
168
169/**
170 * Get the PWM value in terms of a position.
171 *
172 * This is intended to be used by servos.
173 *
174 * @pre SetMaxPositivePwm() called.
175 * @pre SetMinNegativePwm() called.
176 *
177 * @return The position the servo is set to between 0.0 and 1.0.
178 */
179double PWM::GetPosition() const {
180 int32_t status = 0;
181 double position = HAL_GetPWMPosition(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800182 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800183 return position;
184}
185
186/**
187 * Set the PWM value based on a speed.
188 *
189 * This is intended to be used by speed controllers.
190 *
191 * @pre SetMaxPositivePwm() called.
192 * @pre SetMinPositivePwm() called.
193 * @pre SetCenterPwm() called.
194 * @pre SetMaxNegativePwm() called.
195 * @pre SetMinNegativePwm() called.
196 *
197 * @param speed The speed to set the speed controller between -1.0 and 1.0.
198 */
199void PWM::SetSpeed(double speed) {
200 int32_t status = 0;
201 HAL_SetPWMSpeed(m_handle, speed, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800202 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800203}
204
205/**
206 * Get the PWM value in terms of speed.
207 *
208 * This is intended to be used by speed controllers.
209 *
210 * @pre SetMaxPositivePwm() called.
211 * @pre SetMinPositivePwm() called.
212 * @pre SetMaxNegativePwm() called.
213 * @pre SetMinNegativePwm() called.
214 *
215 * @return The most recently set speed between -1.0 and 1.0.
216 */
217double PWM::GetSpeed() const {
218 int32_t status = 0;
219 double speed = HAL_GetPWMSpeed(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800220 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800221 return speed;
222}
223
224/**
225 * Set the PWM value directly to the hardware.
226 *
227 * Write a raw value to a PWM channel.
228 *
229 * @param value Raw PWM value.
230 */
231void PWM::SetRaw(uint16_t value) {
232 int32_t status = 0;
233 HAL_SetPWMRaw(m_handle, value, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800234 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800235}
236
237/**
238 * Get the PWM value directly from the hardware.
239 *
240 * Read a raw value from a PWM channel.
241 *
242 * @return Raw PWM control value.
243 */
244uint16_t PWM::GetRaw() const {
245 int32_t status = 0;
246 uint16_t value = HAL_GetPWMRaw(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800247 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800248
249 return value;
250}
251
252/**
253 * Slow down the PWM signal for old devices.
254 *
255 * @param mult The period multiplier to apply to this channel
256 */
257void PWM::SetPeriodMultiplier(PeriodMultiplier mult) {
258 int32_t status = 0;
259
260 switch (mult) {
261 case kPeriodMultiplier_4X:
262 HAL_SetPWMPeriodScale(m_handle, 3,
263 &status); // Squelch 3 out of 4 outputs
264 break;
265 case kPeriodMultiplier_2X:
266 HAL_SetPWMPeriodScale(m_handle, 1,
267 &status); // Squelch 1 out of 2 outputs
268 break;
269 case kPeriodMultiplier_1X:
270 HAL_SetPWMPeriodScale(m_handle, 0, &status); // Don't squelch any outputs
271 break;
272 default:
Austin Schuh9950f682021-11-06 15:27:58 -0700273 LOG(FATAL) << "Invalid multiplier " << mult;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800274 }
275
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800276 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800277}
278
279/**
280 * Temporarily disables the PWM output. The next set call will reenable
281 * the output.
282 */
283void PWM::SetDisabled() {
284 int32_t status = 0;
285
286 HAL_SetPWMDisabled(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800287 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800288}
289
290void PWM::SetZeroLatch() {
291 int32_t status = 0;
292
293 HAL_LatchPWMZero(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800294 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800295}