blob: c30fbb94c59bdfc2f9847f94b0f912789e486f4b [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)); }
Maxwell Henderson80bec322024-01-09 15:48:44 -0800184 bool Update(uint32_t mask);
James Kuszmaulcf324122023-01-14 14:07:17 -0800185 void CloneTo(TcpCache* other) { std::memcpy(other, this, sizeof(*this)); }
186
Maxwell Henderson80bec322024-01-09 15:48:44 -0800187 bool hasReadMatchInfo = false;
James Kuszmaulcf324122023-01-14 14:07:17 -0800188 HAL_MatchInfo matchInfo;
189 HAL_JoystickDescriptor descriptors[HAL_kMaxJoysticks];
190};
191static_assert(std::is_standard_layout_v<TcpCache>);
192} // namespace
193
194static std::atomic_uint32_t tcpMask{0xFFFFFFFF};
195static TcpCache tcpCache;
196static TcpCache tcpCurrent;
197static wpi::mutex tcpCacheMutex;
198
199constexpr uint32_t combinedMatchInfoMask = kTcpRecvMask_MatchInfoOld |
200 kTcpRecvMask_MatchInfo |
201 kTcpRecvMask_GameSpecific;
202
Maxwell Henderson80bec322024-01-09 15:48:44 -0800203bool TcpCache::Update(uint32_t mask) {
204 bool failedToReadInfo = false;
James Kuszmaulcf324122023-01-14 14:07:17 -0800205 if ((mask & combinedMatchInfoMask) != 0) {
Maxwell Henderson80bec322024-01-09 15:48:44 -0800206 int status = HAL_GetMatchInfoInternal(&matchInfo);
207 if (status != 0) {
208 failedToReadInfo = true;
209 if (!hasReadMatchInfo) {
210 std::memset(&matchInfo, 0, sizeof(matchInfo));
211 }
212 } else {
213 hasReadMatchInfo = true;
214 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800215 }
216 for (int i = 0; i < HAL_kMaxJoysticks; i++) {
217 if ((mask & (1 << i)) != 0) {
218 HAL_GetJoystickDescriptorInternal(i, &descriptors[i]);
219 }
220 }
Maxwell Henderson80bec322024-01-09 15:48:44 -0800221 return failedToReadInfo;
James Kuszmaulcf324122023-01-14 14:07:17 -0800222}
Brian Silverman8fce7482020-01-05 13:18:21 -0800223
Austin Schuh812d0d12021-11-04 20:16:48 -0700224namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -0800225void InitializeFRCDriverStation() {
James Kuszmaulcf324122023-01-14 14:07:17 -0800226 std::memset(&newestControlWord, 0, sizeof(newestControlWord));
227 static FRCDriverStation ds;
228 driverStation = &ds;
Brian Silverman8fce7482020-01-05 13:18:21 -0800229}
Austin Schuh812d0d12021-11-04 20:16:48 -0700230} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800231
James Kuszmaulcf324122023-01-14 14:07:17 -0800232namespace hal {
233static void DefaultPrintErrorImpl(const char* line, size_t size) {
234 std::fwrite(line, size, 1, stderr);
235}
236} // namespace hal
237
238static std::atomic<void (*)(const char* line, size_t size)> gPrintErrorImpl{
239 hal::DefaultPrintErrorImpl};
240
Brian Silverman8fce7482020-01-05 13:18:21 -0800241extern "C" {
242
243int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
244 const char* details, const char* location,
245 const char* callStack, HAL_Bool printMsg) {
246 // Avoid flooding console by keeping track of previous 5 error
247 // messages and only printing again if they're longer than 1 second old.
248 static constexpr int KEEP_MSGS = 5;
249 std::scoped_lock lock(msgMutex);
250 static std::string prevMsg[KEEP_MSGS];
251 static std::chrono::time_point<std::chrono::steady_clock>
252 prevMsgTime[KEEP_MSGS];
253 static bool initialized = false;
254 if (!initialized) {
255 for (int i = 0; i < KEEP_MSGS; i++) {
256 prevMsgTime[i] =
257 std::chrono::steady_clock::now() - std::chrono::seconds(2);
258 }
259 initialized = true;
260 }
261
262 auto curTime = std::chrono::steady_clock::now();
263 int i;
264 for (i = 0; i < KEEP_MSGS; ++i) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700265 if (prevMsg[i] == details) {
266 break;
267 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800268 }
269 int retval = 0;
270 if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700271 std::string_view detailsRef{details};
272 std::string_view locationRef{location};
273 std::string_view callStackRef{callStack};
Brian Silverman8fce7482020-01-05 13:18:21 -0800274
275 // 1 tag, 4 timestamp, 2 seqnum
276 // 2 numOccur, 4 error code, 1 flags, 6 strlen
277 // 1 extra needed for padding on Netcomm end.
278 size_t baseLength = 21;
279
280 if (baseLength + detailsRef.size() + locationRef.size() +
281 callStackRef.size() <=
Austin Schuh1e69f942020-11-14 15:06:14 -0800282 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800283 // Pass through
284 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
285 details, location, callStack);
Austin Schuh1e69f942020-11-14 15:06:14 -0800286 } else if (baseLength + detailsRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800287 // Details too long, cut both location and stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800288 auto newLen = 65535 - baseLength;
Brian Silverman8fce7482020-01-05 13:18:21 -0800289 std::string newDetails{details, newLen};
290 char empty = '\0';
291 retval = FRC_NetworkCommunication_sendError(
292 isError, errorCode, isLVCode, newDetails.c_str(), &empty, &empty);
Austin Schuh1e69f942020-11-14 15:06:14 -0800293 } else if (baseLength + detailsRef.size() + locationRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800294 // Location too long, cut stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800295 auto newLen = 65535 - baseLength - detailsRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800296 std::string newLocation{location, newLen};
297 char empty = '\0';
298 retval = FRC_NetworkCommunication_sendError(
299 isError, errorCode, isLVCode, details, newLocation.c_str(), &empty);
300 } else {
301 // Stack too long
Austin Schuh1e69f942020-11-14 15:06:14 -0800302 auto newLen = 65535 - baseLength - detailsRef.size() - locationRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800303 std::string newCallStack{callStack, newLen};
304 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
305 details, location,
306 newCallStack.c_str());
307 }
308 if (printMsg) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700309 fmt::memory_buffer buf;
Brian Silverman8fce7482020-01-05 13:18:21 -0800310 if (location && location[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700311 fmt::format_to(fmt::appender{buf},
312 "{} at {}: ", isError ? "Error" : "Warning", location);
Brian Silverman8fce7482020-01-05 13:18:21 -0800313 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700314 fmt::format_to(fmt::appender{buf}, "{}\n", details);
Brian Silverman8fce7482020-01-05 13:18:21 -0800315 if (callStack && callStack[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700316 fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
Brian Silverman8fce7482020-01-05 13:18:21 -0800317 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800318 auto printError = gPrintErrorImpl.load();
319 printError(buf.data(), buf.size());
Brian Silverman8fce7482020-01-05 13:18:21 -0800320 }
321 if (i == KEEP_MSGS) {
322 // replace the oldest one
323 i = 0;
324 auto first = prevMsgTime[0];
325 for (int j = 1; j < KEEP_MSGS; ++j) {
326 if (prevMsgTime[j] < first) {
327 first = prevMsgTime[j];
328 i = j;
329 }
330 }
331 prevMsg[i] = details;
332 }
333 prevMsgTime[i] = curTime;
334 }
335 return retval;
336}
337
James Kuszmaulcf324122023-01-14 14:07:17 -0800338void HAL_SetPrintErrorImpl(void (*func)(const char* line, size_t size)) {
339 gPrintErrorImpl.store(func ? func : hal::DefaultPrintErrorImpl);
340}
341
Austin Schuh1e69f942020-11-14 15:06:14 -0800342int32_t HAL_SendConsoleLine(const char* line) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700343 std::string_view lineRef{line};
Austin Schuh1e69f942020-11-14 15:06:14 -0800344 if (lineRef.size() <= 65535) {
345 // Send directly
346 return FRC_NetworkCommunication_sendConsoleLine(line);
347 } else {
348 // Need to truncate
349 std::string newLine{line, 65535};
350 return FRC_NetworkCommunication_sendConsoleLine(newLine.c_str());
351 }
352}
353
Brian Silverman8fce7482020-01-05 13:18:21 -0800354int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800355 std::scoped_lock lock{cacheMutex};
356 *controlWord = newestControlWord;
357 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800358}
359
360int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800361 CHECK_JOYSTICK_NUMBER(joystickNum);
362 std::scoped_lock lock{cacheMutex};
363 *axes = currentRead->axes[joystickNum];
364 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800365}
366
367int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800368 CHECK_JOYSTICK_NUMBER(joystickNum);
369 std::scoped_lock lock{cacheMutex};
370 *povs = currentRead->povs[joystickNum];
371 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800372}
373
374int32_t HAL_GetJoystickButtons(int32_t joystickNum,
375 HAL_JoystickButtons* buttons) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800376 CHECK_JOYSTICK_NUMBER(joystickNum);
377 std::scoped_lock lock{cacheMutex};
378 *buttons = currentRead->buttons[joystickNum];
379 return 0;
380}
381
382void HAL_GetAllJoystickData(HAL_JoystickAxes* axes, HAL_JoystickPOVs* povs,
383 HAL_JoystickButtons* buttons) {
384 std::scoped_lock lock{cacheMutex};
385 std::memcpy(axes, currentRead->axes, sizeof(currentRead->axes));
386 std::memcpy(povs, currentRead->povs, sizeof(currentRead->povs));
387 std::memcpy(buttons, currentRead->buttons, sizeof(currentRead->buttons));
Brian Silverman8fce7482020-01-05 13:18:21 -0800388}
389
390int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
391 HAL_JoystickDescriptor* desc) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800392 CHECK_JOYSTICK_NUMBER(joystickNum);
393 std::scoped_lock lock{tcpCacheMutex};
394 *desc = tcpCurrent.descriptors[joystickNum];
395 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800396}
397
398int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800399 std::scoped_lock lock{tcpCacheMutex};
400 *info = tcpCurrent.matchInfo;
401 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800402}
403
404HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800405 std::scoped_lock lock{cacheMutex};
406 return currentRead->allianceStation;
Brian Silverman8fce7482020-01-05 13:18:21 -0800407}
408
409HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
410 HAL_JoystickDescriptor joystickDesc;
411 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
412 return 0;
413 } else {
414 return joystickDesc.isXbox;
415 }
416}
417
418int32_t HAL_GetJoystickType(int32_t joystickNum) {
419 HAL_JoystickDescriptor joystickDesc;
420 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
421 return -1;
422 } else {
423 return joystickDesc.type;
424 }
425}
426
427char* HAL_GetJoystickName(int32_t joystickNum) {
428 HAL_JoystickDescriptor joystickDesc;
429 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
430 char* name = static_cast<char*>(std::malloc(1));
431 name[0] = '\0';
432 return name;
433 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700434 const size_t len = std::strlen(joystickDesc.name) + 1;
435 char* name = static_cast<char*>(std::malloc(len));
436 std::memcpy(name, joystickDesc.name, len);
Brian Silverman8fce7482020-01-05 13:18:21 -0800437 return name;
438 }
439}
440
Austin Schuh812d0d12021-11-04 20:16:48 -0700441void HAL_FreeJoystickName(char* name) {
442 std::free(name);
443}
Brian Silverman8fce7482020-01-05 13:18:21 -0800444
445int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
446 HAL_JoystickDescriptor joystickDesc;
447 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
448 return -1;
449 } else {
450 return joystickDesc.axisTypes[axis];
451 }
452}
453
454int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
455 int32_t leftRumble, int32_t rightRumble) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800456 CHECK_JOYSTICK_NUMBER(joystickNum);
Brian Silverman8fce7482020-01-05 13:18:21 -0800457 return FRC_NetworkCommunication_setJoystickOutputs(joystickNum, outputs,
458 leftRumble, rightRumble);
459}
460
461double HAL_GetMatchTime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800462 std::scoped_lock lock{cacheMutex};
463 return currentRead->matchTime;
Brian Silverman8fce7482020-01-05 13:18:21 -0800464}
465
466void HAL_ObserveUserProgramStarting(void) {
467 FRC_NetworkCommunication_observeUserProgramStarting();
468}
469
470void HAL_ObserveUserProgramDisabled(void) {
471 FRC_NetworkCommunication_observeUserProgramDisabled();
472}
473
474void HAL_ObserveUserProgramAutonomous(void) {
475 FRC_NetworkCommunication_observeUserProgramAutonomous();
476}
477
478void HAL_ObserveUserProgramTeleop(void) {
479 FRC_NetworkCommunication_observeUserProgramTeleop();
480}
481
482void HAL_ObserveUserProgramTest(void) {
483 FRC_NetworkCommunication_observeUserProgramTest();
484}
485
Brian Silverman8fce7482020-01-05 13:18:21 -0800486// Constant number to be used for our occur handle
487constexpr int32_t refNumber = 42;
James Kuszmaulcf324122023-01-14 14:07:17 -0800488constexpr int32_t tcpRefNumber = 94;
Brian Silverman8fce7482020-01-05 13:18:21 -0800489
James Kuszmaulcf324122023-01-14 14:07:17 -0800490static void tcpOccur(void) {
491 uint32_t mask = FRC_NetworkCommunication_getNewTcpRecvMask();
492 tcpMask.fetch_or(mask);
Brian Silverman8fce7482020-01-05 13:18:21 -0800493}
494
James Kuszmaulcf324122023-01-14 14:07:17 -0800495static void udpOccur(void) {
496 cacheToUpdate->Update();
Brian Silverman8fce7482020-01-05 13:18:21 -0800497
James Kuszmaulcf324122023-01-14 14:07:17 -0800498 JoystickDataCache* given = cacheToUpdate;
499 JoystickDataCache* prev = currentCache.exchange(cacheToUpdate);
500 if (prev == nullptr) {
501 cacheToUpdate = currentReadLocal;
502 currentReadLocal = lastGiven;
503 } else {
504 // Current read local does not update
505 cacheToUpdate = prev;
Austin Schuh812d0d12021-11-04 20:16:48 -0700506 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800507 lastGiven = given;
Brian Silverman8fce7482020-01-05 13:18:21 -0800508
James Kuszmaulcf324122023-01-14 14:07:17 -0800509 driverStation->newDataEvents.Wakeup();
510}
511
512static void newDataOccur(uint32_t refNum) {
513 switch (refNum) {
514 case refNumber:
515 udpOccur();
516 break;
517
518 case tcpRefNumber:
519 tcpOccur();
520 break;
521
522 default:
523 std::printf("Unknown occur %u\n", refNum);
524 break;
525 }
526}
527
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800528HAL_Bool HAL_RefreshDSData(void) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800529 HAL_ControlWord controlWord;
530 std::memset(&controlWord, 0, sizeof(controlWord));
531 FRC_NetworkCommunication_getControlWord(
532 reinterpret_cast<ControlWord_t*>(&controlWord));
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800533 JoystickDataCache* prev;
534 {
535 std::scoped_lock lock{cacheMutex};
536 prev = currentCache.exchange(nullptr);
537 if (prev != nullptr) {
538 currentRead = prev;
539 }
540 // If newest state shows we have a DS attached, just use the
541 // control word out of the cache, As it will be the one in sync
542 // with the data. Otherwise use the state that shows disconnected.
543 if (controlWord.dsAttached) {
544 newestControlWord = currentRead->controlWord;
545 } else {
Maxwell Henderson80bec322024-01-09 15:48:44 -0800546 // Zero out the control word. When the DS has never been connected
547 // this returns garbage. And there is no way we can detect that.
548 std::memset(&controlWord, 0, sizeof(controlWord));
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800549 newestControlWord = controlWord;
550 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800551 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800552
553 uint32_t mask = tcpMask.exchange(0);
554 if (mask != 0) {
Maxwell Henderson80bec322024-01-09 15:48:44 -0800555 bool failedToReadMatchInfo = tcpCache.Update(mask);
556 if (failedToReadMatchInfo) {
557 // If we failed to read match info
558 // we want to try again next iteration
559 tcpMask.fetch_or(combinedMatchInfoMask);
560 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800561 std::scoped_lock tcpLock(tcpCacheMutex);
562 tcpCache.CloneTo(&tcpCurrent);
563 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800564 return prev != nullptr;
James Kuszmaulcf324122023-01-14 14:07:17 -0800565}
566
567void HAL_ProvideNewDataEventHandle(WPI_EventHandle handle) {
568 hal::init::CheckInit();
569 driverStation->newDataEvents.Add(handle);
570}
571
572void HAL_RemoveNewDataEventHandle(WPI_EventHandle handle) {
573 driverStation->newDataEvents.Remove(handle);
574}
575
576HAL_Bool HAL_GetOutputsEnabled(void) {
577 return FRC_NetworkCommunication_getWatchdogActive();
578}
579
580} // extern "C"
581
582namespace hal {
583void InitializeDriverStation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800584 // Set up the occur function internally with NetComm
585 NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
586 // Set up our occur reference number
587 setNewDataOccurRef(refNumber);
James Kuszmaulcf324122023-01-14 14:07:17 -0800588 FRC_NetworkCommunication_setNewTcpDataOccurRef(tcpRefNumber);
Brian Silverman8fce7482020-01-05 13:18:21 -0800589}
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800590
591void WaitForInitialPacket() {
592 wpi::Event waitForInitEvent;
593 driverStation->newDataEvents.Add(waitForInitEvent.GetHandle());
594 bool timed_out = false;
595 wpi::WaitForObject(waitForInitEvent.GetHandle(), 0.1, &timed_out);
596 // Don't care what the result is, just want to give it a chance.
597 driverStation->newDataEvents.Remove(waitForInitEvent.GetHandle());
598}
James Kuszmaulcf324122023-01-14 14:07:17 -0800599} // namespace hal