blob: 37fc65fc7f0662f4ba3980eb1a6298dce2f4613c [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "frc/DriverStation.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <stdint.h>
Brian Silverman8fce7482020-01-05 13:18:21 -08008
Austin Schuh812d0d12021-11-04 20:16:48 -07009#include <array>
10#include <atomic>
11#include <chrono>
12#include <string>
13#include <string_view>
14#include <thread>
15#include <type_traits>
16
17#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080018#include <hal/DriverStation.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070019#include <hal/DriverStationTypes.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080020#include <hal/HALBase.h>
21#include <hal/Power.h>
22#include <networktables/NetworkTable.h>
23#include <networktables/NetworkTableEntry.h>
24#include <networktables/NetworkTableInstance.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070025#include <wpi/condition_variable.h>
26#include <wpi/mutex.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080027
Austin Schuh812d0d12021-11-04 20:16:48 -070028#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080029#include "frc/MotorSafety.h"
30#include "frc/Timer.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080031
32using namespace frc;
33
Austin Schuh812d0d12021-11-04 20:16:48 -070034namespace {
35// A simple class which caches the previous value written to an NT entry
36// Used to prevent redundant, repeated writes of the same value
37template <class T>
38class MatchDataSenderEntry {
39 public:
40 MatchDataSenderEntry(const std::shared_ptr<nt::NetworkTable>& table,
41 std::string_view key, const T& initialVal) {
42 static_assert(std::is_same_v<T, bool> || std::is_same_v<T, double> ||
43 std::is_same_v<T, std::string>,
44 "Invalid type for MatchDataSenderEntry - must be "
45 "to bool, double or std::string");
46
47 ntEntry = table->GetEntry(key);
48 if constexpr (std::is_same_v<T, bool>) {
49 ntEntry.ForceSetBoolean(initialVal);
50 } else if constexpr (std::is_same_v<T, double>) {
51 ntEntry.ForceSetDouble(initialVal);
52 } else if constexpr (std::is_same_v<T, std::string>) {
53 ntEntry.ForceSetString(initialVal);
54 }
55 prevVal = initialVal;
56 }
57
58 void Set(const T& val) {
59 if (val != prevVal) {
60 SetValue(val);
61 prevVal = val;
62 }
63 }
64
65 private:
66 nt::NetworkTableEntry ntEntry;
67 T prevVal;
68
69 void SetValue(bool val) { ntEntry.SetBoolean(val); }
70 void SetValue(double val) { ntEntry.SetDouble(val); }
71 void SetValue(std::string_view val) { ntEntry.SetString(val); }
72};
73
74struct MatchDataSender {
75 std::shared_ptr<nt::NetworkTable> table =
76 nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo");
77 MatchDataSenderEntry<std::string> typeMetaData{table, ".type", "FMSInfo"};
78 MatchDataSenderEntry<std::string> gameSpecificMessage{
79 table, "GameSpecificMessage", ""};
80 MatchDataSenderEntry<std::string> eventName{table, "EventName", ""};
81 MatchDataSenderEntry<double> matchNumber{table, "MatchNumber", 0.0};
82 MatchDataSenderEntry<double> replayNumber{table, "ReplayNumber", 0.0};
83 MatchDataSenderEntry<double> matchType{table, "MatchType", 0.0};
84 MatchDataSenderEntry<bool> alliance{table, "IsRedAlliance", true};
85 MatchDataSenderEntry<double> station{table, "StationNumber", 1.0};
86 MatchDataSenderEntry<double> controlWord{table, "FMSControlData", 0.0};
87};
88
89struct Instance {
90 Instance();
91 ~Instance();
92
93 MatchDataSender matchDataSender;
94
95 // Joystick button rising/falling edge flags
96 wpi::mutex buttonEdgeMutex;
97 std::array<HAL_JoystickButtons, DriverStation::kJoystickPorts>
98 previousButtonStates;
99 std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsPressed;
100 std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsReleased;
101
102 // Internal Driver Station thread
103 std::thread dsThread;
104 std::atomic<bool> isRunning{false};
105
106 mutable wpi::mutex waitForDataMutex;
107 wpi::condition_variable waitForDataCond;
108 int waitForDataCounter = 0;
109
110 bool silenceJoystickWarning = false;
111
112 // Robot state status variables
113 bool userInDisabled = false;
114 bool userInAutonomous = false;
115 bool userInTeleop = false;
116 bool userInTest = false;
117
118 units::second_t nextMessageTime = 0_s;
119};
120} // namespace
121
122static constexpr auto kJoystickUnpluggedMessageInterval = 1_s;
123
124static Instance& GetInstance() {
125 static Instance instance;
126 return instance;
127}
128
129static void Run();
130static void SendMatchData();
131
132/**
133 * Reports errors related to unplugged joysticks.
134 *
135 * Throttles the errors so that they don't overwhelm the DS.
136 */
137static void ReportJoystickUnpluggedErrorV(fmt::string_view format,
138 fmt::format_args args);
139
140template <typename S, typename... Args>
141static inline void ReportJoystickUnpluggedError(const S& format,
142 Args&&... args) {
143 ReportJoystickUnpluggedErrorV(
144 format, fmt::make_args_checked<Args...>(format, args...));
145}
146
147/**
148 * Reports errors related to unplugged joysticks.
149 *
150 * Throttles the errors so that they don't overwhelm the DS.
151 */
152static void ReportJoystickUnpluggedWarningV(fmt::string_view format,
153 fmt::format_args args);
154
155template <typename S, typename... Args>
156static inline void ReportJoystickUnpluggedWarning(const S& format,
157 Args&&... args) {
158 ReportJoystickUnpluggedWarningV(
159 format, fmt::make_args_checked<Args...>(format, args...));
160}
Brian Silverman8fce7482020-01-05 13:18:21 -0800161
Austin Schuh1e69f942020-11-14 15:06:14 -0800162static int& GetDSLastCount() {
163 // There is a rollover error condition here. At Packet# = n * (uintmax), this
164 // will return false when instead it should return true. However, this at a
165 // 20ms rate occurs once every 2.7 years of DS connected runtime, so not
166 // worth the cycles to check.
167 thread_local int lastCount{0};
168 return lastCount;
169}
170
Austin Schuh812d0d12021-11-04 20:16:48 -0700171Instance::Instance() {
172 HAL_Initialize(500, 0);
173
174 // All joysticks should default to having zero axes, povs and buttons, so
175 // uninitialized memory doesn't get sent to motor controllers.
176 for (unsigned int i = 0; i < DriverStation::kJoystickPorts; i++) {
177 joystickButtonsPressed[i] = 0;
178 joystickButtonsReleased[i] = 0;
179 previousButtonStates[i].count = 0;
180 previousButtonStates[i].buttons = 0;
181 }
182
183 dsThread = std::thread(&Run);
184}
185
186Instance::~Instance() {
187 isRunning = false;
Brian Silverman8fce7482020-01-05 13:18:21 -0800188 // Trigger a DS mutex release in case there is no driver station running.
189 HAL_ReleaseDSMutex();
Austin Schuh812d0d12021-11-04 20:16:48 -0700190 dsThread.join();
Brian Silverman8fce7482020-01-05 13:18:21 -0800191}
192
193DriverStation& DriverStation::GetInstance() {
Austin Schuh812d0d12021-11-04 20:16:48 -0700194 ::GetInstance();
Brian Silverman8fce7482020-01-05 13:18:21 -0800195 static DriverStation instance;
196 return instance;
197}
198
Brian Silverman8fce7482020-01-05 13:18:21 -0800199bool DriverStation::GetStickButton(int stick, int button) {
200 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700201 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800202 return false;
203 }
204 if (button <= 0) {
205 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700206 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800207 return false;
208 }
209
210 HAL_JoystickButtons buttons;
211 HAL_GetJoystickButtons(stick, &buttons);
212
213 if (button > buttons.count) {
214 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700215 "Joystick Button {} missing (max {}), check if all controllers are "
216 "plugged in",
217 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800218 return false;
219 }
220
221 return buttons.buttons & 1 << (button - 1);
222}
223
224bool DriverStation::GetStickButtonPressed(int stick, int button) {
225 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700226 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800227 return false;
228 }
229 if (button <= 0) {
230 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700231 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800232 return false;
233 }
234
235 HAL_JoystickButtons buttons;
236 HAL_GetJoystickButtons(stick, &buttons);
237
238 if (button > buttons.count) {
239 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700240 "Joystick Button {} missing (max {}), check if all controllers are "
241 "plugged in",
242 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800243 return false;
244 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700245 auto& inst = ::GetInstance();
246 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800247 // If button was pressed, clear flag and return true
Austin Schuh812d0d12021-11-04 20:16:48 -0700248 if (inst.joystickButtonsPressed[stick] & 1 << (button - 1)) {
249 inst.joystickButtonsPressed[stick] &= ~(1 << (button - 1));
Brian Silverman8fce7482020-01-05 13:18:21 -0800250 return true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800251 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700252 return false;
Brian Silverman8fce7482020-01-05 13:18:21 -0800253}
254
255bool DriverStation::GetStickButtonReleased(int stick, int button) {
256 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700257 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800258 return false;
259 }
260 if (button <= 0) {
261 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700262 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800263 return false;
264 }
265
266 HAL_JoystickButtons buttons;
267 HAL_GetJoystickButtons(stick, &buttons);
268
269 if (button > buttons.count) {
270 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700271 "Joystick Button {} missing (max {}), check if all controllers are "
272 "plugged in",
273 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800274 return false;
275 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700276 auto& inst = ::GetInstance();
277 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800278 // If button was released, clear flag and return true
Austin Schuh812d0d12021-11-04 20:16:48 -0700279 if (inst.joystickButtonsReleased[stick] & 1 << (button - 1)) {
280 inst.joystickButtonsReleased[stick] &= ~(1 << (button - 1));
Brian Silverman8fce7482020-01-05 13:18:21 -0800281 return true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800282 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700283 return false;
Brian Silverman8fce7482020-01-05 13:18:21 -0800284}
285
286double DriverStation::GetStickAxis(int stick, int axis) {
287 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700288 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800289 return 0.0;
290 }
291 if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700292 FRC_ReportError(warn::BadJoystickAxis, "axis {} out of range", axis);
Brian Silverman8fce7482020-01-05 13:18:21 -0800293 return 0.0;
294 }
295
296 HAL_JoystickAxes axes;
297 HAL_GetJoystickAxes(stick, &axes);
298
299 if (axis >= axes.count) {
300 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700301 "Joystick Axis {} missing (max {}), check if all controllers are "
302 "plugged in",
303 axis, axes.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800304 return 0.0;
305 }
306
307 return axes.axes[axis];
308}
309
310int DriverStation::GetStickPOV(int stick, int pov) {
311 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700312 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800313 return -1;
314 }
315 if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700316 FRC_ReportError(warn::BadJoystickAxis, "POV {} out of range", pov);
Brian Silverman8fce7482020-01-05 13:18:21 -0800317 return -1;
318 }
319
320 HAL_JoystickPOVs povs;
321 HAL_GetJoystickPOVs(stick, &povs);
322
323 if (pov >= povs.count) {
324 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700325 "Joystick POV {} missing (max {}), check if all controllers are "
326 "plugged in",
327 pov, povs.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800328 return -1;
329 }
330
331 return povs.povs[pov];
332}
333
Austin Schuh812d0d12021-11-04 20:16:48 -0700334int DriverStation::GetStickButtons(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800335 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700336 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800337 return 0;
338 }
339
340 HAL_JoystickButtons buttons;
341 HAL_GetJoystickButtons(stick, &buttons);
342
343 return buttons.buttons;
344}
345
Austin Schuh812d0d12021-11-04 20:16:48 -0700346int DriverStation::GetStickAxisCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800347 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700348 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800349 return 0;
350 }
351
352 HAL_JoystickAxes axes;
353 HAL_GetJoystickAxes(stick, &axes);
354
355 return axes.count;
356}
357
Austin Schuh812d0d12021-11-04 20:16:48 -0700358int DriverStation::GetStickPOVCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800359 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700360 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800361 return 0;
362 }
363
364 HAL_JoystickPOVs povs;
365 HAL_GetJoystickPOVs(stick, &povs);
366
367 return povs.count;
368}
369
Austin Schuh812d0d12021-11-04 20:16:48 -0700370int DriverStation::GetStickButtonCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800371 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700372 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800373 return 0;
374 }
375
376 HAL_JoystickButtons buttons;
377 HAL_GetJoystickButtons(stick, &buttons);
378
379 return buttons.count;
380}
381
Austin Schuh812d0d12021-11-04 20:16:48 -0700382bool DriverStation::GetJoystickIsXbox(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800383 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700384 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800385 return false;
386 }
387
388 HAL_JoystickDescriptor descriptor;
389 HAL_GetJoystickDescriptor(stick, &descriptor);
390
391 return static_cast<bool>(descriptor.isXbox);
392}
393
Austin Schuh812d0d12021-11-04 20:16:48 -0700394int DriverStation::GetJoystickType(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800395 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700396 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800397 return -1;
398 }
399
400 HAL_JoystickDescriptor descriptor;
401 HAL_GetJoystickDescriptor(stick, &descriptor);
402
403 return static_cast<int>(descriptor.type);
404}
405
Austin Schuh812d0d12021-11-04 20:16:48 -0700406std::string DriverStation::GetJoystickName(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800407 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700408 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800409 }
410
411 HAL_JoystickDescriptor descriptor;
412 HAL_GetJoystickDescriptor(stick, &descriptor);
413
414 return descriptor.name;
415}
416
Austin Schuh812d0d12021-11-04 20:16:48 -0700417int DriverStation::GetJoystickAxisType(int stick, int axis) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800418 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700419 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800420 return -1;
421 }
422
423 HAL_JoystickDescriptor descriptor;
424 HAL_GetJoystickDescriptor(stick, &descriptor);
425
426 return static_cast<bool>(descriptor.axisTypes);
427}
428
Austin Schuh812d0d12021-11-04 20:16:48 -0700429bool DriverStation::IsJoystickConnected(int stick) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800430 return GetStickAxisCount(stick) > 0 || GetStickButtonCount(stick) > 0 ||
431 GetStickPOVCount(stick) > 0;
432}
433
Austin Schuh812d0d12021-11-04 20:16:48 -0700434bool DriverStation::IsEnabled() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800435 HAL_ControlWord controlWord;
436 HAL_GetControlWord(&controlWord);
437 return controlWord.enabled && controlWord.dsAttached;
438}
439
Austin Schuh812d0d12021-11-04 20:16:48 -0700440bool DriverStation::IsDisabled() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800441 HAL_ControlWord controlWord;
442 HAL_GetControlWord(&controlWord);
443 return !(controlWord.enabled && controlWord.dsAttached);
444}
445
Austin Schuh812d0d12021-11-04 20:16:48 -0700446bool DriverStation::IsEStopped() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800447 HAL_ControlWord controlWord;
448 HAL_GetControlWord(&controlWord);
449 return controlWord.eStop;
450}
451
Austin Schuh812d0d12021-11-04 20:16:48 -0700452bool DriverStation::IsAutonomous() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800453 HAL_ControlWord controlWord;
454 HAL_GetControlWord(&controlWord);
455 return controlWord.autonomous;
456}
457
Austin Schuh812d0d12021-11-04 20:16:48 -0700458bool DriverStation::IsAutonomousEnabled() {
Austin Schuh1e69f942020-11-14 15:06:14 -0800459 HAL_ControlWord controlWord;
460 HAL_GetControlWord(&controlWord);
461 return controlWord.autonomous && controlWord.enabled;
462}
463
Austin Schuh812d0d12021-11-04 20:16:48 -0700464bool DriverStation::IsOperatorControl() {
465 return IsTeleop();
466}
467
468bool DriverStation::IsTeleop() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800469 HAL_ControlWord controlWord;
470 HAL_GetControlWord(&controlWord);
471 return !(controlWord.autonomous || controlWord.test);
472}
473
Austin Schuh812d0d12021-11-04 20:16:48 -0700474bool DriverStation::IsOperatorControlEnabled() {
475 return IsTeleopEnabled();
476}
477
478bool DriverStation::IsTeleopEnabled() {
Austin Schuh1e69f942020-11-14 15:06:14 -0800479 HAL_ControlWord controlWord;
480 HAL_GetControlWord(&controlWord);
481 return !controlWord.autonomous && !controlWord.test && controlWord.enabled;
482}
483
Austin Schuh812d0d12021-11-04 20:16:48 -0700484bool DriverStation::IsTest() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800485 HAL_ControlWord controlWord;
486 HAL_GetControlWord(&controlWord);
487 return controlWord.test;
488}
489
Austin Schuh812d0d12021-11-04 20:16:48 -0700490bool DriverStation::IsDSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800491 HAL_ControlWord controlWord;
492 HAL_GetControlWord(&controlWord);
493 return controlWord.dsAttached;
494}
495
Austin Schuh812d0d12021-11-04 20:16:48 -0700496bool DriverStation::IsNewControlData() {
497 auto& inst = ::GetInstance();
498 std::unique_lock lock(inst.waitForDataMutex);
Austin Schuh1e69f942020-11-14 15:06:14 -0800499 int& lastCount = GetDSLastCount();
Austin Schuh812d0d12021-11-04 20:16:48 -0700500 int currentCount = inst.waitForDataCounter;
501 if (lastCount == currentCount) {
502 return false;
503 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800504 lastCount = currentCount;
505 return true;
506}
Brian Silverman8fce7482020-01-05 13:18:21 -0800507
Austin Schuh812d0d12021-11-04 20:16:48 -0700508bool DriverStation::IsFMSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800509 HAL_ControlWord controlWord;
510 HAL_GetControlWord(&controlWord);
511 return controlWord.fmsAttached;
512}
513
Austin Schuh812d0d12021-11-04 20:16:48 -0700514std::string DriverStation::GetGameSpecificMessage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800515 HAL_MatchInfo info;
516 HAL_GetMatchInfo(&info);
517 return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
518 info.gameSpecificMessageSize);
519}
520
Austin Schuh812d0d12021-11-04 20:16:48 -0700521std::string DriverStation::GetEventName() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800522 HAL_MatchInfo info;
523 HAL_GetMatchInfo(&info);
524 return info.eventName;
525}
526
Austin Schuh812d0d12021-11-04 20:16:48 -0700527DriverStation::MatchType DriverStation::GetMatchType() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800528 HAL_MatchInfo info;
529 HAL_GetMatchInfo(&info);
530 return static_cast<DriverStation::MatchType>(info.matchType);
531}
532
Austin Schuh812d0d12021-11-04 20:16:48 -0700533int DriverStation::GetMatchNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800534 HAL_MatchInfo info;
535 HAL_GetMatchInfo(&info);
536 return info.matchNumber;
537}
538
Austin Schuh812d0d12021-11-04 20:16:48 -0700539int DriverStation::GetReplayNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800540 HAL_MatchInfo info;
541 HAL_GetMatchInfo(&info);
542 return info.replayNumber;
543}
544
Austin Schuh812d0d12021-11-04 20:16:48 -0700545DriverStation::Alliance DriverStation::GetAlliance() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800546 int32_t status = 0;
547 auto allianceStationID = HAL_GetAllianceStation(&status);
548 switch (allianceStationID) {
549 case HAL_AllianceStationID_kRed1:
550 case HAL_AllianceStationID_kRed2:
551 case HAL_AllianceStationID_kRed3:
552 return kRed;
553 case HAL_AllianceStationID_kBlue1:
554 case HAL_AllianceStationID_kBlue2:
555 case HAL_AllianceStationID_kBlue3:
556 return kBlue;
557 default:
558 return kInvalid;
559 }
560}
561
Austin Schuh812d0d12021-11-04 20:16:48 -0700562int DriverStation::GetLocation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800563 int32_t status = 0;
564 auto allianceStationID = HAL_GetAllianceStation(&status);
565 switch (allianceStationID) {
566 case HAL_AllianceStationID_kRed1:
567 case HAL_AllianceStationID_kBlue1:
568 return 1;
569 case HAL_AllianceStationID_kRed2:
570 case HAL_AllianceStationID_kBlue2:
571 return 2;
572 case HAL_AllianceStationID_kRed3:
573 case HAL_AllianceStationID_kBlue3:
574 return 3;
575 default:
576 return 0;
577 }
578}
579
Austin Schuh812d0d12021-11-04 20:16:48 -0700580void DriverStation::WaitForData() {
581 WaitForData(0_s);
582}
Brian Silverman8fce7482020-01-05 13:18:21 -0800583
Austin Schuh812d0d12021-11-04 20:16:48 -0700584bool DriverStation::WaitForData(units::second_t timeout) {
585 auto& inst = ::GetInstance();
586 auto timeoutTime = std::chrono::steady_clock::now() +
587 std::chrono::steady_clock::duration{timeout};
Brian Silverman8fce7482020-01-05 13:18:21 -0800588
Austin Schuh812d0d12021-11-04 20:16:48 -0700589 std::unique_lock lock(inst.waitForDataMutex);
Austin Schuh1e69f942020-11-14 15:06:14 -0800590 int& lastCount = GetDSLastCount();
Austin Schuh812d0d12021-11-04 20:16:48 -0700591 int currentCount = inst.waitForDataCounter;
Austin Schuh1e69f942020-11-14 15:06:14 -0800592 if (lastCount != currentCount) {
593 lastCount = currentCount;
594 return true;
595 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700596 while (inst.waitForDataCounter == currentCount) {
597 if (timeout > 0_s) {
598 auto timedOut = inst.waitForDataCond.wait_until(lock, timeoutTime);
Brian Silverman8fce7482020-01-05 13:18:21 -0800599 if (timedOut == std::cv_status::timeout) {
600 return false;
601 }
602 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700603 inst.waitForDataCond.wait(lock);
Brian Silverman8fce7482020-01-05 13:18:21 -0800604 }
605 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700606 lastCount = inst.waitForDataCounter;
Brian Silverman8fce7482020-01-05 13:18:21 -0800607 return true;
608}
609
Austin Schuh812d0d12021-11-04 20:16:48 -0700610double DriverStation::GetMatchTime() {
611 int32_t status = 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800612 return HAL_GetMatchTime(&status);
613}
614
Austin Schuh812d0d12021-11-04 20:16:48 -0700615double DriverStation::GetBatteryVoltage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800616 int32_t status = 0;
617 double voltage = HAL_GetVinVoltage(&status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700618 FRC_CheckErrorStatus(status, "{}", "getVinVoltage");
Brian Silverman8fce7482020-01-05 13:18:21 -0800619
620 return voltage;
621}
622
Austin Schuh812d0d12021-11-04 20:16:48 -0700623void DriverStation::InDisabled(bool entering) {
624 ::GetInstance().userInDisabled = entering;
Brian Silverman8fce7482020-01-05 13:18:21 -0800625}
626
Austin Schuh812d0d12021-11-04 20:16:48 -0700627void DriverStation::InAutonomous(bool entering) {
628 ::GetInstance().userInAutonomous = entering;
629}
630
631void DriverStation::InOperatorControl(bool entering) {
632 InTeleop(entering);
633}
634
635void DriverStation::InTeleop(bool entering) {
636 ::GetInstance().userInTeleop = entering;
637}
638
639void DriverStation::InTest(bool entering) {
640 ::GetInstance().userInTest = entering;
641}
642
643void DriverStation::WakeupWaitForData() {
644 auto& inst = ::GetInstance();
645 std::scoped_lock waitLock(inst.waitForDataMutex);
646 // Nofify all threads
647 inst.waitForDataCounter++;
648 inst.waitForDataCond.notify_all();
649}
650
651/**
652 * Copy data from the DS task for the user.
653 *
654 * If no new data exists, it will just be returned, otherwise
655 * the data will be copied from the DS polling loop.
656 */
657void GetData() {
658 auto& inst = ::GetInstance();
Brian Silverman8fce7482020-01-05 13:18:21 -0800659 {
660 // Compute the pressed and released buttons
661 HAL_JoystickButtons currentButtons;
Austin Schuh812d0d12021-11-04 20:16:48 -0700662 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800663
Austin Schuh812d0d12021-11-04 20:16:48 -0700664 for (int32_t i = 0; i < DriverStation::kJoystickPorts; i++) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800665 HAL_GetJoystickButtons(i, &currentButtons);
666
667 // If buttons weren't pressed and are now, set flags in m_buttonsPressed
Austin Schuh812d0d12021-11-04 20:16:48 -0700668 inst.joystickButtonsPressed[i] |=
669 ~inst.previousButtonStates[i].buttons & currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800670
671 // If buttons were pressed and aren't now, set flags in m_buttonsReleased
Austin Schuh812d0d12021-11-04 20:16:48 -0700672 inst.joystickButtonsReleased[i] |=
673 inst.previousButtonStates[i].buttons & ~currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800674
Austin Schuh812d0d12021-11-04 20:16:48 -0700675 inst.previousButtonStates[i] = currentButtons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800676 }
677 }
678
Austin Schuh812d0d12021-11-04 20:16:48 -0700679 DriverStation::WakeupWaitForData();
Brian Silverman8fce7482020-01-05 13:18:21 -0800680 SendMatchData();
681}
682
Austin Schuh1e69f942020-11-14 15:06:14 -0800683void DriverStation::SilenceJoystickConnectionWarning(bool silence) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700684 ::GetInstance().silenceJoystickWarning = silence;
Austin Schuh1e69f942020-11-14 15:06:14 -0800685}
686
Austin Schuh812d0d12021-11-04 20:16:48 -0700687bool DriverStation::IsJoystickConnectionWarningSilenced() {
688 return !IsFMSAttached() && ::GetInstance().silenceJoystickWarning;
Austin Schuh1e69f942020-11-14 15:06:14 -0800689}
690
Austin Schuh812d0d12021-11-04 20:16:48 -0700691void ReportJoystickUnpluggedErrorV(fmt::string_view format,
692 fmt::format_args args) {
693 auto& inst = GetInstance();
694 auto currentTime = Timer::GetFPGATimestamp();
695 if (currentTime > inst.nextMessageTime) {
696 ReportErrorV(err::Error, "", 0, "", format, args);
697 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Brian Silverman8fce7482020-01-05 13:18:21 -0800698 }
699}
700
Austin Schuh812d0d12021-11-04 20:16:48 -0700701void ReportJoystickUnpluggedWarningV(fmt::string_view format,
702 fmt::format_args args) {
703 auto& inst = GetInstance();
704 if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
705 auto currentTime = Timer::GetFPGATimestamp();
706 if (currentTime > inst.nextMessageTime) {
707 ReportErrorV(warn::Warning, "", 0, "", format, args);
708 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Austin Schuh1e69f942020-11-14 15:06:14 -0800709 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800710 }
711}
712
Austin Schuh812d0d12021-11-04 20:16:48 -0700713void Run() {
714 auto& inst = GetInstance();
715 inst.isRunning = true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800716 int safetyCounter = 0;
Austin Schuh812d0d12021-11-04 20:16:48 -0700717 while (inst.isRunning) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800718 HAL_WaitForDSData();
719 GetData();
720
Austin Schuh812d0d12021-11-04 20:16:48 -0700721 if (DriverStation::IsDisabled()) {
722 safetyCounter = 0;
723 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800724
725 if (++safetyCounter >= 4) {
726 MotorSafety::CheckMotors();
727 safetyCounter = 0;
728 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700729 if (inst.userInDisabled) {
730 HAL_ObserveUserProgramDisabled();
731 }
732 if (inst.userInAutonomous) {
733 HAL_ObserveUserProgramAutonomous();
734 }
735 if (inst.userInTeleop) {
736 HAL_ObserveUserProgramTeleop();
737 }
738 if (inst.userInTest) {
739 HAL_ObserveUserProgramTest();
740 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800741 }
742}
743
Austin Schuh812d0d12021-11-04 20:16:48 -0700744void SendMatchData() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800745 int32_t status = 0;
746 HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
747 bool isRedAlliance = false;
748 int stationNumber = 1;
749 switch (alliance) {
750 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
751 isRedAlliance = false;
752 stationNumber = 1;
753 break;
754 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
755 isRedAlliance = false;
756 stationNumber = 2;
757 break;
758 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
759 isRedAlliance = false;
760 stationNumber = 3;
761 break;
762 case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
763 isRedAlliance = true;
764 stationNumber = 1;
765 break;
766 case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
767 isRedAlliance = true;
768 stationNumber = 2;
769 break;
770 default:
771 isRedAlliance = true;
772 stationNumber = 3;
773 break;
774 }
775
776 HAL_MatchInfo tmpDataStore;
777 HAL_GetMatchInfo(&tmpDataStore);
778
Austin Schuh812d0d12021-11-04 20:16:48 -0700779 auto& inst = GetInstance();
780 inst.matchDataSender.alliance.Set(isRedAlliance);
781 inst.matchDataSender.station.Set(stationNumber);
782 inst.matchDataSender.eventName.Set(tmpDataStore.eventName);
783 inst.matchDataSender.gameSpecificMessage.Set(
Brian Silverman8fce7482020-01-05 13:18:21 -0800784 std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
785 tmpDataStore.gameSpecificMessageSize));
Austin Schuh812d0d12021-11-04 20:16:48 -0700786 inst.matchDataSender.matchNumber.Set(tmpDataStore.matchNumber);
787 inst.matchDataSender.replayNumber.Set(tmpDataStore.replayNumber);
788 inst.matchDataSender.matchType.Set(static_cast<int>(tmpDataStore.matchType));
Brian Silverman8fce7482020-01-05 13:18:21 -0800789
790 HAL_ControlWord ctlWord;
791 HAL_GetControlWord(&ctlWord);
792 int32_t wordInt = 0;
793 std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
Austin Schuh812d0d12021-11-04 20:16:48 -0700794 inst.matchDataSender.controlWord.Set(wordInt);
Brian Silverman8fce7482020-01-05 13:18:21 -0800795}