Split Sendable into NT and non-NT portions (#3432)

The non-NT portion has been moved to wpiutil.
The NT portion has been moved to ntcore (as NTSendable).

SendableBuilder similarly split and moved.

SendableRegistry moved to wpiutil.

In C++, SendableHelper also moved to wpiutil.

This enables use of Sendable from wpimath and also enables
moving several classes from wpilib to wpimath.
This commit is contained in:
Peter Johnson
2021-06-13 16:38:05 -07:00
committed by GitHub
parent ef4ea84cb5
commit b417d961ec
196 changed files with 1147 additions and 891 deletions

View File

@@ -4,8 +4,8 @@
#include "frc/smartdashboard/Field2d.h"
#include "frc/smartdashboard/SendableBuilder.h"
#include "frc/smartdashboard/SendableRegistry.h"
#include <networktables/NTSendableBuilder.h>
#include <wpi/sendable/SendableRegistry.h>
using namespace frc;
@@ -13,7 +13,7 @@ Field2d::Field2d() {
m_objects.emplace_back(
std::make_unique<FieldObject2d>("Robot", FieldObject2d::private_init{}));
m_objects[0]->SetPose(Pose2d{});
SendableRegistry::GetInstance().Add(this, "Field");
wpi::SendableRegistry::GetInstance().Add(this, "Field");
}
Field2d::Field2d(Field2d&& rhs) : SendableHelper(std::move(rhs)) {
@@ -67,7 +67,7 @@ FieldObject2d* Field2d::GetRobotObject() {
return m_objects[0].get();
}
void Field2d::InitSendable(SendableBuilder& builder) {
void Field2d::InitSendable(nt::NTSendableBuilder& builder) {
builder.SetSmartDashboardType("Field2d");
m_table = builder.GetTable();

View File

@@ -6,7 +6,7 @@
#include <cstdio>
#include "frc/smartdashboard/SendableBuilder.h"
#include <networktables/NTSendableBuilder.h>
using namespace frc;
@@ -41,7 +41,7 @@ void Mechanism2d::SetBackgroundColor(const Color8Bit& color) {
}
}
void Mechanism2d::InitSendable(SendableBuilder& builder) {
void Mechanism2d::InitSendable(nt::NTSendableBuilder& builder) {
builder.SetSmartDashboardType("Mechanism2d");
m_table = builder.GetTable();

View File

@@ -4,8 +4,6 @@
#include "frc/smartdashboard/MechanismRoot2d.h"
#include "frc/smartdashboard/Sendable.h"
#include "frc/smartdashboard/SendableHelper.h"
#include "frc/util/Color8Bit.h"
using namespace frc;

View File

@@ -20,7 +20,7 @@ std::shared_ptr<nt::NetworkTable> SendableBuilderImpl::GetTable() {
return m_table;
}
bool SendableBuilderImpl::HasTable() const {
bool SendableBuilderImpl::IsPublished() const {
return m_table != nullptr;
}
@@ -28,7 +28,7 @@ bool SendableBuilderImpl::IsActuator() const {
return m_actuator;
}
void SendableBuilderImpl::UpdateTable() {
void SendableBuilderImpl::Update() {
uint64_t time = nt::Now();
for (auto& property : m_properties) {
if (property.update) {

View File

@@ -4,14 +4,14 @@
#include "frc/smartdashboard/SendableChooserBase.h"
#include "frc/smartdashboard/SendableRegistry.h"
#include <wpi/sendable/SendableRegistry.h>
using namespace frc;
std::atomic_int SendableChooserBase::s_instances{0};
SendableChooserBase::SendableChooserBase() : m_instance{s_instances++} {
SendableRegistry::GetInstance().Add(this, "SendableChooser", m_instance);
wpi::SendableRegistry::GetInstance().Add(this, "SendableChooser", m_instance);
}
SendableChooserBase::SendableChooserBase(SendableChooserBase&& oth)

View File

@@ -1,400 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/smartdashboard/SendableRegistry.h"
#include <memory>
#include <fmt/format.h>
#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;
bool liveWindow = false;
wpi::SmallVector<std::shared_ptr<void>, 2> data;
void SetName(std::string_view moduleType, int channel) {
name = fmt::format("{}[{}]", moduleType, channel);
}
void SetName(std::string_view moduleType, int moduleNumber, int channel) {
name = fmt::format("{}[{},{}]", moduleType, moduleNumber, channel);
}
};
wpi::recursive_mutex mutex;
wpi::UidVector<std::unique_ptr<Component>, 32> components;
wpi::DenseMap<void*, UID> componentMap;
int nextDataHandle = 0;
Component& GetOrAdd(void* sendable, UID* uid = nullptr);
};
SendableRegistry::Impl::Component& SendableRegistry::Impl::GetOrAdd(
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() {
static SendableRegistry instance;
return instance;
}
void SendableRegistry::Add(Sendable* sendable, std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(sendable);
comp.sendable = sendable;
comp.name = name;
}
void SendableRegistry::Add(Sendable* sendable, std::string_view moduleType,
int channel) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(sendable);
comp.sendable = sendable;
comp.SetName(moduleType, channel);
}
void SendableRegistry::Add(Sendable* sendable, std::string_view 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);
}
void SendableRegistry::Add(Sendable* sendable, std::string_view subsystem,
std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(sendable);
comp.sendable = sendable;
comp.name = name;
comp.subsystem = subsystem;
}
void SendableRegistry::AddLW(Sendable* sendable, std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(sendable);
comp.sendable = sendable;
comp.liveWindow = true;
comp.name = name;
}
void SendableRegistry::AddLW(Sendable* sendable, std::string_view 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);
}
void SendableRegistry::AddLW(Sendable* sendable, std::string_view 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);
}
void SendableRegistry::AddLW(Sendable* sendable, std::string_view subsystem,
std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(sendable);
comp.sendable = sendable;
comp.liveWindow = true;
comp.name = name;
comp.subsystem = subsystem;
}
void SendableRegistry::AddChild(Sendable* parent, Sendable* child) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(child);
comp.parent = parent;
}
void SendableRegistry::AddChild(Sendable* parent, void* child) {
std::scoped_lock lock(m_impl->mutex);
auto& comp = m_impl->GetOrAdd(child);
comp.parent = parent;
}
bool SendableRegistry::Remove(Sendable* sendable) {
std::scoped_lock lock(m_impl->mutex);
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);
// update any parent pointers
for (auto&& comp : m_impl->components) {
if (comp->parent == sendable) {
comp->parent = nullptr;
}
}
return true;
}
void SendableRegistry::Move(Sendable* to, Sendable* from) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(from);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
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);
}
// update any parent pointers
for (auto&& comp : m_impl->components) {
if (comp->parent == from) {
comp->parent = to;
}
}
}
bool SendableRegistry::Contains(const Sendable* sendable) const {
std::scoped_lock lock(m_impl->mutex);
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->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return {};
}
return m_impl->components[it->getSecond() - 1]->name;
}
void SendableRegistry::SetName(Sendable* sendable, std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return;
}
m_impl->components[it->getSecond() - 1]->name = name;
}
void SendableRegistry::SetName(Sendable* sendable, std::string_view moduleType,
int channel) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return;
}
m_impl->components[it->getSecond() - 1]->SetName(moduleType, channel);
}
void SendableRegistry::SetName(Sendable* sendable, std::string_view moduleType,
int moduleNumber, int channel) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return;
}
m_impl->components[it->getSecond() - 1]->SetName(moduleType, moduleNumber,
channel);
}
void SendableRegistry::SetName(Sendable* sendable, std::string_view subsystem,
std::string_view name) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return;
}
auto& comp = *m_impl->components[it->getSecond() - 1];
comp.name = name;
comp.subsystem = subsystem;
}
std::string SendableRegistry::GetSubsystem(const Sendable* sendable) const {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return {};
}
return m_impl->components[it->getSecond() - 1]->subsystem;
}
void SendableRegistry::SetSubsystem(Sendable* sendable,
std::string_view subsystem) {
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
return;
}
m_impl->components[it->getSecond() - 1]->subsystem = subsystem;
}
int SendableRegistry::GetDataHandle() {
std::scoped_lock lock(m_impl->mutex);
return m_impl->nextDataHandle++;
}
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->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
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]);
} else {
comp.data.resize(handle + 1);
}
comp.data[handle] = std::move(data);
return rv;
}
std::shared_ptr<void> SendableRegistry::GetData(Sendable* sendable,
int handle) {
assert(handle >= 0);
std::scoped_lock lock(m_impl->mutex);
auto it = m_impl->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
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->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
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->componentMap.find(sendable);
if (it == m_impl->componentMap.end() ||
!m_impl->components[it->getSecond() - 1]) {
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);
if ((uid - 1) >= m_impl->components.size() || !m_impl->components[uid - 1]) {
return nullptr;
}
return m_impl->components[uid - 1]->sendable;
}
void SendableRegistry::Publish(UID sendableUid,
std::shared_ptr<nt::NetworkTable> table) {
std::scoped_lock lock(m_impl->mutex);
if (sendableUid == 0 || (sendableUid - 1) >= m_impl->components.size() ||
!m_impl->components[sendableUid - 1]) {
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);
if ((sendableUid - 1) >= m_impl->components.size() ||
!m_impl->components[sendableUid - 1]) {
return;
}
m_impl->components[sendableUid - 1]->builder.UpdateTable();
}
void SendableRegistry::ForeachLiveWindow(
int dataHandle,
wpi::function_ref<void(CallbackData& data)> callback) const {
assert(dataHandle >= 0);
std::scoped_lock lock(m_impl->mutex);
wpi::SmallVector<Impl::Component*, 128> components;
for (auto&& comp : m_impl->components) {
components.emplace_back(comp.get());
}
for (auto comp : components) {
if (comp && 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);
}
}
}
SendableRegistry::SendableRegistry() : m_impl(new Impl) {}

View File

@@ -9,9 +9,10 @@
#include <networktables/NetworkTableInstance.h>
#include <wpi/StringMap.h>
#include <wpi/mutex.h>
#include <wpi/sendable/SendableRegistry.h>
#include "frc/Errors.h"
#include "frc/smartdashboard/SendableRegistry.h"
#include "frc/smartdashboard/SendableBuilderImpl.h"
using namespace frc;
@@ -21,7 +22,7 @@ class Singleton {
static Singleton& GetInstance();
std::shared_ptr<nt::NetworkTable> table;
wpi::StringMap<SendableRegistry::UID> tablesToData;
wpi::StringMap<wpi::SendableRegistry::UID> tablesToData;
wpi::mutex tablesToDataMutex;
private:
@@ -84,41 +85,45 @@ nt::NetworkTableEntry SmartDashboard::GetEntry(std::string_view key) {
return Singleton::GetInstance().table->GetEntry(key);
}
void SmartDashboard::PutData(std::string_view key, Sendable* data) {
void SmartDashboard::PutData(std::string_view key, wpi::Sendable* data) {
if (!data) {
throw FRC_MakeError(err::NullParameter, "{}", "value");
}
auto& inst = Singleton::GetInstance();
std::scoped_lock lock(inst.tablesToDataMutex);
auto& uid = inst.tablesToData[key];
auto& registry = SendableRegistry::GetInstance();
Sendable* sddata = registry.GetSendable(uid);
auto& registry = wpi::SendableRegistry::GetInstance();
wpi::Sendable* sddata = registry.GetSendable(uid);
if (sddata != data) {
uid = registry.GetUniqueId(data);
auto dataTable = inst.table->GetSubTable(key);
registry.Publish(uid, dataTable);
auto builder = std::make_unique<SendableBuilderImpl>();
auto builderPtr = builder.get();
builderPtr->SetTable(dataTable);
registry.Publish(uid, std::move(builder));
builderPtr->StartListeners();
dataTable->GetEntry(".name").SetString(key);
}
}
void SmartDashboard::PutData(Sendable* value) {
void SmartDashboard::PutData(wpi::Sendable* value) {
if (!value) {
throw FRC_MakeError(err::NullParameter, "{}", "value");
}
auto name = SendableRegistry::GetInstance().GetName(value);
auto name = wpi::SendableRegistry::GetInstance().GetName(value);
if (!name.empty()) {
PutData(name, value);
}
}
Sendable* SmartDashboard::GetData(std::string_view key) {
wpi::Sendable* SmartDashboard::GetData(std::string_view key) {
auto& inst = Singleton::GetInstance();
std::scoped_lock lock(inst.tablesToDataMutex);
auto it = inst.tablesToData.find(key);
if (it == inst.tablesToData.end()) {
throw FRC_MakeError(err::SmartDashboardMissingKey, "{}", key);
}
return SendableRegistry::GetInstance().GetSendable(it->getValue());
return wpi::SendableRegistry::GetInstance().GetSendable(it->getValue());
}
bool SmartDashboard::PutBoolean(std::string_view keyName, bool value) {
@@ -257,7 +262,7 @@ void SmartDashboard::PostListenerTask(std::function<void()> task) {
}
void SmartDashboard::UpdateValues() {
auto& registry = SendableRegistry::GetInstance();
auto& registry = wpi::SendableRegistry::GetInstance();
auto& inst = Singleton::GetInstance();
listenerExecutor.RunListenerTasks();
std::scoped_lock lock(inst.tablesToDataMutex);