blob: 67b2eb728a4579a62edb52ec716ff59ead717f6c [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 "hal/DriverStation.h"
6
7#ifdef __APPLE__
8#include <pthread.h>
9#endif
10
James Kuszmaulcf324122023-01-14 14:07:17 -080011#include <atomic>
Brian Silverman8fce7482020-01-05 13:18:21 -080012#include <cstdio>
13#include <cstdlib>
14#include <cstring>
15#include <string>
16
Austin Schuh812d0d12021-11-04 20:16:48 -070017#include <fmt/format.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080018#include <wpi/EventVector.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080019#include <wpi/condition_variable.h>
20#include <wpi/mutex.h>
21
22#include "HALInitializer.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080023#include "hal/Errors.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080024#include "hal/cpp/fpga_clock.h"
25#include "hal/simulation/MockHooks.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080026#include "mockdata/DriverStationDataInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080027
28static wpi::mutex msgMutex;
Brian Silverman8fce7482020-01-05 13:18:21 -080029static std::atomic<HALSIM_SendErrorHandler> sendErrorHandler{nullptr};
Austin Schuh1e69f942020-11-14 15:06:14 -080030static std::atomic<HALSIM_SendConsoleLineHandler> sendConsoleLineHandler{
31 nullptr};
Brian Silverman8fce7482020-01-05 13:18:21 -080032
James Kuszmaulcf324122023-01-14 14:07:17 -080033using namespace hal;
34
35static constexpr int kJoystickPorts = 6;
36
37namespace {
38struct JoystickDataCache {
39 JoystickDataCache() { std::memset(this, 0, sizeof(*this)); }
40 void Update();
41
42 HAL_JoystickAxes axes[kJoystickPorts];
43 HAL_JoystickPOVs povs[kJoystickPorts];
44 HAL_JoystickButtons buttons[kJoystickPorts];
45 HAL_AllianceStationID allianceStation;
46 double matchTime;
47};
48static_assert(std::is_standard_layout_v<JoystickDataCache>);
49// static_assert(std::is_trivial_v<JoystickDataCache>);
50
51static std::atomic_bool gShutdown{false};
52
53struct FRCDriverStation {
54 ~FRCDriverStation() { gShutdown = true; }
55 wpi::EventVector newDataEvents;
56 wpi::mutex cacheMutex;
57};
58} // namespace
59
60void JoystickDataCache::Update() {
61 for (int i = 0; i < kJoystickPorts; i++) {
62 SimDriverStationData->GetJoystickAxes(i, &axes[i]);
63 SimDriverStationData->GetJoystickPOVs(i, &povs[i]);
64 SimDriverStationData->GetJoystickButtons(i, &buttons[i]);
65 }
66 allianceStation = SimDriverStationData->allianceStationId;
67 matchTime = SimDriverStationData->matchTime;
68}
69
70#define CHECK_JOYSTICK_NUMBER(stickNum) \
71 if ((stickNum) < 0 || (stickNum) >= HAL_kMaxJoysticks) \
72 return PARAMETER_OUT_OF_RANGE
73
74static HAL_ControlWord newestControlWord;
75static JoystickDataCache caches[3];
76static JoystickDataCache* currentRead = &caches[0];
77static JoystickDataCache* currentReadLocal = &caches[0];
James Kuszmaulb13e13f2023-11-22 20:44:04 -080078static std::atomic<JoystickDataCache*> currentCache{nullptr};
James Kuszmaulcf324122023-01-14 14:07:17 -080079static JoystickDataCache* lastGiven = &caches[1];
80static JoystickDataCache* cacheToUpdate = &caches[2];
81
82static ::FRCDriverStation* driverStation;
83
Austin Schuh812d0d12021-11-04 20:16:48 -070084namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080085void InitializeDriverStation() {
James Kuszmaulcf324122023-01-14 14:07:17 -080086 static FRCDriverStation ds;
87 driverStation = &ds;
Brian Silverman8fce7482020-01-05 13:18:21 -080088}
Austin Schuh812d0d12021-11-04 20:16:48 -070089} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080090
James Kuszmaulcf324122023-01-14 14:07:17 -080091namespace hal {
92static void DefaultPrintErrorImpl(const char* line, size_t size) {
93 std::fwrite(line, size, 1, stderr);
94}
95} // namespace hal
96
97static std::atomic<void (*)(const char* line, size_t size)> gPrintErrorImpl{
98 hal::DefaultPrintErrorImpl};
Brian Silverman8fce7482020-01-05 13:18:21 -080099
100extern "C" {
101
102void HALSIM_SetSendError(HALSIM_SendErrorHandler handler) {
103 sendErrorHandler.store(handler);
104}
105
Austin Schuh1e69f942020-11-14 15:06:14 -0800106void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler) {
107 sendConsoleLineHandler.store(handler);
108}
109
Brian Silverman8fce7482020-01-05 13:18:21 -0800110int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
111 const char* details, const char* location,
112 const char* callStack, HAL_Bool printMsg) {
113 auto errorHandler = sendErrorHandler.load();
Austin Schuh812d0d12021-11-04 20:16:48 -0700114 if (errorHandler) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800115 return errorHandler(isError, errorCode, isLVCode, details, location,
116 callStack, printMsg);
Austin Schuh812d0d12021-11-04 20:16:48 -0700117 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800118 // Avoid flooding console by keeping track of previous 5 error
119 // messages and only printing again if they're longer than 1 second old.
120 static constexpr int KEEP_MSGS = 5;
121 std::scoped_lock lock(msgMutex);
122 static std::string prevMsg[KEEP_MSGS];
Austin Schuh1e69f942020-11-14 15:06:14 -0800123 static fpga_clock::time_point prevMsgTime[KEEP_MSGS];
Brian Silverman8fce7482020-01-05 13:18:21 -0800124 static bool initialized = false;
125 if (!initialized) {
126 for (int i = 0; i < KEEP_MSGS; i++) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800127 prevMsgTime[i] = fpga_clock::now() - std::chrono::seconds(2);
Brian Silverman8fce7482020-01-05 13:18:21 -0800128 }
129 initialized = true;
130 }
131
Austin Schuh1e69f942020-11-14 15:06:14 -0800132 auto curTime = fpga_clock::now();
Brian Silverman8fce7482020-01-05 13:18:21 -0800133 int i;
134 for (i = 0; i < KEEP_MSGS; ++i) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700135 if (prevMsg[i] == details) {
136 break;
137 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800138 }
139 int retval = 0;
140 if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
141 printMsg = true;
142 if (printMsg) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700143 fmt::memory_buffer buf;
Brian Silverman8fce7482020-01-05 13:18:21 -0800144 if (location && location[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700145 fmt::format_to(fmt::appender{buf},
146 "{} at {}: ", isError ? "Error" : "Warning", location);
Brian Silverman8fce7482020-01-05 13:18:21 -0800147 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700148 fmt::format_to(fmt::appender{buf}, "{}\n", details);
Brian Silverman8fce7482020-01-05 13:18:21 -0800149 if (callStack && callStack[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700150 fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
Brian Silverman8fce7482020-01-05 13:18:21 -0800151 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800152 auto printError = gPrintErrorImpl.load();
153 printError(buf.data(), buf.size());
Brian Silverman8fce7482020-01-05 13:18:21 -0800154 }
155 if (i == KEEP_MSGS) {
156 // replace the oldest one
157 i = 0;
158 auto first = prevMsgTime[0];
159 for (int j = 1; j < KEEP_MSGS; ++j) {
160 if (prevMsgTime[j] < first) {
161 first = prevMsgTime[j];
162 i = j;
163 }
164 }
165 prevMsg[i] = details;
166 }
167 prevMsgTime[i] = curTime;
168 }
169 return retval;
170}
171
James Kuszmaulcf324122023-01-14 14:07:17 -0800172void HAL_SetPrintErrorImpl(void (*func)(const char* line, size_t size)) {
173 gPrintErrorImpl.store(func ? func : hal::DefaultPrintErrorImpl);
174}
175
Austin Schuh1e69f942020-11-14 15:06:14 -0800176int32_t HAL_SendConsoleLine(const char* line) {
177 auto handler = sendConsoleLineHandler.load();
178 if (handler) {
179 return handler(line);
180 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700181 std::puts(line);
182 std::fflush(stdout);
Austin Schuh1e69f942020-11-14 15:06:14 -0800183 return 0;
184}
185
Brian Silverman8fce7482020-01-05 13:18:21 -0800186int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800187 if (gShutdown) {
188 return INCOMPATIBLE_STATE;
189 }
190 std::scoped_lock lock{driverStation->cacheMutex};
191 *controlWord = newestControlWord;
Brian Silverman8fce7482020-01-05 13:18:21 -0800192 return 0;
193}
194
195HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800196 if (gShutdown) {
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800197 return HAL_AllianceStationID_kUnknown;
James Kuszmaulcf324122023-01-14 14:07:17 -0800198 }
199 std::scoped_lock lock{driverStation->cacheMutex};
200 return currentRead->allianceStation;
Brian Silverman8fce7482020-01-05 13:18:21 -0800201}
202
203int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800204 if (gShutdown) {
205 return INCOMPATIBLE_STATE;
206 }
207 CHECK_JOYSTICK_NUMBER(joystickNum);
208 std::scoped_lock lock{driverStation->cacheMutex};
209 *axes = currentRead->axes[joystickNum];
Brian Silverman8fce7482020-01-05 13:18:21 -0800210 return 0;
211}
212
213int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800214 if (gShutdown) {
215 return INCOMPATIBLE_STATE;
216 }
217 CHECK_JOYSTICK_NUMBER(joystickNum);
218 std::scoped_lock lock{driverStation->cacheMutex};
219 *povs = currentRead->povs[joystickNum];
Brian Silverman8fce7482020-01-05 13:18:21 -0800220 return 0;
221}
222
223int32_t HAL_GetJoystickButtons(int32_t joystickNum,
224 HAL_JoystickButtons* buttons) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800225 if (gShutdown) {
226 return INCOMPATIBLE_STATE;
227 }
228 CHECK_JOYSTICK_NUMBER(joystickNum);
229 std::scoped_lock lock{driverStation->cacheMutex};
230 *buttons = currentRead->buttons[joystickNum];
Brian Silverman8fce7482020-01-05 13:18:21 -0800231 return 0;
232}
233
James Kuszmaulcf324122023-01-14 14:07:17 -0800234void HAL_GetAllJoystickData(HAL_JoystickAxes* axes, HAL_JoystickPOVs* povs,
235 HAL_JoystickButtons* buttons) {
236 if (gShutdown) {
237 return;
238 }
239 std::scoped_lock lock{driverStation->cacheMutex};
240 std::memcpy(axes, currentRead->axes, sizeof(currentRead->axes));
241 std::memcpy(povs, currentRead->povs, sizeof(currentRead->povs));
242 std::memcpy(buttons, currentRead->buttons, sizeof(currentRead->buttons));
243}
244
Brian Silverman8fce7482020-01-05 13:18:21 -0800245int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
246 HAL_JoystickDescriptor* desc) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800247 CHECK_JOYSTICK_NUMBER(joystickNum);
Brian Silverman8fce7482020-01-05 13:18:21 -0800248 SimDriverStationData->GetJoystickDescriptor(joystickNum, desc);
249 return 0;
250}
251
252HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
253 HAL_JoystickDescriptor desc;
254 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
255 return desc.isXbox;
256}
257
258int32_t HAL_GetJoystickType(int32_t joystickNum) {
259 HAL_JoystickDescriptor desc;
260 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
261 return desc.type;
262}
263
264char* HAL_GetJoystickName(int32_t joystickNum) {
265 HAL_JoystickDescriptor desc;
266 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
267 size_t len = std::strlen(desc.name);
268 char* name = static_cast<char*>(std::malloc(len + 1));
269 std::memcpy(name, desc.name, len + 1);
270 return name;
271}
272
Austin Schuh812d0d12021-11-04 20:16:48 -0700273void HAL_FreeJoystickName(char* name) {
274 std::free(name);
275}
Brian Silverman8fce7482020-01-05 13:18:21 -0800276
Austin Schuh812d0d12021-11-04 20:16:48 -0700277int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
278 return 0;
279}
Brian Silverman8fce7482020-01-05 13:18:21 -0800280
281int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
282 int32_t leftRumble, int32_t rightRumble) {
283 SimDriverStationData->SetJoystickOutputs(joystickNum, outputs, leftRumble,
284 rightRumble);
285 return 0;
286}
287
288double HAL_GetMatchTime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800289 if (gShutdown) {
290 return 0;
291 }
292 std::scoped_lock lock{driverStation->cacheMutex};
293 return currentRead->matchTime;
Brian Silverman8fce7482020-01-05 13:18:21 -0800294}
295
296int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
297 SimDriverStationData->GetMatchInfo(info);
298 return 0;
299}
300
Austin Schuh812d0d12021-11-04 20:16:48 -0700301void HAL_ObserveUserProgramStarting(void) {
302 HALSIM_SetProgramStarted();
303}
Brian Silverman8fce7482020-01-05 13:18:21 -0800304
305void HAL_ObserveUserProgramDisabled(void) {
306 // TODO
307}
308
309void HAL_ObserveUserProgramAutonomous(void) {
310 // TODO
311}
312
313void HAL_ObserveUserProgramTeleop(void) {
314 // TODO
315}
316
317void HAL_ObserveUserProgramTest(void) {
318 // TODO
319}
320
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800321HAL_Bool HAL_RefreshDSData(void) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800322 if (gShutdown) {
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800323 return false;
James Kuszmaulcf324122023-01-14 14:07:17 -0800324 }
325 HAL_ControlWord controlWord;
326 std::memset(&controlWord, 0, sizeof(controlWord));
327 controlWord.enabled = SimDriverStationData->enabled;
328 controlWord.autonomous = SimDriverStationData->autonomous;
329 controlWord.test = SimDriverStationData->test;
330 controlWord.eStop = SimDriverStationData->eStop;
331 controlWord.fmsAttached = SimDriverStationData->fmsAttached;
332 controlWord.dsAttached = SimDriverStationData->dsAttached;
333 std::scoped_lock lock{driverStation->cacheMutex};
334 JoystickDataCache* prev = currentCache.exchange(nullptr);
335 if (prev != nullptr) {
336 currentRead = prev;
337 }
338 newestControlWord = controlWord;
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800339 return prev != nullptr;
Brian Silverman8fce7482020-01-05 13:18:21 -0800340}
341
James Kuszmaulcf324122023-01-14 14:07:17 -0800342void HAL_ProvideNewDataEventHandle(WPI_EventHandle handle) {
343 if (gShutdown) {
344 return;
Austin Schuh812d0d12021-11-04 20:16:48 -0700345 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800346 hal::init::CheckInit();
James Kuszmaulcf324122023-01-14 14:07:17 -0800347 driverStation->newDataEvents.Add(handle);
Brian Silverman8fce7482020-01-05 13:18:21 -0800348}
349
James Kuszmaulcf324122023-01-14 14:07:17 -0800350void HAL_RemoveNewDataEventHandle(WPI_EventHandle handle) {
351 if (gShutdown) {
352 return;
353 }
354 driverStation->newDataEvents.Remove(handle);
355}
356
357HAL_Bool HAL_GetOutputsEnabled(void) {
358 if (gShutdown) {
359 return false;
360 }
361 std::scoped_lock lock{driverStation->cacheMutex};
362 return newestControlWord.enabled && newestControlWord.dsAttached;
Austin Schuh812d0d12021-11-04 20:16:48 -0700363}
Brian Silverman8fce7482020-01-05 13:18:21 -0800364
365} // extern "C"
James Kuszmaulcf324122023-01-14 14:07:17 -0800366
367namespace hal {
368void NewDriverStationData() {
369 if (gShutdown) {
370 return;
371 }
372 cacheToUpdate->Update();
373
374 JoystickDataCache* given = cacheToUpdate;
375 JoystickDataCache* prev = currentCache.exchange(cacheToUpdate);
376 if (prev == nullptr) {
377 cacheToUpdate = currentReadLocal;
378 currentReadLocal = lastGiven;
379 } else {
380 // Current read local does not update
381 cacheToUpdate = prev;
382 }
383 lastGiven = given;
384
385 driverStation->newDataEvents.Wakeup();
386 SimDriverStationData->CallNewDataCallbacks();
387}
388
389void InitializeDriverStation() {
390 SimDriverStationData->ResetData();
391}
392} // namespace hal