mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[ntcore] NetworkTables 4 (#3217)
This commit is contained in:
@@ -34,16 +34,18 @@ class NTMechanismObjectModel;
|
||||
|
||||
class NTMechanismGroupImpl final {
|
||||
public:
|
||||
NTMechanismGroupImpl(NT_Inst inst, std::string_view path,
|
||||
NTMechanismGroupImpl(nt::NetworkTableInstance inst, std::string_view path,
|
||||
std::string_view name)
|
||||
: m_inst{inst}, m_path{path}, m_name{name} {}
|
||||
|
||||
const char* GetName() const { return m_name.c_str(); }
|
||||
void ForEachObject(wpi::function_ref<void(MechanismObjectModel& model)> func);
|
||||
void NTUpdate(const nt::EntryNotification& event, std::string_view name);
|
||||
|
||||
void NTUpdate(const nt::TopicNotification& event, std::string_view name);
|
||||
void NTUpdate(const nt::ValueNotification& event, std::string_view name);
|
||||
|
||||
protected:
|
||||
NT_Inst m_inst;
|
||||
nt::NetworkTableInstance m_inst;
|
||||
std::string m_path;
|
||||
std::string m_name;
|
||||
std::vector<std::unique_ptr<NTMechanismObjectModel>> m_objects;
|
||||
@@ -51,14 +53,14 @@ class NTMechanismGroupImpl final {
|
||||
|
||||
class NTMechanismObjectModel final : public MechanismObjectModel {
|
||||
public:
|
||||
NTMechanismObjectModel(NT_Inst inst, std::string_view path,
|
||||
NTMechanismObjectModel(nt::NetworkTableInstance inst, std::string_view path,
|
||||
std::string_view name)
|
||||
: m_group{inst, path, name},
|
||||
m_type{nt::GetEntry(inst, fmt::format("{}/.type", path))},
|
||||
m_color{nt::GetEntry(inst, fmt::format("{}/color", path))},
|
||||
m_weight{nt::GetEntry(inst, fmt::format("{}/weight", path))},
|
||||
m_angle{nt::GetEntry(inst, fmt::format("{}/angle", path))},
|
||||
m_length{nt::GetEntry(inst, fmt::format("{}/length", path))} {}
|
||||
m_typeTopic{inst.GetTopic(fmt::format("{}/.type", path))},
|
||||
m_colorTopic{inst.GetTopic(fmt::format("{}/color", path))},
|
||||
m_weightTopic{inst.GetTopic(fmt::format("{}/weight", path))},
|
||||
m_angleTopic{inst.GetTopic(fmt::format("{}/angle", path))},
|
||||
m_lengthTopic{inst.GetTopic(fmt::format("{}/length", path))} {}
|
||||
|
||||
const char* GetName() const final { return m_group.GetName(); }
|
||||
void ForEachObject(
|
||||
@@ -72,16 +74,17 @@ class NTMechanismObjectModel final : public MechanismObjectModel {
|
||||
frc::Rotation2d GetAngle() const final { return m_angleValue; }
|
||||
units::meter_t GetLength() const final { return m_lengthValue; }
|
||||
|
||||
bool NTUpdate(const nt::EntryNotification& event, std::string_view childName);
|
||||
bool NTUpdate(const nt::TopicNotification& event, std::string_view name);
|
||||
void NTUpdate(const nt::ValueNotification& event, std::string_view name);
|
||||
|
||||
private:
|
||||
NTMechanismGroupImpl m_group;
|
||||
|
||||
NT_Entry m_type;
|
||||
NT_Entry m_color;
|
||||
NT_Entry m_weight;
|
||||
NT_Entry m_angle;
|
||||
NT_Entry m_length;
|
||||
nt::Topic m_typeTopic;
|
||||
nt::Topic m_colorTopic;
|
||||
nt::Topic m_weightTopic;
|
||||
nt::Topic m_angleTopic;
|
||||
nt::Topic m_lengthTopic;
|
||||
|
||||
std::string m_typeValue;
|
||||
ImU32 m_colorValue = IM_COL32_WHITE;
|
||||
@@ -99,7 +102,7 @@ void NTMechanismGroupImpl::ForEachObject(
|
||||
}
|
||||
}
|
||||
|
||||
void NTMechanismGroupImpl::NTUpdate(const nt::EntryNotification& event,
|
||||
void NTMechanismGroupImpl::NTUpdate(const nt::TopicNotification& event,
|
||||
std::string_view name) {
|
||||
if (name.empty()) {
|
||||
return;
|
||||
@@ -115,7 +118,7 @@ void NTMechanismGroupImpl::NTUpdate(const nt::EntryNotification& event,
|
||||
[](const auto& e, std::string_view name) { return e->GetName() < name; });
|
||||
bool match = it != m_objects.end() && (*it)->GetName() == name;
|
||||
|
||||
if (event.flags & NT_NOTIFY_NEW) {
|
||||
if (event.flags & NT_TOPIC_NOTIFY_PUBLISH) {
|
||||
if (!match) {
|
||||
it = m_objects.emplace(
|
||||
it, std::make_unique<NTMechanismObjectModel>(
|
||||
@@ -123,6 +126,7 @@ void NTMechanismGroupImpl::NTUpdate(const nt::EntryNotification& event,
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if ((*it)->NTUpdate(event, childName)) {
|
||||
m_objects.erase(it);
|
||||
@@ -130,43 +134,74 @@ void NTMechanismGroupImpl::NTUpdate(const nt::EntryNotification& event,
|
||||
}
|
||||
}
|
||||
|
||||
bool NTMechanismObjectModel::NTUpdate(const nt::EntryNotification& event,
|
||||
void NTMechanismGroupImpl::NTUpdate(const nt::ValueNotification& event,
|
||||
std::string_view name) {
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
std::string_view childName;
|
||||
std::tie(name, childName) = wpi::split(name, '/');
|
||||
if (childName.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(
|
||||
m_objects.begin(), m_objects.end(), name,
|
||||
[](const auto& e, std::string_view name) { return e->GetName() < name; });
|
||||
if (it != m_objects.end() && (*it)->GetName() == name) {
|
||||
(*it)->NTUpdate(event, childName);
|
||||
}
|
||||
}
|
||||
|
||||
bool NTMechanismObjectModel::NTUpdate(const nt::TopicNotification& event,
|
||||
std::string_view childName) {
|
||||
if (event.entry == m_type) {
|
||||
if ((event.flags & NT_NOTIFY_DELETE) != 0) {
|
||||
if (event.info.topic == m_typeTopic.GetHandle()) {
|
||||
if (event.flags & NT_TOPIC_NOTIFY_UNPUBLISH) {
|
||||
return true;
|
||||
}
|
||||
if (event.value && event.value->IsString()) {
|
||||
m_typeValue = event.value->GetString();
|
||||
}
|
||||
} else if (event.entry == m_color) {
|
||||
if (event.value && event.value->IsString()) {
|
||||
ConvertColor(event.value->GetString(), &m_colorValue);
|
||||
}
|
||||
} else if (event.entry == m_weight) {
|
||||
if (event.value && event.value->IsDouble()) {
|
||||
m_weightValue = event.value->GetDouble();
|
||||
}
|
||||
} else if (event.entry == m_angle) {
|
||||
if (event.value && event.value->IsDouble()) {
|
||||
m_angleValue = units::degree_t{event.value->GetDouble()};
|
||||
}
|
||||
} else if (event.entry == m_length) {
|
||||
if (event.value && event.value->IsDouble()) {
|
||||
m_lengthValue = units::meter_t{event.value->GetDouble()};
|
||||
}
|
||||
} else {
|
||||
} else if (event.info.topic != m_colorTopic.GetHandle() &&
|
||||
event.info.topic != m_weightTopic.GetHandle() &&
|
||||
event.info.topic != m_angleTopic.GetHandle() &&
|
||||
event.info.topic != m_lengthTopic.GetHandle()) {
|
||||
m_group.NTUpdate(event, childName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NTMechanismObjectModel::NTUpdate(const nt::ValueNotification& event,
|
||||
std::string_view childName) {
|
||||
if (event.topic == m_typeTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsString()) {
|
||||
m_typeValue = event.value.GetString();
|
||||
}
|
||||
} else if (event.topic == m_colorTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsString()) {
|
||||
ConvertColor(event.value.GetString(), &m_colorValue);
|
||||
}
|
||||
} else if (event.topic == m_weightTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDouble()) {
|
||||
m_weightValue = event.value.GetDouble();
|
||||
}
|
||||
} else if (event.topic == m_angleTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDouble()) {
|
||||
m_angleValue = units::degree_t{event.value.GetDouble()};
|
||||
}
|
||||
} else if (event.topic == m_lengthTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDouble()) {
|
||||
m_lengthValue = units::meter_t{event.value.GetDouble()};
|
||||
}
|
||||
} else {
|
||||
m_group.NTUpdate(event, childName);
|
||||
}
|
||||
}
|
||||
|
||||
class NTMechanism2DModel::RootModel final : public MechanismRootModel {
|
||||
public:
|
||||
RootModel(NT_Inst inst, std::string_view path, std::string_view name)
|
||||
RootModel(nt::NetworkTableInstance inst, std::string_view path,
|
||||
std::string_view name)
|
||||
: m_group{inst, path, name},
|
||||
m_x{nt::GetEntry(inst, fmt::format("{}/x", path))},
|
||||
m_y{nt::GetEntry(inst, fmt::format("{}/y", path))} {}
|
||||
m_xTopic{inst.GetTopic(fmt::format("{}/x", path))},
|
||||
m_yTopic{inst.GetTopic(fmt::format("{}/y", path))} {}
|
||||
|
||||
const char* GetName() const final { return m_group.GetName(); }
|
||||
void ForEachObject(
|
||||
@@ -174,31 +209,24 @@ class NTMechanism2DModel::RootModel final : public MechanismRootModel {
|
||||
m_group.ForEachObject(func);
|
||||
}
|
||||
|
||||
bool NTUpdate(const nt::EntryNotification& event, std::string_view childName);
|
||||
bool NTUpdate(const nt::TopicNotification& event, std::string_view childName);
|
||||
void NTUpdate(const nt::ValueNotification& event, std::string_view childName);
|
||||
|
||||
frc::Translation2d GetPosition() const override { return m_pos; };
|
||||
|
||||
private:
|
||||
NTMechanismGroupImpl m_group;
|
||||
NT_Entry m_x;
|
||||
NT_Entry m_y;
|
||||
nt::Topic m_xTopic;
|
||||
nt::Topic m_yTopic;
|
||||
frc::Translation2d m_pos;
|
||||
};
|
||||
|
||||
bool NTMechanism2DModel::RootModel::NTUpdate(const nt::EntryNotification& event,
|
||||
bool NTMechanism2DModel::RootModel::NTUpdate(const nt::TopicNotification& event,
|
||||
std::string_view childName) {
|
||||
if ((event.flags & NT_NOTIFY_DELETE) != 0 &&
|
||||
(event.entry == m_x || event.entry == m_y)) {
|
||||
return true;
|
||||
} else if (event.entry == m_x) {
|
||||
if (event.value && event.value->IsDouble()) {
|
||||
m_pos = frc::Translation2d{units::meter_t{event.value->GetDouble()},
|
||||
m_pos.Y()};
|
||||
}
|
||||
} else if (event.entry == m_y) {
|
||||
if (event.value && event.value->IsDouble()) {
|
||||
m_pos = frc::Translation2d{m_pos.X(),
|
||||
units::meter_t{event.value->GetDouble()}};
|
||||
if (event.info.topic == m_xTopic.GetHandle() ||
|
||||
event.info.topic == m_yTopic.GetHandle()) {
|
||||
if (event.flags & NT_TOPIC_NOTIFY_UNPUBLISH) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
m_group.NTUpdate(event, childName);
|
||||
@@ -206,36 +234,95 @@ bool NTMechanism2DModel::RootModel::NTUpdate(const nt::EntryNotification& event,
|
||||
return false;
|
||||
}
|
||||
|
||||
NTMechanism2DModel::NTMechanism2DModel(std::string_view path)
|
||||
: NTMechanism2DModel{nt::GetDefaultInstance(), path} {}
|
||||
void NTMechanism2DModel::RootModel::NTUpdate(const nt::ValueNotification& event,
|
||||
std::string_view childName) {
|
||||
if (event.topic == m_xTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDouble()) {
|
||||
m_pos = frc::Translation2d{units::meter_t{event.value.GetDouble()},
|
||||
m_pos.Y()};
|
||||
}
|
||||
} else if (event.topic == m_yTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDouble()) {
|
||||
m_pos = frc::Translation2d{m_pos.X(),
|
||||
units::meter_t{event.value.GetDouble()}};
|
||||
}
|
||||
} else {
|
||||
m_group.NTUpdate(event, childName);
|
||||
}
|
||||
}
|
||||
|
||||
NTMechanism2DModel::NTMechanism2DModel(NT_Inst inst, std::string_view path)
|
||||
: m_nt{inst},
|
||||
NTMechanism2DModel::NTMechanism2DModel(std::string_view path)
|
||||
: NTMechanism2DModel{nt::NetworkTableInstance::GetDefault(), path} {}
|
||||
|
||||
NTMechanism2DModel::NTMechanism2DModel(nt::NetworkTableInstance inst,
|
||||
std::string_view path)
|
||||
: m_inst{inst},
|
||||
m_path{fmt::format("{}/", path)},
|
||||
m_name{m_nt.GetEntry(fmt::format("{}/.name", path))},
|
||||
m_dimensions{m_nt.GetEntry(fmt::format("{}/dims", path))},
|
||||
m_bgColor{m_nt.GetEntry(fmt::format("{}/backgroundColor", path))},
|
||||
m_tableSub{inst,
|
||||
{{m_path}},
|
||||
{{nt::PubSubOption::SendAll(true),
|
||||
nt::PubSubOption::Periodic(0.05)}}},
|
||||
m_nameTopic{m_inst.GetTopic(fmt::format("{}/.name", path))},
|
||||
m_dimensionsTopic{m_inst.GetTopic(fmt::format("{}/dims", path))},
|
||||
m_bgColorTopic{m_inst.GetTopic(fmt::format("{}/backgroundColor", path))},
|
||||
m_topicListener{m_inst},
|
||||
m_valueListener{m_inst},
|
||||
m_dimensionsValue{1_m, 1_m} {
|
||||
m_nt.AddListener(m_path, NT_NOTIFY_LOCAL | NT_NOTIFY_NEW | NT_NOTIFY_DELETE |
|
||||
NT_NOTIFY_UPDATE | NT_NOTIFY_IMMEDIATE);
|
||||
m_topicListener.Add(m_tableSub, NT_TOPIC_NOTIFY_PUBLISH |
|
||||
NT_TOPIC_NOTIFY_UNPUBLISH |
|
||||
NT_TOPIC_NOTIFY_IMMEDIATE);
|
||||
m_valueListener.Add(m_tableSub,
|
||||
NT_VALUE_NOTIFY_IMMEDIATE | NT_VALUE_NOTIFY_LOCAL);
|
||||
}
|
||||
|
||||
NTMechanism2DModel::~NTMechanism2DModel() = default;
|
||||
|
||||
void NTMechanism2DModel::Update() {
|
||||
for (auto&& event : m_nt.PollListener()) {
|
||||
for (auto&& event : m_topicListener.ReadQueue()) {
|
||||
auto name = wpi::drop_front(event.info.name, m_path.size());
|
||||
if (name.empty() || name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
std::string_view childName;
|
||||
std::tie(name, childName) = wpi::split(name, '/');
|
||||
if (childName.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(m_roots.begin(), m_roots.end(), name,
|
||||
[](const auto& e, std::string_view name) {
|
||||
return e->GetName() < name;
|
||||
});
|
||||
bool match = it != m_roots.end() && (*it)->GetName() == name;
|
||||
|
||||
if (event.flags & NT_TOPIC_NOTIFY_PUBLISH) {
|
||||
if (!match) {
|
||||
it = m_roots.emplace(
|
||||
it, std::make_unique<RootModel>(
|
||||
m_inst, fmt::format("{}{}", m_path, name), name));
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if ((*it)->NTUpdate(event, childName)) {
|
||||
m_roots.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& event : m_valueListener.ReadQueue()) {
|
||||
// .name
|
||||
if (event.entry == m_name) {
|
||||
if (event.value && event.value->IsString()) {
|
||||
m_nameValue = event.value->GetString();
|
||||
if (event.topic == m_nameTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsString()) {
|
||||
m_nameValue = event.value.GetString();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// dims
|
||||
if (event.entry == m_dimensions) {
|
||||
if (event.value && event.value->IsDoubleArray()) {
|
||||
auto arr = event.value->GetDoubleArray();
|
||||
if (event.topic == m_dimensionsTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsDoubleArray()) {
|
||||
auto arr = event.value.GetDoubleArray();
|
||||
if (arr.size() == 2) {
|
||||
m_dimensionsValue = frc::Translation2d{units::meter_t{arr[0]},
|
||||
units::meter_t{arr[1]}};
|
||||
@@ -244,50 +331,16 @@ void NTMechanism2DModel::Update() {
|
||||
}
|
||||
|
||||
// backgroundColor
|
||||
if (event.entry == m_bgColor) {
|
||||
if (event.value && event.value->IsString()) {
|
||||
ConvertColor(event.value->GetString(), &m_bgColorValue);
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view name = event.name;
|
||||
if (wpi::starts_with(name, m_path)) {
|
||||
name.remove_prefix(m_path.size());
|
||||
if (name.empty() || name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
std::string_view childName;
|
||||
std::tie(name, childName) = wpi::split(name, '/');
|
||||
if (childName.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(m_roots.begin(), m_roots.end(), name,
|
||||
[](const auto& e, std::string_view name) {
|
||||
return e->GetName() < name;
|
||||
});
|
||||
bool match = it != m_roots.end() && (*it)->GetName() == name;
|
||||
|
||||
if (event.flags & NT_NOTIFY_NEW) {
|
||||
if (!match) {
|
||||
it = m_roots.emplace(
|
||||
it,
|
||||
std::make_unique<RootModel>(
|
||||
m_nt.GetInstance(), fmt::format("{}{}", m_path, name), name));
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if ((*it)->NTUpdate(event, childName)) {
|
||||
m_roots.erase(it);
|
||||
}
|
||||
if (event.topic == m_bgColorTopic.GetHandle()) {
|
||||
if (event.value && event.value.IsString()) {
|
||||
ConvertColor(event.value.GetString(), &m_bgColorValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NTMechanism2DModel::Exists() {
|
||||
return m_nt.IsConnected() && nt::GetEntryType(m_name) != NT_UNASSIGNED;
|
||||
return m_inst.IsConnected() && m_nameTopic.Exists();
|
||||
}
|
||||
|
||||
bool NTMechanism2DModel::IsReadOnly() {
|
||||
|
||||
Reference in New Issue
Block a user