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