blob: 12739c82f3a9db19dcb404874389f28e336afc9c [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 <atomic>
6#include <chrono>
7#include <cstdlib>
8#include <cstring>
9#include <limits>
Austin Schuh812d0d12021-11-04 20:16:48 -070010#include <string>
11#include <string_view>
Brian Silverman8fce7482020-01-05 13:18:21 -080012
13#include <FRC_NetworkCommunication/FRCComm.h>
14#include <FRC_NetworkCommunication/NetCommRPCProxy_Occur.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070015#include <fmt/format.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080016#include <wpi/EventVector.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080017#include <wpi/SafeThread.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080018#include <wpi/SmallVector.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080019#include <wpi/condition_variable.h>
20#include <wpi/mutex.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080021
James Kuszmaulcf324122023-01-14 14:07:17 -080022#include "HALInitializer.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080023#include "hal/DriverStation.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080024#include "hal/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080025
26static_assert(sizeof(int32_t) >= sizeof(int),
27 "FRC_NetworkComm status variable is larger than 32 bits");
28
James Kuszmaulcf324122023-01-14 14:07:17 -080029namespace {
Brian Silverman8fce7482020-01-05 13:18:21 -080030struct HAL_JoystickAxesInt {
31 int16_t count;
32 int16_t axes[HAL_kMaxJoystickAxes];
33};
James Kuszmaulcf324122023-01-14 14:07:17 -080034} // namespace
Brian Silverman8fce7482020-01-05 13:18:21 -080035
James Kuszmaulcf324122023-01-14 14:07:17 -080036namespace {
37struct JoystickDataCache {
38 JoystickDataCache() { std::memset(this, 0, sizeof(*this)); }
39 void Update();
40
41 HAL_JoystickAxes axes[HAL_kMaxJoysticks];
42 HAL_JoystickPOVs povs[HAL_kMaxJoysticks];
43 HAL_JoystickButtons buttons[HAL_kMaxJoysticks];
44 HAL_AllianceStationID allianceStation;
45 float matchTime;
James Kuszmaulb13e13f2023-11-22 20:44:04 -080046 HAL_ControlWord controlWord;
James Kuszmaulcf324122023-01-14 14:07:17 -080047};
48static_assert(std::is_standard_layout_v<JoystickDataCache>);
49// static_assert(std::is_trivial_v<JoystickDataCache>);
50
51struct FRCDriverStation {
52 wpi::EventVector newDataEvents;
53};
54} // namespace
55
56static ::FRCDriverStation* driverStation;
Brian Silverman8fce7482020-01-05 13:18:21 -080057
58// Message and Data variables
59static wpi::mutex msgMutex;
60
61static int32_t HAL_GetJoystickAxesInternal(int32_t joystickNum,
62 HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -080063 HAL_JoystickAxesInt netcommAxes;
Brian Silverman8fce7482020-01-05 13:18:21 -080064
65 int retVal = FRC_NetworkCommunication_getJoystickAxes(
James Kuszmaulcf324122023-01-14 14:07:17 -080066 joystickNum, reinterpret_cast<JoystickAxes_t*>(&netcommAxes),
Brian Silverman8fce7482020-01-05 13:18:21 -080067 HAL_kMaxJoystickAxes);
68
69 // copy integer values to double values
James Kuszmaulcf324122023-01-14 14:07:17 -080070 axes->count = netcommAxes.count;
Brian Silverman8fce7482020-01-05 13:18:21 -080071 // current scaling is -128 to 127, can easily be patched in the future by
72 // changing this function.
James Kuszmaulcf324122023-01-14 14:07:17 -080073 for (int32_t i = 0; i < netcommAxes.count; i++) {
74 int8_t value = netcommAxes.axes[i];
75 axes->raw[i] = value;
Brian Silverman8fce7482020-01-05 13:18:21 -080076 if (value < 0) {
77 axes->axes[i] = value / 128.0;
78 } else {
79 axes->axes[i] = value / 127.0;
80 }
81 }
82
83 return retVal;
84}
85
86static int32_t HAL_GetJoystickPOVsInternal(int32_t joystickNum,
87 HAL_JoystickPOVs* povs) {
88 return FRC_NetworkCommunication_getJoystickPOVs(
89 joystickNum, reinterpret_cast<JoystickPOV_t*>(povs),
90 HAL_kMaxJoystickPOVs);
91}
92
93static int32_t HAL_GetJoystickButtonsInternal(int32_t joystickNum,
94 HAL_JoystickButtons* buttons) {
95 return FRC_NetworkCommunication_getJoystickButtons(
96 joystickNum, &buttons->buttons, &buttons->count);
97}
James Kuszmaulcf324122023-01-14 14:07:17 -080098
99void JoystickDataCache::Update() {
100 for (int i = 0; i < HAL_kMaxJoysticks; i++) {
101 HAL_GetJoystickAxesInternal(i, &axes[i]);
102 HAL_GetJoystickPOVsInternal(i, &povs[i]);
103 HAL_GetJoystickButtonsInternal(i, &buttons[i]);
104 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800105 AllianceStationID_t alliance = kAllianceStationID_red1;
106 FRC_NetworkCommunication_getAllianceStation(&alliance);
107 int allianceInt = alliance;
108 allianceInt += 1;
109 allianceStation = static_cast<HAL_AllianceStationID>(allianceInt);
James Kuszmaulcf324122023-01-14 14:07:17 -0800110 FRC_NetworkCommunication_getMatchTime(&matchTime);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800111 FRC_NetworkCommunication_getControlWord(
112 reinterpret_cast<ControlWord_t*>(&controlWord));
James Kuszmaulcf324122023-01-14 14:07:17 -0800113}
114
115#define CHECK_JOYSTICK_NUMBER(stickNum) \
116 if ((stickNum) < 0 || (stickNum) >= HAL_kMaxJoysticks) \
117 return PARAMETER_OUT_OF_RANGE
118
119static HAL_ControlWord newestControlWord;
120static JoystickDataCache caches[3];
121static JoystickDataCache* currentRead = &caches[0];
122static JoystickDataCache* currentReadLocal = &caches[0];
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800123static std::atomic<JoystickDataCache*> currentCache{nullptr};
James Kuszmaulcf324122023-01-14 14:07:17 -0800124static JoystickDataCache* lastGiven = &caches[1];
125static JoystickDataCache* cacheToUpdate = &caches[2];
126
127static wpi::mutex cacheMutex;
128
Brian Silverman8fce7482020-01-05 13:18:21 -0800129/**
Austin Schuh812d0d12021-11-04 20:16:48 -0700130 * Retrieve the Joystick Descriptor for particular slot.
Brian Silverman8fce7482020-01-05 13:18:21 -0800131 *
Austin Schuh812d0d12021-11-04 20:16:48 -0700132 * @param[out] desc descriptor (data transfer object) to fill in. desc is filled
133 * in regardless of success. In other words, if descriptor is
134 * not available, desc is filled in with default values
135 * matching the init-values in Java and C++ Driverstation for
136 * when caller requests a too-large joystick index.
Brian Silverman8fce7482020-01-05 13:18:21 -0800137 * @return error code reported from Network Comm back-end. Zero is good,
Austin Schuh812d0d12021-11-04 20:16:48 -0700138 * nonzero is bad.
Brian Silverman8fce7482020-01-05 13:18:21 -0800139 */
140static int32_t HAL_GetJoystickDescriptorInternal(int32_t joystickNum,
141 HAL_JoystickDescriptor* desc) {
142 desc->isXbox = 0;
143 desc->type = (std::numeric_limits<uint8_t>::max)();
144 desc->name[0] = '\0';
145 desc->axisCount =
146 HAL_kMaxJoystickAxes; /* set to the desc->axisTypes's capacity */
147 desc->buttonCount = 0;
148 desc->povCount = 0;
149 int retval = FRC_NetworkCommunication_getJoystickDesc(
150 joystickNum, &desc->isXbox, &desc->type,
151 reinterpret_cast<char*>(&desc->name), &desc->axisCount,
152 reinterpret_cast<uint8_t*>(&desc->axisTypes), &desc->buttonCount,
153 &desc->povCount);
154 /* check the return, if there is an error and the RIOimage predates FRC2017,
155 * then axisCount needs to be cleared */
156 if (retval != 0) {
157 /* set count to zero so downstream code doesn't decode invalid axisTypes. */
158 desc->axisCount = 0;
159 }
160 return retval;
161}
162
Brian Silverman8fce7482020-01-05 13:18:21 -0800163static int32_t HAL_GetMatchInfoInternal(HAL_MatchInfo* info) {
164 MatchType_t matchType = MatchType_t::kMatchType_none;
Austin Schuh75263e32022-02-22 18:05:32 -0800165 info->gameSpecificMessageSize = sizeof(info->gameSpecificMessage);
Brian Silverman8fce7482020-01-05 13:18:21 -0800166 int status = FRC_NetworkCommunication_getMatchInfo(
167 info->eventName, &matchType, &info->matchNumber, &info->replayNumber,
168 info->gameSpecificMessage, &info->gameSpecificMessageSize);
169
Austin Schuh75263e32022-02-22 18:05:32 -0800170 if (info->gameSpecificMessageSize > sizeof(info->gameSpecificMessage)) {
171 info->gameSpecificMessageSize = 0;
172 }
173
Brian Silverman8fce7482020-01-05 13:18:21 -0800174 info->matchType = static_cast<HAL_MatchType>(matchType);
175
176 *(std::end(info->eventName) - 1) = '\0';
177
178 return status;
179}
180
James Kuszmaulcf324122023-01-14 14:07:17 -0800181namespace {
182struct TcpCache {
183 TcpCache() { std::memset(this, 0, sizeof(*this)); }
184 void Update(uint32_t mask);
185 void CloneTo(TcpCache* other) { std::memcpy(other, this, sizeof(*this)); }
186
187 HAL_MatchInfo matchInfo;
188 HAL_JoystickDescriptor descriptors[HAL_kMaxJoysticks];
189};
190static_assert(std::is_standard_layout_v<TcpCache>);
191} // namespace
192
193static std::atomic_uint32_t tcpMask{0xFFFFFFFF};
194static TcpCache tcpCache;
195static TcpCache tcpCurrent;
196static wpi::mutex tcpCacheMutex;
197
198constexpr uint32_t combinedMatchInfoMask = kTcpRecvMask_MatchInfoOld |
199 kTcpRecvMask_MatchInfo |
200 kTcpRecvMask_GameSpecific;
201
202void TcpCache::Update(uint32_t mask) {
203 if ((mask & combinedMatchInfoMask) != 0) {
204 HAL_GetMatchInfoInternal(&matchInfo);
205 }
206 for (int i = 0; i < HAL_kMaxJoysticks; i++) {
207 if ((mask & (1 << i)) != 0) {
208 HAL_GetJoystickDescriptorInternal(i, &descriptors[i]);
209 }
210 }
211}
Brian Silverman8fce7482020-01-05 13:18:21 -0800212
Austin Schuh812d0d12021-11-04 20:16:48 -0700213namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -0800214void InitializeFRCDriverStation() {
James Kuszmaulcf324122023-01-14 14:07:17 -0800215 std::memset(&newestControlWord, 0, sizeof(newestControlWord));
216 static FRCDriverStation ds;
217 driverStation = &ds;
Brian Silverman8fce7482020-01-05 13:18:21 -0800218}
Austin Schuh812d0d12021-11-04 20:16:48 -0700219} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800220
James Kuszmaulcf324122023-01-14 14:07:17 -0800221namespace hal {
222static void DefaultPrintErrorImpl(const char* line, size_t size) {
223 std::fwrite(line, size, 1, stderr);
224}
225} // namespace hal
226
227static std::atomic<void (*)(const char* line, size_t size)> gPrintErrorImpl{
228 hal::DefaultPrintErrorImpl};
229
Brian Silverman8fce7482020-01-05 13:18:21 -0800230extern "C" {
231
232int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
233 const char* details, const char* location,
234 const char* callStack, HAL_Bool printMsg) {
235 // Avoid flooding console by keeping track of previous 5 error
236 // messages and only printing again if they're longer than 1 second old.
237 static constexpr int KEEP_MSGS = 5;
238 std::scoped_lock lock(msgMutex);
239 static std::string prevMsg[KEEP_MSGS];
240 static std::chrono::time_point<std::chrono::steady_clock>
241 prevMsgTime[KEEP_MSGS];
242 static bool initialized = false;
243 if (!initialized) {
244 for (int i = 0; i < KEEP_MSGS; i++) {
245 prevMsgTime[i] =
246 std::chrono::steady_clock::now() - std::chrono::seconds(2);
247 }
248 initialized = true;
249 }
250
251 auto curTime = std::chrono::steady_clock::now();
252 int i;
253 for (i = 0; i < KEEP_MSGS; ++i) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700254 if (prevMsg[i] == details) {
255 break;
256 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800257 }
258 int retval = 0;
259 if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700260 std::string_view detailsRef{details};
261 std::string_view locationRef{location};
262 std::string_view callStackRef{callStack};
Brian Silverman8fce7482020-01-05 13:18:21 -0800263
264 // 1 tag, 4 timestamp, 2 seqnum
265 // 2 numOccur, 4 error code, 1 flags, 6 strlen
266 // 1 extra needed for padding on Netcomm end.
267 size_t baseLength = 21;
268
269 if (baseLength + detailsRef.size() + locationRef.size() +
270 callStackRef.size() <=
Austin Schuh1e69f942020-11-14 15:06:14 -0800271 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800272 // Pass through
273 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
274 details, location, callStack);
Austin Schuh1e69f942020-11-14 15:06:14 -0800275 } else if (baseLength + detailsRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800276 // Details too long, cut both location and stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800277 auto newLen = 65535 - baseLength;
Brian Silverman8fce7482020-01-05 13:18:21 -0800278 std::string newDetails{details, newLen};
279 char empty = '\0';
280 retval = FRC_NetworkCommunication_sendError(
281 isError, errorCode, isLVCode, newDetails.c_str(), &empty, &empty);
Austin Schuh1e69f942020-11-14 15:06:14 -0800282 } else if (baseLength + detailsRef.size() + locationRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800283 // Location too long, cut stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800284 auto newLen = 65535 - baseLength - detailsRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800285 std::string newLocation{location, newLen};
286 char empty = '\0';
287 retval = FRC_NetworkCommunication_sendError(
288 isError, errorCode, isLVCode, details, newLocation.c_str(), &empty);
289 } else {
290 // Stack too long
Austin Schuh1e69f942020-11-14 15:06:14 -0800291 auto newLen = 65535 - baseLength - detailsRef.size() - locationRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800292 std::string newCallStack{callStack, newLen};
293 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
294 details, location,
295 newCallStack.c_str());
296 }
297 if (printMsg) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700298 fmt::memory_buffer buf;
Brian Silverman8fce7482020-01-05 13:18:21 -0800299 if (location && location[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700300 fmt::format_to(fmt::appender{buf},
301 "{} at {}: ", isError ? "Error" : "Warning", location);
Brian Silverman8fce7482020-01-05 13:18:21 -0800302 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700303 fmt::format_to(fmt::appender{buf}, "{}\n", details);
Brian Silverman8fce7482020-01-05 13:18:21 -0800304 if (callStack && callStack[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700305 fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
Brian Silverman8fce7482020-01-05 13:18:21 -0800306 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800307 auto printError = gPrintErrorImpl.load();
308 printError(buf.data(), buf.size());
Brian Silverman8fce7482020-01-05 13:18:21 -0800309 }
310 if (i == KEEP_MSGS) {
311 // replace the oldest one
312 i = 0;
313 auto first = prevMsgTime[0];
314 for (int j = 1; j < KEEP_MSGS; ++j) {
315 if (prevMsgTime[j] < first) {
316 first = prevMsgTime[j];
317 i = j;
318 }
319 }
320 prevMsg[i] = details;
321 }
322 prevMsgTime[i] = curTime;
323 }
324 return retval;
325}
326
James Kuszmaulcf324122023-01-14 14:07:17 -0800327void HAL_SetPrintErrorImpl(void (*func)(const char* line, size_t size)) {
328 gPrintErrorImpl.store(func ? func : hal::DefaultPrintErrorImpl);
329}
330
Austin Schuh1e69f942020-11-14 15:06:14 -0800331int32_t HAL_SendConsoleLine(const char* line) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700332 std::string_view lineRef{line};
Austin Schuh1e69f942020-11-14 15:06:14 -0800333 if (lineRef.size() <= 65535) {
334 // Send directly
335 return FRC_NetworkCommunication_sendConsoleLine(line);
336 } else {
337 // Need to truncate
338 std::string newLine{line, 65535};
339 return FRC_NetworkCommunication_sendConsoleLine(newLine.c_str());
340 }
341}
342
Brian Silverman8fce7482020-01-05 13:18:21 -0800343int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800344 std::scoped_lock lock{cacheMutex};
345 *controlWord = newestControlWord;
346 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800347}
348
349int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800350 CHECK_JOYSTICK_NUMBER(joystickNum);
351 std::scoped_lock lock{cacheMutex};
352 *axes = currentRead->axes[joystickNum];
353 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800354}
355
356int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800357 CHECK_JOYSTICK_NUMBER(joystickNum);
358 std::scoped_lock lock{cacheMutex};
359 *povs = currentRead->povs[joystickNum];
360 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800361}
362
363int32_t HAL_GetJoystickButtons(int32_t joystickNum,
364 HAL_JoystickButtons* buttons) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800365 CHECK_JOYSTICK_NUMBER(joystickNum);
366 std::scoped_lock lock{cacheMutex};
367 *buttons = currentRead->buttons[joystickNum];
368 return 0;
369}
370
371void HAL_GetAllJoystickData(HAL_JoystickAxes* axes, HAL_JoystickPOVs* povs,
372 HAL_JoystickButtons* buttons) {
373 std::scoped_lock lock{cacheMutex};
374 std::memcpy(axes, currentRead->axes, sizeof(currentRead->axes));
375 std::memcpy(povs, currentRead->povs, sizeof(currentRead->povs));
376 std::memcpy(buttons, currentRead->buttons, sizeof(currentRead->buttons));
Brian Silverman8fce7482020-01-05 13:18:21 -0800377}
378
379int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
380 HAL_JoystickDescriptor* desc) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800381 CHECK_JOYSTICK_NUMBER(joystickNum);
382 std::scoped_lock lock{tcpCacheMutex};
383 *desc = tcpCurrent.descriptors[joystickNum];
384 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800385}
386
387int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800388 std::scoped_lock lock{tcpCacheMutex};
389 *info = tcpCurrent.matchInfo;
390 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800391}
392
393HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800394 std::scoped_lock lock{cacheMutex};
395 return currentRead->allianceStation;
Brian Silverman8fce7482020-01-05 13:18:21 -0800396}
397
398HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
399 HAL_JoystickDescriptor joystickDesc;
400 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
401 return 0;
402 } else {
403 return joystickDesc.isXbox;
404 }
405}
406
407int32_t HAL_GetJoystickType(int32_t joystickNum) {
408 HAL_JoystickDescriptor joystickDesc;
409 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
410 return -1;
411 } else {
412 return joystickDesc.type;
413 }
414}
415
416char* HAL_GetJoystickName(int32_t joystickNum) {
417 HAL_JoystickDescriptor joystickDesc;
418 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
419 char* name = static_cast<char*>(std::malloc(1));
420 name[0] = '\0';
421 return name;
422 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700423 const size_t len = std::strlen(joystickDesc.name) + 1;
424 char* name = static_cast<char*>(std::malloc(len));
425 std::memcpy(name, joystickDesc.name, len);
Brian Silverman8fce7482020-01-05 13:18:21 -0800426 return name;
427 }
428}
429
Austin Schuh812d0d12021-11-04 20:16:48 -0700430void HAL_FreeJoystickName(char* name) {
431 std::free(name);
432}
Brian Silverman8fce7482020-01-05 13:18:21 -0800433
434int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
435 HAL_JoystickDescriptor joystickDesc;
436 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
437 return -1;
438 } else {
439 return joystickDesc.axisTypes[axis];
440 }
441}
442
443int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
444 int32_t leftRumble, int32_t rightRumble) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800445 CHECK_JOYSTICK_NUMBER(joystickNum);
Brian Silverman8fce7482020-01-05 13:18:21 -0800446 return FRC_NetworkCommunication_setJoystickOutputs(joystickNum, outputs,
447 leftRumble, rightRumble);
448}
449
450double HAL_GetMatchTime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800451 std::scoped_lock lock{cacheMutex};
452 return currentRead->matchTime;
Brian Silverman8fce7482020-01-05 13:18:21 -0800453}
454
455void HAL_ObserveUserProgramStarting(void) {
456 FRC_NetworkCommunication_observeUserProgramStarting();
457}
458
459void HAL_ObserveUserProgramDisabled(void) {
460 FRC_NetworkCommunication_observeUserProgramDisabled();
461}
462
463void HAL_ObserveUserProgramAutonomous(void) {
464 FRC_NetworkCommunication_observeUserProgramAutonomous();
465}
466
467void HAL_ObserveUserProgramTeleop(void) {
468 FRC_NetworkCommunication_observeUserProgramTeleop();
469}
470
471void HAL_ObserveUserProgramTest(void) {
472 FRC_NetworkCommunication_observeUserProgramTest();
473}
474
Brian Silverman8fce7482020-01-05 13:18:21 -0800475// Constant number to be used for our occur handle
476constexpr int32_t refNumber = 42;
James Kuszmaulcf324122023-01-14 14:07:17 -0800477constexpr int32_t tcpRefNumber = 94;
Brian Silverman8fce7482020-01-05 13:18:21 -0800478
James Kuszmaulcf324122023-01-14 14:07:17 -0800479static void tcpOccur(void) {
480 uint32_t mask = FRC_NetworkCommunication_getNewTcpRecvMask();
481 tcpMask.fetch_or(mask);
Brian Silverman8fce7482020-01-05 13:18:21 -0800482}
483
James Kuszmaulcf324122023-01-14 14:07:17 -0800484static void udpOccur(void) {
485 cacheToUpdate->Update();
Brian Silverman8fce7482020-01-05 13:18:21 -0800486
James Kuszmaulcf324122023-01-14 14:07:17 -0800487 JoystickDataCache* given = cacheToUpdate;
488 JoystickDataCache* prev = currentCache.exchange(cacheToUpdate);
489 if (prev == nullptr) {
490 cacheToUpdate = currentReadLocal;
491 currentReadLocal = lastGiven;
492 } else {
493 // Current read local does not update
494 cacheToUpdate = prev;
Austin Schuh812d0d12021-11-04 20:16:48 -0700495 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800496 lastGiven = given;
Brian Silverman8fce7482020-01-05 13:18:21 -0800497
James Kuszmaulcf324122023-01-14 14:07:17 -0800498 driverStation->newDataEvents.Wakeup();
499}
500
501static void newDataOccur(uint32_t refNum) {
502 switch (refNum) {
503 case refNumber:
504 udpOccur();
505 break;
506
507 case tcpRefNumber:
508 tcpOccur();
509 break;
510
511 default:
512 std::printf("Unknown occur %u\n", refNum);
513 break;
514 }
515}
516
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800517HAL_Bool HAL_RefreshDSData(void) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800518 HAL_ControlWord controlWord;
519 std::memset(&controlWord, 0, sizeof(controlWord));
520 FRC_NetworkCommunication_getControlWord(
521 reinterpret_cast<ControlWord_t*>(&controlWord));
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800522 JoystickDataCache* prev;
523 {
524 std::scoped_lock lock{cacheMutex};
525 prev = currentCache.exchange(nullptr);
526 if (prev != nullptr) {
527 currentRead = prev;
528 }
529 // If newest state shows we have a DS attached, just use the
530 // control word out of the cache, As it will be the one in sync
531 // with the data. Otherwise use the state that shows disconnected.
532 if (controlWord.dsAttached) {
533 newestControlWord = currentRead->controlWord;
534 } else {
535 newestControlWord = controlWord;
536 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800537 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800538
539 uint32_t mask = tcpMask.exchange(0);
540 if (mask != 0) {
541 tcpCache.Update(mask);
542 std::scoped_lock tcpLock(tcpCacheMutex);
543 tcpCache.CloneTo(&tcpCurrent);
544 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800545 return prev != nullptr;
James Kuszmaulcf324122023-01-14 14:07:17 -0800546}
547
548void HAL_ProvideNewDataEventHandle(WPI_EventHandle handle) {
549 hal::init::CheckInit();
550 driverStation->newDataEvents.Add(handle);
551}
552
553void HAL_RemoveNewDataEventHandle(WPI_EventHandle handle) {
554 driverStation->newDataEvents.Remove(handle);
555}
556
557HAL_Bool HAL_GetOutputsEnabled(void) {
558 return FRC_NetworkCommunication_getWatchdogActive();
559}
560
561} // extern "C"
562
563namespace hal {
564void InitializeDriverStation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800565 // Set up the occur function internally with NetComm
566 NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
567 // Set up our occur reference number
568 setNewDataOccurRef(refNumber);
James Kuszmaulcf324122023-01-14 14:07:17 -0800569 FRC_NetworkCommunication_setNewTcpDataOccurRef(tcpRefNumber);
Brian Silverman8fce7482020-01-05 13:18:21 -0800570}
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800571
572void WaitForInitialPacket() {
573 wpi::Event waitForInitEvent;
574 driverStation->newDataEvents.Add(waitForInitEvent.GetHandle());
575 bool timed_out = false;
576 wpi::WaitForObject(waitForInitEvent.GetHandle(), 0.1, &timed_out);
577 // Don't care what the result is, just want to give it a chance.
578 driverStation->newDataEvents.Remove(waitForInitEvent.GetHandle());
579}
James Kuszmaulcf324122023-01-14 14:07:17 -0800580} // namespace hal