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