@@ -55,6 +55,7 @@ struct FRCDriverStation {
55
55
~FRCDriverStation () { gShutdown = true ; }
56
56
wpi::EventVector newDataEvents;
57
57
wpi::mutex cacheMutex;
58
+ wpi::mutex tcpCacheMutex;
58
59
};
59
60
} // namespace
60
61
@@ -90,6 +91,29 @@ static std::atomic<JoystickDataCache*> currentCache{nullptr};
90
91
static JoystickDataCache* lastGiven = &caches[1 ];
91
92
static JoystickDataCache* cacheToUpdate = &caches[2 ];
92
93
94
+ namespace {
95
+ struct TcpCache {
96
+ TcpCache () { std::memset (this , 0 , sizeof (*this )); }
97
+ void Update ();
98
+ void CloneTo (TcpCache* other) { std::memcpy (other, this , sizeof (*this )); }
99
+
100
+ HAL_MatchInfo matchInfo;
101
+ HAL_JoystickDescriptor descriptors[HAL_kMaxJoysticks];
102
+ };
103
+ static_assert (std::is_standard_layout_v<TcpCache>);
104
+ } // namespace
105
+
106
+ static TcpCache tcpCache;
107
+ static TcpCache tcpCurrent;
108
+
109
+ void TcpCache::Update () {
110
+ SimDriverStationData->GetMatchInfo (&matchInfo);
111
+
112
+ for (int i = 0 ; i < HAL_kMaxJoysticks; i++) {
113
+ SimDriverStationData->GetJoystickDescriptor (i, &descriptors[i]);
114
+ }
115
+ }
116
+
93
117
static ::FRCDriverStation* driverStation;
94
118
95
119
namespace hal ::init {
@@ -256,32 +280,47 @@ void HAL_GetAllJoystickData(HAL_JoystickAxes* axes, HAL_JoystickPOVs* povs,
256
280
int32_t HAL_GetJoystickDescriptor (int32_t joystickNum,
257
281
HAL_JoystickDescriptor* desc) {
258
282
CHECK_JOYSTICK_NUMBER (joystickNum);
259
- SimDriverStationData->GetJoystickDescriptor (joystickNum, desc);
283
+ std::scoped_lock lock{driverStation->tcpCacheMutex };
284
+ *desc = tcpCurrent.descriptors [joystickNum];
260
285
return 0 ;
261
286
}
262
287
263
288
HAL_Bool HAL_GetJoystickIsXbox (int32_t joystickNum) {
264
- HAL_JoystickDescriptor desc;
265
- SimDriverStationData->GetJoystickDescriptor (joystickNum, &desc);
266
- return desc.isXbox ;
289
+ HAL_JoystickDescriptor joystickDesc;
290
+ if (HAL_GetJoystickDescriptor (joystickNum, &joystickDesc) < 0 ) {
291
+ return 0 ;
292
+ } else {
293
+ return joystickDesc.isXbox ;
294
+ }
267
295
}
268
296
269
297
int32_t HAL_GetJoystickType (int32_t joystickNum) {
270
- HAL_JoystickDescriptor desc;
271
- SimDriverStationData->GetJoystickDescriptor (joystickNum, &desc);
272
- return desc.type ;
298
+ HAL_JoystickDescriptor joystickDesc;
299
+ if (HAL_GetJoystickDescriptor (joystickNum, &joystickDesc) < 0 ) {
300
+ return -1 ;
301
+ } else {
302
+ return joystickDesc.type ;
303
+ }
273
304
}
274
305
275
306
void HAL_GetJoystickName (struct WPI_String * name, int32_t joystickNum) {
276
- HAL_JoystickDescriptor desc;
277
- SimDriverStationData->GetJoystickDescriptor (joystickNum, &desc);
278
- size_t len = std::strlen (desc.name );
307
+ HAL_JoystickDescriptor joystickDesc;
308
+ const char * cName = joystickDesc.name ;
309
+ if (HAL_GetJoystickDescriptor (joystickNum, &joystickDesc) < 0 ) {
310
+ cName = " " ;
311
+ }
312
+ auto len = std::strlen (cName);
279
313
auto write = WPI_AllocateString (name, len);
280
- std::memcpy (write, desc. name , len);
314
+ std::memcpy (write, cName , len);
281
315
}
282
316
283
317
int32_t HAL_GetJoystickAxisType (int32_t joystickNum, int32_t axis) {
284
- return 0 ;
318
+ HAL_JoystickDescriptor joystickDesc;
319
+ if (HAL_GetJoystickDescriptor (joystickNum, &joystickDesc) < 0 ) {
320
+ return -1 ;
321
+ } else {
322
+ return joystickDesc.axisTypes [axis];
323
+ }
285
324
}
286
325
287
326
int32_t HAL_SetJoystickOutputs (int32_t joystickNum, int64_t outputs,
@@ -300,7 +339,8 @@ double HAL_GetMatchTime(int32_t* status) {
300
339
}
301
340
302
341
int32_t HAL_GetMatchInfo (HAL_MatchInfo* info) {
303
- SimDriverStationData->GetMatchInfo (info);
342
+ std::scoped_lock lock{driverStation->tcpCacheMutex };
343
+ *info = tcpCurrent.matchInfo ;
304
344
return 0 ;
305
345
}
306
346
@@ -329,31 +369,42 @@ HAL_Bool HAL_RefreshDSData(void) {
329
369
return false ;
330
370
}
331
371
bool dsAttached = SimDriverStationData->dsAttached ;
332
- std::scoped_lock lock{driverStation->cacheMutex };
333
- JoystickDataCache* prev = currentCache.exchange (nullptr );
334
- if (prev != nullptr ) {
335
- currentRead = prev;
372
+ JoystickDataCache* prev;
373
+ {
374
+ std::scoped_lock lock{driverStation->cacheMutex };
375
+ prev = currentCache.exchange (nullptr );
376
+ if (prev != nullptr ) {
377
+ currentRead = prev;
378
+ }
379
+ // If newest state shows we have a DS attached, just use the
380
+ // control word out of the cache, As it will be the one in sync
381
+ // with the data. If no data has been updated, at this point,
382
+ // and a DS wasn't attached previously, this will still return
383
+ // a zeroed out control word, with is the correct state for
384
+ // no new data.
385
+ if (!dsAttached) {
386
+ // If the DS is not attached, we need to zero out the control word.
387
+ // This is because HAL_RefreshDSData is called asynchronously from
388
+ // the DS data. The dsAttached variable comes directly from netcomm
389
+ // and could be updated before the caches are. If that happens,
390
+ // we would end up returning the previous cached control word,
391
+ // which is out of sync with the current control word and could
392
+ // break invariants such as which alliance station is in used.
393
+ // Also, when the DS has never been connected the rest of the fields
394
+ // in control word are garbage, so we also need to zero out in that
395
+ // case too
396
+ std::memset (¤tRead->controlWord , 0 ,
397
+ sizeof (currentRead->controlWord ));
398
+ }
399
+ newestControlWord = currentRead->controlWord ;
336
400
}
337
- // If newest state shows we have a DS attached, just use the
338
- // control word out of the cache, As it will be the one in sync
339
- // with the data. If no data has been updated, at this point,
340
- // and a DS wasn't attached previously, this will still return
341
- // a zeroed out control word, with is the correct state for
342
- // no new data.
343
- if (!dsAttached) {
344
- // If the DS is not attached, we need to zero out the control word.
345
- // This is because HAL_RefreshDSData is called asynchronously from
346
- // the DS data. The dsAttached variable comes directly from netcomm
347
- // and could be updated before the caches are. If that happens,
348
- // we would end up returning the previous cached control word,
349
- // which is out of sync with the current control word and could
350
- // break invariants such as which alliance station is in used.
351
- // Also, when the DS has never been connected the rest of the fields
352
- // in control word are garbage, so we also need to zero out in that
353
- // case too
354
- std::memset (¤tRead->controlWord , 0 , sizeof (currentRead->controlWord ));
401
+
402
+ {
403
+ tcpCache.Update ();
404
+ std::scoped_lock tcpLock (driverStation->tcpCacheMutex );
405
+ tcpCache.CloneTo (&tcpCurrent);
355
406
}
356
- newestControlWord = currentRead-> controlWord ;
407
+
357
408
return prev != nullptr ;
358
409
}
359
410
0 commit comments