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