From 05c25deb7b3c330c86ca3fc1f9804a4dfdb49f4a Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Thu, 17 Oct 2019 22:01:31 -0700 Subject: [PATCH] Fix move handling of C++ Sendable in SmartDashboard and LiveWindow --- .../main/native/cpp/livewindow/LiveWindow.cpp | 80 ++++---- .../smartdashboard/SendableBuilderImpl.cpp | 4 + .../cpp/smartdashboard/SendableRegistry.cpp | 182 ++++++++++++------ .../cpp/smartdashboard/SmartDashboard.cpp | 36 ++-- .../frc/smartdashboard/SendableBuilderImpl.h | 13 +- .../frc/smartdashboard/SendableRegistry.h | 63 +++++- 6 files changed, 244 insertions(+), 134 deletions(-) diff --git a/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp b/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp index 0c8801bbd2..1f011f556e 100644 --- a/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp +++ b/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp @@ -24,7 +24,6 @@ struct LiveWindow::Impl { Impl(); struct Component { - SendableBuilderImpl builder; bool firstTime = true; bool telemetryEnabled = true; }; @@ -85,13 +84,11 @@ void LiveWindow::DisableTelemetry(Sendable* sendable) { void LiveWindow::DisableAllTelemetry() { std::scoped_lock lock(m_impl->mutex); m_impl->telemetryEnabled = false; - m_impl->registry.ForeachLiveWindow( - m_impl->dataHandle, [&](Sendable*, wpi::StringRef, wpi::StringRef, - Sendable*, std::shared_ptr& data) { - if (!data) data = std::make_shared(); - std::static_pointer_cast(data)->telemetryEnabled = - false; - }); + m_impl->registry.ForeachLiveWindow(m_impl->dataHandle, [&](auto& cbdata) { + if (!cbdata.data) cbdata.data = std::make_shared(); + std::static_pointer_cast(cbdata.data)->telemetryEnabled = + false; + }); } bool LiveWindow::IsEnabled() const { @@ -111,13 +108,9 @@ void LiveWindow::SetEnabled(bool enabled) { scheduler->SetEnabled(false); scheduler->RemoveAll(); } else { - m_impl->registry.ForeachLiveWindow( - m_impl->dataHandle, [&](Sendable*, wpi::StringRef, wpi::StringRef, - Sendable*, std::shared_ptr& data) { - if (data) - std::static_pointer_cast(data) - ->builder.StopLiveWindowMode(); - }); + m_impl->registry.ForeachLiveWindow(m_impl->dataHandle, [&](auto& cbdata) { + cbdata.builder.StopLiveWindowMode(); + }); scheduler->SetEnabled(true); } m_impl->enabledEntry.SetBoolean(enabled); @@ -132,42 +125,39 @@ void LiveWindow::UpdateValuesUnsafe() { // Only do this if either LiveWindow mode or telemetry is enabled. if (!m_impl->liveWindowEnabled && !m_impl->telemetryEnabled) return; - m_impl->registry.ForeachLiveWindow( - m_impl->dataHandle, - [&](Sendable* sendable, wpi::StringRef name, wpi::StringRef subsystem, - Sendable* parent, std::shared_ptr& data) { - if (!sendable || parent) return; + m_impl->registry.ForeachLiveWindow(m_impl->dataHandle, [&](auto& cbdata) { + if (!cbdata.sendable || cbdata.parent) return; - if (!data) data = std::make_shared(); + if (!cbdata.data) cbdata.data = std::make_shared(); - auto& comp = *std::static_pointer_cast(data); + auto& comp = *std::static_pointer_cast(cbdata.data); - if (!m_impl->liveWindowEnabled && !comp.telemetryEnabled) return; + if (!m_impl->liveWindowEnabled && !comp.telemetryEnabled) return; - if (comp.firstTime) { - // By holding off creating the NetworkTable entries, it allows the - // components to be redefined. This allows default sensor and actuator - // values to be created that are replaced with the custom names from - // users calling setName. - if (name.empty()) return; - auto ssTable = m_impl->liveWindowTable->GetSubTable(subsystem); - std::shared_ptr table; - // Treat name==subsystem as top level of subsystem - if (name == subsystem) - table = ssTable; - else - table = ssTable->GetSubTable(name); - table->GetEntry(".name").SetString(name); - comp.builder.SetTable(table); - sendable->InitSendable(comp.builder); - ssTable->GetEntry(".type").SetString("LW Subsystem"); + if (comp.firstTime) { + // By holding off creating the NetworkTable entries, it allows the + // components to be redefined. This allows default sensor and actuator + // values to be created that are replaced with the custom names from + // users calling setName. + if (cbdata.name.empty()) return; + auto ssTable = m_impl->liveWindowTable->GetSubTable(cbdata.subsystem); + std::shared_ptr table; + // Treat name==subsystem as top level of subsystem + if (cbdata.name == cbdata.subsystem) + table = ssTable; + else + table = ssTable->GetSubTable(cbdata.name); + table->GetEntry(".name").SetString(cbdata.name); + cbdata.builder.SetTable(table); + cbdata.sendable->InitSendable(cbdata.builder); + ssTable->GetEntry(".type").SetString("LW Subsystem"); - comp.firstTime = false; - } + comp.firstTime = false; + } - if (m_impl->startLiveWindow) comp.builder.StartLiveWindowMode(); - comp.builder.UpdateTable(); - }); + if (m_impl->startLiveWindow) cbdata.builder.StartLiveWindowMode(); + cbdata.builder.UpdateTable(); + }); m_impl->startLiveWindow = false; } diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp index ac4a107fc3..d075deb12b 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp @@ -23,6 +23,8 @@ std::shared_ptr SendableBuilderImpl::GetTable() { return m_table; } +bool SendableBuilderImpl::HasTable() const { return m_table != nullptr; } + bool SendableBuilderImpl::IsActuator() const { return m_actuator; } void SendableBuilderImpl::UpdateTable() { @@ -53,6 +55,8 @@ void SendableBuilderImpl::StopLiveWindowMode() { if (m_safeState) m_safeState(); } +void SendableBuilderImpl::ClearProperties() { m_properties.clear(); } + void SendableBuilderImpl::SetSmartDashboardType(const wpi::Twine& type) { m_table->GetEntry(".type").SetString(type); } diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SendableRegistry.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SendableRegistry.cpp index d6ad48a34c..56a27dc6d0 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SendableRegistry.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SendableRegistry.cpp @@ -7,15 +7,22 @@ #include "frc/smartdashboard/SendableRegistry.h" +#include + #include #include +#include #include +#include "frc/smartdashboard/Sendable.h" +#include "frc/smartdashboard/SendableBuilderImpl.h" + using namespace frc; struct SendableRegistry::Impl { struct Component { Sendable* sendable = nullptr; + SendableBuilderImpl builder; std::string name; std::string subsystem = "Ungrouped"; Sendable* parent = nullptr; @@ -37,17 +44,21 @@ struct SendableRegistry::Impl { wpi::mutex mutex; - wpi::DenseMap components; + wpi::UidVector, 32> components; + wpi::DenseMap componentMap; int nextDataHandle = 0; - Component& GetOrAdd(Sendable* sendable); + Component& GetOrAdd(void* sendable, UID* uid = nullptr); }; SendableRegistry::Impl::Component& SendableRegistry::Impl::GetOrAdd( - Sendable* sendable) { - auto& comp = components[sendable]; - comp.sendable = sendable; - return comp; + void* sendable, UID* uid) { + UID& compUid = componentMap[sendable]; + if (compUid == 0) + compUid = components.emplace_back(std::make_unique()) + 1; + if (uid) *uid = compUid; + + return *components[compUid - 1]; } SendableRegistry& SendableRegistry::GetInstance() { @@ -58,6 +69,7 @@ SendableRegistry& SendableRegistry::GetInstance() { void SendableRegistry::Add(Sendable* sendable, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.name = name.str(); } @@ -65,6 +77,7 @@ void SendableRegistry::Add(Sendable* sendable, const wpi::Twine& moduleType, int channel) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.SetName(moduleType, channel); } @@ -72,6 +85,7 @@ void SendableRegistry::Add(Sendable* sendable, const wpi::Twine& moduleType, int moduleNumber, int channel) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.SetName(moduleType, moduleNumber, channel); } @@ -79,6 +93,7 @@ void SendableRegistry::Add(Sendable* sendable, const wpi::Twine& subsystem, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.name = name.str(); comp.subsystem = subsystem.str(); } @@ -86,6 +101,7 @@ void SendableRegistry::Add(Sendable* sendable, const wpi::Twine& subsystem, void SendableRegistry::AddLW(Sendable* sendable, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.liveWindow = true; comp.name = name.str(); } @@ -94,6 +110,7 @@ void SendableRegistry::AddLW(Sendable* sendable, const wpi::Twine& moduleType, int channel) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.liveWindow = true; comp.SetName(moduleType, channel); } @@ -102,6 +119,7 @@ void SendableRegistry::AddLW(Sendable* sendable, const wpi::Twine& moduleType, int moduleNumber, int channel) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.liveWindow = true; comp.SetName(moduleType, moduleNumber, channel); } @@ -110,6 +128,7 @@ void SendableRegistry::AddLW(Sendable* sendable, const wpi::Twine& subsystem, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); auto& comp = m_impl->GetOrAdd(sendable); + comp.sendable = sendable; comp.liveWindow = true; comp.name = name.str(); comp.subsystem = subsystem.str(); @@ -117,82 +136,95 @@ void SendableRegistry::AddLW(Sendable* sendable, const wpi::Twine& subsystem, void SendableRegistry::AddChild(Sendable* parent, void* child) { std::scoped_lock lock(m_impl->mutex); - auto& comp = m_impl->components[child]; + auto& comp = m_impl->GetOrAdd(child); comp.parent = parent; } bool SendableRegistry::Remove(Sendable* sendable) { std::scoped_lock lock(m_impl->mutex); - return m_impl->components.erase(sendable); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return false; + UID compUid = it->getSecond(); + m_impl->components.erase(compUid - 1); + m_impl->componentMap.erase(it); + return true; } void SendableRegistry::Move(Sendable* to, Sendable* from) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(from); - if (it == m_impl->components.end()) return; - Impl::Component old = std::move(it->getSecond()); - m_impl->components.erase(it); - m_impl->components[to] = std::move(old); - m_impl->components[to].sendable = to; + auto it = m_impl->componentMap.find(from); + if (it == m_impl->componentMap.end()) return; + UID compUid = it->getSecond(); + m_impl->componentMap.erase(it); + m_impl->componentMap[to] = compUid; + auto& comp = *m_impl->components[compUid - 1]; + comp.sendable = to; + if (comp.builder.HasTable()) { + // rebuild builder, as lambda captures can point to "from" + comp.builder.ClearProperties(); + to->InitSendable(comp.builder); + } } bool SendableRegistry::Contains(const Sendable* sendable) const { std::scoped_lock lock(m_impl->mutex); - return m_impl->components.count(sendable) != 0; + return m_impl->componentMap.count(sendable) != 0; } std::string SendableRegistry::GetName(const Sendable* sendable) const { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return std::string{}; - return it->getSecond().name; + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return std::string{}; + return m_impl->components[it->getSecond() - 1]->name; } void SendableRegistry::SetName(Sendable* sendable, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().name = name.str(); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->name = name.str(); } void SendableRegistry::SetName(Sendable* sendable, const wpi::Twine& moduleType, int channel) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().SetName(moduleType, channel); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->SetName(moduleType, channel); } void SendableRegistry::SetName(Sendable* sendable, const wpi::Twine& moduleType, int moduleNumber, int channel) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().SetName(moduleType, moduleNumber, channel); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->SetName(moduleType, moduleNumber, + channel); } void SendableRegistry::SetName(Sendable* sendable, const wpi::Twine& subsystem, const wpi::Twine& name) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().name = name.str(); - it->getSecond().subsystem = subsystem.str(); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + auto& comp = *m_impl->components[it->getSecond() - 1]; + comp.name = name.str(); + comp.subsystem = subsystem.str(); } std::string SendableRegistry::GetSubsystem(const Sendable* sendable) const { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return std::string{}; - return it->getSecond().subsystem; + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return std::string{}; + return m_impl->components[it->getSecond() - 1]->subsystem; } void SendableRegistry::SetSubsystem(Sendable* sendable, const wpi::Twine& subsystem) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().subsystem = subsystem.str(); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->subsystem = subsystem.str(); } int SendableRegistry::GetDataHandle() { @@ -204,9 +236,9 @@ std::shared_ptr SendableRegistry::SetData(Sendable* sendable, int handle, std::shared_ptr data) { assert(handle >= 0); std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return nullptr; - auto& comp = it->getSecond(); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return nullptr; + auto& comp = *m_impl->components[it->getSecond() - 1]; std::shared_ptr rv; if (static_cast(handle) < comp.data.size()) rv = std::move(comp.data[handle]); @@ -220,42 +252,72 @@ std::shared_ptr SendableRegistry::GetData(Sendable* sendable, int handle) { assert(handle >= 0); std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return nullptr; - auto& comp = it->getSecond(); + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return nullptr; + auto& comp = *m_impl->components[it->getSecond() - 1]; if (static_cast(handle) >= comp.data.size()) return nullptr; return comp.data[handle]; } void SendableRegistry::EnableLiveWindow(Sendable* sendable) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().liveWindow = true; + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->liveWindow = true; } void SendableRegistry::DisableLiveWindow(Sendable* sendable) { std::scoped_lock lock(m_impl->mutex); - auto it = m_impl->components.find(sendable); - if (it == m_impl->components.end()) return; - it->getSecond().liveWindow = false; + auto it = m_impl->componentMap.find(sendable); + if (it == m_impl->componentMap.end()) return; + m_impl->components[it->getSecond() - 1]->liveWindow = false; +} + +SendableRegistry::UID SendableRegistry::GetUniqueId(Sendable* sendable) { + std::scoped_lock lock(m_impl->mutex); + UID uid; + auto& comp = m_impl->GetOrAdd(sendable, &uid); + comp.sendable = sendable; + return uid; +} + +Sendable* SendableRegistry::GetSendable(UID uid) { + if (uid == 0) return nullptr; + std::scoped_lock lock(m_impl->mutex); + return m_impl->components[uid - 1]->sendable; +} + +void SendableRegistry::Publish(UID sendableUid, + std::shared_ptr table) { + std::scoped_lock lock(m_impl->mutex); + if (sendableUid == 0) return; + auto& comp = *m_impl->components[sendableUid - 1]; + comp.builder = SendableBuilderImpl{}; // clear any current builder + comp.builder.SetTable(table); + comp.sendable->InitSendable(comp.builder); + comp.builder.UpdateTable(); + comp.builder.StartListeners(); +} + +void SendableRegistry::Update(UID sendableUid) { + if (sendableUid == 0) return; + std::scoped_lock lock(m_impl->mutex); + m_impl->components[sendableUid - 1]->builder.UpdateTable(); } void SendableRegistry::ForeachLiveWindow( int dataHandle, - wpi::function_ref& data)> - callback) const { + wpi::function_ref callback) const { assert(dataHandle >= 0); std::scoped_lock lock(m_impl->mutex); - for (auto& i : m_impl->components) { - auto& comp = i.getSecond(); - if (comp.sendable && comp.liveWindow) { - if (static_cast(dataHandle) >= comp.data.size()) - comp.data.resize(dataHandle + 1); - callback(comp.sendable, comp.name, comp.subsystem, comp.parent, - comp.data[dataHandle]); + for (auto&& comp : m_impl->components) { + if (comp->sendable && comp->liveWindow) { + if (static_cast(dataHandle) >= comp->data.size()) + comp->data.resize(dataHandle + 1); + CallbackData cbdata{comp->sendable, comp->name, + comp->subsystem, comp->parent, + comp->data[dataHandle], comp->builder}; + callback(cbdata); } } } diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp index 9d0a366cff..e8c9700d73 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp @@ -14,27 +14,17 @@ #include #include "frc/WPIErrors.h" -#include "frc/smartdashboard/SendableBuilderImpl.h" #include "frc/smartdashboard/SendableRegistry.h" using namespace frc; namespace { -class SmartDashboardData { - public: - SmartDashboardData() = default; - explicit SmartDashboardData(Sendable* sendable_) : sendable(sendable_) {} - - Sendable* sendable = nullptr; - SendableBuilderImpl builder; -}; - class Singleton { public: static Singleton& GetInstance(); std::shared_ptr table; - wpi::StringMap tablesToData; + wpi::StringMap tablesToData; wpi::mutex tablesToDataMutex; private: @@ -98,14 +88,13 @@ void SmartDashboard::PutData(wpi::StringRef key, Sendable* data) { } auto& inst = Singleton::GetInstance(); std::scoped_lock lock(inst.tablesToDataMutex); - auto& sddata = inst.tablesToData[key]; - if (!sddata.sendable || sddata.sendable != data) { - sddata = SmartDashboardData(data); + auto& uid = inst.tablesToData[key]; + auto& registry = SendableRegistry::GetInstance(); + Sendable* sddata = registry.GetSendable(uid); + if (sddata != data) { + uid = registry.GetUniqueId(data); auto dataTable = inst.table->GetSubTable(key); - sddata.builder.SetTable(dataTable); - data->InitSendable(sddata.builder); - sddata.builder.UpdateTable(); - sddata.builder.StartListeners(); + registry.Publish(uid, dataTable); dataTable->GetEntry(".name").SetString(key); } } @@ -122,12 +111,12 @@ void SmartDashboard::PutData(Sendable* value) { Sendable* SmartDashboard::GetData(wpi::StringRef key) { auto& inst = Singleton::GetInstance(); std::scoped_lock lock(inst.tablesToDataMutex); - auto data = inst.tablesToData.find(key); - if (data == inst.tablesToData.end()) { + auto it = inst.tablesToData.find(key); + if (it == inst.tablesToData.end()) { wpi_setGlobalWPIErrorWithContext(SmartDashboardMissingKey, key); return nullptr; } - return data->getValue().sendable; + return SendableRegistry::GetInstance().GetSendable(it->getValue()); } bool SmartDashboard::PutBoolean(wpi::StringRef keyName, bool value) { @@ -262,10 +251,9 @@ void SmartDashboard::PostListenerTask(std::function task) { } void SmartDashboard::UpdateValues() { + auto& registry = SendableRegistry::GetInstance(); auto& inst = Singleton::GetInstance(); std::scoped_lock lock(inst.tablesToDataMutex); - for (auto& i : inst.tablesToData) { - i.getValue().builder.UpdateTable(); - } + for (auto& i : inst.tablesToData) registry.Update(i.getValue()); listenerExecutor.RunListenerTasks(); } diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h index e10f08507b..eb69dcd09b 100644 --- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h +++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------*/ -/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */ +/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ @@ -45,6 +45,12 @@ class SendableBuilderImpl : public SendableBuilder { */ std::shared_ptr GetTable(); + /** + * Return whether this sendable has an associated table. + * @return True if it has a table, false if not. + */ + bool HasTable() const; + /** * Return whether this sendable should be treated as an actuator. * @return True if actuator, false if not. @@ -78,6 +84,11 @@ class SendableBuilderImpl : public SendableBuilder { */ void StopLiveWindowMode(); + /** + * Clear properties. + */ + void ClearProperties(); + void SetSmartDashboardType(const wpi::Twine& type) override; void SetActuator(bool value) override; void SetSafeState(std::function func) override; diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h index 2628f4fbad..53dbba3ee0 100644 --- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h +++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h @@ -10,12 +10,14 @@ #include #include +#include #include #include namespace frc { class Sendable; +class SendableBuilderImpl; /** * The SendableRegistry class is the public interface for registering sensors @@ -26,6 +28,8 @@ class SendableRegistry { SendableRegistry(const SendableRegistry&) = delete; SendableRegistry& operator=(const SendableRegistry&) = delete; + using UID = size_t; + /** * Gets an instance of the SendableRegistry class. * @@ -252,6 +256,60 @@ class SendableRegistry { */ void DisableLiveWindow(Sendable* sendable); + /** + * Get unique id for an object. Since objects can move, use this instead + * of storing Sendable* directly if ownership is in question. + * + * @param sendable object + * @return unique id + */ + UID GetUniqueId(Sendable* sendable); + + /** + * Get sendable object for a given unique id. + * + * @param uid unique id + * @return sendable object (may be null) + */ + Sendable* GetSendable(UID uid); + + /** + * Publishes an object in the registry to a network table. + * + * @param sendableUid sendable unique id + * @param table network table + */ + void Publish(UID sendableUid, std::shared_ptr table); + + /** + * Updates network table information from an object. + * + * @param sendableUid sendable unique id + */ + void Update(UID sendableUid); + + /** + * Data passed to ForeachLiveWindow() callback function + */ + struct CallbackData { + CallbackData(Sendable* sendable_, wpi::StringRef name_, + wpi::StringRef subsystem_, Sendable* parent_, + std::shared_ptr& data_, SendableBuilderImpl& builder_) + : sendable(sendable_), + name(name_), + subsystem(subsystem_), + parent(parent_), + data(data_), + builder(builder_) {} + + Sendable* sendable; + wpi::StringRef name; + wpi::StringRef subsystem; + Sendable* parent; + std::shared_ptr& data; + SendableBuilderImpl& builder; + }; + /** * Iterates over LiveWindow-enabled objects in the registry. * It is *not* safe to call other SendableRegistry functions from the @@ -262,10 +320,7 @@ class SendableRegistry { */ void ForeachLiveWindow( int dataHandle, - wpi::function_ref& data)> - callback) const; + wpi::function_ref callback) const; private: SendableRegistry();