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