From 5a06b81673af3df974bb88dfa3b69b8daa6b02af Mon Sep 17 00:00:00 2001 From: Gold856 <117957790+Gold856@users.noreply.github.com> Date: Thu, 2 Jul 2026 02:07:51 -0400 Subject: [PATCH] [wpilib] Publish AllianceStationID (#8856) Glass now internally uses the AllianceStationID enum, but the two separate topics remain for simple use cases. The Invalid alliance is now published as Red, Station 0, instead of 3. Fixes #6488 and fixes #8725. --- glass/src/libnt/native/cpp/NTFMS.cpp | 21 +++++-------------- .../include/wpi/glass/networktables/NTFMS.hpp | 3 +-- .../internal/DriverStationBackend.cpp | 13 +++++++++--- .../internal/DriverStationBackend.java | 15 ++++++++++--- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/glass/src/libnt/native/cpp/NTFMS.cpp b/glass/src/libnt/native/cpp/NTFMS.cpp index e6a0cedf43..3ab0ff9dda 100644 --- a/glass/src/libnt/native/cpp/NTFMS.cpp +++ b/glass/src/libnt/native/cpp/NTFMS.cpp @@ -32,10 +32,9 @@ NTFMSModel::NTFMSModel(wpi::nt::NetworkTableInstance inst, : m_inst{inst}, m_gameDataSubscriber{ inst.GetStringTopic(fmt::format("{}/GameData", path)).Subscribe("")}, - m_alliance{inst.GetBooleanTopic(fmt::format("{}/IsRedAlliance", path)) - .Subscribe(false)}, - m_station{inst.GetIntegerTopic(fmt::format("{}/StationNumber", path)) - .Subscribe(0)}, + m_allianceStation{ + inst.GetIntegerTopic(fmt::format("{}/AllianceStationID", path)) + .Subscribe(0)}, m_controlWord{inst.GetRawTopic(fmt::format("{}/ControlWord", path)) .Subscribe("struct:ControlWord", {})}, m_fmsAttached{fmt::format("NT_FMS:FMSAttached:{}", path)}, @@ -47,18 +46,8 @@ NTFMSModel::NTFMSModel(wpi::nt::NetworkTableInstance inst, m_gameData{fmt::format("NT_FMS:GameData:{}", path)} {} void NTFMSModel::Update() { - for (auto&& v : m_alliance.ReadQueue()) { - int allianceStationId = m_allianceStationId.GetValue(); - allianceStationId %= 3; - // true if red - allianceStationId += 3 * (v.value ? 0 : 1); - m_allianceStationId.SetValue(allianceStationId, v.time); - } - for (auto&& v : m_station.ReadQueue()) { - int allianceStationId = m_allianceStationId.GetValue(); - bool isRed = (allianceStationId < 3); - // the NT value is 1-indexed - m_allianceStationId.SetValue(v.value - 1 + 3 * (isRed ? 0 : 1), v.time); + for (auto&& v : m_allianceStation.ReadQueue()) { + m_allianceStationId.SetValue(v.value, v.time); } for (auto&& v : m_controlWord.ReadQueue()) { if (v.value.size() != sizeof(uint64_t)) { diff --git a/glass/src/libnt/native/include/wpi/glass/networktables/NTFMS.hpp b/glass/src/libnt/native/include/wpi/glass/networktables/NTFMS.hpp index c2e7178c9a..b0df43e670 100644 --- a/glass/src/libnt/native/include/wpi/glass/networktables/NTFMS.hpp +++ b/glass/src/libnt/native/include/wpi/glass/networktables/NTFMS.hpp @@ -53,8 +53,7 @@ class NTFMSModel : public FMSModel { private: wpi::nt::NetworkTableInstance m_inst; wpi::nt::StringSubscriber m_gameDataSubscriber; - wpi::nt::BooleanSubscriber m_alliance; - wpi::nt::IntegerSubscriber m_station; + wpi::nt::IntegerSubscriber m_allianceStation; wpi::nt::RawSubscriber m_controlWord; BooleanSource m_fmsAttached; diff --git a/wpilibc/src/main/native/cpp/driverstation/internal/DriverStationBackend.cpp b/wpilibc/src/main/native/cpp/driverstation/internal/DriverStationBackend.cpp index ab55d2c3d7..925574c9b1 100644 --- a/wpilibc/src/main/native/cpp/driverstation/internal/DriverStationBackend.cpp +++ b/wpilibc/src/main/native/cpp/driverstation/internal/DriverStationBackend.cpp @@ -107,6 +107,8 @@ struct MatchDataSender { true}; MatchDataSenderEntry station{table, "StationNumber", 1}; + MatchDataSenderEntry allianceStation{ + table, "AllianceStationID", 0}; wpi::nt::StructPublisher controlWord; wpi::nt::StringPublisher opMode; wpi::hal::ControlWord prevControlWord; @@ -931,10 +933,14 @@ void SendMatchData() { isRedAlliance = true; stationNumber = 2; break; - default: + case HAL_ALLIANCE_STATION_RED_3: isRedAlliance = true; stationNumber = 3; break; + default: + isRedAlliance = true; + stationNumber = 0; + break; } HAL_MatchInfo tmpDataStore; @@ -944,14 +950,15 @@ void SendMatchData() { HAL_GetGameData(&tmpGameData); auto& inst = GetInstance(); - inst.matchDataSender.alliance.Set(isRedAlliance); - inst.matchDataSender.station.Set(stationNumber); inst.matchDataSender.eventName.Set(tmpDataStore.eventName); inst.matchDataSender.gameData.Set( std::string(reinterpret_cast(tmpGameData.gameData))); inst.matchDataSender.matchNumber.Set(tmpDataStore.matchNumber); inst.matchDataSender.replayNumber.Set(tmpDataStore.replayNumber); inst.matchDataSender.matchType.Set(static_cast(tmpDataStore.matchType)); + inst.matchDataSender.alliance.Set(isRedAlliance); + inst.matchDataSender.station.Set(stationNumber); + inst.matchDataSender.allianceStation.Set(alliance); hal::ControlWord ctlWord = hal::GetControlWord(); if (ctlWord != inst.matchDataSender.prevControlWord) { diff --git a/wpilibj/src/main/java/org/wpilib/driverstation/internal/DriverStationBackend.java b/wpilibj/src/main/java/org/wpilib/driverstation/internal/DriverStationBackend.java index 6088e505d6..39d0bd9a27 100644 --- a/wpilibj/src/main/java/org/wpilib/driverstation/internal/DriverStationBackend.java +++ b/wpilibj/src/main/java/org/wpilib/driverstation/internal/DriverStationBackend.java @@ -161,15 +161,17 @@ public final class DriverStationBackend { final IntegerPublisher matchType; final BooleanPublisher alliance; final IntegerPublisher station; + final IntegerPublisher allianceStation; final StructPublisher controlWord; final StringPublisher opMode; - boolean oldIsRedAlliance = true; - int oldStationNumber = 1; String oldEventName = ""; String oldGameData = ""; int oldMatchNumber; int oldReplayNumber; int oldMatchType; + boolean oldIsRedAlliance = true; + int oldStationNumber = 1; + int oldAllianceStation = 0; final ControlWord oldControlWord = new ControlWord(); final ControlWord currentControlWord = new ControlWord(); @@ -194,6 +196,8 @@ public final class DriverStationBackend { alliance.set(true); station = table.getIntegerTopic("StationNumber").publish(); station.set(1); + allianceStation = table.getIntegerTopic("AllianceStationID").publish(); + allianceStation.set(0); controlWord = table.getStructTopic("ControlWord", ControlWord.struct).publish(); controlWord.set(oldControlWord); opMode = table.getStringTopic("OpMode").publish(); @@ -207,7 +211,8 @@ public final class DriverStationBackend { switch (allianceID) { case BLUE_1, RED_1 -> 1; case BLUE_2, RED_2 -> 2; - case BLUE_3, RED_3, UNKNOWN -> 3; + case BLUE_3, RED_3 -> 3; + case UNKNOWN -> 0; }; final boolean isRedAlliance = switch (allianceID) { @@ -240,6 +245,10 @@ public final class DriverStationBackend { station.set(stationNumber); oldStationNumber = stationNumber; } + if (oldAllianceStation != allianceID.ordinal()) { + allianceStation.set(allianceID.ordinal()); + oldAllianceStation = allianceID.ordinal(); + } if (!oldEventName.equals(currentEventName)) { eventName.set(currentEventName); oldEventName = currentEventName;