mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
Fix move handling of C++ Sendable in SmartDashboard and LiveWindow
This commit is contained in:
@@ -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<void>& data) {
|
||||
if (!data) data = std::make_shared<Impl::Component>();
|
||||
std::static_pointer_cast<Impl::Component>(data)->telemetryEnabled =
|
||||
false;
|
||||
});
|
||||
m_impl->registry.ForeachLiveWindow(m_impl->dataHandle, [&](auto& cbdata) {
|
||||
if (!cbdata.data) cbdata.data = std::make_shared<Impl::Component>();
|
||||
std::static_pointer_cast<Impl::Component>(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<void>& data) {
|
||||
if (data)
|
||||
std::static_pointer_cast<Impl::Component>(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<void>& 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<Impl::Component>();
|
||||
if (!cbdata.data) cbdata.data = std::make_shared<Impl::Component>();
|
||||
|
||||
auto& comp = *std::static_pointer_cast<Impl::Component>(data);
|
||||
auto& comp = *std::static_pointer_cast<Impl::Component>(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<NetworkTable> 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<NetworkTable> 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;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ std::shared_ptr<nt::NetworkTable> 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);
|
||||
}
|
||||
|
||||
@@ -7,15 +7,22 @@
|
||||
|
||||
#include "frc/smartdashboard/SendableRegistry.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <wpi/DenseMap.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/UidVector.h>
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
#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<void*, Component> components;
|
||||
wpi::UidVector<std::unique_ptr<Component>, 32> components;
|
||||
wpi::DenseMap<void*, UID> 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<Component>()) + 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<void> SendableRegistry::SetData(Sendable* sendable, int handle,
|
||||
std::shared_ptr<void> 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<void> rv;
|
||||
if (static_cast<size_t>(handle) < comp.data.size())
|
||||
rv = std::move(comp.data[handle]);
|
||||
@@ -220,42 +252,72 @@ std::shared_ptr<void> 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<size_t>(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<NetworkTable> 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<void(Sendable* sendable, wpi::StringRef name,
|
||||
wpi::StringRef subsystem, Sendable* parent,
|
||||
std::shared_ptr<void>& data)>
|
||||
callback) const {
|
||||
wpi::function_ref<void(CallbackData& data)> 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<size_t>(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<size_t>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,27 +14,17 @@
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
#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<nt::NetworkTable> table;
|
||||
wpi::StringMap<SmartDashboardData> tablesToData;
|
||||
wpi::StringMap<SendableRegistry::UID> 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<void()> 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();
|
||||
}
|
||||
|
||||
@@ -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<nt::NetworkTable> 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<void()> func) override;
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <networktables/NetworkTable.h>
|
||||
#include <wpi/STLExtras.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
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<NetworkTable> 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<void>& 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<void>& 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<void(Sendable* sendable, wpi::StringRef name,
|
||||
wpi::StringRef subsystem, Sendable* parent,
|
||||
std::shared_ptr<void>& data)>
|
||||
callback) const;
|
||||
wpi::function_ref<void(CallbackData& cbdata)> callback) const;
|
||||
|
||||
private:
|
||||
SendableRegistry();
|
||||
|
||||
Reference in New Issue
Block a user