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