blob: 7c6488340a78f52b44a15356b4844b648e5b16a5 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
Brian Silverman41cdd3e2019-01-19 19:48:58 -08003/* 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 "frc/DriverStation.h"
9
10#include <chrono>
11
James Kuszmaul4b81d302019-12-14 20:53:14 -080012#include <hal/DriverStation.h>
13#include <hal/FRCUsageReporting.h>
14#include <hal/HALBase.h>
Brian Silverman41cdd3e2019-01-19 19:48:58 -080015#include <hal/Power.h>
Brian Silverman41cdd3e2019-01-19 19:48:58 -080016#include <networktables/NetworkTable.h>
17#include <networktables/NetworkTableEntry.h>
18#include <networktables/NetworkTableInstance.h>
19#include <wpi/SmallString.h>
20#include <wpi/StringRef.h>
21
22#include "frc/AnalogInput.h"
23#include "frc/MotorSafety.h"
24#include "frc/Timer.h"
25#include "frc/Utility.h"
26#include "frc/WPIErrors.h"
27
28namespace frc {
29
30class MatchDataSender {
31 public:
32 std::shared_ptr<nt::NetworkTable> table;
33 nt::NetworkTableEntry typeMetadata;
34 nt::NetworkTableEntry gameSpecificMessage;
35 nt::NetworkTableEntry eventName;
36 nt::NetworkTableEntry matchNumber;
37 nt::NetworkTableEntry replayNumber;
38 nt::NetworkTableEntry matchType;
39 nt::NetworkTableEntry alliance;
40 nt::NetworkTableEntry station;
41 nt::NetworkTableEntry controlWord;
42
43 MatchDataSender() {
44 table = nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo");
45 typeMetadata = table->GetEntry(".type");
46 typeMetadata.ForceSetString("FMSInfo");
47 gameSpecificMessage = table->GetEntry("GameSpecificMessage");
48 gameSpecificMessage.ForceSetString("");
49 eventName = table->GetEntry("EventName");
50 eventName.ForceSetString("");
51 matchNumber = table->GetEntry("MatchNumber");
52 matchNumber.ForceSetDouble(0);
53 replayNumber = table->GetEntry("ReplayNumber");
54 replayNumber.ForceSetDouble(0);
55 matchType = table->GetEntry("MatchType");
56 matchType.ForceSetDouble(0);
57 alliance = table->GetEntry("IsRedAlliance");
58 alliance.ForceSetBoolean(true);
59 station = table->GetEntry("StationNumber");
60 station.ForceSetDouble(1);
61 controlWord = table->GetEntry("FMSControlData");
62 controlWord.ForceSetDouble(0);
63 }
64};
65} // namespace frc
66
67using namespace frc;
68
69static constexpr double kJoystickUnpluggedMessageInterval = 1.0;
70
71DriverStation::~DriverStation() {
72 m_isRunning = false;
73 // Trigger a DS mutex release in case there is no driver station running.
74 HAL_ReleaseDSMutex();
75 m_dsThread.join();
76}
77
78DriverStation& DriverStation::GetInstance() {
79 static DriverStation instance;
80 return instance;
81}
82
83void DriverStation::ReportError(const wpi::Twine& error) {
84 wpi::SmallString<128> temp;
85 HAL_SendError(1, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
86 1);
87}
88
89void DriverStation::ReportWarning(const wpi::Twine& error) {
90 wpi::SmallString<128> temp;
91 HAL_SendError(0, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
92 1);
93}
94
95void DriverStation::ReportError(bool isError, int32_t code,
96 const wpi::Twine& error,
97 const wpi::Twine& location,
98 const wpi::Twine& stack) {
99 wpi::SmallString<128> errorTemp;
100 wpi::SmallString<128> locationTemp;
101 wpi::SmallString<128> stackTemp;
102 HAL_SendError(isError, code, 0,
103 error.toNullTerminatedStringRef(errorTemp).data(),
104 location.toNullTerminatedStringRef(locationTemp).data(),
105 stack.toNullTerminatedStringRef(stackTemp).data(), 1);
106}
107
108bool DriverStation::GetStickButton(int stick, int button) {
109 if (stick < 0 || stick >= kJoystickPorts) {
110 wpi_setWPIError(BadJoystickIndex);
111 return false;
112 }
113 if (button <= 0) {
114 ReportJoystickUnpluggedError(
115 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
116 return false;
117 }
118
119 HAL_JoystickButtons buttons;
120 HAL_GetJoystickButtons(stick, &buttons);
121
122 if (button > buttons.count) {
123 ReportJoystickUnpluggedWarning(
124 "Joystick Button missing, check if all controllers are plugged in");
125 return false;
126 }
127
128 return buttons.buttons & 1 << (button - 1);
129}
130
131bool DriverStation::GetStickButtonPressed(int stick, int button) {
132 if (stick < 0 || stick >= kJoystickPorts) {
133 wpi_setWPIError(BadJoystickIndex);
134 return false;
135 }
136 if (button <= 0) {
137 ReportJoystickUnpluggedError(
138 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
139 return false;
140 }
141
142 HAL_JoystickButtons buttons;
143 HAL_GetJoystickButtons(stick, &buttons);
144
145 if (button > buttons.count) {
146 ReportJoystickUnpluggedWarning(
147 "Joystick Button missing, check if all controllers are plugged in");
148 return false;
149 }
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800150 std::unique_lock lock(m_buttonEdgeMutex);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800151 // If button was pressed, clear flag and return true
152 if (m_joystickButtonsPressed[stick] & 1 << (button - 1)) {
153 m_joystickButtonsPressed[stick] &= ~(1 << (button - 1));
154 return true;
155 } else {
156 return false;
157 }
158}
159
160bool DriverStation::GetStickButtonReleased(int stick, int button) {
161 if (stick < 0 || stick >= kJoystickPorts) {
162 wpi_setWPIError(BadJoystickIndex);
163 return false;
164 }
165 if (button <= 0) {
166 ReportJoystickUnpluggedError(
167 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
168 return false;
169 }
170
171 HAL_JoystickButtons buttons;
172 HAL_GetJoystickButtons(stick, &buttons);
173
174 if (button > buttons.count) {
175 ReportJoystickUnpluggedWarning(
176 "Joystick Button missing, check if all controllers are plugged in");
177 return false;
178 }
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800179 std::unique_lock lock(m_buttonEdgeMutex);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800180 // If button was released, clear flag and return true
181 if (m_joystickButtonsReleased[stick] & 1 << (button - 1)) {
182 m_joystickButtonsReleased[stick] &= ~(1 << (button - 1));
183 return true;
184 } else {
185 return false;
186 }
187}
188
189double DriverStation::GetStickAxis(int stick, int axis) {
190 if (stick < 0 || stick >= kJoystickPorts) {
191 wpi_setWPIError(BadJoystickIndex);
192 return 0.0;
193 }
194 if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
195 wpi_setWPIError(BadJoystickAxis);
196 return 0.0;
197 }
198
199 HAL_JoystickAxes axes;
200 HAL_GetJoystickAxes(stick, &axes);
201
202 if (axis >= axes.count) {
203 ReportJoystickUnpluggedWarning(
204 "Joystick Axis missing, check if all controllers are plugged in");
205 return 0.0;
206 }
207
208 return axes.axes[axis];
209}
210
211int DriverStation::GetStickPOV(int stick, int pov) {
212 if (stick < 0 || stick >= kJoystickPorts) {
213 wpi_setWPIError(BadJoystickIndex);
214 return -1;
215 }
216 if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
217 wpi_setWPIError(BadJoystickAxis);
218 return -1;
219 }
220
221 HAL_JoystickPOVs povs;
222 HAL_GetJoystickPOVs(stick, &povs);
223
224 if (pov >= povs.count) {
225 ReportJoystickUnpluggedWarning(
226 "Joystick POV missing, check if all controllers are plugged in");
227 return -1;
228 }
229
230 return povs.povs[pov];
231}
232
233int DriverStation::GetStickButtons(int stick) const {
234 if (stick < 0 || stick >= kJoystickPorts) {
235 wpi_setWPIError(BadJoystickIndex);
236 return 0;
237 }
238
239 HAL_JoystickButtons buttons;
240 HAL_GetJoystickButtons(stick, &buttons);
241
242 return buttons.buttons;
243}
244
245int DriverStation::GetStickAxisCount(int stick) const {
246 if (stick < 0 || stick >= kJoystickPorts) {
247 wpi_setWPIError(BadJoystickIndex);
248 return 0;
249 }
250
251 HAL_JoystickAxes axes;
252 HAL_GetJoystickAxes(stick, &axes);
253
254 return axes.count;
255}
256
257int DriverStation::GetStickPOVCount(int stick) const {
258 if (stick < 0 || stick >= kJoystickPorts) {
259 wpi_setWPIError(BadJoystickIndex);
260 return 0;
261 }
262
263 HAL_JoystickPOVs povs;
264 HAL_GetJoystickPOVs(stick, &povs);
265
266 return povs.count;
267}
268
269int DriverStation::GetStickButtonCount(int stick) const {
270 if (stick < 0 || stick >= kJoystickPorts) {
271 wpi_setWPIError(BadJoystickIndex);
272 return 0;
273 }
274
275 HAL_JoystickButtons buttons;
276 HAL_GetJoystickButtons(stick, &buttons);
277
278 return buttons.count;
279}
280
281bool DriverStation::GetJoystickIsXbox(int stick) const {
282 if (stick < 0 || stick >= kJoystickPorts) {
283 wpi_setWPIError(BadJoystickIndex);
284 return false;
285 }
286
287 HAL_JoystickDescriptor descriptor;
288 HAL_GetJoystickDescriptor(stick, &descriptor);
289
290 return static_cast<bool>(descriptor.isXbox);
291}
292
293int DriverStation::GetJoystickType(int stick) const {
294 if (stick < 0 || stick >= kJoystickPorts) {
295 wpi_setWPIError(BadJoystickIndex);
296 return -1;
297 }
298
299 HAL_JoystickDescriptor descriptor;
300 HAL_GetJoystickDescriptor(stick, &descriptor);
301
302 return static_cast<int>(descriptor.type);
303}
304
305std::string DriverStation::GetJoystickName(int stick) const {
306 if (stick < 0 || stick >= kJoystickPorts) {
307 wpi_setWPIError(BadJoystickIndex);
308 }
309
310 HAL_JoystickDescriptor descriptor;
311 HAL_GetJoystickDescriptor(stick, &descriptor);
312
313 return descriptor.name;
314}
315
316int DriverStation::GetJoystickAxisType(int stick, int axis) const {
317 if (stick < 0 || stick >= kJoystickPorts) {
318 wpi_setWPIError(BadJoystickIndex);
319 return -1;
320 }
321
322 HAL_JoystickDescriptor descriptor;
323 HAL_GetJoystickDescriptor(stick, &descriptor);
324
325 return static_cast<bool>(descriptor.axisTypes);
326}
327
328bool DriverStation::IsEnabled() const {
329 HAL_ControlWord controlWord;
330 HAL_GetControlWord(&controlWord);
331 return controlWord.enabled && controlWord.dsAttached;
332}
333
334bool DriverStation::IsDisabled() const {
335 HAL_ControlWord controlWord;
336 HAL_GetControlWord(&controlWord);
337 return !(controlWord.enabled && controlWord.dsAttached);
338}
339
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800340bool DriverStation::IsEStopped() const {
341 HAL_ControlWord controlWord;
342 HAL_GetControlWord(&controlWord);
343 return controlWord.eStop;
344}
345
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800346bool DriverStation::IsAutonomous() const {
347 HAL_ControlWord controlWord;
348 HAL_GetControlWord(&controlWord);
349 return controlWord.autonomous;
350}
351
352bool DriverStation::IsOperatorControl() const {
353 HAL_ControlWord controlWord;
354 HAL_GetControlWord(&controlWord);
355 return !(controlWord.autonomous || controlWord.test);
356}
357
358bool DriverStation::IsTest() const {
359 HAL_ControlWord controlWord;
360 HAL_GetControlWord(&controlWord);
361 return controlWord.test;
362}
363
364bool DriverStation::IsDSAttached() const {
365 HAL_ControlWord controlWord;
366 HAL_GetControlWord(&controlWord);
367 return controlWord.dsAttached;
368}
369
370bool DriverStation::IsNewControlData() const { return HAL_IsNewControlData(); }
371
372bool DriverStation::IsFMSAttached() const {
373 HAL_ControlWord controlWord;
374 HAL_GetControlWord(&controlWord);
375 return controlWord.fmsAttached;
376}
377
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800378std::string DriverStation::GetGameSpecificMessage() const {
379 HAL_MatchInfo info;
380 HAL_GetMatchInfo(&info);
381 return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
382 info.gameSpecificMessageSize);
383}
384
385std::string DriverStation::GetEventName() const {
386 HAL_MatchInfo info;
387 HAL_GetMatchInfo(&info);
388 return info.eventName;
389}
390
391DriverStation::MatchType DriverStation::GetMatchType() const {
392 HAL_MatchInfo info;
393 HAL_GetMatchInfo(&info);
394 return static_cast<DriverStation::MatchType>(info.matchType);
395}
396
397int DriverStation::GetMatchNumber() const {
398 HAL_MatchInfo info;
399 HAL_GetMatchInfo(&info);
400 return info.matchNumber;
401}
402
403int DriverStation::GetReplayNumber() const {
404 HAL_MatchInfo info;
405 HAL_GetMatchInfo(&info);
406 return info.replayNumber;
407}
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
426int DriverStation::GetLocation() const {
427 int32_t status = 0;
428 auto allianceStationID = HAL_GetAllianceStation(&status);
429 switch (allianceStationID) {
430 case HAL_AllianceStationID_kRed1:
431 case HAL_AllianceStationID_kBlue1:
432 return 1;
433 case HAL_AllianceStationID_kRed2:
434 case HAL_AllianceStationID_kBlue2:
435 return 2;
436 case HAL_AllianceStationID_kRed3:
437 case HAL_AllianceStationID_kBlue3:
438 return 3;
439 default:
440 return 0;
441 }
442}
443
444void DriverStation::WaitForData() { WaitForData(0); }
445
446bool DriverStation::WaitForData(double timeout) {
447 auto timeoutTime =
448 std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
449
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800450 std::unique_lock lock(m_waitForDataMutex);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800451 int currentCount = m_waitForDataCounter;
452 while (m_waitForDataCounter == currentCount) {
453 if (timeout > 0) {
454 auto timedOut = m_waitForDataCond.wait_until(lock, timeoutTime);
455 if (timedOut == std::cv_status::timeout) {
456 return false;
457 }
458 } else {
459 m_waitForDataCond.wait(lock);
460 }
461 }
462 return true;
463}
464
465double DriverStation::GetMatchTime() const {
466 int32_t status;
467 return HAL_GetMatchTime(&status);
468}
469
470double DriverStation::GetBatteryVoltage() const {
471 int32_t status = 0;
472 double voltage = HAL_GetVinVoltage(&status);
473 wpi_setErrorWithContext(status, "getVinVoltage");
474
475 return voltage;
476}
477
James Kuszmaul4b81d302019-12-14 20:53:14 -0800478void DriverStation::WakeupWaitForData() {
479 std::scoped_lock waitLock(m_waitForDataMutex);
480 // Nofify all threads
481 m_waitForDataCounter++;
482 m_waitForDataCond.notify_all();
483}
484
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800485void DriverStation::GetData() {
486 {
487 // Compute the pressed and released buttons
488 HAL_JoystickButtons currentButtons;
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800489 std::unique_lock lock(m_buttonEdgeMutex);
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800490
491 for (int32_t i = 0; i < kJoystickPorts; i++) {
492 HAL_GetJoystickButtons(i, &currentButtons);
493
494 // If buttons weren't pressed and are now, set flags in m_buttonsPressed
495 m_joystickButtonsPressed[i] |=
496 ~m_previousButtonStates[i].buttons & currentButtons.buttons;
497
498 // If buttons were pressed and aren't now, set flags in m_buttonsReleased
499 m_joystickButtonsReleased[i] |=
500 m_previousButtonStates[i].buttons & ~currentButtons.buttons;
501
502 m_previousButtonStates[i] = currentButtons;
503 }
504 }
505
James Kuszmaul4b81d302019-12-14 20:53:14 -0800506 WakeupWaitForData();
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800507 SendMatchData();
508}
509
510DriverStation::DriverStation() {
511 HAL_Initialize(500, 0);
512 m_waitForDataCounter = 0;
513
514 m_matchDataSender = std::make_unique<MatchDataSender>();
515
516 // All joysticks should default to having zero axes, povs and buttons, so
517 // uninitialized memory doesn't get sent to speed controllers.
518 for (unsigned int i = 0; i < kJoystickPorts; i++) {
519 m_joystickButtonsPressed[i] = 0;
520 m_joystickButtonsReleased[i] = 0;
521 m_previousButtonStates[i].count = 0;
522 m_previousButtonStates[i].buttons = 0;
523 }
524
525 m_dsThread = std::thread(&DriverStation::Run, this);
526}
527
528void DriverStation::ReportJoystickUnpluggedError(const wpi::Twine& message) {
529 double currentTime = Timer::GetFPGATimestamp();
530 if (currentTime > m_nextMessageTime) {
531 ReportError(message);
532 m_nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
533 }
534}
535
536void DriverStation::ReportJoystickUnpluggedWarning(const wpi::Twine& message) {
537 double currentTime = Timer::GetFPGATimestamp();
538 if (currentTime > m_nextMessageTime) {
539 ReportWarning(message);
540 m_nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
541 }
542}
543
544void DriverStation::Run() {
545 m_isRunning = true;
546 int safetyCounter = 0;
547 while (m_isRunning) {
548 HAL_WaitForDSData();
549 GetData();
550
551 if (IsDisabled()) safetyCounter = 0;
552
553 if (++safetyCounter >= 4) {
554 MotorSafety::CheckMotors();
555 safetyCounter = 0;
556 }
557 if (m_userInDisabled) HAL_ObserveUserProgramDisabled();
558 if (m_userInAutonomous) HAL_ObserveUserProgramAutonomous();
559 if (m_userInTeleop) HAL_ObserveUserProgramTeleop();
560 if (m_userInTest) HAL_ObserveUserProgramTest();
561 }
562}
563
564void DriverStation::SendMatchData() {
565 int32_t status = 0;
566 HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
567 bool isRedAlliance = false;
568 int stationNumber = 1;
569 switch (alliance) {
570 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
571 isRedAlliance = false;
572 stationNumber = 1;
573 break;
574 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
575 isRedAlliance = false;
576 stationNumber = 2;
577 break;
578 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
579 isRedAlliance = false;
580 stationNumber = 3;
581 break;
582 case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
583 isRedAlliance = true;
584 stationNumber = 1;
585 break;
586 case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
587 isRedAlliance = true;
588 stationNumber = 2;
589 break;
590 default:
591 isRedAlliance = true;
592 stationNumber = 3;
593 break;
594 }
595
596 HAL_MatchInfo tmpDataStore;
597 HAL_GetMatchInfo(&tmpDataStore);
598
599 m_matchDataSender->alliance.SetBoolean(isRedAlliance);
600 m_matchDataSender->station.SetDouble(stationNumber);
601 m_matchDataSender->eventName.SetString(tmpDataStore.eventName);
602 m_matchDataSender->gameSpecificMessage.SetString(
603 std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
604 tmpDataStore.gameSpecificMessageSize));
605 m_matchDataSender->matchNumber.SetDouble(tmpDataStore.matchNumber);
606 m_matchDataSender->replayNumber.SetDouble(tmpDataStore.replayNumber);
607 m_matchDataSender->matchType.SetDouble(
608 static_cast<int>(tmpDataStore.matchType));
609
610 HAL_ControlWord ctlWord;
611 HAL_GetControlWord(&ctlWord);
612 int32_t wordInt = 0;
613 std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
614 m_matchDataSender->controlWord.SetDouble(wordInt);
615}