From aa34aacf6eff05477400bbcc46a2e9e4014e0059 Mon Sep 17 00:00:00 2001 From: Starlight220 <53231611+Starlight220@users.noreply.github.com> Date: Mon, 27 Mar 2023 06:12:55 +0300 Subject: [PATCH] [wpilib] Shuffleboard: Keep duplicates on SelectTab() (#5198) --- .../cpp/shuffleboard/ShuffleboardInstance.cpp | 8 ++++-- .../shuffleboard/ShuffleboardInstanceTest.cpp | 21 +++++++++++++++ .../shuffleboard/ShuffleboardInstance.java | 4 ++- .../ShuffleboardInstanceTest.java | 27 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp index a315b9072f..a19cc6a3f0 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp @@ -20,12 +20,16 @@ struct ShuffleboardInstance::Impl { bool tabsChanged = false; std::shared_ptr rootTable; std::shared_ptr rootMetaTable; + nt::StringPublisher selectedTabPub; }; ShuffleboardInstance::ShuffleboardInstance(nt::NetworkTableInstance ntInstance) : m_impl(new Impl) { m_impl->rootTable = ntInstance.GetTable(Shuffleboard::kBaseTableName); m_impl->rootMetaTable = m_impl->rootTable->GetSubTable(".metadata"); + m_impl->selectedTabPub = + m_impl->rootMetaTable->GetStringTopic("Selected") + .Publish(nt::PubSubOptions{.keepDuplicates = true}); HAL_Report(HALUsageReporting::kResourceType_Shuffleboard, 0); } @@ -75,9 +79,9 @@ void ShuffleboardInstance::DisableActuatorWidgets() { } void ShuffleboardInstance::SelectTab(int index) { - m_impl->rootMetaTable->GetEntry("Selected").SetDouble(index); + m_impl->selectedTabPub.Set(std::to_string(index)); } void ShuffleboardInstance::SelectTab(std::string_view title) { - m_impl->rootMetaTable->GetEntry("Selected").SetString(title); + m_impl->selectedTabPub.Set(title); } diff --git a/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp b/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp index 0b0c8dfb7e..a42a8f93d3 100644 --- a/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp +++ b/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include "frc/shuffleboard/ShuffleboardInstance.h" #include "gtest/gtest.h" @@ -106,3 +108,22 @@ TEST(ShuffleboardInstanceTest, NestedActuatorWidgetsAreDisabled) { EXPECT_FALSE(controllable) << "The nested actuator widget should have been disabled"; } + +TEST(ShuffleboardInstanceTest, DuplicateSelectTabs) { + NTWrapper ntInst; + frc::detail::ShuffleboardInstance shuffleboardInst{ntInst.inst}; + std::atomic_int counter = 0; + auto listener = nt::NetworkTableListener::CreateListener( + ntInst.inst.GetStringTopic("/Shuffleboard/.metadata/Selected"), + nt::EventFlags::kValueAll | nt::EventFlags::kImmediate, + [&counter](auto& event) { counter++; }); + + // There shouldn't be anything there + EXPECT_EQ(0, counter); + + shuffleboardInst.SelectTab("tab1"); + shuffleboardInst.SelectTab("tab1"); + EXPECT_TRUE(ntInst.inst.WaitForListenerQueue(0.005)) + << "Listener queue timed out!"; + EXPECT_EQ(2, counter); +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java index 6c03dedfc8..df2f117e1d 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java @@ -10,6 +10,7 @@ import edu.wpi.first.hal.FRCNetComm.tResourceType; import edu.wpi.first.hal.HAL; import edu.wpi.first.networktables.NetworkTable; import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.PubSubOption; import edu.wpi.first.networktables.StringPublisher; import java.util.LinkedHashMap; import java.util.Map; @@ -32,7 +33,8 @@ final class ShuffleboardInstance implements ShuffleboardRoot { requireNonNullParam(ntInstance, "ntInstance", "ShuffleboardInstance"); m_rootTable = ntInstance.getTable(Shuffleboard.kBaseTableName); m_rootMetaTable = m_rootTable.getSubTable(".metadata"); - m_selectedTabPub = m_rootMetaTable.getStringTopic("Selected").publish(); + m_selectedTabPub = + m_rootMetaTable.getStringTopic("Selected").publish(PubSubOption.keepDuplicates(true)); HAL.report(tResourceType.kResourceType_Shuffleboard, 0); } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java index 53369f10d4..576af59147 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java @@ -11,7 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import edu.wpi.first.networktables.GenericEntry; import edu.wpi.first.networktables.NetworkTableEntry; +import edu.wpi.first.networktables.NetworkTableEvent.Kind; import edu.wpi.first.networktables.NetworkTableInstance; +import java.util.EnumSet; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -121,4 +124,28 @@ class ShuffleboardInstanceTest { controllable = controllableEntry.getValue().getBoolean(); assertFalse(controllable, "The nested actuator widget should have been disabled"); } + + @Test + void testDuplicateSelectTabs() { + int listener = 0; + AtomicInteger counter = new AtomicInteger(); + try { + listener = + m_ntInstance.addListener( + m_ntInstance.getStringTopic("/Shuffleboard/.metadata/Selected"), + EnumSet.of(Kind.kValueAll, Kind.kImmediate), + event -> counter.incrementAndGet()); + + // There shouldn't be anything there + assertEquals(0, counter.get()); + + m_shuffleboardInstance.selectTab("tab1"); + m_shuffleboardInstance.selectTab("tab1"); + assertTrue(m_ntInstance.waitForListenerQueue(0.005), "Listener queue timed out!"); + assertEquals(2, counter.get()); + + } finally { + m_ntInstance.removeListener(listener); + } + } }