blob: 32262236a830db740c9ef88fa44ad6f4c1f992df [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "DriverStation.h"
9#include "AnalogInput.h"
10#include "Timer.h"
11#include "NetworkCommunication/FRCComm.h"
12#include "MotorSafetyHelper.h"
13#include "Utility.h"
14#include "WPIErrors.h"
15#include <string.h>
16#include "Log.hpp"
17
18// set the logging level
19TLogLevel dsLogLevel = logDEBUG;
20const double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
21
22#define DS_LOG(level) \
23 if (level > dsLogLevel) \
24 ; \
25 else \
26 Log().Get(level)
27
28const uint32_t DriverStation::kJoystickPorts;
29
30/**
31 * DriverStation constructor.
32 *
33 * This is only called once the first time GetInstance() is called
34 */
35DriverStation::DriverStation() {
36 // All joysticks should default to having zero axes, povs and buttons, so
37 // uninitialized memory doesn't get sent to speed controllers.
38 for (unsigned int i = 0; i < kJoystickPorts; i++) {
39 m_joystickAxes[i].count = 0;
40 m_joystickPOVs[i].count = 0;
41 m_joystickButtons[i].count = 0;
42 m_joystickDescriptor[i].isXbox = 0;
43 m_joystickDescriptor[i].type = -1;
44 m_joystickDescriptor[i].name[0] = '\0';
45 }
46 // Register that semaphore with the network communications task.
47 // It will signal when new packet data is available.
48 HALSetNewDataSem(&m_packetDataAvailableCond);
49
50 AddToSingletonList();
51
52 m_task = Task("DriverStation", &DriverStation::Run, this);
53}
54
55DriverStation::~DriverStation() {
56 m_isRunning = false;
57 m_task.join();
58
59 // Unregister our semaphore.
60 HALSetNewDataSem(nullptr);
61}
62
63void DriverStation::Run() {
64 m_isRunning = true;
65 int period = 0;
66 while (m_isRunning) {
67 {
68 std::unique_lock<priority_mutex> lock(m_packetDataAvailableMutex);
69 m_packetDataAvailableCond.wait(lock);
70 }
71 GetData();
72 m_waitForDataCond.notify_all();
73
74 if (++period >= 4) {
75 MotorSafetyHelper::CheckMotors();
76 period = 0;
77 }
78 if (m_userInDisabled) HALNetworkCommunicationObserveUserProgramDisabled();
79 if (m_userInAutonomous)
80 HALNetworkCommunicationObserveUserProgramAutonomous();
81 if (m_userInTeleop) HALNetworkCommunicationObserveUserProgramTeleop();
82 if (m_userInTest) HALNetworkCommunicationObserveUserProgramTest();
83 }
84}
85
86/**
87 * Return a pointer to the singleton DriverStation.
88 * @return Pointer to the DS instance
89 */
90DriverStation &DriverStation::GetInstance() {
Brian Silverman1a675112016-02-20 20:42:49 -050091 static DriverStation *instance = new DriverStation();
92 return *instance;
Brian Silverman26e4e522015-12-17 01:56:40 -050093}
94
95/**
96 * Copy data from the DS task for the user.
97 * If no new data exists, it will just be returned, otherwise
98 * the data will be copied from the DS polling loop.
99 */
100void DriverStation::GetData() {
101 // Get the status of all of the joysticks
102 for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
103 HALGetJoystickAxes(stick, &m_joystickAxes[stick]);
104 HALGetJoystickPOVs(stick, &m_joystickPOVs[stick]);
105 HALGetJoystickButtons(stick, &m_joystickButtons[stick]);
106 HALGetJoystickDescriptor(stick, &m_joystickDescriptor[stick]);
107 }
108 m_newControlData.give();
109}
110
111/**
112 * Read the battery voltage.
113 *
114 * @return The battery voltage in Volts.
115 */
116float DriverStation::GetBatteryVoltage() const {
117 int32_t status = 0;
118 float voltage = getVinVoltage(&status);
119 wpi_setErrorWithContext(status, "getVinVoltage");
120
121 return voltage;
122}
123
124/**
125 * Reports errors related to unplugged joysticks
126 * Throttles the errors so that they don't overwhelm the DS
127 */
128void DriverStation::ReportJoystickUnpluggedError(std::string message) {
129 double currentTime = Timer::GetFPGATimestamp();
130 if (currentTime > m_nextMessageTime) {
131 ReportError(message);
132 m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
133 }
134}
135
136/**
Brian Silverman1a675112016-02-20 20:42:49 -0500137 * Reports errors related to unplugged joysticks
138 * Throttles the errors so that they don't overwhelm the DS
139 */
140void DriverStation::ReportJoystickUnpluggedWarning(std::string message) {
141 double currentTime = Timer::GetFPGATimestamp();
142 if (currentTime > m_nextMessageTime) {
143 ReportWarning(message);
144 m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
145 }
146}
147
148/**
Brian Silverman26e4e522015-12-17 01:56:40 -0500149 * Returns the number of axes on a given joystick port
150 *
151 * @param stick The joystick port number
152 * @return The number of axes on the indicated joystick
153 */
154int DriverStation::GetStickAxisCount(uint32_t stick) const {
155 if (stick >= kJoystickPorts) {
156 wpi_setWPIError(BadJoystickIndex);
157 return 0;
158 }
159 HALJoystickAxes joystickAxes;
160 HALGetJoystickAxes(stick, &joystickAxes);
161 return joystickAxes.count;
162}
163
164/**
165 * Returns the name of the joystick at the given port
166 *
167 * @param stick The joystick port number
168 * @return The name of the joystick at the given port
169 */
170std::string DriverStation::GetJoystickName(uint32_t stick) const {
171 if (stick >= kJoystickPorts) {
172 wpi_setWPIError(BadJoystickIndex);
173 }
Brian Silverman1a675112016-02-20 20:42:49 -0500174 std::string retVal(m_joystickDescriptor[stick].name);
Brian Silverman26e4e522015-12-17 01:56:40 -0500175 return retVal;
176}
177
178/**
179 * Returns the type of joystick at a given port
180 *
181 * @param stick The joystick port number
182 * @return The HID type of joystick at the given port
183 */
184int DriverStation::GetJoystickType(uint32_t stick) const {
185 if (stick >= kJoystickPorts) {
186 wpi_setWPIError(BadJoystickIndex);
187 return -1;
188 }
189 return (int)m_joystickDescriptor[stick].type;
190}
191
192/**
193 * Returns a boolean indicating if the controller is an xbox controller.
194 *
195 * @param stick The joystick port number
196 * @return A boolean that is true if the controller is an xbox controller.
197 */
198bool DriverStation::GetJoystickIsXbox(uint32_t stick) const {
199 if (stick >= kJoystickPorts) {
200 wpi_setWPIError(BadJoystickIndex);
201 return false;
202 }
203 return (bool)m_joystickDescriptor[stick].isXbox;
204}
205
206/**
207 * Returns the types of Axes on a given joystick port
208 *
209 * @param stick The joystick port number and the target axis
210 * @return What type of axis the axis is reporting to be
211 */
212int DriverStation::GetJoystickAxisType(uint32_t stick, uint8_t axis) const {
213 if (stick >= kJoystickPorts) {
214 wpi_setWPIError(BadJoystickIndex);
215 return -1;
216 }
217 return m_joystickDescriptor[stick].axisTypes[axis];
218}
219
220/**
221 * Returns the number of POVs on a given joystick port
222 *
223 * @param stick The joystick port number
224 * @return The number of POVs on the indicated joystick
225 */
226int DriverStation::GetStickPOVCount(uint32_t stick) const {
227 if (stick >= kJoystickPorts) {
228 wpi_setWPIError(BadJoystickIndex);
229 return 0;
230 }
231 HALJoystickPOVs joystickPOVs;
232 HALGetJoystickPOVs(stick, &joystickPOVs);
233 return joystickPOVs.count;
234}
235
236/**
237 * Returns the number of buttons on a given joystick port
238 *
239 * @param stick The joystick port number
240 * @return The number of buttons on the indicated joystick
241 */
242int DriverStation::GetStickButtonCount(uint32_t stick) const {
243 if (stick >= kJoystickPorts) {
244 wpi_setWPIError(BadJoystickIndex);
245 return 0;
246 }
247 HALJoystickButtons joystickButtons;
248 HALGetJoystickButtons(stick, &joystickButtons);
249 return joystickButtons.count;
250}
251
252/**
253 * Get the value of the axis on a joystick.
254 * This depends on the mapping of the joystick connected to the specified port.
255 *
256 * @param stick The joystick to read.
257 * @param axis The analog axis value to read from the joystick.
258 * @return The value of the axis on the joystick.
259 */
260float DriverStation::GetStickAxis(uint32_t stick, uint32_t axis) {
261 if (stick >= kJoystickPorts) {
262 wpi_setWPIError(BadJoystickIndex);
263 return 0;
264 }
265
266 if (axis >= m_joystickAxes[stick].count) {
267 if (axis >= kMaxJoystickAxes)
268 wpi_setWPIError(BadJoystickAxis);
269 else
Brian Silverman1a675112016-02-20 20:42:49 -0500270 ReportJoystickUnpluggedWarning(
271 "Joystick Axis missing, check if all controllers are plugged in");
Brian Silverman26e4e522015-12-17 01:56:40 -0500272 return 0.0f;
273 }
274
275 int8_t value = m_joystickAxes[stick].axes[axis];
276
277 if (value < 0) {
278 return value / 128.0f;
279 } else {
280 return value / 127.0f;
281 }
282}
283
284/**
285 * Get the state of a POV on the joystick.
286 *
287 * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
288 */
289int DriverStation::GetStickPOV(uint32_t stick, uint32_t pov) {
290 if (stick >= kJoystickPorts) {
291 wpi_setWPIError(BadJoystickIndex);
292 return -1;
293 }
294
295 if (pov >= m_joystickPOVs[stick].count) {
296 if (pov >= kMaxJoystickPOVs)
297 wpi_setWPIError(BadJoystickAxis);
298 else
Brian Silverman1a675112016-02-20 20:42:49 -0500299 ReportJoystickUnpluggedWarning(
300 "Joystick POV missing, check if all controllers are plugged in");
Brian Silverman26e4e522015-12-17 01:56:40 -0500301 return -1;
302 }
303
304 return m_joystickPOVs[stick].povs[pov];
305}
306
307/**
308 * The state of the buttons on the joystick.
309 *
310 * @param stick The joystick to read.
311 * @return The state of the buttons on the joystick.
312 */
313uint32_t DriverStation::GetStickButtons(uint32_t stick) const {
314 if (stick >= kJoystickPorts) {
315 wpi_setWPIError(BadJoystickIndex);
316 return 0;
317 }
318
319 return m_joystickButtons[stick].buttons;
320}
321
322/**
323 * The state of one joystick button. Button indexes begin at 1.
324 *
325 * @param stick The joystick to read.
326 * @param button The button index, beginning at 1.
327 * @return The state of the joystick button.
328 */
329bool DriverStation::GetStickButton(uint32_t stick, uint8_t button) {
330 if (stick >= kJoystickPorts) {
331 wpi_setWPIError(BadJoystickIndex);
332 return false;
333 }
334
335 if (button > m_joystickButtons[stick].count) {
Brian Silverman1a675112016-02-20 20:42:49 -0500336 ReportJoystickUnpluggedWarning(
337 "Joystick Button missing, check if all controllers are plugged in");
Brian Silverman26e4e522015-12-17 01:56:40 -0500338 return false;
339 }
340 if (button == 0) {
341 ReportJoystickUnpluggedError(
Brian Silverman1a675112016-02-20 20:42:49 -0500342 "Button indexes begin at 1 in WPILib for C++ and Java");
Brian Silverman26e4e522015-12-17 01:56:40 -0500343 return false;
344 }
345 return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0;
346}
347
348/**
349 * Check if the DS has enabled the robot
350 * @return True if the robot is enabled and the DS is connected
351 */
352bool DriverStation::IsEnabled() const {
353 HALControlWord controlWord;
354 memset(&controlWord, 0, sizeof(controlWord));
355 HALGetControlWord(&controlWord);
356 return controlWord.enabled && controlWord.dsAttached;
357}
358
359/**
360 * Check if the robot is disabled
361 * @return True if the robot is explicitly disabled or the DS is not connected
362 */
363bool DriverStation::IsDisabled() const {
364 HALControlWord controlWord;
365 memset(&controlWord, 0, sizeof(controlWord));
366 HALGetControlWord(&controlWord);
367 return !(controlWord.enabled && controlWord.dsAttached);
368}
369
370/**
371 * Check if the DS is commanding autonomous mode
372 * @return True if the robot is being commanded to be in autonomous mode
373 */
374bool DriverStation::IsAutonomous() const {
375 HALControlWord controlWord;
376 memset(&controlWord, 0, sizeof(controlWord));
377 HALGetControlWord(&controlWord);
378 return controlWord.autonomous;
379}
380
381/**
382 * Check if the DS is commanding teleop mode
383 * @return True if the robot is being commanded to be in teleop mode
384 */
385bool DriverStation::IsOperatorControl() const {
386 HALControlWord controlWord;
387 memset(&controlWord, 0, sizeof(controlWord));
388 HALGetControlWord(&controlWord);
389 return !(controlWord.autonomous || controlWord.test);
390}
391
392/**
393 * Check if the DS is commanding test mode
394 * @return True if the robot is being commanded to be in test mode
395 */
396bool DriverStation::IsTest() const {
397 HALControlWord controlWord;
398 HALGetControlWord(&controlWord);
399 return controlWord.test;
400}
401
402/**
403 * Check if the DS is attached
404 * @return True if the DS is connected to the robot
405 */
406bool DriverStation::IsDSAttached() const {
407 HALControlWord controlWord;
408 memset(&controlWord, 0, sizeof(controlWord));
409 HALGetControlWord(&controlWord);
410 return controlWord.dsAttached;
411}
412
413/**
414 * Check if the FPGA outputs are enabled. The outputs may be disabled if the
415 * robot is disabled
416 * or e-stopped, the watchdog has expired, or if the roboRIO browns out.
417 * @return True if the FPGA outputs are enabled.
418 */
419bool DriverStation::IsSysActive() const {
420 int32_t status = 0;
421 bool retVal = HALGetSystemActive(&status);
422 wpi_setErrorWithContext(status, getHALErrorMessage(status));
423 return retVal;
424}
425
426/**
427 * Check if the system is browned out.
428 * @return True if the system is browned out
429 */
430bool DriverStation::IsSysBrownedOut() const {
431 int32_t status = 0;
432 bool retVal = HALGetBrownedOut(&status);
433 wpi_setErrorWithContext(status, getHALErrorMessage(status));
434 return retVal;
435}
436
437/**
438 * Has a new control packet from the driver station arrived since the last time
439 * this function was called?
440 * Warning: If you call this function from more than one place at the same time,
441 * you will not get the get the intended behaviour.
442 * @return True if the control data has been updated since the last call.
443 */
444bool DriverStation::IsNewControlData() const {
445 return m_newControlData.tryTake() == false;
446}
447
448/**
449 * Is the driver station attached to a Field Management System?
450 * @return True if the robot is competing on a field being controlled by a Field
451 * Management System
452 */
453bool DriverStation::IsFMSAttached() const {
454 HALControlWord controlWord;
455 HALGetControlWord(&controlWord);
456 return controlWord.fmsAttached;
457}
458
459/**
460 * Return the alliance that the driver station says it is on.
461 * This could return kRed or kBlue
462 * @return The Alliance enum (kRed, kBlue or kInvalid)
463 */
464DriverStation::Alliance DriverStation::GetAlliance() const {
465 HALAllianceStationID allianceStationID;
466 HALGetAllianceStation(&allianceStationID);
467 switch (allianceStationID) {
468 case kHALAllianceStationID_red1:
469 case kHALAllianceStationID_red2:
470 case kHALAllianceStationID_red3:
471 return kRed;
472 case kHALAllianceStationID_blue1:
473 case kHALAllianceStationID_blue2:
474 case kHALAllianceStationID_blue3:
475 return kBlue;
476 default:
477 return kInvalid;
478 }
479}
480
481/**
482 * Return the driver station location on the field
483 * This could return 1, 2, or 3
484 * @return The location of the driver station (1-3, 0 for invalid)
485 */
486uint32_t DriverStation::GetLocation() const {
487 HALAllianceStationID allianceStationID;
488 HALGetAllianceStation(&allianceStationID);
489 switch (allianceStationID) {
490 case kHALAllianceStationID_red1:
491 case kHALAllianceStationID_blue1:
492 return 1;
493 case kHALAllianceStationID_red2:
494 case kHALAllianceStationID_blue2:
495 return 2;
496 case kHALAllianceStationID_red3:
497 case kHALAllianceStationID_blue3:
498 return 3;
499 default:
500 return 0;
501 }
502}
503
504/**
505 * Wait until a new packet comes from the driver station
506 * This blocks on a semaphore, so the waiting is efficient.
507 * This is a good way to delay processing until there is new driver station data
508 * to act on
509 */
510void DriverStation::WaitForData() {
511 std::unique_lock<priority_mutex> lock(m_waitForDataMutex);
512 m_waitForDataCond.wait(lock);
513}
514
515/**
516 * Return the approximate match time
517 * The FMS does not send an official match time to the robots, but does send an
518 * approximate match time.
519 * The value will count down the time remaining in the current period (auto or
520 * teleop).
521 * Warning: This is not an official time (so it cannot be used to dispute ref
522 * calls or guarantee that a function
523 * will trigger before the match ends)
524 * The Practice Match function of the DS approximates the behaviour seen on the
525 * field.
526 * @return Time remaining in current match period (auto or teleop)
527 */
528double DriverStation::GetMatchTime() const {
529 float matchTime;
530 HALGetMatchTime(&matchTime);
531 return (double)matchTime;
532}
533
534/**
535 * Report an error to the DriverStation messages window.
536 * The error is also printed to the program console.
537 */
538void DriverStation::ReportError(std::string error) {
Brian Silverman1a675112016-02-20 20:42:49 -0500539 HALSendError(1, 1, 0, error.c_str(), "", "", 1);
540}
Brian Silverman26e4e522015-12-17 01:56:40 -0500541
Brian Silverman1a675112016-02-20 20:42:49 -0500542/**
543 * Report a warning to the DriverStation messages window.
544 * The warning is also printed to the program console.
545 */
546void DriverStation::ReportWarning(std::string error) {
547 HALSendError(0, 1, 0, error.c_str(), "", "", 1);
548}
549
550/**
551 * Report an error to the DriverStation messages window.
552 * The error is also printed to the program console.
553 */
554void DriverStation::ReportError(bool is_error, int32_t code,
555 const std::string &error,
556 const std::string &location,
557 const std::string &stack) {
558 HALSendError(is_error, code, 0, error.c_str(), location.c_str(),
559 stack.c_str(), 1);
Brian Silverman26e4e522015-12-17 01:56:40 -0500560}