blob: 8f80427d2284ed3229e0b13f80365b5e8a1b8022 [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>
James Kuszmaulcf324122023-01-14 14:07:17 -080012#include <span>
Austin Schuh812d0d12021-11-04 20:16:48 -070013#include <string>
14#include <string_view>
15#include <thread>
16#include <type_traits>
17
18#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080019#include <hal/DriverStation.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070020#include <hal/DriverStationTypes.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080021#include <hal/HALBase.h>
22#include <hal/Power.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080023#include <networktables/BooleanTopic.h>
24#include <networktables/IntegerTopic.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080025#include <networktables/NetworkTable.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080026#include <networktables/NetworkTableInstance.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080027#include <networktables/StringTopic.h>
28#include <wpi/DataLog.h>
29#include <wpi/EventVector.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070030#include <wpi/condition_variable.h>
31#include <wpi/mutex.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080032#include <wpi/timestamp.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080033
Austin Schuh812d0d12021-11-04 20:16:48 -070034#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080035#include "frc/MotorSafety.h"
36#include "frc/Timer.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080037
38using namespace frc;
39
Austin Schuh812d0d12021-11-04 20:16:48 -070040namespace {
41// A simple class which caches the previous value written to an NT entry
42// Used to prevent redundant, repeated writes of the same value
James Kuszmaulcf324122023-01-14 14:07:17 -080043template <typename Topic>
Austin Schuh812d0d12021-11-04 20:16:48 -070044class MatchDataSenderEntry {
45 public:
46 MatchDataSenderEntry(const std::shared_ptr<nt::NetworkTable>& table,
James Kuszmaulcf324122023-01-14 14:07:17 -080047 std::string_view key,
48 typename Topic::ParamType initialVal)
49 : publisher{Topic{table->GetTopic(key)}.Publish()}, prevVal{initialVal} {
50 publisher.Set(initialVal);
Austin Schuh812d0d12021-11-04 20:16:48 -070051 }
52
James Kuszmaulcf324122023-01-14 14:07:17 -080053 void Set(typename Topic::ParamType val) {
Austin Schuh812d0d12021-11-04 20:16:48 -070054 if (val != prevVal) {
James Kuszmaulcf324122023-01-14 14:07:17 -080055 publisher.Set(val);
Austin Schuh812d0d12021-11-04 20:16:48 -070056 prevVal = val;
57 }
58 }
59
60 private:
James Kuszmaulcf324122023-01-14 14:07:17 -080061 typename Topic::PublisherType publisher;
62 typename Topic::ValueType prevVal;
Austin Schuh812d0d12021-11-04 20:16:48 -070063};
64
65struct MatchDataSender {
66 std::shared_ptr<nt::NetworkTable> table =
67 nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo");
James Kuszmaulcf324122023-01-14 14:07:17 -080068 MatchDataSenderEntry<nt::StringTopic> typeMetaData{table, ".type", "FMSInfo"};
69 MatchDataSenderEntry<nt::StringTopic> gameSpecificMessage{
Austin Schuh812d0d12021-11-04 20:16:48 -070070 table, "GameSpecificMessage", ""};
James Kuszmaulcf324122023-01-14 14:07:17 -080071 MatchDataSenderEntry<nt::StringTopic> eventName{table, "EventName", ""};
72 MatchDataSenderEntry<nt::IntegerTopic> matchNumber{table, "MatchNumber", 0};
73 MatchDataSenderEntry<nt::IntegerTopic> replayNumber{table, "ReplayNumber", 0};
74 MatchDataSenderEntry<nt::IntegerTopic> matchType{table, "MatchType", 0};
75 MatchDataSenderEntry<nt::BooleanTopic> alliance{table, "IsRedAlliance", true};
76 MatchDataSenderEntry<nt::IntegerTopic> station{table, "StationNumber", 1};
77 MatchDataSenderEntry<nt::IntegerTopic> controlWord{table, "FMSControlData",
78 0};
79};
80
81class JoystickLogSender {
82 public:
83 void Init(wpi::log::DataLog& log, unsigned int stick, int64_t timestamp);
84 void Send(uint64_t timestamp);
85
86 private:
87 void AppendButtons(HAL_JoystickButtons buttons, uint64_t timestamp);
88 void AppendPOVs(const HAL_JoystickPOVs& povs, uint64_t timestamp);
89
90 unsigned int m_stick;
91 HAL_JoystickButtons m_prevButtons;
92 HAL_JoystickAxes m_prevAxes;
93 HAL_JoystickPOVs m_prevPOVs;
94 wpi::log::BooleanArrayLogEntry m_logButtons;
95 wpi::log::FloatArrayLogEntry m_logAxes;
96 wpi::log::IntegerArrayLogEntry m_logPOVs;
97};
98
99class DataLogSender {
100 public:
101 void Init(wpi::log::DataLog& log, bool logJoysticks, int64_t timestamp);
102 void Send(uint64_t timestamp);
103
104 private:
105 std::atomic_bool m_initialized{false};
106
107 HAL_ControlWord m_prevControlWord;
108 wpi::log::BooleanLogEntry m_logEnabled;
109 wpi::log::BooleanLogEntry m_logAutonomous;
110 wpi::log::BooleanLogEntry m_logTest;
111 wpi::log::BooleanLogEntry m_logEstop;
112
113 bool m_logJoysticks;
114 std::array<JoystickLogSender, DriverStation::kJoystickPorts> m_joysticks;
Austin Schuh812d0d12021-11-04 20:16:48 -0700115};
116
117struct Instance {
118 Instance();
119 ~Instance();
120
James Kuszmaulcf324122023-01-14 14:07:17 -0800121 wpi::EventVector refreshEvents;
Austin Schuh812d0d12021-11-04 20:16:48 -0700122 MatchDataSender matchDataSender;
James Kuszmaulcf324122023-01-14 14:07:17 -0800123 std::atomic<DataLogSender*> dataLogSender{nullptr};
Austin Schuh812d0d12021-11-04 20:16:48 -0700124
125 // Joystick button rising/falling edge flags
126 wpi::mutex buttonEdgeMutex;
127 std::array<HAL_JoystickButtons, DriverStation::kJoystickPorts>
128 previousButtonStates;
129 std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsPressed;
130 std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsReleased;
131
Austin Schuh812d0d12021-11-04 20:16:48 -0700132 bool silenceJoystickWarning = false;
133
134 // Robot state status variables
135 bool userInDisabled = false;
136 bool userInAutonomous = false;
137 bool userInTeleop = false;
138 bool userInTest = false;
139
140 units::second_t nextMessageTime = 0_s;
141};
142} // namespace
143
144static constexpr auto kJoystickUnpluggedMessageInterval = 1_s;
145
146static Instance& GetInstance() {
147 static Instance instance;
148 return instance;
149}
150
Austin Schuh812d0d12021-11-04 20:16:48 -0700151static void SendMatchData();
152
153/**
154 * Reports errors related to unplugged joysticks.
155 *
156 * Throttles the errors so that they don't overwhelm the DS.
157 */
158static void ReportJoystickUnpluggedErrorV(fmt::string_view format,
159 fmt::format_args args);
160
161template <typename S, typename... Args>
162static inline void ReportJoystickUnpluggedError(const S& format,
163 Args&&... args) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800164 ReportJoystickUnpluggedErrorV(format, fmt::make_format_args(args...));
Austin Schuh812d0d12021-11-04 20:16:48 -0700165}
166
167/**
168 * Reports errors related to unplugged joysticks.
169 *
170 * Throttles the errors so that they don't overwhelm the DS.
171 */
172static void ReportJoystickUnpluggedWarningV(fmt::string_view format,
173 fmt::format_args args);
174
175template <typename S, typename... Args>
176static inline void ReportJoystickUnpluggedWarning(const S& format,
177 Args&&... args) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800178 ReportJoystickUnpluggedWarningV(format, fmt::make_format_args(args...));
Austin Schuh1e69f942020-11-14 15:06:14 -0800179}
180
Austin Schuh812d0d12021-11-04 20:16:48 -0700181Instance::Instance() {
182 HAL_Initialize(500, 0);
183
184 // All joysticks should default to having zero axes, povs and buttons, so
185 // uninitialized memory doesn't get sent to motor controllers.
186 for (unsigned int i = 0; i < DriverStation::kJoystickPorts; i++) {
187 joystickButtonsPressed[i] = 0;
188 joystickButtonsReleased[i] = 0;
189 previousButtonStates[i].count = 0;
190 previousButtonStates[i].buttons = 0;
191 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700192}
193
194Instance::~Instance() {
James Kuszmaulcf324122023-01-14 14:07:17 -0800195 if (dataLogSender) {
196 delete dataLogSender.load();
197 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800198}
199
Brian Silverman8fce7482020-01-05 13:18:21 -0800200bool DriverStation::GetStickButton(int stick, int button) {
201 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700202 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800203 return false;
204 }
205 if (button <= 0) {
206 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700207 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800208 return false;
209 }
210
211 HAL_JoystickButtons buttons;
212 HAL_GetJoystickButtons(stick, &buttons);
213
214 if (button > buttons.count) {
215 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700216 "Joystick Button {} missing (max {}), check if all controllers are "
217 "plugged in",
218 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800219 return false;
220 }
221
222 return buttons.buttons & 1 << (button - 1);
223}
224
225bool DriverStation::GetStickButtonPressed(int stick, int button) {
226 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700227 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800228 return false;
229 }
230 if (button <= 0) {
231 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700232 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800233 return false;
234 }
235
236 HAL_JoystickButtons buttons;
237 HAL_GetJoystickButtons(stick, &buttons);
238
239 if (button > buttons.count) {
240 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700241 "Joystick Button {} missing (max {}), check if all controllers are "
242 "plugged in",
243 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800244 return false;
245 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700246 auto& inst = ::GetInstance();
247 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800248 // If button was pressed, clear flag and return true
Austin Schuh812d0d12021-11-04 20:16:48 -0700249 if (inst.joystickButtonsPressed[stick] & 1 << (button - 1)) {
250 inst.joystickButtonsPressed[stick] &= ~(1 << (button - 1));
Brian Silverman8fce7482020-01-05 13:18:21 -0800251 return true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800252 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700253 return false;
Brian Silverman8fce7482020-01-05 13:18:21 -0800254}
255
256bool DriverStation::GetStickButtonReleased(int stick, int button) {
257 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700258 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800259 return false;
260 }
261 if (button <= 0) {
262 ReportJoystickUnpluggedError(
Austin Schuh812d0d12021-11-04 20:16:48 -0700263 "Joystick Button {} index out of range; indexes begin at 1", button);
Brian Silverman8fce7482020-01-05 13:18:21 -0800264 return false;
265 }
266
267 HAL_JoystickButtons buttons;
268 HAL_GetJoystickButtons(stick, &buttons);
269
270 if (button > buttons.count) {
271 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700272 "Joystick Button {} missing (max {}), check if all controllers are "
273 "plugged in",
274 button, buttons.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800275 return false;
276 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700277 auto& inst = ::GetInstance();
278 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800279 // If button was released, clear flag and return true
Austin Schuh812d0d12021-11-04 20:16:48 -0700280 if (inst.joystickButtonsReleased[stick] & 1 << (button - 1)) {
281 inst.joystickButtonsReleased[stick] &= ~(1 << (button - 1));
Brian Silverman8fce7482020-01-05 13:18:21 -0800282 return true;
Brian Silverman8fce7482020-01-05 13:18:21 -0800283 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700284 return false;
Brian Silverman8fce7482020-01-05 13:18:21 -0800285}
286
287double DriverStation::GetStickAxis(int stick, int axis) {
288 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700289 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800290 return 0.0;
291 }
292 if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700293 FRC_ReportError(warn::BadJoystickAxis, "axis {} out of range", axis);
Brian Silverman8fce7482020-01-05 13:18:21 -0800294 return 0.0;
295 }
296
297 HAL_JoystickAxes axes;
298 HAL_GetJoystickAxes(stick, &axes);
299
300 if (axis >= axes.count) {
301 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700302 "Joystick Axis {} missing (max {}), check if all controllers are "
303 "plugged in",
304 axis, axes.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800305 return 0.0;
306 }
307
308 return axes.axes[axis];
309}
310
311int DriverStation::GetStickPOV(int stick, int pov) {
312 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700313 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800314 return -1;
315 }
316 if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700317 FRC_ReportError(warn::BadJoystickAxis, "POV {} out of range", pov);
Brian Silverman8fce7482020-01-05 13:18:21 -0800318 return -1;
319 }
320
321 HAL_JoystickPOVs povs;
322 HAL_GetJoystickPOVs(stick, &povs);
323
324 if (pov >= povs.count) {
325 ReportJoystickUnpluggedWarning(
Austin Schuh812d0d12021-11-04 20:16:48 -0700326 "Joystick POV {} missing (max {}), check if all controllers are "
327 "plugged in",
328 pov, povs.count);
Brian Silverman8fce7482020-01-05 13:18:21 -0800329 return -1;
330 }
331
332 return povs.povs[pov];
333}
334
Austin Schuh812d0d12021-11-04 20:16:48 -0700335int DriverStation::GetStickButtons(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800336 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700337 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800338 return 0;
339 }
340
341 HAL_JoystickButtons buttons;
342 HAL_GetJoystickButtons(stick, &buttons);
343
344 return buttons.buttons;
345}
346
Austin Schuh812d0d12021-11-04 20:16:48 -0700347int DriverStation::GetStickAxisCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800348 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700349 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800350 return 0;
351 }
352
353 HAL_JoystickAxes axes;
354 HAL_GetJoystickAxes(stick, &axes);
355
356 return axes.count;
357}
358
Austin Schuh812d0d12021-11-04 20:16:48 -0700359int DriverStation::GetStickPOVCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800360 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700361 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800362 return 0;
363 }
364
365 HAL_JoystickPOVs povs;
366 HAL_GetJoystickPOVs(stick, &povs);
367
368 return povs.count;
369}
370
Austin Schuh812d0d12021-11-04 20:16:48 -0700371int DriverStation::GetStickButtonCount(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800372 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700373 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800374 return 0;
375 }
376
377 HAL_JoystickButtons buttons;
378 HAL_GetJoystickButtons(stick, &buttons);
379
380 return buttons.count;
381}
382
Austin Schuh812d0d12021-11-04 20:16:48 -0700383bool DriverStation::GetJoystickIsXbox(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800384 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700385 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800386 return false;
387 }
388
389 HAL_JoystickDescriptor descriptor;
390 HAL_GetJoystickDescriptor(stick, &descriptor);
391
392 return static_cast<bool>(descriptor.isXbox);
393}
394
Austin Schuh812d0d12021-11-04 20:16:48 -0700395int DriverStation::GetJoystickType(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800396 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700397 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800398 return -1;
399 }
400
401 HAL_JoystickDescriptor descriptor;
402 HAL_GetJoystickDescriptor(stick, &descriptor);
403
404 return static_cast<int>(descriptor.type);
405}
406
Austin Schuh812d0d12021-11-04 20:16:48 -0700407std::string DriverStation::GetJoystickName(int stick) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800408 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700409 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800410 }
411
412 HAL_JoystickDescriptor descriptor;
413 HAL_GetJoystickDescriptor(stick, &descriptor);
414
415 return descriptor.name;
416}
417
Austin Schuh812d0d12021-11-04 20:16:48 -0700418int DriverStation::GetJoystickAxisType(int stick, int axis) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800419 if (stick < 0 || stick >= kJoystickPorts) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700420 FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
Brian Silverman8fce7482020-01-05 13:18:21 -0800421 return -1;
422 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800423 if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
424 FRC_ReportError(warn::BadJoystickAxis, "axis {} out of range", axis);
425 return -1;
426 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800427
428 HAL_JoystickDescriptor descriptor;
429 HAL_GetJoystickDescriptor(stick, &descriptor);
430
James Kuszmaulcf324122023-01-14 14:07:17 -0800431 return descriptor.axisTypes[axis];
Brian Silverman8fce7482020-01-05 13:18:21 -0800432}
433
Austin Schuh812d0d12021-11-04 20:16:48 -0700434bool DriverStation::IsJoystickConnected(int stick) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800435 return GetStickAxisCount(stick) > 0 || GetStickButtonCount(stick) > 0 ||
436 GetStickPOVCount(stick) > 0;
437}
438
Austin Schuh812d0d12021-11-04 20:16:48 -0700439bool DriverStation::IsEnabled() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800440 HAL_ControlWord controlWord;
441 HAL_GetControlWord(&controlWord);
442 return controlWord.enabled && controlWord.dsAttached;
443}
444
Austin Schuh812d0d12021-11-04 20:16:48 -0700445bool DriverStation::IsDisabled() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800446 HAL_ControlWord controlWord;
447 HAL_GetControlWord(&controlWord);
448 return !(controlWord.enabled && controlWord.dsAttached);
449}
450
Austin Schuh812d0d12021-11-04 20:16:48 -0700451bool DriverStation::IsEStopped() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800452 HAL_ControlWord controlWord;
453 HAL_GetControlWord(&controlWord);
454 return controlWord.eStop;
455}
456
Austin Schuh812d0d12021-11-04 20:16:48 -0700457bool DriverStation::IsAutonomous() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800458 HAL_ControlWord controlWord;
459 HAL_GetControlWord(&controlWord);
460 return controlWord.autonomous;
461}
462
Austin Schuh812d0d12021-11-04 20:16:48 -0700463bool DriverStation::IsAutonomousEnabled() {
Austin Schuh1e69f942020-11-14 15:06:14 -0800464 HAL_ControlWord controlWord;
465 HAL_GetControlWord(&controlWord);
466 return controlWord.autonomous && controlWord.enabled;
467}
468
Austin Schuh812d0d12021-11-04 20:16:48 -0700469bool DriverStation::IsTeleop() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800470 HAL_ControlWord controlWord;
471 HAL_GetControlWord(&controlWord);
472 return !(controlWord.autonomous || controlWord.test);
473}
474
Austin Schuh812d0d12021-11-04 20:16:48 -0700475bool DriverStation::IsTeleopEnabled() {
Austin Schuh1e69f942020-11-14 15:06:14 -0800476 HAL_ControlWord controlWord;
477 HAL_GetControlWord(&controlWord);
478 return !controlWord.autonomous && !controlWord.test && controlWord.enabled;
479}
480
Austin Schuh812d0d12021-11-04 20:16:48 -0700481bool DriverStation::IsTest() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800482 HAL_ControlWord controlWord;
483 HAL_GetControlWord(&controlWord);
484 return controlWord.test;
485}
486
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800487bool DriverStation::IsTestEnabled() {
488 HAL_ControlWord controlWord;
489 HAL_GetControlWord(&controlWord);
490 return controlWord.test && controlWord.enabled;
491}
492
Austin Schuh812d0d12021-11-04 20:16:48 -0700493bool DriverStation::IsDSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800494 HAL_ControlWord controlWord;
495 HAL_GetControlWord(&controlWord);
496 return controlWord.dsAttached;
497}
498
Austin Schuh812d0d12021-11-04 20:16:48 -0700499bool DriverStation::IsFMSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800500 HAL_ControlWord controlWord;
501 HAL_GetControlWord(&controlWord);
502 return controlWord.fmsAttached;
503}
504
Austin Schuh812d0d12021-11-04 20:16:48 -0700505std::string DriverStation::GetGameSpecificMessage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800506 HAL_MatchInfo info;
507 HAL_GetMatchInfo(&info);
508 return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
509 info.gameSpecificMessageSize);
510}
511
Austin Schuh812d0d12021-11-04 20:16:48 -0700512std::string DriverStation::GetEventName() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800513 HAL_MatchInfo info;
514 HAL_GetMatchInfo(&info);
515 return info.eventName;
516}
517
Austin Schuh812d0d12021-11-04 20:16:48 -0700518DriverStation::MatchType DriverStation::GetMatchType() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800519 HAL_MatchInfo info;
520 HAL_GetMatchInfo(&info);
521 return static_cast<DriverStation::MatchType>(info.matchType);
522}
523
Austin Schuh812d0d12021-11-04 20:16:48 -0700524int DriverStation::GetMatchNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800525 HAL_MatchInfo info;
526 HAL_GetMatchInfo(&info);
527 return info.matchNumber;
528}
529
Austin Schuh812d0d12021-11-04 20:16:48 -0700530int DriverStation::GetReplayNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800531 HAL_MatchInfo info;
532 HAL_GetMatchInfo(&info);
533 return info.replayNumber;
534}
535
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800536std::optional<DriverStation::Alliance> DriverStation::GetAlliance() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800537 int32_t status = 0;
538 auto allianceStationID = HAL_GetAllianceStation(&status);
539 switch (allianceStationID) {
540 case HAL_AllianceStationID_kRed1:
541 case HAL_AllianceStationID_kRed2:
542 case HAL_AllianceStationID_kRed3:
543 return kRed;
544 case HAL_AllianceStationID_kBlue1:
545 case HAL_AllianceStationID_kBlue2:
546 case HAL_AllianceStationID_kBlue3:
547 return kBlue;
548 default:
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800549 return {};
Brian Silverman8fce7482020-01-05 13:18:21 -0800550 }
551}
552
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800553std::optional<int> DriverStation::GetLocation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800554 int32_t status = 0;
555 auto allianceStationID = HAL_GetAllianceStation(&status);
556 switch (allianceStationID) {
557 case HAL_AllianceStationID_kRed1:
558 case HAL_AllianceStationID_kBlue1:
559 return 1;
560 case HAL_AllianceStationID_kRed2:
561 case HAL_AllianceStationID_kBlue2:
562 return 2;
563 case HAL_AllianceStationID_kRed3:
564 case HAL_AllianceStationID_kBlue3:
565 return 3;
566 default:
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800567 return {};
Brian Silverman8fce7482020-01-05 13:18:21 -0800568 }
569}
570
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800571bool DriverStation::WaitForDsConnection(units::second_t timeout) {
572 wpi::Event event{true, false};
573 HAL_ProvideNewDataEventHandle(event.GetHandle());
574 bool result = false;
575 if (timeout == 0_s) {
576 result = wpi::WaitForObject(event.GetHandle());
577 } else {
578 result = wpi::WaitForObject(event.GetHandle(), timeout.value(), nullptr);
579 }
580
581 HAL_RemoveNewDataEventHandle(event.GetHandle());
582 return result;
583}
584
585units::second_t DriverStation::GetMatchTime() {
Austin Schuh812d0d12021-11-04 20:16:48 -0700586 int32_t status = 0;
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800587 return units::second_t{HAL_GetMatchTime(&status)};
Brian Silverman8fce7482020-01-05 13:18:21 -0800588}
589
Austin Schuh812d0d12021-11-04 20:16:48 -0700590double DriverStation::GetBatteryVoltage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800591 int32_t status = 0;
592 double voltage = HAL_GetVinVoltage(&status);
James Kuszmaulcf324122023-01-14 14:07:17 -0800593 FRC_CheckErrorStatus(status, "getVinVoltage");
Brian Silverman8fce7482020-01-05 13:18:21 -0800594
595 return voltage;
596}
597
Austin Schuh812d0d12021-11-04 20:16:48 -0700598/**
599 * Copy data from the DS task for the user.
600 *
601 * If no new data exists, it will just be returned, otherwise
602 * the data will be copied from the DS polling loop.
603 */
James Kuszmaulcf324122023-01-14 14:07:17 -0800604void DriverStation::RefreshData() {
605 HAL_RefreshDSData();
Austin Schuh812d0d12021-11-04 20:16:48 -0700606 auto& inst = ::GetInstance();
Brian Silverman8fce7482020-01-05 13:18:21 -0800607 {
608 // Compute the pressed and released buttons
609 HAL_JoystickButtons currentButtons;
Austin Schuh812d0d12021-11-04 20:16:48 -0700610 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800611
Austin Schuh812d0d12021-11-04 20:16:48 -0700612 for (int32_t i = 0; i < DriverStation::kJoystickPorts; i++) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800613 HAL_GetJoystickButtons(i, &currentButtons);
614
615 // If buttons weren't pressed and are now, set flags in m_buttonsPressed
Austin Schuh812d0d12021-11-04 20:16:48 -0700616 inst.joystickButtonsPressed[i] |=
617 ~inst.previousButtonStates[i].buttons & currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800618
619 // If buttons were pressed and aren't now, set flags in m_buttonsReleased
Austin Schuh812d0d12021-11-04 20:16:48 -0700620 inst.joystickButtonsReleased[i] |=
621 inst.previousButtonStates[i].buttons & ~currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800622
Austin Schuh812d0d12021-11-04 20:16:48 -0700623 inst.previousButtonStates[i] = currentButtons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800624 }
625 }
626
James Kuszmaulcf324122023-01-14 14:07:17 -0800627 inst.refreshEvents.Wakeup();
628
Brian Silverman8fce7482020-01-05 13:18:21 -0800629 SendMatchData();
James Kuszmaulcf324122023-01-14 14:07:17 -0800630 if (auto sender = inst.dataLogSender.load()) {
631 sender->Send(wpi::Now());
632 }
633}
634
635void DriverStation::ProvideRefreshedDataEventHandle(WPI_EventHandle handle) {
636 auto& inst = ::GetInstance();
637 inst.refreshEvents.Add(handle);
638}
639
640void DriverStation::RemoveRefreshedDataEventHandle(WPI_EventHandle handle) {
641 auto& inst = ::GetInstance();
642 inst.refreshEvents.Remove(handle);
Brian Silverman8fce7482020-01-05 13:18:21 -0800643}
644
Austin Schuh1e69f942020-11-14 15:06:14 -0800645void DriverStation::SilenceJoystickConnectionWarning(bool silence) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700646 ::GetInstance().silenceJoystickWarning = silence;
Austin Schuh1e69f942020-11-14 15:06:14 -0800647}
648
Austin Schuh812d0d12021-11-04 20:16:48 -0700649bool DriverStation::IsJoystickConnectionWarningSilenced() {
650 return !IsFMSAttached() && ::GetInstance().silenceJoystickWarning;
Austin Schuh1e69f942020-11-14 15:06:14 -0800651}
652
James Kuszmaulcf324122023-01-14 14:07:17 -0800653void DriverStation::StartDataLog(wpi::log::DataLog& log, bool logJoysticks) {
654 auto& inst = ::GetInstance();
655 // Note: cannot safely replace, because we wouldn't know when to delete the
656 // "old" one. Instead do a compare and exchange with nullptr. We check first
657 // with a simple load to avoid the new in the common case.
658 if (inst.dataLogSender.load()) {
659 return;
660 }
661 DataLogSender* oldSender = nullptr;
662 DataLogSender* newSender = new DataLogSender;
663 inst.dataLogSender.compare_exchange_strong(oldSender, newSender);
664 if (oldSender) {
665 delete newSender; // already had a sender
666 } else {
667 newSender->Init(log, logJoysticks, wpi::Now());
668 }
669}
670
Austin Schuh812d0d12021-11-04 20:16:48 -0700671void ReportJoystickUnpluggedErrorV(fmt::string_view format,
672 fmt::format_args args) {
673 auto& inst = GetInstance();
674 auto currentTime = Timer::GetFPGATimestamp();
675 if (currentTime > inst.nextMessageTime) {
676 ReportErrorV(err::Error, "", 0, "", format, args);
677 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Brian Silverman8fce7482020-01-05 13:18:21 -0800678 }
679}
680
Austin Schuh812d0d12021-11-04 20:16:48 -0700681void ReportJoystickUnpluggedWarningV(fmt::string_view format,
682 fmt::format_args args) {
683 auto& inst = GetInstance();
684 if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
685 auto currentTime = Timer::GetFPGATimestamp();
686 if (currentTime > inst.nextMessageTime) {
687 ReportErrorV(warn::Warning, "", 0, "", format, args);
688 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Austin Schuh1e69f942020-11-14 15:06:14 -0800689 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800690 }
691}
692
Austin Schuh812d0d12021-11-04 20:16:48 -0700693void SendMatchData() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800694 int32_t status = 0;
695 HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
696 bool isRedAlliance = false;
697 int stationNumber = 1;
698 switch (alliance) {
699 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
700 isRedAlliance = false;
701 stationNumber = 1;
702 break;
703 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
704 isRedAlliance = false;
705 stationNumber = 2;
706 break;
707 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
708 isRedAlliance = false;
709 stationNumber = 3;
710 break;
711 case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
712 isRedAlliance = true;
713 stationNumber = 1;
714 break;
715 case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
716 isRedAlliance = true;
717 stationNumber = 2;
718 break;
719 default:
720 isRedAlliance = true;
721 stationNumber = 3;
722 break;
723 }
724
725 HAL_MatchInfo tmpDataStore;
726 HAL_GetMatchInfo(&tmpDataStore);
727
Austin Schuh812d0d12021-11-04 20:16:48 -0700728 auto& inst = GetInstance();
729 inst.matchDataSender.alliance.Set(isRedAlliance);
730 inst.matchDataSender.station.Set(stationNumber);
731 inst.matchDataSender.eventName.Set(tmpDataStore.eventName);
732 inst.matchDataSender.gameSpecificMessage.Set(
Brian Silverman8fce7482020-01-05 13:18:21 -0800733 std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
734 tmpDataStore.gameSpecificMessageSize));
Austin Schuh812d0d12021-11-04 20:16:48 -0700735 inst.matchDataSender.matchNumber.Set(tmpDataStore.matchNumber);
736 inst.matchDataSender.replayNumber.Set(tmpDataStore.replayNumber);
737 inst.matchDataSender.matchType.Set(static_cast<int>(tmpDataStore.matchType));
Brian Silverman8fce7482020-01-05 13:18:21 -0800738
739 HAL_ControlWord ctlWord;
740 HAL_GetControlWord(&ctlWord);
741 int32_t wordInt = 0;
742 std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
Austin Schuh812d0d12021-11-04 20:16:48 -0700743 inst.matchDataSender.controlWord.Set(wordInt);
Brian Silverman8fce7482020-01-05 13:18:21 -0800744}
James Kuszmaulcf324122023-01-14 14:07:17 -0800745
746void JoystickLogSender::Init(wpi::log::DataLog& log, unsigned int stick,
747 int64_t timestamp) {
748 m_stick = stick;
749
750 m_logButtons = wpi::log::BooleanArrayLogEntry{
751 log, fmt::format("DS:joystick{}/buttons", stick), timestamp};
752 m_logAxes = wpi::log::FloatArrayLogEntry{
753 log, fmt::format("DS:joystick{}/axes", stick), timestamp};
754 m_logPOVs = wpi::log::IntegerArrayLogEntry{
755 log, fmt::format("DS:joystick{}/povs", stick), timestamp};
756
757 HAL_GetJoystickButtons(m_stick, &m_prevButtons);
758 HAL_GetJoystickAxes(m_stick, &m_prevAxes);
759 HAL_GetJoystickPOVs(m_stick, &m_prevPOVs);
760 AppendButtons(m_prevButtons, timestamp);
761 m_logAxes.Append(
762 std::span<const float>{m_prevAxes.axes,
763 static_cast<size_t>(m_prevAxes.count)},
764 timestamp);
765 AppendPOVs(m_prevPOVs, timestamp);
766}
767
768void JoystickLogSender::Send(uint64_t timestamp) {
769 HAL_JoystickButtons buttons;
770 HAL_GetJoystickButtons(m_stick, &buttons);
771 if (buttons.count != m_prevButtons.count ||
772 buttons.buttons != m_prevButtons.buttons) {
773 AppendButtons(buttons, timestamp);
774 }
775 m_prevButtons = buttons;
776
777 HAL_JoystickAxes axes;
778 HAL_GetJoystickAxes(m_stick, &axes);
779 if (axes.count != m_prevAxes.count ||
780 std::memcmp(axes.axes, m_prevAxes.axes,
781 sizeof(axes.axes[0]) * axes.count) != 0) {
782 m_logAxes.Append(
783 std::span<const float>{axes.axes, static_cast<size_t>(axes.count)},
784 timestamp);
785 }
786 m_prevAxes = axes;
787
788 HAL_JoystickPOVs povs;
789 HAL_GetJoystickPOVs(m_stick, &povs);
790 if (povs.count != m_prevPOVs.count ||
791 std::memcmp(povs.povs, m_prevPOVs.povs,
792 sizeof(povs.povs[0]) * povs.count) != 0) {
793 AppendPOVs(povs, timestamp);
794 }
795 m_prevPOVs = povs;
796}
797
798void JoystickLogSender::AppendButtons(HAL_JoystickButtons buttons,
799 uint64_t timestamp) {
800 uint8_t buttonsArr[32];
801 for (unsigned int i = 0; i < buttons.count; ++i) {
802 buttonsArr[i] = (buttons.buttons & (1u << i)) != 0;
803 }
804 m_logButtons.Append(std::span<const uint8_t>{buttonsArr, buttons.count},
805 timestamp);
806}
807
808void JoystickLogSender::AppendPOVs(const HAL_JoystickPOVs& povs,
809 uint64_t timestamp) {
810 int64_t povsArr[HAL_kMaxJoystickPOVs];
811 for (int i = 0; i < povs.count; ++i) {
812 povsArr[i] = povs.povs[i];
813 }
814 m_logPOVs.Append(
815 std::span<const int64_t>{povsArr, static_cast<size_t>(povs.count)},
816 timestamp);
817}
818
819void DataLogSender::Init(wpi::log::DataLog& log, bool logJoysticks,
820 int64_t timestamp) {
821 m_logEnabled = wpi::log::BooleanLogEntry{log, "DS:enabled", timestamp};
822 m_logAutonomous = wpi::log::BooleanLogEntry{log, "DS:autonomous", timestamp};
823 m_logTest = wpi::log::BooleanLogEntry{log, "DS:test", timestamp};
824 m_logEstop = wpi::log::BooleanLogEntry{log, "DS:estop", timestamp};
825
826 // append initial control word values
827 HAL_GetControlWord(&m_prevControlWord);
828 m_logEnabled.Append(m_prevControlWord.enabled, timestamp);
829 m_logAutonomous.Append(m_prevControlWord.autonomous, timestamp);
830 m_logTest.Append(m_prevControlWord.test, timestamp);
831 m_logEstop.Append(m_prevControlWord.eStop, timestamp);
832
833 m_logJoysticks = logJoysticks;
834 if (logJoysticks) {
835 unsigned int i = 0;
836 for (auto&& joystick : m_joysticks) {
837 joystick.Init(log, i++, timestamp);
838 }
839 }
840
841 m_initialized = true;
842}
843
844void DataLogSender::Send(uint64_t timestamp) {
845 if (!m_initialized) {
846 return;
847 }
848
849 // append control word value changes
850 HAL_ControlWord ctlWord;
851 HAL_GetControlWord(&ctlWord);
852 if (ctlWord.enabled != m_prevControlWord.enabled) {
853 m_logEnabled.Append(ctlWord.enabled, timestamp);
854 }
855 if (ctlWord.autonomous != m_prevControlWord.autonomous) {
856 m_logAutonomous.Append(ctlWord.autonomous, timestamp);
857 }
858 if (ctlWord.test != m_prevControlWord.test) {
859 m_logTest.Append(ctlWord.test, timestamp);
860 }
861 if (ctlWord.eStop != m_prevControlWord.eStop) {
862 m_logEstop.Append(ctlWord.eStop, timestamp);
863 }
864 m_prevControlWord = ctlWord;
865
866 if (m_logJoysticks) {
867 // append joystick value changes
868 for (auto&& joystick : m_joysticks) {
869 joystick.Send(timestamp);
870 }
871 }
872}