blob: 723cdacfa8e8c1abeb6d256d4ddfbe5ce166e90f [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
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14#include <string>
15
Austin Schuh812d0d12021-11-04 20:16:48 -070016#include <fmt/format.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080017#include <wpi/condition_variable.h>
18#include <wpi/mutex.h>
19
20#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080021#include "hal/cpp/fpga_clock.h"
22#include "hal/simulation/MockHooks.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080023#include "mockdata/DriverStationDataInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080024
25static wpi::mutex msgMutex;
26static wpi::condition_variable* newDSDataAvailableCond;
27static wpi::mutex newDSDataAvailableMutex;
28static int newDSDataAvailableCounter{0};
29static std::atomic_bool isFinalized{false};
30static std::atomic<HALSIM_SendErrorHandler> sendErrorHandler{nullptr};
Austin Schuh1e69f942020-11-14 15:06:14 -080031static std::atomic<HALSIM_SendConsoleLineHandler> sendConsoleLineHandler{
32 nullptr};
Brian Silverman8fce7482020-01-05 13:18:21 -080033
Austin Schuh812d0d12021-11-04 20:16:48 -070034namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080035void InitializeDriverStation() {
36 static wpi::condition_variable nddaC;
37 newDSDataAvailableCond = &nddaC;
38}
Austin Schuh812d0d12021-11-04 20:16:48 -070039} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080040
41using namespace hal;
42
43extern "C" {
44
45void HALSIM_SetSendError(HALSIM_SendErrorHandler handler) {
46 sendErrorHandler.store(handler);
47}
48
Austin Schuh1e69f942020-11-14 15:06:14 -080049void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler) {
50 sendConsoleLineHandler.store(handler);
51}
52
Brian Silverman8fce7482020-01-05 13:18:21 -080053int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
54 const char* details, const char* location,
55 const char* callStack, HAL_Bool printMsg) {
56 auto errorHandler = sendErrorHandler.load();
Austin Schuh812d0d12021-11-04 20:16:48 -070057 if (errorHandler) {
Brian Silverman8fce7482020-01-05 13:18:21 -080058 return errorHandler(isError, errorCode, isLVCode, details, location,
59 callStack, printMsg);
Austin Schuh812d0d12021-11-04 20:16:48 -070060 }
Brian Silverman8fce7482020-01-05 13:18:21 -080061 // Avoid flooding console by keeping track of previous 5 error
62 // messages and only printing again if they're longer than 1 second old.
63 static constexpr int KEEP_MSGS = 5;
64 std::scoped_lock lock(msgMutex);
65 static std::string prevMsg[KEEP_MSGS];
Austin Schuh1e69f942020-11-14 15:06:14 -080066 static fpga_clock::time_point prevMsgTime[KEEP_MSGS];
Brian Silverman8fce7482020-01-05 13:18:21 -080067 static bool initialized = false;
68 if (!initialized) {
69 for (int i = 0; i < KEEP_MSGS; i++) {
Austin Schuh1e69f942020-11-14 15:06:14 -080070 prevMsgTime[i] = fpga_clock::now() - std::chrono::seconds(2);
Brian Silverman8fce7482020-01-05 13:18:21 -080071 }
72 initialized = true;
73 }
74
Austin Schuh1e69f942020-11-14 15:06:14 -080075 auto curTime = fpga_clock::now();
Brian Silverman8fce7482020-01-05 13:18:21 -080076 int i;
77 for (i = 0; i < KEEP_MSGS; ++i) {
Austin Schuh812d0d12021-11-04 20:16:48 -070078 if (prevMsg[i] == details) {
79 break;
80 }
Brian Silverman8fce7482020-01-05 13:18:21 -080081 }
82 int retval = 0;
83 if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
84 printMsg = true;
85 if (printMsg) {
Austin Schuh812d0d12021-11-04 20:16:48 -070086 fmt::memory_buffer buf;
Brian Silverman8fce7482020-01-05 13:18:21 -080087 if (location && location[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -070088 fmt::format_to(fmt::appender{buf},
89 "{} at {}: ", isError ? "Error" : "Warning", location);
Brian Silverman8fce7482020-01-05 13:18:21 -080090 }
Austin Schuh812d0d12021-11-04 20:16:48 -070091 fmt::format_to(fmt::appender{buf}, "{}\n", details);
Brian Silverman8fce7482020-01-05 13:18:21 -080092 if (callStack && callStack[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -070093 fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
Brian Silverman8fce7482020-01-05 13:18:21 -080094 }
Austin Schuh812d0d12021-11-04 20:16:48 -070095 std::fwrite(buf.data(), buf.size(), 1, stderr);
Brian Silverman8fce7482020-01-05 13:18:21 -080096 }
97 if (i == KEEP_MSGS) {
98 // replace the oldest one
99 i = 0;
100 auto first = prevMsgTime[0];
101 for (int j = 1; j < KEEP_MSGS; ++j) {
102 if (prevMsgTime[j] < first) {
103 first = prevMsgTime[j];
104 i = j;
105 }
106 }
107 prevMsg[i] = details;
108 }
109 prevMsgTime[i] = curTime;
110 }
111 return retval;
112}
113
Austin Schuh1e69f942020-11-14 15:06:14 -0800114int32_t HAL_SendConsoleLine(const char* line) {
115 auto handler = sendConsoleLineHandler.load();
116 if (handler) {
117 return handler(line);
118 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700119 std::puts(line);
120 std::fflush(stdout);
Austin Schuh1e69f942020-11-14 15:06:14 -0800121 return 0;
122}
123
Brian Silverman8fce7482020-01-05 13:18:21 -0800124int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700125 std::memset(controlWord, 0, sizeof(HAL_ControlWord));
Brian Silverman8fce7482020-01-05 13:18:21 -0800126 controlWord->enabled = SimDriverStationData->enabled;
127 controlWord->autonomous = SimDriverStationData->autonomous;
128 controlWord->test = SimDriverStationData->test;
129 controlWord->eStop = SimDriverStationData->eStop;
130 controlWord->fmsAttached = SimDriverStationData->fmsAttached;
131 controlWord->dsAttached = SimDriverStationData->dsAttached;
132 return 0;
133}
134
135HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
136 *status = 0;
137 return SimDriverStationData->allianceStationId;
138}
139
140int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
141 SimDriverStationData->GetJoystickAxes(joystickNum, axes);
142 return 0;
143}
144
145int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
146 SimDriverStationData->GetJoystickPOVs(joystickNum, povs);
147 return 0;
148}
149
150int32_t HAL_GetJoystickButtons(int32_t joystickNum,
151 HAL_JoystickButtons* buttons) {
152 SimDriverStationData->GetJoystickButtons(joystickNum, buttons);
153 return 0;
154}
155
156int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
157 HAL_JoystickDescriptor* desc) {
158 SimDriverStationData->GetJoystickDescriptor(joystickNum, desc);
159 return 0;
160}
161
162HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
163 HAL_JoystickDescriptor desc;
164 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
165 return desc.isXbox;
166}
167
168int32_t HAL_GetJoystickType(int32_t joystickNum) {
169 HAL_JoystickDescriptor desc;
170 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
171 return desc.type;
172}
173
174char* HAL_GetJoystickName(int32_t joystickNum) {
175 HAL_JoystickDescriptor desc;
176 SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
177 size_t len = std::strlen(desc.name);
178 char* name = static_cast<char*>(std::malloc(len + 1));
179 std::memcpy(name, desc.name, len + 1);
180 return name;
181}
182
Austin Schuh812d0d12021-11-04 20:16:48 -0700183void HAL_FreeJoystickName(char* name) {
184 std::free(name);
185}
Brian Silverman8fce7482020-01-05 13:18:21 -0800186
Austin Schuh812d0d12021-11-04 20:16:48 -0700187int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
188 return 0;
189}
Brian Silverman8fce7482020-01-05 13:18:21 -0800190
191int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
192 int32_t leftRumble, int32_t rightRumble) {
193 SimDriverStationData->SetJoystickOutputs(joystickNum, outputs, leftRumble,
194 rightRumble);
195 return 0;
196}
197
198double HAL_GetMatchTime(int32_t* status) {
199 return SimDriverStationData->matchTime;
200}
201
202int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
203 SimDriverStationData->GetMatchInfo(info);
204 return 0;
205}
206
Austin Schuh812d0d12021-11-04 20:16:48 -0700207void HAL_ObserveUserProgramStarting(void) {
208 HALSIM_SetProgramStarted();
209}
Brian Silverman8fce7482020-01-05 13:18:21 -0800210
211void HAL_ObserveUserProgramDisabled(void) {
212 // TODO
213}
214
215void HAL_ObserveUserProgramAutonomous(void) {
216 // TODO
217}
218
219void HAL_ObserveUserProgramTeleop(void) {
220 // TODO
221}
222
223void HAL_ObserveUserProgramTest(void) {
224 // TODO
225}
226
Brian Silverman8fce7482020-01-05 13:18:21 -0800227static int& GetThreadLocalLastCount() {
228 // There is a rollover error condition here. At Packet# = n * (uintmax), this
229 // will return false when instead it should return true. However, this at a
230 // 20ms rate occurs once every 2.7 years of DS connected runtime, so not
231 // worth the cycles to check.
Austin Schuh1e69f942020-11-14 15:06:14 -0800232 thread_local int lastCount{0};
Brian Silverman8fce7482020-01-05 13:18:21 -0800233 return lastCount;
234}
235
Austin Schuh1e69f942020-11-14 15:06:14 -0800236HAL_Bool HAL_IsNewControlData(void) {
237 std::scoped_lock lock(newDSDataAvailableMutex);
Brian Silverman8fce7482020-01-05 13:18:21 -0800238 int& lastCount = GetThreadLocalLastCount();
Austin Schuh1e69f942020-11-14 15:06:14 -0800239 int currentCount = newDSDataAvailableCounter;
Austin Schuh812d0d12021-11-04 20:16:48 -0700240 if (lastCount == currentCount) {
241 return false;
242 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800243 lastCount = currentCount;
244 return true;
245}
246
Austin Schuh812d0d12021-11-04 20:16:48 -0700247void HAL_WaitForDSData(void) {
248 HAL_WaitForDSDataTimeout(0);
249}
Austin Schuh1e69f942020-11-14 15:06:14 -0800250
251HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800252 std::unique_lock lock(newDSDataAvailableMutex);
Austin Schuh1e69f942020-11-14 15:06:14 -0800253 int& lastCount = GetThreadLocalLastCount();
Brian Silverman8fce7482020-01-05 13:18:21 -0800254 int currentCount = newDSDataAvailableCounter;
255 if (lastCount != currentCount) {
256 lastCount = currentCount;
257 return true;
258 }
259
260 if (isFinalized.load()) {
261 return false;
262 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800263 auto timeoutTime =
264 std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
265
266 while (newDSDataAvailableCounter == currentCount) {
267 if (timeout > 0) {
268 auto timedOut = newDSDataAvailableCond->wait_until(lock, timeoutTime);
269 if (timedOut == std::cv_status::timeout) {
270 return false;
271 }
272 } else {
273 newDSDataAvailableCond->wait(lock);
274 }
275 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800276 lastCount = newDSDataAvailableCounter;
Brian Silverman8fce7482020-01-05 13:18:21 -0800277 return true;
278}
279
280// Constant number to be used for our occur handle
281constexpr int32_t refNumber = 42;
282
283static int32_t newDataOccur(uint32_t refNum) {
284 // Since we could get other values, require our specific handle
285 // to signal our threads
Austin Schuh812d0d12021-11-04 20:16:48 -0700286 if (refNum != refNumber) {
287 return 0;
288 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800289 SimDriverStationData->CallNewDataCallbacks();
Brian Silverman8fce7482020-01-05 13:18:21 -0800290 std::scoped_lock lock(newDSDataAvailableMutex);
291 // Nofify all threads
292 newDSDataAvailableCounter++;
293 newDSDataAvailableCond->notify_all();
294 return 0;
295}
296
297void HAL_InitializeDriverStation(void) {
298 hal::init::CheckInit();
299 static std::atomic_bool initialized{false};
300 static wpi::mutex initializeMutex;
301 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700302 if (initialized) {
303 return;
304 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800305
306 std::scoped_lock lock(initializeMutex);
307 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700308 if (initialized) {
309 return;
310 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800311
312 SimDriverStationData->ResetData();
313
314 std::atexit([]() {
315 isFinalized.store(true);
316 HAL_ReleaseDSMutex();
317 });
318
319 initialized = true;
320}
321
Austin Schuh812d0d12021-11-04 20:16:48 -0700322void HAL_ReleaseDSMutex(void) {
323 newDataOccur(refNumber);
324}
Brian Silverman8fce7482020-01-05 13:18:21 -0800325
326} // extern "C"