mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
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:
417
wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp
Normal file
417
wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
// 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 "wpi/sendable/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 "wpi/sendable/Sendable.h"
|
||||
#include "wpi/sendable/SendableBuilder.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
struct SendableRegistry::Impl {
|
||||
struct Component {
|
||||
Sendable* sendable = nullptr;
|
||||
std::unique_ptr<SendableBuilder> 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;
|
||||
|
||||
std::function<std::unique_ptr<SendableBuilder>()> liveWindowFactory;
|
||||
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::SetLiveWindowBuilderFactory(
|
||||
std::function<std::unique_ptr<SendableBuilder>()> factory) {
|
||||
m_impl->liveWindowFactory = std::move(factory);
|
||||
}
|
||||
|
||||
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;
|
||||
if (m_impl->liveWindowFactory) {
|
||||
comp.builder = m_impl->liveWindowFactory();
|
||||
}
|
||||
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;
|
||||
if (m_impl->liveWindowFactory) {
|
||||
comp.builder = m_impl->liveWindowFactory();
|
||||
}
|
||||
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;
|
||||
if (m_impl->liveWindowFactory) {
|
||||
comp.builder = m_impl->liveWindowFactory();
|
||||
}
|
||||
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;
|
||||
if (m_impl->liveWindowFactory) {
|
||||
comp.builder = m_impl->liveWindowFactory();
|
||||
}
|
||||
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 && comp.builder->IsPublished()) {
|
||||
// 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::unique_ptr<SendableBuilder> builder) {
|
||||
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 = std::move(builder); // clear any current builder
|
||||
comp.sendable->InitSendable(*comp.builder);
|
||||
comp.builder->Update();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (m_impl->components[sendableUid - 1]->builder) {
|
||||
m_impl->components[sendableUid - 1]->builder->Update();
|
||||
}
|
||||
}
|
||||
|
||||
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->builder && 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) {}
|
||||
26
wpiutil/src/main/native/include/wpi/sendable/Sendable.h
Normal file
26
wpiutil/src/main/native/include/wpi/sendable/Sendable.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class SendableBuilder;
|
||||
|
||||
/**
|
||||
* Interface for Sendable objects.
|
||||
*/
|
||||
class Sendable {
|
||||
public:
|
||||
virtual ~Sendable() = default;
|
||||
|
||||
/**
|
||||
* Initializes this Sendable object.
|
||||
*
|
||||
* @param builder sendable builder
|
||||
*/
|
||||
virtual void InitSendable(SendableBuilder& builder) = 0;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
217
wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
Normal file
217
wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
Normal file
@@ -0,0 +1,217 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/span.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class SendableBuilder {
|
||||
public:
|
||||
/**
|
||||
* The backend kinds used for the sendable builder.
|
||||
*/
|
||||
enum BackendKind { kUnknown, kNetworkTables };
|
||||
|
||||
virtual ~SendableBuilder() = default;
|
||||
|
||||
/**
|
||||
* Set the string representation of the named data type that will be used
|
||||
* by the smart dashboard for this sendable.
|
||||
*
|
||||
* @param type data type
|
||||
*/
|
||||
virtual void SetSmartDashboardType(std::string_view type) = 0;
|
||||
|
||||
/**
|
||||
* Set a flag indicating if this sendable should be treated as an actuator.
|
||||
* By default this flag is false.
|
||||
*
|
||||
* @param value true if actuator, false if not
|
||||
*/
|
||||
virtual void SetActuator(bool value) = 0;
|
||||
|
||||
/**
|
||||
* Set the function that should be called to set the Sendable into a safe
|
||||
* state. This is called when entering and exiting Live Window mode.
|
||||
*
|
||||
* @param func function
|
||||
*/
|
||||
virtual void SetSafeState(std::function<void()> func) = 0;
|
||||
|
||||
/**
|
||||
* Add a boolean property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddBooleanProperty(std::string_view key,
|
||||
std::function<bool()> getter,
|
||||
std::function<void(bool)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a double property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddDoubleProperty(std::string_view key,
|
||||
std::function<double()> getter,
|
||||
std::function<void(double)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a string property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddStringProperty(
|
||||
std::string_view key, std::function<std::string()> getter,
|
||||
std::function<void(std::string_view)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a boolean array property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddBooleanArrayProperty(
|
||||
std::string_view key, std::function<std::vector<int>()> getter,
|
||||
std::function<void(wpi::span<const int>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a double array property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddDoubleArrayProperty(
|
||||
std::string_view key, std::function<std::vector<double>()> getter,
|
||||
std::function<void(wpi::span<const double>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a string array property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddStringArrayProperty(
|
||||
std::string_view key, std::function<std::vector<std::string>()> getter,
|
||||
std::function<void(wpi::span<const std::string>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a raw property.
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddRawProperty(std::string_view key,
|
||||
std::function<std::string()> getter,
|
||||
std::function<void(std::string_view)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a string property (SmallString form).
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddSmallStringProperty(
|
||||
std::string_view key,
|
||||
std::function<std::string_view(wpi::SmallVectorImpl<char>& buf)> getter,
|
||||
std::function<void(std::string_view)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a boolean array property (SmallVector form).
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddSmallBooleanArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<wpi::span<const int>(wpi::SmallVectorImpl<int>& buf)>
|
||||
getter,
|
||||
std::function<void(wpi::span<const int>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a double array property (SmallVector form).
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddSmallDoubleArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<wpi::span<const double>(wpi::SmallVectorImpl<double>& buf)>
|
||||
getter,
|
||||
std::function<void(wpi::span<const double>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a string array property (SmallVector form).
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddSmallStringArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<
|
||||
wpi::span<const std::string>(wpi::SmallVectorImpl<std::string>& buf)>
|
||||
getter,
|
||||
std::function<void(wpi::span<const std::string>)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Add a raw property (SmallVector form).
|
||||
*
|
||||
* @param key property name
|
||||
* @param getter getter function (returns current value)
|
||||
* @param setter setter function (sets new value)
|
||||
*/
|
||||
virtual void AddSmallRawProperty(
|
||||
std::string_view key,
|
||||
std::function<std::string_view(wpi::SmallVectorImpl<char>& buf)> getter,
|
||||
std::function<void(std::string_view)> setter) = 0;
|
||||
|
||||
/**
|
||||
* Gets the kind of backend being used.
|
||||
*
|
||||
* @return Backend kind
|
||||
*/
|
||||
virtual BackendKind GetBackendKind() const = 0;
|
||||
|
||||
/**
|
||||
* Return whether this sendable has been published.
|
||||
*
|
||||
* @return True if it has been published, false if not.
|
||||
*/
|
||||
virtual bool IsPublished() const = 0;
|
||||
|
||||
/**
|
||||
* Update the published values by calling the getters for all properties.
|
||||
*/
|
||||
virtual void Update() = 0;
|
||||
|
||||
/**
|
||||
* Clear properties.
|
||||
*/
|
||||
virtual void ClearProperties() = 0;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
175
wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h
Normal file
175
wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h
Normal file
@@ -0,0 +1,175 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/deprecated.h"
|
||||
#include "wpi/sendable/SendableRegistry.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* A helper class for use with objects that add themselves to SendableRegistry.
|
||||
* It takes care of properly calling Move() and Remove() on move and
|
||||
* destruction. No action is taken if the object is copied.
|
||||
* Use public inheritance with CRTP when using this class.
|
||||
* @tparam CRTP derived class
|
||||
*/
|
||||
template <typename Derived>
|
||||
class SendableHelper {
|
||||
public:
|
||||
SendableHelper(const SendableHelper& rhs) = default;
|
||||
SendableHelper& operator=(const SendableHelper& rhs) = default;
|
||||
|
||||
SendableHelper(SendableHelper&& rhs) {
|
||||
// it is safe to call Move() multiple times with the same rhs
|
||||
SendableRegistry::GetInstance().Move(static_cast<Derived*>(this),
|
||||
static_cast<Derived*>(&rhs));
|
||||
}
|
||||
|
||||
SendableHelper& operator=(SendableHelper&& rhs) {
|
||||
// it is safe to call Move() multiple times with the same rhs
|
||||
SendableRegistry::GetInstance().Move(static_cast<Derived*>(this),
|
||||
static_cast<Derived*>(&rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this Sendable object.
|
||||
*
|
||||
* @deprecated use SendableRegistry::GetName()
|
||||
*
|
||||
* @return Name
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::GetName()")
|
||||
std::string GetName() const {
|
||||
return SendableRegistry::GetInstance().GetName(
|
||||
static_cast<const Derived*>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this Sendable object.
|
||||
*
|
||||
* @deprecated use SendableRegistry::SetName()
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::SetName()")
|
||||
void SetName(std::string_view name) {
|
||||
SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets both the subsystem name and device name of this Sendable object.
|
||||
*
|
||||
* @deprecated use SendableRegistry::SetName()
|
||||
*
|
||||
* @param subsystem subsystem name
|
||||
* @param name device name
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::SetName()")
|
||||
void SetName(std::string_view subsystem, std::string_view name) {
|
||||
SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
|
||||
subsystem, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subsystem name of this Sendable object.
|
||||
*
|
||||
* @deprecated use SendableRegistry::GetSubsystem().
|
||||
*
|
||||
* @return Subsystem name
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::GetSubsystem()")
|
||||
std::string GetSubsystem() const {
|
||||
return SendableRegistry::GetInstance().GetSubsystem(
|
||||
static_cast<const Derived*>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subsystem name of this Sendable object.
|
||||
*
|
||||
* @deprecated use SendableRegistry::SetSubsystem()
|
||||
*
|
||||
* @param subsystem subsystem name
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::SetSubsystem()")
|
||||
void SetSubsystem(std::string_view subsystem) {
|
||||
SendableRegistry::GetInstance().SetSubsystem(static_cast<Derived*>(this),
|
||||
subsystem);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Add a child component.
|
||||
*
|
||||
* @deprecated use SendableRegistry::AddChild()
|
||||
*
|
||||
* @param child child component
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::AddChild()")
|
||||
void AddChild(std::shared_ptr<Sendable> child) {
|
||||
SendableRegistry::GetInstance().AddChild(static_cast<Derived*>(this),
|
||||
child.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child component.
|
||||
*
|
||||
* @deprecated use SendableRegistry::AddChild()
|
||||
*
|
||||
* @param child child component
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::AddChild()")
|
||||
void AddChild(void* child) {
|
||||
SendableRegistry::GetInstance().AddChild(static_cast<Derived*>(this),
|
||||
child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the sensor with a channel number.
|
||||
*
|
||||
* @deprecated use SendableRegistry::SetName()
|
||||
*
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::SetName()")
|
||||
void SetName(std::string_view moduleType, int channel) {
|
||||
SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
|
||||
moduleType, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the sensor with a module and channel number.
|
||||
*
|
||||
* @deprecated use SendableRegistry::SetName()
|
||||
*
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param moduleNumber The number of the particular module type
|
||||
* @param channel The channel number the device is plugged into (usually
|
||||
* PWM)
|
||||
*/
|
||||
WPI_DEPRECATED("use SendableRegistry::SetName()")
|
||||
void SetName(std::string_view moduleType, int moduleNumber, int channel) {
|
||||
SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
|
||||
moduleType, moduleNumber, channel);
|
||||
}
|
||||
|
||||
protected:
|
||||
SendableHelper() = default;
|
||||
|
||||
~SendableHelper() {
|
||||
// it is safe to call Remove() multiple times with the same object
|
||||
SendableRegistry::GetInstance().Remove(static_cast<Derived*>(this));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
346
wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h
Normal file
346
wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h
Normal file
@@ -0,0 +1,346 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/function_ref.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
class Sendable;
|
||||
class SendableBuilder;
|
||||
|
||||
/**
|
||||
* The SendableRegistry class is the public interface for registering sensors
|
||||
* and actuators for use on dashboards and LiveWindow.
|
||||
*/
|
||||
class SendableRegistry {
|
||||
public:
|
||||
SendableRegistry(const SendableRegistry&) = delete;
|
||||
SendableRegistry& operator=(const SendableRegistry&) = delete;
|
||||
|
||||
using UID = size_t;
|
||||
|
||||
/**
|
||||
* Gets an instance of the SendableRegistry class.
|
||||
*
|
||||
* This is a singleton to guarantee that there is only a single instance
|
||||
* regardless of how many times GetInstance is called.
|
||||
*/
|
||||
static SendableRegistry& GetInstance();
|
||||
|
||||
/**
|
||||
* Sets the factory for LiveWindow builders.
|
||||
*
|
||||
* @param factory factory function
|
||||
*/
|
||||
void SetLiveWindowBuilderFactory(
|
||||
std::function<std::unique_ptr<SendableBuilder>()> factory);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param name component name
|
||||
*/
|
||||
void Add(Sendable* sendable, std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void Add(Sendable* sendable, std::string_view moduleType, int channel);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param moduleNumber The number of the particular module type
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void Add(Sendable* sendable, std::string_view moduleType, int moduleNumber,
|
||||
int channel);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param subsystem subsystem name
|
||||
* @param name component name
|
||||
*/
|
||||
void Add(Sendable* sendable, std::string_view subsystem,
|
||||
std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry and LiveWindow.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param name component name
|
||||
*/
|
||||
void AddLW(Sendable* sendable, std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry and LiveWindow.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void AddLW(Sendable* sendable, std::string_view moduleType, int channel);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry and LiveWindow.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param moduleNumber The number of the particular module type
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void AddLW(Sendable* sendable, std::string_view moduleType, int moduleNumber,
|
||||
int channel);
|
||||
|
||||
/**
|
||||
* Adds an object to the registry and LiveWindow.
|
||||
*
|
||||
* @param sendable object to add
|
||||
* @param subsystem subsystem name
|
||||
* @param name component name
|
||||
*/
|
||||
void AddLW(Sendable* sendable, std::string_view subsystem,
|
||||
std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds a child object to an object. Adds the child object to the registry
|
||||
* if it's not already present.
|
||||
*
|
||||
* @param parent parent object
|
||||
* @param child child object
|
||||
*/
|
||||
void AddChild(Sendable* parent, Sendable* child);
|
||||
|
||||
/**
|
||||
* Adds a child object to an object. Adds the child object to the registry
|
||||
* if it's not already present.
|
||||
*
|
||||
* @param parent parent object
|
||||
* @param child child object
|
||||
*/
|
||||
void AddChild(Sendable* parent, void* child);
|
||||
|
||||
/**
|
||||
* Removes an object from the registry.
|
||||
*
|
||||
* @param sendable object to remove
|
||||
* @return true if the object was removed; false if it was not present
|
||||
*/
|
||||
bool Remove(Sendable* sendable);
|
||||
|
||||
/**
|
||||
* Moves an object in the registry (for use in move constructors/assignments).
|
||||
*
|
||||
* @param to new object
|
||||
* @param from old object
|
||||
*/
|
||||
void Move(Sendable* to, Sendable* from);
|
||||
|
||||
/**
|
||||
* Determines if an object is in the registry.
|
||||
*
|
||||
* @param sendable object to check
|
||||
* @return True if in registry, false if not.
|
||||
*/
|
||||
bool Contains(const Sendable* sendable) const;
|
||||
|
||||
/**
|
||||
* Gets the name of an object.
|
||||
*
|
||||
* @param sendable object
|
||||
* @return Name (empty if object is not in registry)
|
||||
*/
|
||||
std::string GetName(const Sendable* sendable) const;
|
||||
|
||||
/**
|
||||
* Sets the name of an object.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param name name
|
||||
*/
|
||||
void SetName(Sendable* sendable, std::string_view name);
|
||||
|
||||
/**
|
||||
* Sets the name of an object with a channel number.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void SetName(Sendable* sendable, std::string_view moduleType, int channel);
|
||||
|
||||
/**
|
||||
* Sets the name of an object with a module and channel number.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param moduleType A string that defines the module name in the label for
|
||||
* the value
|
||||
* @param moduleNumber The number of the particular module type
|
||||
* @param channel The channel number the device is plugged into
|
||||
*/
|
||||
void SetName(Sendable* sendable, std::string_view moduleType,
|
||||
int moduleNumber, int channel);
|
||||
|
||||
/**
|
||||
* Sets both the subsystem name and device name of an object.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param subsystem subsystem name
|
||||
* @param name device name
|
||||
*/
|
||||
void SetName(Sendable* sendable, std::string_view subsystem,
|
||||
std::string_view name);
|
||||
|
||||
/**
|
||||
* Gets the subsystem name of an object.
|
||||
*
|
||||
* @param sendable object
|
||||
* @return Subsystem name (empty if object is not in registry)
|
||||
*/
|
||||
std::string GetSubsystem(const Sendable* sendable) const;
|
||||
|
||||
/**
|
||||
* Sets the subsystem name of an object.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param subsystem subsystem name
|
||||
*/
|
||||
void SetSubsystem(Sendable* sendable, std::string_view subsystem);
|
||||
|
||||
/**
|
||||
* Gets a unique handle for setting/getting data with SetData() and GetData().
|
||||
*
|
||||
* @return Handle
|
||||
*/
|
||||
int GetDataHandle();
|
||||
|
||||
/**
|
||||
* Associates arbitrary data with an object in the registry.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param handle data handle returned by GetDataHandle()
|
||||
* @param data data to set
|
||||
* @return Previous data (may be null)
|
||||
*/
|
||||
std::shared_ptr<void> SetData(Sendable* sendable, int handle,
|
||||
std::shared_ptr<void> data);
|
||||
|
||||
/**
|
||||
* Gets arbitrary data associated with an object in the registry.
|
||||
*
|
||||
* @param sendable object
|
||||
* @param handle data handle returned by GetDataHandle()
|
||||
* @return data (may be null if none associated)
|
||||
*/
|
||||
std::shared_ptr<void> GetData(Sendable* sendable, int handle);
|
||||
|
||||
/**
|
||||
* Enables LiveWindow for an object.
|
||||
*
|
||||
* @param sendable object
|
||||
*/
|
||||
void EnableLiveWindow(Sendable* sendable);
|
||||
|
||||
/**
|
||||
* Disables LiveWindow for an object.
|
||||
*
|
||||
* @param sendable object
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param sendableUid sendable unique id
|
||||
* @param builder publisher backend
|
||||
*/
|
||||
void Publish(UID sendableUid, std::unique_ptr<SendableBuilder> builder);
|
||||
|
||||
/**
|
||||
* Updates published information from an object.
|
||||
*
|
||||
* @param sendableUid sendable unique id
|
||||
*/
|
||||
void Update(UID sendableUid);
|
||||
|
||||
/**
|
||||
* Data passed to ForeachLiveWindow() callback function
|
||||
*/
|
||||
struct CallbackData {
|
||||
CallbackData(Sendable* sendable_, std::string_view name_,
|
||||
std::string_view subsystem_, wpi::Sendable* parent_,
|
||||
std::shared_ptr<void>& data_, SendableBuilder& builder_)
|
||||
: sendable(sendable_),
|
||||
name(name_),
|
||||
subsystem(subsystem_),
|
||||
parent(parent_),
|
||||
data(data_),
|
||||
builder(builder_) {}
|
||||
|
||||
Sendable* sendable;
|
||||
std::string_view name;
|
||||
std::string_view subsystem;
|
||||
Sendable* parent;
|
||||
std::shared_ptr<void>& data;
|
||||
SendableBuilder& builder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates over LiveWindow-enabled objects in the registry.
|
||||
* It is *not* safe to call other SendableRegistry functions from the
|
||||
* callback (this will likely deadlock).
|
||||
*
|
||||
* @param dataHandle data handle to get data pointer passed to callback
|
||||
* @param callback function to call for each object
|
||||
*/
|
||||
void ForeachLiveWindow(
|
||||
int dataHandle,
|
||||
wpi::function_ref<void(CallbackData& cbdata)> callback) const;
|
||||
|
||||
private:
|
||||
SendableRegistry();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
Reference in New Issue
Block a user