@@ -44,6 +44,7 @@ struct JoystickDataCache {
4444 HAL_JoystickButtons buttons[kJoystickPorts ];
4545 HAL_AllianceStationID allianceStation;
4646 double matchTime;
47+ HAL_ControlWord controlWord;
4748};
4849static_assert (std::is_standard_layout_v<JoystickDataCache>);
4950// static_assert(std::is_trivial_v<JoystickDataCache>);
@@ -65,6 +66,16 @@ void JoystickDataCache::Update() {
6566 }
6667 allianceStation = SimDriverStationData->allianceStationId ;
6768 matchTime = SimDriverStationData->matchTime ;
69+
70+ HAL_ControlWord tmpControlWord;
71+ std::memset (&tmpControlWord, 0 , sizeof (tmpControlWord));
72+ tmpControlWord.enabled = SimDriverStationData->enabled ;
73+ tmpControlWord.autonomous = SimDriverStationData->autonomous ;
74+ tmpControlWord.test = SimDriverStationData->test ;
75+ tmpControlWord.eStop = SimDriverStationData->eStop ;
76+ tmpControlWord.fmsAttached = SimDriverStationData->fmsAttached ;
77+ tmpControlWord.dsAttached = SimDriverStationData->dsAttached ;
78+ this ->controlWord = tmpControlWord;
6879}
6980
7081#define CHECK_JOYSTICK_NUMBER (stickNum ) \
@@ -322,20 +333,32 @@ HAL_Bool HAL_RefreshDSData(void) {
322333 if (gShutdown ) {
323334 return false ;
324335 }
325- HAL_ControlWord controlWord;
326- std::memset (&controlWord, 0 , sizeof (controlWord));
327- controlWord.enabled = SimDriverStationData->enabled ;
328- controlWord.autonomous = SimDriverStationData->autonomous ;
329- controlWord.test = SimDriverStationData->test ;
330- controlWord.eStop = SimDriverStationData->eStop ;
331- controlWord.fmsAttached = SimDriverStationData->fmsAttached ;
332- controlWord.dsAttached = SimDriverStationData->dsAttached ;
336+ bool dsAttached = SimDriverStationData->dsAttached ;
333337 std::scoped_lock lock{driverStation->cacheMutex };
334338 JoystickDataCache* prev = currentCache.exchange (nullptr );
335339 if (prev != nullptr ) {
336340 currentRead = prev;
337341 }
338- newestControlWord = controlWord;
342+ // If newest state shows we have a DS attached, just use the
343+ // control word out of the cache, As it will be the one in sync
344+ // with the data. If no data has been updated, at this point,
345+ // and a DS wasn't attached previously, this will still return
346+ // a zeroed out control word, with is the correct state for
347+ // no new data.
348+ if (!dsAttached) {
349+ // If the DS is not attached, we need to zero out the control word.
350+ // This is because HAL_RefreshDSData is called asynchronously from
351+ // the DS data. The dsAttached variable comes directly from netcomm
352+ // and could be updated before the caches are. If that happens,
353+ // we would end up returning the previous cached control word,
354+ // which is out of sync with the current control word and could
355+ // break invariants such as which alliance station is in used.
356+ // Also, when the DS has never been connected the rest of the fields
357+ // in control word are garbage, so we also need to zero out in that
358+ // case too
359+ std::memset (¤tRead->controlWord , 0 , sizeof (currentRead->controlWord ));
360+ }
361+ newestControlWord = currentRead->controlWord ;
339362 return prev != nullptr ;
340363}
341364
@@ -369,6 +392,7 @@ void NewDriverStationData() {
369392 if (gShutdown ) {
370393 return ;
371394 }
395+ SimDriverStationData->dsAttached = true ;
372396 cacheToUpdate->Update ();
373397
374398 JoystickDataCache* given = cacheToUpdate;
@@ -382,7 +406,6 @@ void NewDriverStationData() {
382406 }
383407 lastGiven = given;
384408
385- SimDriverStationData->dsAttached = true ;
386409 driverStation->newDataEvents .Wakeup ();
387410 SimDriverStationData->CallNewDataCallbacks ();
388411}
0 commit comments