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