blob: fd91d955eae8cba7552b0d4d0f4b3c097dbf363b [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -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 "DriverStation.h"
9
10#include <chrono>
11
12#include "AnalogInput.h"
13#include "FRC_NetworkCommunication/FRCComm.h"
14#include "HAL/HAL.h"
15#include "HAL/Power.h"
16#include "HAL/cpp/Log.h"
17#include "MotorSafetyHelper.h"
18#include "Timer.h"
19#include "Utility.h"
20#include "WPIErrors.h"
21#include "llvm/SmallString.h"
22
23using namespace frc;
24
25const double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
26
27const int DriverStation::kJoystickPorts;
28
29DriverStation::~DriverStation() {
30 m_isRunning = false;
31 m_dsThread.join();
32}
33
34/**
35 * Return a pointer to the singleton DriverStation.
36 *
37 * @return Pointer to the DS instance
38 */
39DriverStation& DriverStation::GetInstance() {
40 static DriverStation instance;
41 return instance;
42}
43
44/**
45 * Report an error to the DriverStation messages window.
46 *
47 * The error is also printed to the program console.
48 */
49void DriverStation::ReportError(llvm::StringRef error) {
50 llvm::SmallString<128> temp;
51 HAL_SendError(1, 1, 0, error.c_str(temp), "", "", 1);
52}
53
54/**
55 * Report a warning to the DriverStation messages window.
56 *
57 * The warning is also printed to the program console.
58 */
59void DriverStation::ReportWarning(llvm::StringRef error) {
60 llvm::SmallString<128> temp;
61 HAL_SendError(0, 1, 0, error.c_str(temp), "", "", 1);
62}
63
64/**
65 * Report an error to the DriverStation messages window.
66 *
67 * The error is also printed to the program console.
68 */
69void DriverStation::ReportError(bool is_error, int32_t code,
70 llvm::StringRef error, llvm::StringRef location,
71 llvm::StringRef stack) {
72 llvm::SmallString<128> errorTemp;
73 llvm::SmallString<128> locationTemp;
74 llvm::SmallString<128> stackTemp;
75 HAL_SendError(is_error, code, 0, error.c_str(errorTemp),
76 location.c_str(locationTemp), stack.c_str(stackTemp), 1);
77}
78
79/**
80 * Get the value of the axis on a joystick.
81 *
82 * This depends on the mapping of the joystick connected to the specified port.
83 *
84 * @param stick The joystick to read.
85 * @param axis The analog axis value to read from the joystick.
86 * @return The value of the axis on the joystick.
87 */
88double DriverStation::GetStickAxis(int stick, int axis) {
89 if (stick >= kJoystickPorts) {
90 wpi_setWPIError(BadJoystickIndex);
91 return 0;
92 }
93 std::unique_lock<priority_mutex> lock(m_joystickDataMutex);
94 if (axis >= m_joystickAxes[stick].count) {
95 // Unlock early so error printing isn't locked.
96 m_joystickDataMutex.unlock();
97 lock.release();
98 if (axis >= HAL_kMaxJoystickAxes)
99 wpi_setWPIError(BadJoystickAxis);
100 else
101 ReportJoystickUnpluggedWarning(
102 "Joystick Axis missing, check if all controllers are plugged in");
103 return 0.0;
104 }
105
106 return m_joystickAxes[stick].axes[axis];
107}
108
109/**
110 * Get the state of a POV on the joystick.
111 *
112 * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
113 */
114int DriverStation::GetStickPOV(int stick, int pov) {
115 if (stick >= kJoystickPorts) {
116 wpi_setWPIError(BadJoystickIndex);
117 return -1;
118 }
119 std::unique_lock<priority_mutex> lock(m_joystickDataMutex);
120 if (pov >= m_joystickPOVs[stick].count) {
121 // Unlock early so error printing isn't locked.
122 lock.unlock();
123 if (pov >= HAL_kMaxJoystickPOVs)
124 wpi_setWPIError(BadJoystickAxis);
125 else
126 ReportJoystickUnpluggedWarning(
127 "Joystick POV missing, check if all controllers are plugged in");
128 return -1;
129 }
130
131 return m_joystickPOVs[stick].povs[pov];
132}
133
134/**
135 * The state of the buttons on the joystick.
136 *
137 * @param stick The joystick to read.
138 * @return The state of the buttons on the joystick.
139 */
140int DriverStation::GetStickButtons(int stick) const {
141 if (stick >= kJoystickPorts) {
142 wpi_setWPIError(BadJoystickIndex);
143 return 0;
144 }
145 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
146 return m_joystickButtons[stick].buttons;
147}
148
149/**
150 * The state of one joystick button. Button indexes begin at 1.
151 *
152 * @param stick The joystick to read.
153 * @param button The button index, beginning at 1.
154 * @return The state of the joystick button.
155 */
156bool DriverStation::GetStickButton(int stick, int button) {
157 if (stick >= kJoystickPorts) {
158 wpi_setWPIError(BadJoystickIndex);
159 return false;
160 }
161 if (button == 0) {
162 ReportJoystickUnpluggedError(
163 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
164 return false;
165 }
166 std::unique_lock<priority_mutex> lock(m_joystickDataMutex);
167 if (button > m_joystickButtons[stick].count) {
168 // Unlock early so error printing isn't locked.
169 lock.unlock();
170 ReportJoystickUnpluggedWarning(
171 "Joystick Button missing, check if all controllers are "
172 "plugged in");
173 return false;
174 }
175
176 return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0;
177}
178
179/**
180 * Returns the number of axes on a given joystick port.
181 *
182 * @param stick The joystick port number
183 * @return The number of axes on the indicated joystick
184 */
185int DriverStation::GetStickAxisCount(int stick) const {
186 if (stick >= kJoystickPorts) {
187 wpi_setWPIError(BadJoystickIndex);
188 return 0;
189 }
190 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
191 return m_joystickAxes[stick].count;
192}
193
194/**
195 * Returns the number of POVs on a given joystick port.
196 *
197 * @param stick The joystick port number
198 * @return The number of POVs on the indicated joystick
199 */
200int DriverStation::GetStickPOVCount(int stick) const {
201 if (stick >= kJoystickPorts) {
202 wpi_setWPIError(BadJoystickIndex);
203 return 0;
204 }
205 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
206 return m_joystickPOVs[stick].count;
207}
208
209/**
210 * Returns the number of buttons on a given joystick port.
211 *
212 * @param stick The joystick port number
213 * @return The number of buttons on the indicated joystick
214 */
215int DriverStation::GetStickButtonCount(int stick) const {
216 if (stick >= kJoystickPorts) {
217 wpi_setWPIError(BadJoystickIndex);
218 return 0;
219 }
220 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
221 return m_joystickButtons[stick].count;
222}
223
224/**
225 * Returns a boolean indicating if the controller is an xbox controller.
226 *
227 * @param stick The joystick port number
228 * @return A boolean that is true if the controller is an xbox controller.
229 */
230bool DriverStation::GetJoystickIsXbox(int stick) const {
231 if (stick >= kJoystickPorts) {
232 wpi_setWPIError(BadJoystickIndex);
233 return false;
234 }
235 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
236 return static_cast<bool>(m_joystickDescriptor[stick].isXbox);
237}
238
239/**
240 * Returns the type of joystick at a given port.
241 *
242 * @param stick The joystick port number
243 * @return The HID type of joystick at the given port
244 */
245int DriverStation::GetJoystickType(int stick) const {
246 if (stick >= kJoystickPorts) {
247 wpi_setWPIError(BadJoystickIndex);
248 return -1;
249 }
250 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
251 return static_cast<int>(m_joystickDescriptor[stick].type);
252}
253
254/**
255 * Returns the name of the joystick at the given port.
256 *
257 * @param stick The joystick port number
258 * @return The name of the joystick at the given port
259 */
260std::string DriverStation::GetJoystickName(int stick) const {
261 if (stick >= kJoystickPorts) {
262 wpi_setWPIError(BadJoystickIndex);
263 }
264 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
265 std::string retVal(m_joystickDescriptor[stick].name);
266 return retVal;
267}
268
269/**
270 * Returns the types of Axes on a given joystick port.
271 *
272 * @param stick The joystick port number and the target axis
273 * @return What type of axis the axis is reporting to be
274 */
275int DriverStation::GetJoystickAxisType(int stick, int axis) const {
276 if (stick >= kJoystickPorts) {
277 wpi_setWPIError(BadJoystickIndex);
278 return -1;
279 }
280 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
281 return m_joystickDescriptor[stick].axisTypes[axis];
282}
283
284/**
285 * Check if the DS has enabled the robot.
286 *
287 * @return True if the robot is enabled and the DS is connected
288 */
289bool DriverStation::IsEnabled() const {
290 HAL_ControlWord controlWord;
291 UpdateControlWord(false, controlWord);
292 return controlWord.enabled && controlWord.dsAttached;
293}
294
295/**
296 * Check if the robot is disabled.
297 *
298 * @return True if the robot is explicitly disabled or the DS is not connected
299 */
300bool DriverStation::IsDisabled() const {
301 HAL_ControlWord controlWord;
302 UpdateControlWord(false, controlWord);
303 return !(controlWord.enabled && controlWord.dsAttached);
304}
305
306/**
307 * Check if the DS is commanding autonomous mode.
308 *
309 * @return True if the robot is being commanded to be in autonomous mode
310 */
311bool DriverStation::IsAutonomous() const {
312 HAL_ControlWord controlWord;
313 UpdateControlWord(false, controlWord);
314 return controlWord.autonomous;
315}
316
317/**
318 * Check if the DS is commanding teleop mode.
319 *
320 * @return True if the robot is being commanded to be in teleop mode
321 */
322bool DriverStation::IsOperatorControl() const {
323 HAL_ControlWord controlWord;
324 UpdateControlWord(false, controlWord);
325 return !(controlWord.autonomous || controlWord.test);
326}
327
328/**
329 * Check if the DS is commanding test mode.
330 *
331 * @return True if the robot is being commanded to be in test mode
332 */
333bool DriverStation::IsTest() const {
334 HAL_ControlWord controlWord;
335 UpdateControlWord(false, controlWord);
336 return controlWord.test;
337}
338
339/**
340 * Check if the DS is attached.
341 *
342 * @return True if the DS is connected to the robot
343 */
344bool DriverStation::IsDSAttached() const {
345 HAL_ControlWord controlWord;
346 UpdateControlWord(false, controlWord);
347 return controlWord.dsAttached;
348}
349
350/**
351 * Has a new control packet from the driver station arrived since the last time
352 * this function was called?
353 *
354 * Warning: If you call this function from more than one place at the same time,
355 * you will not get the intended behavior.
356 *
357 * @return True if the control data has been updated since the last call.
358 */
359bool DriverStation::IsNewControlData() const {
360 return m_newControlData.exchange(false);
361}
362
363/**
364 * Is the driver station attached to a Field Management System?
365 *
366 * @return True if the robot is competing on a field being controlled by a Field
367 * Management System
368 */
369bool DriverStation::IsFMSAttached() const {
370 HAL_ControlWord controlWord;
371 UpdateControlWord(false, controlWord);
372 return controlWord.fmsAttached;
373}
374
375/**
376 * Check if the FPGA outputs are enabled.
377 *
378 * The outputs may be disabled if the robot is disabled or e-stopped, the
379 * watchdog has expired, or if the roboRIO browns out.
380 *
381 * @return True if the FPGA outputs are enabled.
382 */
383bool DriverStation::IsSysActive() const {
384 int32_t status = 0;
385 bool retVal = HAL_GetSystemActive(&status);
386 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
387 return retVal;
388}
389
390/**
391 * Check if the system is browned out.
392 *
393 * @return True if the system is browned out
394 */
395bool DriverStation::IsBrownedOut() const {
396 int32_t status = 0;
397 bool retVal = HAL_GetBrownedOut(&status);
398 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
399 return retVal;
400}
401
402/**
403 * Return the alliance that the driver station says it is on.
404 *
405 * This could return kRed or kBlue.
406 *
407 * @return The Alliance enum (kRed, kBlue or kInvalid)
408 */
409DriverStation::Alliance DriverStation::GetAlliance() const {
410 int32_t status = 0;
411 auto allianceStationID = HAL_GetAllianceStation(&status);
412 switch (allianceStationID) {
413 case HAL_AllianceStationID_kRed1:
414 case HAL_AllianceStationID_kRed2:
415 case HAL_AllianceStationID_kRed3:
416 return kRed;
417 case HAL_AllianceStationID_kBlue1:
418 case HAL_AllianceStationID_kBlue2:
419 case HAL_AllianceStationID_kBlue3:
420 return kBlue;
421 default:
422 return kInvalid;
423 }
424}
425
426/**
427 * Return the driver station location on the field.
428 *
429 * This could return 1, 2, or 3.
430 *
431 * @return The location of the driver station (1-3, 0 for invalid)
432 */
433int DriverStation::GetLocation() const {
434 int32_t status = 0;
435 auto allianceStationID = HAL_GetAllianceStation(&status);
436 switch (allianceStationID) {
437 case HAL_AllianceStationID_kRed1:
438 case HAL_AllianceStationID_kBlue1:
439 return 1;
440 case HAL_AllianceStationID_kRed2:
441 case HAL_AllianceStationID_kBlue2:
442 return 2;
443 case HAL_AllianceStationID_kRed3:
444 case HAL_AllianceStationID_kBlue3:
445 return 3;
446 default:
447 return 0;
448 }
449}
450
451/**
452 * Wait until a new packet comes from the driver station.
453 *
454 * This blocks on a semaphore, so the waiting is efficient.
455 *
456 * This is a good way to delay processing until there is new driver station data
457 * to act on.
458 */
459void DriverStation::WaitForData() { WaitForData(0); }
460
461/**
462 * Wait until a new packet comes from the driver station, or wait for a timeout.
463 *
464 * If the timeout is less then or equal to 0, wait indefinitely.
465 *
466 * Timeout is in milliseconds
467 *
468 * This blocks on a semaphore, so the waiting is efficient.
469 *
470 * This is a good way to delay processing until there is new driver station data
471 * to act on.
472 *
473 * @param timeout Timeout time in seconds
474 *
475 * @return true if new data, otherwise false
476 */
477bool DriverStation::WaitForData(double timeout) {
478#if defined(_MSC_VER) && _MSC_VER < 1900
479 auto timeoutTime = std::chrono::steady_clock::now() +
480 std::chrono::duration<int64_t, std::nano>(
481 static_cast<int64_t>(timeout * 1e9));
482#else
483 auto timeoutTime =
484 std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
485#endif
486
487 std::unique_lock<priority_mutex> lock(m_waitForDataMutex);
488 while (!m_waitForDataPredicate) {
489 if (timeout > 0) {
490 auto timedOut = m_waitForDataCond.wait_until(lock, timeoutTime);
491 if (timedOut == std::cv_status::timeout) {
492 return false;
493 }
494 } else {
495 m_waitForDataCond.wait(lock);
496 }
497 }
498 m_waitForDataPredicate = false;
499 return true;
500}
501
502/**
503 * Return the approximate match time.
504 *
505 * The FMS does not send an official match time to the robots, but does send an
506 * approximate match time. The value will count down the time remaining in the
507 * current period (auto or teleop).
508 *
509 * Warning: This is not an official time (so it cannot be used to dispute ref
510 * calls or guarantee that a function will trigger before the match ends).
511 *
512 * The Practice Match function of the DS approximates the behaviour seen on the
513 * field.
514 *
515 * @return Time remaining in current match period (auto or teleop)
516 */
517double DriverStation::GetMatchTime() const {
518 int32_t status;
519 return HAL_GetMatchTime(&status);
520}
521
522/**
523 * Read the battery voltage.
524 *
525 * @return The battery voltage in Volts.
526 */
527double DriverStation::GetBatteryVoltage() const {
528 int32_t status = 0;
529 double voltage = HAL_GetVinVoltage(&status);
530 wpi_setErrorWithContext(status, "getVinVoltage");
531
532 return voltage;
533}
534
535/**
536 * Copy data from the DS task for the user.
537 *
538 * If no new data exists, it will just be returned, otherwise
539 * the data will be copied from the DS polling loop.
540 */
541void DriverStation::GetData() {
542 // Get the status of all of the joysticks, and save to the cache
543 for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
544 HAL_GetJoystickAxes(stick, &m_joystickAxesCache[stick]);
545 HAL_GetJoystickPOVs(stick, &m_joystickPOVsCache[stick]);
546 HAL_GetJoystickButtons(stick, &m_joystickButtonsCache[stick]);
547 HAL_GetJoystickDescriptor(stick, &m_joystickDescriptorCache[stick]);
548 }
549 // Force a control word update, to make sure the data is the newest.
550 HAL_ControlWord controlWord;
551 UpdateControlWord(true, controlWord);
552 // Obtain a write lock on the data, swap the cached data into the
553 // main data arrays
554 std::lock_guard<priority_mutex> lock(m_joystickDataMutex);
555 m_joystickAxes.swap(m_joystickAxesCache);
556 m_joystickPOVs.swap(m_joystickPOVsCache);
557 m_joystickButtons.swap(m_joystickButtonsCache);
558 m_joystickDescriptor.swap(m_joystickDescriptorCache);
559}
560
561/**
562 * DriverStation constructor.
563 *
564 * This is only called once the first time GetInstance() is called
565 */
566DriverStation::DriverStation() {
567 m_joystickAxes = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
568 m_joystickPOVs = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
569 m_joystickButtons = std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
570 m_joystickDescriptor =
571 std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
572 m_joystickAxesCache = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
573 m_joystickPOVsCache = std::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
574 m_joystickButtonsCache =
575 std::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
576 m_joystickDescriptorCache =
577 std::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
578
579 // All joysticks should default to having zero axes, povs and buttons, so
580 // uninitialized memory doesn't get sent to speed controllers.
581 for (unsigned int i = 0; i < kJoystickPorts; i++) {
582 m_joystickAxes[i].count = 0;
583 m_joystickPOVs[i].count = 0;
584 m_joystickButtons[i].count = 0;
585 m_joystickDescriptor[i].isXbox = 0;
586 m_joystickDescriptor[i].type = -1;
587 m_joystickDescriptor[i].name[0] = '\0';
588
589 m_joystickAxesCache[i].count = 0;
590 m_joystickPOVsCache[i].count = 0;
591 m_joystickButtonsCache[i].count = 0;
592 m_joystickDescriptorCache[i].isXbox = 0;
593 m_joystickDescriptorCache[i].type = -1;
594 m_joystickDescriptorCache[i].name[0] = '\0';
595 }
596
597 m_dsThread = std::thread(&DriverStation::Run, this);
598}
599
600/**
601 * Reports errors related to unplugged joysticks
602 * Throttles the errors so that they don't overwhelm the DS
603 */
604void DriverStation::ReportJoystickUnpluggedError(llvm::StringRef message) {
605 double currentTime = Timer::GetFPGATimestamp();
606 if (currentTime > m_nextMessageTime) {
607 ReportError(message);
608 m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
609 }
610}
611
612/**
613 * Reports errors related to unplugged joysticks.
614 *
615 * Throttles the errors so that they don't overwhelm the DS.
616 */
617void DriverStation::ReportJoystickUnpluggedWarning(llvm::StringRef message) {
618 double currentTime = Timer::GetFPGATimestamp();
619 if (currentTime > m_nextMessageTime) {
620 ReportWarning(message);
621 m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
622 }
623}
624
625void DriverStation::Run() {
626 m_isRunning = true;
627 int period = 0;
628 while (m_isRunning) {
629 HAL_WaitForDSData();
630 GetData();
631 // notify IsNewControlData variables
632 m_newControlData = true;
633
634 // notify WaitForData block
635 {
636 std::lock_guard<priority_mutex> lock(m_waitForDataMutex);
637 m_waitForDataPredicate = true;
638 }
639 m_waitForDataCond.notify_all();
640
641 if (++period >= 4) {
642 MotorSafetyHelper::CheckMotors();
643 period = 0;
644 }
645 if (m_userInDisabled) HAL_ObserveUserProgramDisabled();
646 if (m_userInAutonomous) HAL_ObserveUserProgramAutonomous();
647 if (m_userInTeleop) HAL_ObserveUserProgramTeleop();
648 if (m_userInTest) HAL_ObserveUserProgramTest();
649 }
650}
651
652/**
653 * Gets ControlWord data from the cache. If 50ms has passed, or the force
654 * parameter is set, the cached data is updated. Otherwise the data is just
655 * copied from the cache.
656 *
657 * @param force True to force an update to the cache, otherwise update if 50ms
658 * have passed.
659 * @param controlWord Structure to put the return control word data into.
660 */
661void DriverStation::UpdateControlWord(bool force,
662 HAL_ControlWord& controlWord) const {
663 auto now = std::chrono::steady_clock::now();
664 std::lock_guard<priority_mutex> lock(m_controlWordMutex);
665 // Update every 50 ms or on force.
666 if ((now - m_lastControlWordUpdate > std::chrono::milliseconds(50)) ||
667 force) {
668 HAL_GetControlWord(&m_controlWordCache);
669 m_lastControlWordUpdate = now;
670 }
671 controlWord = m_controlWordCache;
672}