blob: aead3439af590daa45e1ecf8f9d68ec2d8481c63 [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
Austin Schuh812d0d12021-11-04 20:16:48 -0700487bool DriverStation::IsDSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800488 HAL_ControlWord controlWord;
489 HAL_GetControlWord(&controlWord);
490 return controlWord.dsAttached;
491}
492
Austin Schuh812d0d12021-11-04 20:16:48 -0700493bool DriverStation::IsFMSAttached() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800494 HAL_ControlWord controlWord;
495 HAL_GetControlWord(&controlWord);
496 return controlWord.fmsAttached;
497}
498
Austin Schuh812d0d12021-11-04 20:16:48 -0700499std::string DriverStation::GetGameSpecificMessage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800500 HAL_MatchInfo info;
501 HAL_GetMatchInfo(&info);
502 return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
503 info.gameSpecificMessageSize);
504}
505
Austin Schuh812d0d12021-11-04 20:16:48 -0700506std::string DriverStation::GetEventName() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800507 HAL_MatchInfo info;
508 HAL_GetMatchInfo(&info);
509 return info.eventName;
510}
511
Austin Schuh812d0d12021-11-04 20:16:48 -0700512DriverStation::MatchType DriverStation::GetMatchType() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800513 HAL_MatchInfo info;
514 HAL_GetMatchInfo(&info);
515 return static_cast<DriverStation::MatchType>(info.matchType);
516}
517
Austin Schuh812d0d12021-11-04 20:16:48 -0700518int DriverStation::GetMatchNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800519 HAL_MatchInfo info;
520 HAL_GetMatchInfo(&info);
521 return info.matchNumber;
522}
523
Austin Schuh812d0d12021-11-04 20:16:48 -0700524int DriverStation::GetReplayNumber() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800525 HAL_MatchInfo info;
526 HAL_GetMatchInfo(&info);
527 return info.replayNumber;
528}
529
Austin Schuh812d0d12021-11-04 20:16:48 -0700530DriverStation::Alliance DriverStation::GetAlliance() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800531 int32_t status = 0;
532 auto allianceStationID = HAL_GetAllianceStation(&status);
533 switch (allianceStationID) {
534 case HAL_AllianceStationID_kRed1:
535 case HAL_AllianceStationID_kRed2:
536 case HAL_AllianceStationID_kRed3:
537 return kRed;
538 case HAL_AllianceStationID_kBlue1:
539 case HAL_AllianceStationID_kBlue2:
540 case HAL_AllianceStationID_kBlue3:
541 return kBlue;
542 default:
543 return kInvalid;
544 }
545}
546
Austin Schuh812d0d12021-11-04 20:16:48 -0700547int DriverStation::GetLocation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800548 int32_t status = 0;
549 auto allianceStationID = HAL_GetAllianceStation(&status);
550 switch (allianceStationID) {
551 case HAL_AllianceStationID_kRed1:
552 case HAL_AllianceStationID_kBlue1:
553 return 1;
554 case HAL_AllianceStationID_kRed2:
555 case HAL_AllianceStationID_kBlue2:
556 return 2;
557 case HAL_AllianceStationID_kRed3:
558 case HAL_AllianceStationID_kBlue3:
559 return 3;
560 default:
561 return 0;
562 }
563}
564
Austin Schuh812d0d12021-11-04 20:16:48 -0700565double DriverStation::GetMatchTime() {
566 int32_t status = 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800567 return HAL_GetMatchTime(&status);
568}
569
Austin Schuh812d0d12021-11-04 20:16:48 -0700570double DriverStation::GetBatteryVoltage() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800571 int32_t status = 0;
572 double voltage = HAL_GetVinVoltage(&status);
James Kuszmaulcf324122023-01-14 14:07:17 -0800573 FRC_CheckErrorStatus(status, "getVinVoltage");
Brian Silverman8fce7482020-01-05 13:18:21 -0800574
575 return voltage;
576}
577
Austin Schuh812d0d12021-11-04 20:16:48 -0700578/**
579 * Copy data from the DS task for the user.
580 *
581 * If no new data exists, it will just be returned, otherwise
582 * the data will be copied from the DS polling loop.
583 */
James Kuszmaulcf324122023-01-14 14:07:17 -0800584void DriverStation::RefreshData() {
585 HAL_RefreshDSData();
Austin Schuh812d0d12021-11-04 20:16:48 -0700586 auto& inst = ::GetInstance();
Brian Silverman8fce7482020-01-05 13:18:21 -0800587 {
588 // Compute the pressed and released buttons
589 HAL_JoystickButtons currentButtons;
Austin Schuh812d0d12021-11-04 20:16:48 -0700590 std::unique_lock lock(inst.buttonEdgeMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800591
Austin Schuh812d0d12021-11-04 20:16:48 -0700592 for (int32_t i = 0; i < DriverStation::kJoystickPorts; i++) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800593 HAL_GetJoystickButtons(i, &currentButtons);
594
595 // If buttons weren't pressed and are now, set flags in m_buttonsPressed
Austin Schuh812d0d12021-11-04 20:16:48 -0700596 inst.joystickButtonsPressed[i] |=
597 ~inst.previousButtonStates[i].buttons & currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800598
599 // If buttons were pressed and aren't now, set flags in m_buttonsReleased
Austin Schuh812d0d12021-11-04 20:16:48 -0700600 inst.joystickButtonsReleased[i] |=
601 inst.previousButtonStates[i].buttons & ~currentButtons.buttons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800602
Austin Schuh812d0d12021-11-04 20:16:48 -0700603 inst.previousButtonStates[i] = currentButtons;
Brian Silverman8fce7482020-01-05 13:18:21 -0800604 }
605 }
606
James Kuszmaulcf324122023-01-14 14:07:17 -0800607 inst.refreshEvents.Wakeup();
608
Brian Silverman8fce7482020-01-05 13:18:21 -0800609 SendMatchData();
James Kuszmaulcf324122023-01-14 14:07:17 -0800610 if (auto sender = inst.dataLogSender.load()) {
611 sender->Send(wpi::Now());
612 }
613}
614
615void DriverStation::ProvideRefreshedDataEventHandle(WPI_EventHandle handle) {
616 auto& inst = ::GetInstance();
617 inst.refreshEvents.Add(handle);
618}
619
620void DriverStation::RemoveRefreshedDataEventHandle(WPI_EventHandle handle) {
621 auto& inst = ::GetInstance();
622 inst.refreshEvents.Remove(handle);
Brian Silverman8fce7482020-01-05 13:18:21 -0800623}
624
Austin Schuh1e69f942020-11-14 15:06:14 -0800625void DriverStation::SilenceJoystickConnectionWarning(bool silence) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700626 ::GetInstance().silenceJoystickWarning = silence;
Austin Schuh1e69f942020-11-14 15:06:14 -0800627}
628
Austin Schuh812d0d12021-11-04 20:16:48 -0700629bool DriverStation::IsJoystickConnectionWarningSilenced() {
630 return !IsFMSAttached() && ::GetInstance().silenceJoystickWarning;
Austin Schuh1e69f942020-11-14 15:06:14 -0800631}
632
James Kuszmaulcf324122023-01-14 14:07:17 -0800633void DriverStation::StartDataLog(wpi::log::DataLog& log, bool logJoysticks) {
634 auto& inst = ::GetInstance();
635 // Note: cannot safely replace, because we wouldn't know when to delete the
636 // "old" one. Instead do a compare and exchange with nullptr. We check first
637 // with a simple load to avoid the new in the common case.
638 if (inst.dataLogSender.load()) {
639 return;
640 }
641 DataLogSender* oldSender = nullptr;
642 DataLogSender* newSender = new DataLogSender;
643 inst.dataLogSender.compare_exchange_strong(oldSender, newSender);
644 if (oldSender) {
645 delete newSender; // already had a sender
646 } else {
647 newSender->Init(log, logJoysticks, wpi::Now());
648 }
649}
650
Austin Schuh812d0d12021-11-04 20:16:48 -0700651void ReportJoystickUnpluggedErrorV(fmt::string_view format,
652 fmt::format_args args) {
653 auto& inst = GetInstance();
654 auto currentTime = Timer::GetFPGATimestamp();
655 if (currentTime > inst.nextMessageTime) {
656 ReportErrorV(err::Error, "", 0, "", format, args);
657 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Brian Silverman8fce7482020-01-05 13:18:21 -0800658 }
659}
660
Austin Schuh812d0d12021-11-04 20:16:48 -0700661void ReportJoystickUnpluggedWarningV(fmt::string_view format,
662 fmt::format_args args) {
663 auto& inst = GetInstance();
664 if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
665 auto currentTime = Timer::GetFPGATimestamp();
666 if (currentTime > inst.nextMessageTime) {
667 ReportErrorV(warn::Warning, "", 0, "", format, args);
668 inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
Austin Schuh1e69f942020-11-14 15:06:14 -0800669 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800670 }
671}
672
Austin Schuh812d0d12021-11-04 20:16:48 -0700673void SendMatchData() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800674 int32_t status = 0;
675 HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
676 bool isRedAlliance = false;
677 int stationNumber = 1;
678 switch (alliance) {
679 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
680 isRedAlliance = false;
681 stationNumber = 1;
682 break;
683 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
684 isRedAlliance = false;
685 stationNumber = 2;
686 break;
687 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
688 isRedAlliance = false;
689 stationNumber = 3;
690 break;
691 case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
692 isRedAlliance = true;
693 stationNumber = 1;
694 break;
695 case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
696 isRedAlliance = true;
697 stationNumber = 2;
698 break;
699 default:
700 isRedAlliance = true;
701 stationNumber = 3;
702 break;
703 }
704
705 HAL_MatchInfo tmpDataStore;
706 HAL_GetMatchInfo(&tmpDataStore);
707
Austin Schuh812d0d12021-11-04 20:16:48 -0700708 auto& inst = GetInstance();
709 inst.matchDataSender.alliance.Set(isRedAlliance);
710 inst.matchDataSender.station.Set(stationNumber);
711 inst.matchDataSender.eventName.Set(tmpDataStore.eventName);
712 inst.matchDataSender.gameSpecificMessage.Set(
Brian Silverman8fce7482020-01-05 13:18:21 -0800713 std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
714 tmpDataStore.gameSpecificMessageSize));
Austin Schuh812d0d12021-11-04 20:16:48 -0700715 inst.matchDataSender.matchNumber.Set(tmpDataStore.matchNumber);
716 inst.matchDataSender.replayNumber.Set(tmpDataStore.replayNumber);
717 inst.matchDataSender.matchType.Set(static_cast<int>(tmpDataStore.matchType));
Brian Silverman8fce7482020-01-05 13:18:21 -0800718
719 HAL_ControlWord ctlWord;
720 HAL_GetControlWord(&ctlWord);
721 int32_t wordInt = 0;
722 std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
Austin Schuh812d0d12021-11-04 20:16:48 -0700723 inst.matchDataSender.controlWord.Set(wordInt);
Brian Silverman8fce7482020-01-05 13:18:21 -0800724}
James Kuszmaulcf324122023-01-14 14:07:17 -0800725
726void JoystickLogSender::Init(wpi::log::DataLog& log, unsigned int stick,
727 int64_t timestamp) {
728 m_stick = stick;
729
730 m_logButtons = wpi::log::BooleanArrayLogEntry{
731 log, fmt::format("DS:joystick{}/buttons", stick), timestamp};
732 m_logAxes = wpi::log::FloatArrayLogEntry{
733 log, fmt::format("DS:joystick{}/axes", stick), timestamp};
734 m_logPOVs = wpi::log::IntegerArrayLogEntry{
735 log, fmt::format("DS:joystick{}/povs", stick), timestamp};
736
737 HAL_GetJoystickButtons(m_stick, &m_prevButtons);
738 HAL_GetJoystickAxes(m_stick, &m_prevAxes);
739 HAL_GetJoystickPOVs(m_stick, &m_prevPOVs);
740 AppendButtons(m_prevButtons, timestamp);
741 m_logAxes.Append(
742 std::span<const float>{m_prevAxes.axes,
743 static_cast<size_t>(m_prevAxes.count)},
744 timestamp);
745 AppendPOVs(m_prevPOVs, timestamp);
746}
747
748void JoystickLogSender::Send(uint64_t timestamp) {
749 HAL_JoystickButtons buttons;
750 HAL_GetJoystickButtons(m_stick, &buttons);
751 if (buttons.count != m_prevButtons.count ||
752 buttons.buttons != m_prevButtons.buttons) {
753 AppendButtons(buttons, timestamp);
754 }
755 m_prevButtons = buttons;
756
757 HAL_JoystickAxes axes;
758 HAL_GetJoystickAxes(m_stick, &axes);
759 if (axes.count != m_prevAxes.count ||
760 std::memcmp(axes.axes, m_prevAxes.axes,
761 sizeof(axes.axes[0]) * axes.count) != 0) {
762 m_logAxes.Append(
763 std::span<const float>{axes.axes, static_cast<size_t>(axes.count)},
764 timestamp);
765 }
766 m_prevAxes = axes;
767
768 HAL_JoystickPOVs povs;
769 HAL_GetJoystickPOVs(m_stick, &povs);
770 if (povs.count != m_prevPOVs.count ||
771 std::memcmp(povs.povs, m_prevPOVs.povs,
772 sizeof(povs.povs[0]) * povs.count) != 0) {
773 AppendPOVs(povs, timestamp);
774 }
775 m_prevPOVs = povs;
776}
777
778void JoystickLogSender::AppendButtons(HAL_JoystickButtons buttons,
779 uint64_t timestamp) {
780 uint8_t buttonsArr[32];
781 for (unsigned int i = 0; i < buttons.count; ++i) {
782 buttonsArr[i] = (buttons.buttons & (1u << i)) != 0;
783 }
784 m_logButtons.Append(std::span<const uint8_t>{buttonsArr, buttons.count},
785 timestamp);
786}
787
788void JoystickLogSender::AppendPOVs(const HAL_JoystickPOVs& povs,
789 uint64_t timestamp) {
790 int64_t povsArr[HAL_kMaxJoystickPOVs];
791 for (int i = 0; i < povs.count; ++i) {
792 povsArr[i] = povs.povs[i];
793 }
794 m_logPOVs.Append(
795 std::span<const int64_t>{povsArr, static_cast<size_t>(povs.count)},
796 timestamp);
797}
798
799void DataLogSender::Init(wpi::log::DataLog& log, bool logJoysticks,
800 int64_t timestamp) {
801 m_logEnabled = wpi::log::BooleanLogEntry{log, "DS:enabled", timestamp};
802 m_logAutonomous = wpi::log::BooleanLogEntry{log, "DS:autonomous", timestamp};
803 m_logTest = wpi::log::BooleanLogEntry{log, "DS:test", timestamp};
804 m_logEstop = wpi::log::BooleanLogEntry{log, "DS:estop", timestamp};
805
806 // append initial control word values
807 HAL_GetControlWord(&m_prevControlWord);
808 m_logEnabled.Append(m_prevControlWord.enabled, timestamp);
809 m_logAutonomous.Append(m_prevControlWord.autonomous, timestamp);
810 m_logTest.Append(m_prevControlWord.test, timestamp);
811 m_logEstop.Append(m_prevControlWord.eStop, timestamp);
812
813 m_logJoysticks = logJoysticks;
814 if (logJoysticks) {
815 unsigned int i = 0;
816 for (auto&& joystick : m_joysticks) {
817 joystick.Init(log, i++, timestamp);
818 }
819 }
820
821 m_initialized = true;
822}
823
824void DataLogSender::Send(uint64_t timestamp) {
825 if (!m_initialized) {
826 return;
827 }
828
829 // append control word value changes
830 HAL_ControlWord ctlWord;
831 HAL_GetControlWord(&ctlWord);
832 if (ctlWord.enabled != m_prevControlWord.enabled) {
833 m_logEnabled.Append(ctlWord.enabled, timestamp);
834 }
835 if (ctlWord.autonomous != m_prevControlWord.autonomous) {
836 m_logAutonomous.Append(ctlWord.autonomous, timestamp);
837 }
838 if (ctlWord.test != m_prevControlWord.test) {
839 m_logTest.Append(ctlWord.test, timestamp);
840 }
841 if (ctlWord.eStop != m_prevControlWord.eStop) {
842 m_logEstop.Append(ctlWord.eStop, timestamp);
843 }
844 m_prevControlWord = ctlWord;
845
846 if (m_logJoysticks) {
847 // append joystick value changes
848 for (auto&& joystick : m_joysticks) {
849 joystick.Send(timestamp);
850 }
851 }
852}