blob: 72219aa2bb67f324548a2b19b68ac694ff336084 [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;
James Kuszmaulcd622d52023-11-22 20:44:04 -0800106 HAL_SetPWMConfigMicroseconds(m_handle, max * 1000.0, deadbandMax * 1000.0,
107 center * 1000.0, deadbandMin * 1000.0,
108 min * 1000.0, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800109 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800110}
111
112/**
113 * Set the bounds on the PWM values.
114 *
115 * This sets the bounds on the PWM values for a particular each type of
116 * controller. The values determine the upper and lower speeds as well as the
117 * deadband bracket.
118 *
119 * @param max The Minimum pwm value
120 * @param deadbandMax The high end of the deadband range
121 * @param center The center speed (off)
122 * @param deadbandMin The low end of the deadband range
123 * @param min The minimum pwm value
124 */
125void PWM::SetRawBounds(int max, int deadbandMax, int center, int deadbandMin,
126 int min) {
127 int32_t status = 0;
James Kuszmaulcd622d52023-11-22 20:44:04 -0800128 HAL_SetPWMConfigMicroseconds(m_handle, max * 1000, deadbandMax * 1000,
129 center * 1000, deadbandMin * 1000, min * 1000,
130 &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800131 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800132}
133
134/**
135 * Get the bounds on the PWM values.
136 *
137 * This Gets the bounds on the PWM values for a particular each type of
138 * controller. The values determine the upper and lower speeds as well as the
139 * deadband bracket.
140 *
James Kuszmaulcd622d52023-11-22 20:44:04 -0800141 * Values in microseconds.
142 *
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800143 * @param max The Minimum pwm value
144 * @param deadbandMax The high end of the deadband range
145 * @param center The center speed (off)
146 * @param deadbandMin The low end of the deadband range
147 * @param min The minimum pwm value
148 */
149void PWM::GetRawBounds(int *max, int *deadbandMax, int *center,
150 int *deadbandMin, int *min) {
151 int32_t status = 0;
James Kuszmaulcd622d52023-11-22 20:44:04 -0800152 HAL_GetPWMConfigMicroseconds(m_handle, max, deadbandMax, center, deadbandMin,
153 min, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800154 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800155}
156
157/**
158 * Set the PWM value based on a position.
159 *
160 * This is intended to be used by servos.
161 *
162 * @pre SetMaxPositivePwm() called.
163 * @pre SetMinNegativePwm() called.
164 *
165 * @param pos The position to set the servo between 0.0 and 1.0.
166 */
167void PWM::SetPosition(double pos) {
168 int32_t status = 0;
169 HAL_SetPWMPosition(m_handle, pos, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800170 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800171}
172
173/**
174 * Get the PWM value in terms of a position.
175 *
176 * This is intended to be used by servos.
177 *
178 * @pre SetMaxPositivePwm() called.
179 * @pre SetMinNegativePwm() called.
180 *
181 * @return The position the servo is set to between 0.0 and 1.0.
182 */
183double PWM::GetPosition() const {
184 int32_t status = 0;
185 double position = HAL_GetPWMPosition(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800186 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800187 return position;
188}
189
190/**
191 * Set the PWM value based on a speed.
192 *
193 * This is intended to be used by speed controllers.
194 *
195 * @pre SetMaxPositivePwm() called.
196 * @pre SetMinPositivePwm() called.
197 * @pre SetCenterPwm() called.
198 * @pre SetMaxNegativePwm() called.
199 * @pre SetMinNegativePwm() called.
200 *
201 * @param speed The speed to set the speed controller between -1.0 and 1.0.
202 */
203void PWM::SetSpeed(double speed) {
204 int32_t status = 0;
205 HAL_SetPWMSpeed(m_handle, speed, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800206 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800207}
208
209/**
210 * Get the PWM value in terms of speed.
211 *
212 * This is intended to be used by speed controllers.
213 *
214 * @pre SetMaxPositivePwm() called.
215 * @pre SetMinPositivePwm() called.
216 * @pre SetMaxNegativePwm() called.
217 * @pre SetMinNegativePwm() called.
218 *
219 * @return The most recently set speed between -1.0 and 1.0.
220 */
221double PWM::GetSpeed() const {
222 int32_t status = 0;
223 double speed = HAL_GetPWMSpeed(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800224 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800225 return speed;
226}
227
228/**
229 * Set the PWM value directly to the hardware.
230 *
231 * Write a raw value to a PWM channel.
232 *
233 * @param value Raw PWM value.
234 */
235void PWM::SetRaw(uint16_t value) {
236 int32_t status = 0;
James Kuszmaulcd622d52023-11-22 20:44:04 -0800237 HAL_SetPWMPulseTimeMicroseconds(m_handle, value, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800238 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800239}
240
241/**
242 * Get the PWM value directly from the hardware.
243 *
244 * Read a raw value from a PWM channel.
245 *
246 * @return Raw PWM control value.
247 */
248uint16_t PWM::GetRaw() const {
249 int32_t status = 0;
James Kuszmaulcd622d52023-11-22 20:44:04 -0800250 uint16_t value = HAL_GetPWMPulseTimeMicroseconds(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800251 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800252
253 return value;
254}
255
256/**
257 * Slow down the PWM signal for old devices.
258 *
259 * @param mult The period multiplier to apply to this channel
260 */
261void PWM::SetPeriodMultiplier(PeriodMultiplier mult) {
262 int32_t status = 0;
263
264 switch (mult) {
265 case kPeriodMultiplier_4X:
266 HAL_SetPWMPeriodScale(m_handle, 3,
267 &status); // Squelch 3 out of 4 outputs
268 break;
269 case kPeriodMultiplier_2X:
270 HAL_SetPWMPeriodScale(m_handle, 1,
271 &status); // Squelch 1 out of 2 outputs
272 break;
273 case kPeriodMultiplier_1X:
274 HAL_SetPWMPeriodScale(m_handle, 0, &status); // Don't squelch any outputs
275 break;
276 default:
Austin Schuh9950f682021-11-06 15:27:58 -0700277 LOG(FATAL) << "Invalid multiplier " << mult;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800278 }
279
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800280 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800281}
282
283/**
284 * Temporarily disables the PWM output. The next set call will reenable
285 * the output.
286 */
287void PWM::SetDisabled() {
288 int32_t status = 0;
289
290 HAL_SetPWMDisabled(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800291 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800292}
293
294void PWM::SetZeroLatch() {
295 int32_t status = 0;
296
297 HAL_LatchPWMZero(m_handle, &status);
James Kuszmauleb9f6fb2022-02-27 21:04:00 -0800298 HAL_CHECK_STATUS(status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800299}