blob: 2ed0a97c169210cfe3859b728035c108aebf3377 [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
8#include "frc971/wpilib/ahal/DriverStation.h"
9
10#include <chrono>
Vinay Sivae52a6b32021-07-10 15:19:26 -070011#include <memory>
Austin Schuh9950f682021-11-06 15:27:58 -070012#include <string_view>
13#include <functional>
Parker Schuhd3b7a8872018-02-19 16:42:27 -080014
15#include "FRC_NetworkCommunication/FRCComm.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080016#include "frc971/wpilib/ahal/AnalogInput.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080017#include "frc971/wpilib/ahal/WPIErrors.h"
Austin Schuhf6b94632019-02-02 22:11:27 -080018#include "hal/HAL.h"
19#include "hal/Power.h"
20#include "wpi/SmallString.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080021
22using namespace frc;
23
24#define WPI_LIB_FATAL(error_tag) \
25 do { \
26 } while (false)
27
28const int DriverStation::kJoystickPorts;
29
30DriverStation::~DriverStation() {}
31
32/**
33 * Return a pointer to the singleton DriverStation.
34 *
35 * @return Pointer to the DS instance
36 */
37DriverStation &DriverStation::GetInstance() {
38 static DriverStation instance;
39 return instance;
40}
41
42/**
43 * Report an error to the DriverStation messages window.
44 *
45 * The error is also printed to the program console.
46 */
Austin Schuh9950f682021-11-06 15:27:58 -070047void DriverStation::ReportError(const std::string_view &error) {
48 HAL_SendError(1, 1, 0, std::string(error).c_str(), "", "", 1);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080049}
50
51/**
52 * Report a warning to the DriverStation messages window.
53 *
54 * The warning is also printed to the program console.
55 */
Austin Schuh9950f682021-11-06 15:27:58 -070056void DriverStation::ReportWarning(const std::string_view &error) {
57 HAL_SendError(0, 1, 0, std::string(error).c_str(), "", "", 1);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080058}
59
60/**
61 * Report an error to the DriverStation messages window.
62 *
63 * The error is also printed to the program console.
64 */
65void DriverStation::ReportError(bool is_error, int32_t code,
Austin Schuh9950f682021-11-06 15:27:58 -070066 const std::string_view &error,
67 const std::string_view &location,
68 const std::string_view &stack) {
69 HAL_SendError(is_error, code, 0, std::string(error).c_str(),
70 std::string(location).c_str(), std::string(stack).c_str(), 1);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080071}
72
73/**
74 * Get the value of the axis on a joystick.
75 *
76 * This depends on the mapping of the joystick connected to the specified port.
77 *
78 * @param stick The joystick to read.
79 * @param axis The analog axis value to read from the joystick.
80 * @return The value of the axis on the joystick.
81 */
82double DriverStation::GetStickAxis(int stick, int axis) {
83 if (stick >= kJoystickPorts) {
84 WPI_LIB_FATAL(BadJoystickIndex);
85 return 0;
86 }
87 if (axis >= m_joystickAxes[stick].count) {
88 if (axis >= HAL_kMaxJoystickAxes) WPI_LIB_FATAL(BadJoystickAxis);
89 return 0.0;
90 }
91
92 return m_joystickAxes[stick].axes[axis];
93}
94
95/**
96 * Get the state of a POV on the joystick.
97 *
98 * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
99 */
100int DriverStation::GetStickPOV(int stick, int pov) {
101 if (stick >= kJoystickPorts) {
102 WPI_LIB_FATAL(BadJoystickIndex);
103 return -1;
104 }
105 if (pov >= m_joystickPOVs[stick].count) {
106 if (pov >= HAL_kMaxJoystickPOVs) WPI_LIB_FATAL(BadJoystickAxis);
107 return -1;
108 }
109
110 return m_joystickPOVs[stick].povs[pov];
111}
112
113/**
114 * The state of the buttons on the joystick.
115 *
116 * @param stick The joystick to read.
117 * @return The state of the buttons on the joystick.
118 */
119int DriverStation::GetStickButtons(int stick) const {
120 if (stick >= kJoystickPorts) {
121 WPI_LIB_FATAL(BadJoystickIndex);
122 return 0;
123 }
124 return m_joystickButtons[stick].buttons;
125}
126
127/**
128 * The state of one joystick button. Button indexes begin at 1.
129 *
130 * @param stick The joystick to read.
131 * @param button The button index, beginning at 1.
132 * @return The state of the joystick button.
133 */
134bool DriverStation::GetStickButton(int stick, int button) {
135 if (stick >= kJoystickPorts) {
136 WPI_LIB_FATAL(BadJoystickIndex);
137 return false;
138 }
139 if (button == 0) {
140 return false;
141 }
142 if (button > m_joystickButtons[stick].count) {
143 return false;
144 }
145
146 return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0;
147}
148
149/**
150 * Returns the number of axes on a given joystick port.
151 *
152 * @param stick The joystick port number
153 * @return The number of axes on the indicated joystick
154 */
155int DriverStation::GetStickAxisCount(int stick) const {
156 if (stick >= kJoystickPorts) {
157 WPI_LIB_FATAL(BadJoystickIndex);
158 return 0;
159 }
160 return m_joystickAxes[stick].count;
161}
162
163/**
164 * Returns the number of POVs on a given joystick port.
165 *
166 * @param stick The joystick port number
167 * @return The number of POVs on the indicated joystick
168 */
169int DriverStation::GetStickPOVCount(int stick) const {
170 if (stick >= kJoystickPorts) {
171 WPI_LIB_FATAL(BadJoystickIndex);
172 return 0;
173 }
174 return m_joystickPOVs[stick].count;
175}
176
177/**
178 * Returns the number of buttons on a given joystick port.
179 *
180 * @param stick The joystick port number
181 * @return The number of buttons on the indicated joystick
182 */
183int DriverStation::GetStickButtonCount(int stick) const {
184 if (stick >= kJoystickPorts) {
185 WPI_LIB_FATAL(BadJoystickIndex);
186 return 0;
187 }
188 return m_joystickButtons[stick].count;
189}
190
191/**
192 * Returns a boolean indicating if the controller is an xbox controller.
193 *
194 * @param stick The joystick port number
195 * @return A boolean that is true if the controller is an xbox controller.
196 */
197bool DriverStation::GetJoystickIsXbox(int stick) const {
198 if (stick >= kJoystickPorts) {
199 WPI_LIB_FATAL(BadJoystickIndex);
200 return false;
201 }
202 return static_cast<bool>(m_joystickDescriptor[stick].isXbox);
203}
204
205/**
206 * Returns the type of joystick at a given port.
207 *
208 * @param stick The joystick port number
209 * @return The HID type of joystick at the given port
210 */
211int DriverStation::GetJoystickType(int stick) const {
212 if (stick >= kJoystickPorts) {
213 WPI_LIB_FATAL(BadJoystickIndex);
214 return -1;
215 }
216 return static_cast<int>(m_joystickDescriptor[stick].type);
217}
218
219/**
220 * Returns the name of the joystick at the given port.
221 *
222 * @param stick The joystick port number
223 * @return The name of the joystick at the given port
224 */
225std::string DriverStation::GetJoystickName(int stick) const {
226 if (stick >= kJoystickPorts) {
227 WPI_LIB_FATAL(BadJoystickIndex);
228 }
229 std::string retVal(m_joystickDescriptor[stick].name);
230 return retVal;
231}
232
233/**
234 * Returns the types of Axes on a given joystick port.
235 *
236 * @param stick The joystick port number and the target axis
237 * @return What type of axis the axis is reporting to be
238 */
239int DriverStation::GetJoystickAxisType(int stick, int axis) const {
240 if (stick >= kJoystickPorts) {
241 WPI_LIB_FATAL(BadJoystickIndex);
242 return -1;
243 }
244 return m_joystickDescriptor[stick].axisTypes[axis];
245}
246
247/**
248 * Check if the FPGA outputs are enabled.
249 *
250 * The outputs may be disabled if the robot is disabled or e-stopped, the
251 * watchdog has expired, or if the roboRIO browns out.
252 *
253 * @return True if the FPGA outputs are enabled.
254 */
255bool DriverStation::IsSysActive() const {
256 int32_t status = 0;
257 bool retVal = HAL_GetSystemActive(&status);
258 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
259 return retVal;
260}
261
262/**
263 * Check if the system is browned out.
264 *
265 * @return True if the system is browned out
266 */
267bool DriverStation::IsBrownedOut() const {
268 int32_t status = 0;
269 bool retVal = HAL_GetBrownedOut(&status);
270 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
271 return retVal;
272}
273
274/**
275 * Return the alliance that the driver station says it is on.
276 *
277 * This could return kRed or kBlue.
278 *
279 * @return The Alliance enum (kRed, kBlue or kInvalid)
280 */
281DriverStation::Alliance DriverStation::GetAlliance() const {
282 int32_t status = 0;
283 auto allianceStationID = HAL_GetAllianceStation(&status);
284 switch (allianceStationID) {
285 case HAL_AllianceStationID_kRed1:
286 case HAL_AllianceStationID_kRed2:
287 case HAL_AllianceStationID_kRed3:
288 return kRed;
289 case HAL_AllianceStationID_kBlue1:
290 case HAL_AllianceStationID_kBlue2:
291 case HAL_AllianceStationID_kBlue3:
292 return kBlue;
293 default:
294 return kInvalid;
295 }
296}
297
298/**
299 * Return the driver station location on the field.
300 *
301 * This could return 1, 2, or 3.
302 *
303 * @return The location of the driver station (1-3, 0 for invalid)
304 */
305int DriverStation::GetLocation() const {
306 int32_t status = 0;
307 auto allianceStationID = HAL_GetAllianceStation(&status);
308 switch (allianceStationID) {
309 case HAL_AllianceStationID_kRed1:
310 case HAL_AllianceStationID_kBlue1:
311 return 1;
312 case HAL_AllianceStationID_kRed2:
313 case HAL_AllianceStationID_kBlue2:
314 return 2;
315 case HAL_AllianceStationID_kRed3:
316 case HAL_AllianceStationID_kBlue3:
317 return 3;
318 default:
319 return 0;
320 }
321}
322
323/**
324 * Return the approximate match time.
325 *
326 * The FMS does not send an official match time to the robots, but does send an
327 * approximate match time. The value will count down the time remaining in the
328 * current period (auto or teleop).
329 *
330 * Warning: This is not an official time (so it cannot be used to dispute ref
331 * calls or guarantee that a function will trigger before the match ends).
332 *
333 * The Practice Match function of the DS approximates the behaviour seen on the
334 * field.
335 *
336 * @return Time remaining in current match period (auto or teleop)
337 */
338double DriverStation::GetMatchTime() const {
339 int32_t status;
340 return HAL_GetMatchTime(&status);
341}
342
343/**
344 * Read the battery voltage.
345 *
346 * @return The battery voltage in Volts.
347 */
348double DriverStation::GetBatteryVoltage() const {
349 int32_t status = 0;
350 double voltage = HAL_GetVinVoltage(&status);
351 wpi_setErrorWithContext(status, "getVinVoltage");
352
353 return voltage;
354}
355
356/**
357 * Copy data from the DS task for the user.
358 *
359 * If no new data exists, it will just be returned, otherwise
360 * the data will be copied from the DS polling loop.
361 */
362void DriverStation::GetData() {
363 // Get the status of all of the joysticks, and save to the cache
364 for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
365 HAL_GetJoystickAxes(stick, &m_joystickAxesCache[stick]);
366 HAL_GetJoystickPOVs(stick, &m_joystickPOVsCache[stick]);
367 HAL_GetJoystickButtons(stick, &m_joystickButtonsCache[stick]);
368 HAL_GetJoystickDescriptor(stick, &m_joystickDescriptorCache[stick]);
369 }
370 m_joystickAxes.swap(m_joystickAxesCache);
371 m_joystickPOVs.swap(m_joystickPOVsCache);
372 m_joystickButtons.swap(m_joystickButtonsCache);
373 m_joystickDescriptor.swap(m_joystickDescriptorCache);
374
375 HAL_ControlWord control_word;
376 HAL_GetControlWord(&control_word);
377 is_enabled_ = control_word.enabled;
378 is_autonomous_ = control_word.autonomous;
379 is_test_mode_ = control_word.test;
380 is_fms_attached_ = control_word.fmsAttached;
381}
382
383/**
384 * DriverStation constructor.
385 *
386 * This is only called once the first time GetInstance() is called
387 */
388DriverStation::DriverStation() {
389 // The HAL_Observe* functions let the Driver Station know that the
390 // robot code is alive (this influences the Robot Code status light on the
391 // DS, and if the DS thinks you don't have robot code, then you can't enable).
392 HAL_ObserveUserProgramStarting();
393
Vinay Sivae52a6b32021-07-10 15:19:26 -0700394 m_joystickAxes = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
395 m_joystickPOVs = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
396 m_joystickButtons = std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800397 m_joystickDescriptor =
Vinay Sivae52a6b32021-07-10 15:19:26 -0700398 std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
399 m_joystickAxesCache = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
400 m_joystickPOVsCache = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800401 m_joystickButtonsCache =
Vinay Sivae52a6b32021-07-10 15:19:26 -0700402 std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800403 m_joystickDescriptorCache =
Vinay Sivae52a6b32021-07-10 15:19:26 -0700404 std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800405
406 // All joysticks should default to having zero axes, povs and buttons, so
407 // uninitialized memory doesn't get sent to speed controllers.
408 for (unsigned int i = 0; i < kJoystickPorts; i++) {
409 m_joystickAxes[i].count = 0;
410 m_joystickPOVs[i].count = 0;
411 m_joystickButtons[i].count = 0;
412 m_joystickDescriptor[i].isXbox = 0;
413 m_joystickDescriptor[i].type = -1;
414 m_joystickDescriptor[i].name[0] = '\0';
415
416 m_joystickAxesCache[i].count = 0;
417 m_joystickPOVsCache[i].count = 0;
418 m_joystickButtonsCache[i].count = 0;
419 m_joystickDescriptorCache[i].isXbox = 0;
420 m_joystickDescriptorCache[i].type = -1;
421 m_joystickDescriptorCache[i].name[0] = '\0';
422 }
423}
424
425void DriverStation::RunIteration(std::function<void()> on_data) {
426 HAL_WaitForDSData();
427 GetData();
428
429 // We have to feed some sort of watchdog so that the driver's station knows
430 // that the robot code is still alive. HAL_ObserveUserProgramStarting must be
431 // called during initialization (currently called in the constructor of this
432 // class).
433 if (!IsEnabled()) {
434 HAL_ObserveUserProgramDisabled();
435 } else if (IsAutonomous()) {
436 HAL_ObserveUserProgramAutonomous();
437 } else if (IsTestMode()) {
438 HAL_ObserveUserProgramTest();
439 } else {
440 HAL_ObserveUserProgramTeleop();
441 }
442
443 on_data();
444}