blob: e8db9a59ccacfc3375fed90eb3e9d943bc512c2b [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;
46};
47static_assert(std::is_standard_layout_v<JoystickDataCache>);
48// static_assert(std::is_trivial_v<JoystickDataCache>);
49
50struct FRCDriverStation {
51 wpi::EventVector newDataEvents;
52};
53} // namespace
54
55static ::FRCDriverStation* driverStation;
Brian Silverman8fce7482020-01-05 13:18:21 -080056
57// Message and Data variables
58static wpi::mutex msgMutex;
59
60static int32_t HAL_GetJoystickAxesInternal(int32_t joystickNum,
61 HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -080062 HAL_JoystickAxesInt netcommAxes;
Brian Silverman8fce7482020-01-05 13:18:21 -080063
64 int retVal = FRC_NetworkCommunication_getJoystickAxes(
James Kuszmaulcf324122023-01-14 14:07:17 -080065 joystickNum, reinterpret_cast<JoystickAxes_t*>(&netcommAxes),
Brian Silverman8fce7482020-01-05 13:18:21 -080066 HAL_kMaxJoystickAxes);
67
68 // copy integer values to double values
James Kuszmaulcf324122023-01-14 14:07:17 -080069 axes->count = netcommAxes.count;
Brian Silverman8fce7482020-01-05 13:18:21 -080070 // current scaling is -128 to 127, can easily be patched in the future by
71 // changing this function.
James Kuszmaulcf324122023-01-14 14:07:17 -080072 for (int32_t i = 0; i < netcommAxes.count; i++) {
73 int8_t value = netcommAxes.axes[i];
74 axes->raw[i] = value;
Brian Silverman8fce7482020-01-05 13:18:21 -080075 if (value < 0) {
76 axes->axes[i] = value / 128.0;
77 } else {
78 axes->axes[i] = value / 127.0;
79 }
80 }
81
82 return retVal;
83}
84
85static int32_t HAL_GetJoystickPOVsInternal(int32_t joystickNum,
86 HAL_JoystickPOVs* povs) {
87 return FRC_NetworkCommunication_getJoystickPOVs(
88 joystickNum, reinterpret_cast<JoystickPOV_t*>(povs),
89 HAL_kMaxJoystickPOVs);
90}
91
92static int32_t HAL_GetJoystickButtonsInternal(int32_t joystickNum,
93 HAL_JoystickButtons* buttons) {
94 return FRC_NetworkCommunication_getJoystickButtons(
95 joystickNum, &buttons->buttons, &buttons->count);
96}
James Kuszmaulcf324122023-01-14 14:07:17 -080097
98void JoystickDataCache::Update() {
99 for (int i = 0; i < HAL_kMaxJoysticks; i++) {
100 HAL_GetJoystickAxesInternal(i, &axes[i]);
101 HAL_GetJoystickPOVsInternal(i, &povs[i]);
102 HAL_GetJoystickButtonsInternal(i, &buttons[i]);
103 }
104 FRC_NetworkCommunication_getAllianceStation(
105 reinterpret_cast<AllianceStationID_t*>(&allianceStation));
106 FRC_NetworkCommunication_getMatchTime(&matchTime);
107}
108
109#define CHECK_JOYSTICK_NUMBER(stickNum) \
110 if ((stickNum) < 0 || (stickNum) >= HAL_kMaxJoysticks) \
111 return PARAMETER_OUT_OF_RANGE
112
113static HAL_ControlWord newestControlWord;
114static JoystickDataCache caches[3];
115static JoystickDataCache* currentRead = &caches[0];
116static JoystickDataCache* currentReadLocal = &caches[0];
117static std::atomic<JoystickDataCache*> currentCache{&caches[1]};
118static JoystickDataCache* lastGiven = &caches[1];
119static JoystickDataCache* cacheToUpdate = &caches[2];
120
121static wpi::mutex cacheMutex;
122
Brian Silverman8fce7482020-01-05 13:18:21 -0800123/**
Austin Schuh812d0d12021-11-04 20:16:48 -0700124 * Retrieve the Joystick Descriptor for particular slot.
Brian Silverman8fce7482020-01-05 13:18:21 -0800125 *
Austin Schuh812d0d12021-11-04 20:16:48 -0700126 * @param[out] desc descriptor (data transfer object) to fill in. desc is filled
127 * in regardless of success. In other words, if descriptor is
128 * not available, desc is filled in with default values
129 * matching the init-values in Java and C++ Driverstation for
130 * when caller requests a too-large joystick index.
Brian Silverman8fce7482020-01-05 13:18:21 -0800131 * @return error code reported from Network Comm back-end. Zero is good,
Austin Schuh812d0d12021-11-04 20:16:48 -0700132 * nonzero is bad.
Brian Silverman8fce7482020-01-05 13:18:21 -0800133 */
134static int32_t HAL_GetJoystickDescriptorInternal(int32_t joystickNum,
135 HAL_JoystickDescriptor* desc) {
136 desc->isXbox = 0;
137 desc->type = (std::numeric_limits<uint8_t>::max)();
138 desc->name[0] = '\0';
139 desc->axisCount =
140 HAL_kMaxJoystickAxes; /* set to the desc->axisTypes's capacity */
141 desc->buttonCount = 0;
142 desc->povCount = 0;
143 int retval = FRC_NetworkCommunication_getJoystickDesc(
144 joystickNum, &desc->isXbox, &desc->type,
145 reinterpret_cast<char*>(&desc->name), &desc->axisCount,
146 reinterpret_cast<uint8_t*>(&desc->axisTypes), &desc->buttonCount,
147 &desc->povCount);
148 /* check the return, if there is an error and the RIOimage predates FRC2017,
149 * then axisCount needs to be cleared */
150 if (retval != 0) {
151 /* set count to zero so downstream code doesn't decode invalid axisTypes. */
152 desc->axisCount = 0;
153 }
154 return retval;
155}
156
Brian Silverman8fce7482020-01-05 13:18:21 -0800157static int32_t HAL_GetMatchInfoInternal(HAL_MatchInfo* info) {
158 MatchType_t matchType = MatchType_t::kMatchType_none;
Austin Schuh75263e32022-02-22 18:05:32 -0800159 info->gameSpecificMessageSize = sizeof(info->gameSpecificMessage);
Brian Silverman8fce7482020-01-05 13:18:21 -0800160 int status = FRC_NetworkCommunication_getMatchInfo(
161 info->eventName, &matchType, &info->matchNumber, &info->replayNumber,
162 info->gameSpecificMessage, &info->gameSpecificMessageSize);
163
Austin Schuh75263e32022-02-22 18:05:32 -0800164 if (info->gameSpecificMessageSize > sizeof(info->gameSpecificMessage)) {
165 info->gameSpecificMessageSize = 0;
166 }
167
Brian Silverman8fce7482020-01-05 13:18:21 -0800168 info->matchType = static_cast<HAL_MatchType>(matchType);
169
170 *(std::end(info->eventName) - 1) = '\0';
171
172 return status;
173}
174
James Kuszmaulcf324122023-01-14 14:07:17 -0800175namespace {
176struct TcpCache {
177 TcpCache() { std::memset(this, 0, sizeof(*this)); }
178 void Update(uint32_t mask);
179 void CloneTo(TcpCache* other) { std::memcpy(other, this, sizeof(*this)); }
180
181 HAL_MatchInfo matchInfo;
182 HAL_JoystickDescriptor descriptors[HAL_kMaxJoysticks];
183};
184static_assert(std::is_standard_layout_v<TcpCache>);
185} // namespace
186
187static std::atomic_uint32_t tcpMask{0xFFFFFFFF};
188static TcpCache tcpCache;
189static TcpCache tcpCurrent;
190static wpi::mutex tcpCacheMutex;
191
192constexpr uint32_t combinedMatchInfoMask = kTcpRecvMask_MatchInfoOld |
193 kTcpRecvMask_MatchInfo |
194 kTcpRecvMask_GameSpecific;
195
196void TcpCache::Update(uint32_t mask) {
197 if ((mask & combinedMatchInfoMask) != 0) {
198 HAL_GetMatchInfoInternal(&matchInfo);
199 }
200 for (int i = 0; i < HAL_kMaxJoysticks; i++) {
201 if ((mask & (1 << i)) != 0) {
202 HAL_GetJoystickDescriptorInternal(i, &descriptors[i]);
203 }
204 }
205}
Brian Silverman8fce7482020-01-05 13:18:21 -0800206
Austin Schuh812d0d12021-11-04 20:16:48 -0700207namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -0800208void InitializeFRCDriverStation() {
James Kuszmaulcf324122023-01-14 14:07:17 -0800209 std::memset(&newestControlWord, 0, sizeof(newestControlWord));
210 static FRCDriverStation ds;
211 driverStation = &ds;
Brian Silverman8fce7482020-01-05 13:18:21 -0800212}
Austin Schuh812d0d12021-11-04 20:16:48 -0700213} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800214
James Kuszmaulcf324122023-01-14 14:07:17 -0800215namespace hal {
216static void DefaultPrintErrorImpl(const char* line, size_t size) {
217 std::fwrite(line, size, 1, stderr);
218}
219} // namespace hal
220
221static std::atomic<void (*)(const char* line, size_t size)> gPrintErrorImpl{
222 hal::DefaultPrintErrorImpl};
223
Brian Silverman8fce7482020-01-05 13:18:21 -0800224extern "C" {
225
226int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
227 const char* details, const char* location,
228 const char* callStack, HAL_Bool printMsg) {
229 // Avoid flooding console by keeping track of previous 5 error
230 // messages and only printing again if they're longer than 1 second old.
231 static constexpr int KEEP_MSGS = 5;
232 std::scoped_lock lock(msgMutex);
233 static std::string prevMsg[KEEP_MSGS];
234 static std::chrono::time_point<std::chrono::steady_clock>
235 prevMsgTime[KEEP_MSGS];
236 static bool initialized = false;
237 if (!initialized) {
238 for (int i = 0; i < KEEP_MSGS; i++) {
239 prevMsgTime[i] =
240 std::chrono::steady_clock::now() - std::chrono::seconds(2);
241 }
242 initialized = true;
243 }
244
245 auto curTime = std::chrono::steady_clock::now();
246 int i;
247 for (i = 0; i < KEEP_MSGS; ++i) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700248 if (prevMsg[i] == details) {
249 break;
250 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800251 }
252 int retval = 0;
253 if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700254 std::string_view detailsRef{details};
255 std::string_view locationRef{location};
256 std::string_view callStackRef{callStack};
Brian Silverman8fce7482020-01-05 13:18:21 -0800257
258 // 1 tag, 4 timestamp, 2 seqnum
259 // 2 numOccur, 4 error code, 1 flags, 6 strlen
260 // 1 extra needed for padding on Netcomm end.
261 size_t baseLength = 21;
262
263 if (baseLength + detailsRef.size() + locationRef.size() +
264 callStackRef.size() <=
Austin Schuh1e69f942020-11-14 15:06:14 -0800265 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800266 // Pass through
267 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
268 details, location, callStack);
Austin Schuh1e69f942020-11-14 15:06:14 -0800269 } else if (baseLength + detailsRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800270 // Details too long, cut both location and stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800271 auto newLen = 65535 - baseLength;
Brian Silverman8fce7482020-01-05 13:18:21 -0800272 std::string newDetails{details, newLen};
273 char empty = '\0';
274 retval = FRC_NetworkCommunication_sendError(
275 isError, errorCode, isLVCode, newDetails.c_str(), &empty, &empty);
Austin Schuh1e69f942020-11-14 15:06:14 -0800276 } else if (baseLength + detailsRef.size() + locationRef.size() > 65535) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800277 // Location too long, cut stack
Austin Schuh1e69f942020-11-14 15:06:14 -0800278 auto newLen = 65535 - baseLength - detailsRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800279 std::string newLocation{location, newLen};
280 char empty = '\0';
281 retval = FRC_NetworkCommunication_sendError(
282 isError, errorCode, isLVCode, details, newLocation.c_str(), &empty);
283 } else {
284 // Stack too long
Austin Schuh1e69f942020-11-14 15:06:14 -0800285 auto newLen = 65535 - baseLength - detailsRef.size() - locationRef.size();
Brian Silverman8fce7482020-01-05 13:18:21 -0800286 std::string newCallStack{callStack, newLen};
287 retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
288 details, location,
289 newCallStack.c_str());
290 }
291 if (printMsg) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700292 fmt::memory_buffer buf;
Brian Silverman8fce7482020-01-05 13:18:21 -0800293 if (location && location[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700294 fmt::format_to(fmt::appender{buf},
295 "{} at {}: ", isError ? "Error" : "Warning", location);
Brian Silverman8fce7482020-01-05 13:18:21 -0800296 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700297 fmt::format_to(fmt::appender{buf}, "{}\n", details);
Brian Silverman8fce7482020-01-05 13:18:21 -0800298 if (callStack && callStack[0] != '\0') {
Austin Schuh812d0d12021-11-04 20:16:48 -0700299 fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
Brian Silverman8fce7482020-01-05 13:18:21 -0800300 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800301 auto printError = gPrintErrorImpl.load();
302 printError(buf.data(), buf.size());
Brian Silverman8fce7482020-01-05 13:18:21 -0800303 }
304 if (i == KEEP_MSGS) {
305 // replace the oldest one
306 i = 0;
307 auto first = prevMsgTime[0];
308 for (int j = 1; j < KEEP_MSGS; ++j) {
309 if (prevMsgTime[j] < first) {
310 first = prevMsgTime[j];
311 i = j;
312 }
313 }
314 prevMsg[i] = details;
315 }
316 prevMsgTime[i] = curTime;
317 }
318 return retval;
319}
320
James Kuszmaulcf324122023-01-14 14:07:17 -0800321void HAL_SetPrintErrorImpl(void (*func)(const char* line, size_t size)) {
322 gPrintErrorImpl.store(func ? func : hal::DefaultPrintErrorImpl);
323}
324
Austin Schuh1e69f942020-11-14 15:06:14 -0800325int32_t HAL_SendConsoleLine(const char* line) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700326 std::string_view lineRef{line};
Austin Schuh1e69f942020-11-14 15:06:14 -0800327 if (lineRef.size() <= 65535) {
328 // Send directly
329 return FRC_NetworkCommunication_sendConsoleLine(line);
330 } else {
331 // Need to truncate
332 std::string newLine{line, 65535};
333 return FRC_NetworkCommunication_sendConsoleLine(newLine.c_str());
334 }
335}
336
Brian Silverman8fce7482020-01-05 13:18:21 -0800337int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800338 std::scoped_lock lock{cacheMutex};
339 *controlWord = newestControlWord;
340 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800341}
342
343int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800344 CHECK_JOYSTICK_NUMBER(joystickNum);
345 std::scoped_lock lock{cacheMutex};
346 *axes = currentRead->axes[joystickNum];
347 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800348}
349
350int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800351 CHECK_JOYSTICK_NUMBER(joystickNum);
352 std::scoped_lock lock{cacheMutex};
353 *povs = currentRead->povs[joystickNum];
354 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800355}
356
357int32_t HAL_GetJoystickButtons(int32_t joystickNum,
358 HAL_JoystickButtons* buttons) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800359 CHECK_JOYSTICK_NUMBER(joystickNum);
360 std::scoped_lock lock{cacheMutex};
361 *buttons = currentRead->buttons[joystickNum];
362 return 0;
363}
364
365void HAL_GetAllJoystickData(HAL_JoystickAxes* axes, HAL_JoystickPOVs* povs,
366 HAL_JoystickButtons* buttons) {
367 std::scoped_lock lock{cacheMutex};
368 std::memcpy(axes, currentRead->axes, sizeof(currentRead->axes));
369 std::memcpy(povs, currentRead->povs, sizeof(currentRead->povs));
370 std::memcpy(buttons, currentRead->buttons, sizeof(currentRead->buttons));
Brian Silverman8fce7482020-01-05 13:18:21 -0800371}
372
373int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
374 HAL_JoystickDescriptor* desc) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800375 CHECK_JOYSTICK_NUMBER(joystickNum);
376 std::scoped_lock lock{tcpCacheMutex};
377 *desc = tcpCurrent.descriptors[joystickNum];
378 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800379}
380
381int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800382 std::scoped_lock lock{tcpCacheMutex};
383 *info = tcpCurrent.matchInfo;
384 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800385}
386
387HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800388 std::scoped_lock lock{cacheMutex};
389 return currentRead->allianceStation;
Brian Silverman8fce7482020-01-05 13:18:21 -0800390}
391
392HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum) {
393 HAL_JoystickDescriptor joystickDesc;
394 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
395 return 0;
396 } else {
397 return joystickDesc.isXbox;
398 }
399}
400
401int32_t HAL_GetJoystickType(int32_t joystickNum) {
402 HAL_JoystickDescriptor joystickDesc;
403 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
404 return -1;
405 } else {
406 return joystickDesc.type;
407 }
408}
409
410char* HAL_GetJoystickName(int32_t joystickNum) {
411 HAL_JoystickDescriptor joystickDesc;
412 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
413 char* name = static_cast<char*>(std::malloc(1));
414 name[0] = '\0';
415 return name;
416 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700417 const size_t len = std::strlen(joystickDesc.name) + 1;
418 char* name = static_cast<char*>(std::malloc(len));
419 std::memcpy(name, joystickDesc.name, len);
Brian Silverman8fce7482020-01-05 13:18:21 -0800420 return name;
421 }
422}
423
Austin Schuh812d0d12021-11-04 20:16:48 -0700424void HAL_FreeJoystickName(char* name) {
425 std::free(name);
426}
Brian Silverman8fce7482020-01-05 13:18:21 -0800427
428int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
429 HAL_JoystickDescriptor joystickDesc;
430 if (HAL_GetJoystickDescriptor(joystickNum, &joystickDesc) < 0) {
431 return -1;
432 } else {
433 return joystickDesc.axisTypes[axis];
434 }
435}
436
437int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
438 int32_t leftRumble, int32_t rightRumble) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800439 CHECK_JOYSTICK_NUMBER(joystickNum);
Brian Silverman8fce7482020-01-05 13:18:21 -0800440 return FRC_NetworkCommunication_setJoystickOutputs(joystickNum, outputs,
441 leftRumble, rightRumble);
442}
443
444double HAL_GetMatchTime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800445 std::scoped_lock lock{cacheMutex};
446 return currentRead->matchTime;
Brian Silverman8fce7482020-01-05 13:18:21 -0800447}
448
449void HAL_ObserveUserProgramStarting(void) {
450 FRC_NetworkCommunication_observeUserProgramStarting();
451}
452
453void HAL_ObserveUserProgramDisabled(void) {
454 FRC_NetworkCommunication_observeUserProgramDisabled();
455}
456
457void HAL_ObserveUserProgramAutonomous(void) {
458 FRC_NetworkCommunication_observeUserProgramAutonomous();
459}
460
461void HAL_ObserveUserProgramTeleop(void) {
462 FRC_NetworkCommunication_observeUserProgramTeleop();
463}
464
465void HAL_ObserveUserProgramTest(void) {
466 FRC_NetworkCommunication_observeUserProgramTest();
467}
468
Brian Silverman8fce7482020-01-05 13:18:21 -0800469// Constant number to be used for our occur handle
470constexpr int32_t refNumber = 42;
James Kuszmaulcf324122023-01-14 14:07:17 -0800471constexpr int32_t tcpRefNumber = 94;
Brian Silverman8fce7482020-01-05 13:18:21 -0800472
James Kuszmaulcf324122023-01-14 14:07:17 -0800473static void tcpOccur(void) {
474 uint32_t mask = FRC_NetworkCommunication_getNewTcpRecvMask();
475 tcpMask.fetch_or(mask);
Brian Silverman8fce7482020-01-05 13:18:21 -0800476}
477
James Kuszmaulcf324122023-01-14 14:07:17 -0800478static void udpOccur(void) {
479 cacheToUpdate->Update();
Brian Silverman8fce7482020-01-05 13:18:21 -0800480
James Kuszmaulcf324122023-01-14 14:07:17 -0800481 JoystickDataCache* given = cacheToUpdate;
482 JoystickDataCache* prev = currentCache.exchange(cacheToUpdate);
483 if (prev == nullptr) {
484 cacheToUpdate = currentReadLocal;
485 currentReadLocal = lastGiven;
486 } else {
487 // Current read local does not update
488 cacheToUpdate = prev;
Austin Schuh812d0d12021-11-04 20:16:48 -0700489 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800490 lastGiven = given;
Brian Silverman8fce7482020-01-05 13:18:21 -0800491
James Kuszmaulcf324122023-01-14 14:07:17 -0800492 driverStation->newDataEvents.Wakeup();
493}
494
495static void newDataOccur(uint32_t refNum) {
496 switch (refNum) {
497 case refNumber:
498 udpOccur();
499 break;
500
501 case tcpRefNumber:
502 tcpOccur();
503 break;
504
505 default:
506 std::printf("Unknown occur %u\n", refNum);
507 break;
508 }
509}
510
511void HAL_RefreshDSData(void) {
512 HAL_ControlWord controlWord;
513 std::memset(&controlWord, 0, sizeof(controlWord));
514 FRC_NetworkCommunication_getControlWord(
515 reinterpret_cast<ControlWord_t*>(&controlWord));
516 std::scoped_lock lock{cacheMutex};
517 JoystickDataCache* prev = currentCache.exchange(nullptr);
518 if (prev != nullptr) {
519 currentRead = prev;
520 }
521 newestControlWord = controlWord;
522
523 uint32_t mask = tcpMask.exchange(0);
524 if (mask != 0) {
525 tcpCache.Update(mask);
526 std::scoped_lock tcpLock(tcpCacheMutex);
527 tcpCache.CloneTo(&tcpCurrent);
528 }
529}
530
531void HAL_ProvideNewDataEventHandle(WPI_EventHandle handle) {
532 hal::init::CheckInit();
533 driverStation->newDataEvents.Add(handle);
534}
535
536void HAL_RemoveNewDataEventHandle(WPI_EventHandle handle) {
537 driverStation->newDataEvents.Remove(handle);
538}
539
540HAL_Bool HAL_GetOutputsEnabled(void) {
541 return FRC_NetworkCommunication_getWatchdogActive();
542}
543
544} // extern "C"
545
546namespace hal {
547void InitializeDriverStation() {
Brian Silverman8fce7482020-01-05 13:18:21 -0800548 // Set up the occur function internally with NetComm
549 NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
550 // Set up our occur reference number
551 setNewDataOccurRef(refNumber);
James Kuszmaulcf324122023-01-14 14:07:17 -0800552 FRC_NetworkCommunication_setNewTcpDataOccurRef(tcpRefNumber);
Brian Silverman8fce7482020-01-05 13:18:21 -0800553}
James Kuszmaulcf324122023-01-14 14:07:17 -0800554} // namespace hal