diff --git a/wpilibc/src/main/native/cpp/DriverStation.cpp b/wpilibc/src/main/native/cpp/DriverStation.cpp index dbb99f9b57..781dcd2fec 100644 --- a/wpilibc/src/main/native/cpp/DriverStation.cpp +++ b/wpilibc/src/main/native/cpp/DriverStation.cpp @@ -8,6 +8,8 @@ #include "frc/DriverStation.h" #include +#include +#include #include #include @@ -23,41 +25,71 @@ #include "frc/WPIErrors.h" namespace frc { +// A simple class which caches the previous value written to an NT entry +// Used to prevent redundant, repeated writes of the same value +template +class MatchDataSenderEntry { + public: + MatchDataSenderEntry(const std::shared_ptr& table, + const wpi::Twine& key, const T& initialVal) { + static_assert(std::is_convertible() || + std::is_convertible() || + std::is_convertible(), + "Invalid type for MatchDataSenderEntry - must be convertable " + "to bool, double or wpi::Twine"); + + ntEntry = table->GetEntry(key); + if constexpr (std::is_convertible()) { + ntEntry.ForceSetBoolean(initialVal); + } else if constexpr (std::is_convertible()) { + ntEntry.ForceSetDouble(initialVal); + } else if constexpr (std::is_convertible()) { + ntEntry.ForceSetString(initialVal); + } + prevVal = initialVal; + } + + void Set(const T& val) { + if (val != prevVal) { + SetValue(val); + prevVal = val; + } + } + + private: + nt::NetworkTableEntry ntEntry; + T prevVal; + + void SetValue(bool val) { ntEntry.SetBoolean(val); } + void SetValue(double val) { ntEntry.SetDouble(val); } + void SetValue(const wpi::Twine& val) { ntEntry.SetString(val); } +}; class MatchDataSender { public: std::shared_ptr table; - nt::NetworkTableEntry typeMetadata; - nt::NetworkTableEntry gameSpecificMessage; - nt::NetworkTableEntry eventName; - nt::NetworkTableEntry matchNumber; - nt::NetworkTableEntry replayNumber; - nt::NetworkTableEntry matchType; - nt::NetworkTableEntry alliance; - nt::NetworkTableEntry station; - nt::NetworkTableEntry controlWord; + MatchDataSenderEntry typeMetaData; + MatchDataSenderEntry gameSpecificMessage; + MatchDataSenderEntry eventName; + MatchDataSenderEntry matchNumber; + MatchDataSenderEntry replayNumber; + MatchDataSenderEntry matchType; + MatchDataSenderEntry alliance; + MatchDataSenderEntry station; + MatchDataSenderEntry controlWord; - MatchDataSender() { - table = nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo"); - typeMetadata = table->GetEntry(".type"); - typeMetadata.ForceSetString("FMSInfo"); - gameSpecificMessage = table->GetEntry("GameSpecificMessage"); - gameSpecificMessage.ForceSetString(""); - eventName = table->GetEntry("EventName"); - eventName.ForceSetString(""); - matchNumber = table->GetEntry("MatchNumber"); - matchNumber.ForceSetDouble(0); - replayNumber = table->GetEntry("ReplayNumber"); - replayNumber.ForceSetDouble(0); - matchType = table->GetEntry("MatchType"); - matchType.ForceSetDouble(0); - alliance = table->GetEntry("IsRedAlliance"); - alliance.ForceSetBoolean(true); - station = table->GetEntry("StationNumber"); - station.ForceSetDouble(1); - controlWord = table->GetEntry("FMSControlData"); - controlWord.ForceSetDouble(0); - } + MatchDataSender() + : table(nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo")), + typeMetaData(table, ".type", "FMSInfo"), + gameSpecificMessage(table, "GameSpecificMessage", ""), + eventName(table, "EventName", ""), + matchNumber(table, "MatchNumber", 0.0), + replayNumber(table, "ReplayNumber", 0.0), + matchType(table, "MatchType", 0.0), + alliance(table, "IsRedAlliance", true), + station(table, "StationNumber", 1.0), + controlWord(table, "FMSControlData", 0.0) {} }; } // namespace frc @@ -642,20 +674,19 @@ void DriverStation::SendMatchData() { HAL_MatchInfo tmpDataStore; HAL_GetMatchInfo(&tmpDataStore); - m_matchDataSender->alliance.SetBoolean(isRedAlliance); - m_matchDataSender->station.SetDouble(stationNumber); - m_matchDataSender->eventName.SetString(tmpDataStore.eventName); - m_matchDataSender->gameSpecificMessage.SetString( + m_matchDataSender->alliance.Set(isRedAlliance); + m_matchDataSender->station.Set(stationNumber); + m_matchDataSender->eventName.Set(tmpDataStore.eventName); + m_matchDataSender->gameSpecificMessage.Set( std::string(reinterpret_cast(tmpDataStore.gameSpecificMessage), tmpDataStore.gameSpecificMessageSize)); - m_matchDataSender->matchNumber.SetDouble(tmpDataStore.matchNumber); - m_matchDataSender->replayNumber.SetDouble(tmpDataStore.replayNumber); - m_matchDataSender->matchType.SetDouble( - static_cast(tmpDataStore.matchType)); + m_matchDataSender->matchNumber.Set(tmpDataStore.matchNumber); + m_matchDataSender->replayNumber.Set(tmpDataStore.replayNumber); + m_matchDataSender->matchType.Set(static_cast(tmpDataStore.matchType)); HAL_ControlWord ctlWord; HAL_GetControlWord(&ctlWord); int32_t wordInt = 0; std::memcpy(&wordInt, &ctlWord, sizeof(wordInt)); - m_matchDataSender->controlWord.SetDouble(wordInt); + m_matchDataSender->controlWord.Set(wordInt); }