2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2016-01-02 03:02:34 -08:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/livewindow/LiveWindow.h"
|
2016-09-25 16:50:13 -07:00
|
|
|
|
2017-12-07 23:34:29 -08:00
|
|
|
#include <networktables/NetworkTable.h>
|
|
|
|
|
#include <networktables/NetworkTableEntry.h>
|
|
|
|
|
#include <networktables/NetworkTableInstance.h>
|
2018-04-29 23:33:19 -07:00
|
|
|
#include <wpi/mutex.h>
|
2021-06-13 16:38:05 -07:00
|
|
|
#include <wpi/sendable/Sendable.h>
|
|
|
|
|
#include <wpi/sendable/SendableRegistry.h>
|
2017-08-27 00:11:52 -07:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/smartdashboard/SendableBuilderImpl.h"
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2016-11-01 22:33:12 -07:00
|
|
|
using namespace frc;
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
namespace {
|
|
|
|
|
struct Component {
|
|
|
|
|
bool firstTime = true;
|
2022-06-08 22:13:00 -07:00
|
|
|
bool telemetryEnabled = false;
|
2021-06-15 23:06:03 -07:00
|
|
|
};
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
struct Instance {
|
|
|
|
|
Instance() {
|
|
|
|
|
wpi::SendableRegistry::SetLiveWindowBuilderFactory(
|
|
|
|
|
[] { return std::make_unique<SendableBuilderImpl>(); });
|
|
|
|
|
}
|
2017-12-04 23:28:33 -08:00
|
|
|
|
|
|
|
|
wpi::mutex mutex;
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int dataHandle = wpi::SendableRegistry::GetDataHandle();
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::shared_ptr<nt::NetworkTable> liveWindowTable =
|
|
|
|
|
nt::NetworkTableInstance::GetDefault().GetTable("LiveWindow");
|
|
|
|
|
std::shared_ptr<nt::NetworkTable> statusTable =
|
|
|
|
|
liveWindowTable->GetSubTable(".status");
|
|
|
|
|
nt::NetworkTableEntry enabledEntry = statusTable->GetEntry("LW Enabled");
|
2017-12-04 23:28:33 -08:00
|
|
|
|
|
|
|
|
bool startLiveWindow = false;
|
|
|
|
|
bool liveWindowEnabled = false;
|
2022-06-08 22:13:00 -07:00
|
|
|
bool telemetryEnabled = false;
|
2019-09-14 15:22:54 -05:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::function<void()> enabled;
|
|
|
|
|
std::function<void()> disabled;
|
|
|
|
|
|
2021-06-13 16:38:05 -07:00
|
|
|
std::shared_ptr<Component> GetOrAdd(wpi::Sendable* sendable);
|
2017-12-04 23:28:33 -08:00
|
|
|
};
|
2021-06-15 23:06:03 -07:00
|
|
|
} // namespace
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2022-02-10 01:14:12 -05:00
|
|
|
static std::unique_ptr<Instance>& GetInstanceHolder() {
|
|
|
|
|
static std::unique_ptr<Instance> instance = std::make_unique<Instance>();
|
2021-06-15 23:06:03 -07:00
|
|
|
return instance;
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-10 01:14:12 -05:00
|
|
|
static Instance& GetInstance() {
|
|
|
|
|
return *GetInstanceHolder();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef __FRC_ROBORIO__
|
|
|
|
|
namespace frc::impl {
|
|
|
|
|
void ResetLiveWindow() {
|
|
|
|
|
std::make_unique<Instance>().swap(GetInstanceHolder());
|
|
|
|
|
}
|
|
|
|
|
} // namespace frc::impl
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::shared_ptr<Component> Instance::GetOrAdd(wpi::Sendable* sendable) {
|
2019-09-14 15:22:54 -05:00
|
|
|
auto data = std::static_pointer_cast<Component>(
|
2021-06-15 23:06:03 -07:00
|
|
|
wpi::SendableRegistry::GetData(sendable, dataHandle));
|
2019-09-14 15:22:54 -05:00
|
|
|
if (!data) {
|
|
|
|
|
data = std::make_shared<Component>();
|
2021-06-15 23:06:03 -07:00
|
|
|
wpi::SendableRegistry::SetData(sendable, dataHandle, data);
|
2019-09-14 15:22:54 -05:00
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void LiveWindow::SetEnabledCallback(std::function<void()> func) {
|
|
|
|
|
::GetInstance().enabled = func;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LiveWindow::SetDisabledCallback(std::function<void()> func) {
|
|
|
|
|
::GetInstance().disabled = func;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:38:05 -07:00
|
|
|
void LiveWindow::EnableTelemetry(wpi::Sendable* sendable) {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
2017-12-04 23:28:33 -08:00
|
|
|
// Re-enable global setting in case DisableAllTelemetry() was called.
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.telemetryEnabled = true;
|
|
|
|
|
inst.GetOrAdd(sendable)->telemetryEnabled = true;
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:38:05 -07:00
|
|
|
void LiveWindow::DisableTelemetry(wpi::Sendable* sendable) {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
|
|
|
|
inst.GetOrAdd(sendable)->telemetryEnabled = false;
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LiveWindow::DisableAllTelemetry() {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
|
|
|
|
inst.telemetryEnabled = false;
|
|
|
|
|
wpi::SendableRegistry::ForeachLiveWindow(inst.dataHandle, [&](auto& cbdata) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!cbdata.data) {
|
2021-06-15 23:06:03 -07:00
|
|
|
cbdata.data = std::make_shared<Component>();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
std::static_pointer_cast<Component>(cbdata.data)->telemetryEnabled = false;
|
2019-10-17 22:01:31 -07:00
|
|
|
});
|
2017-12-04 23:28:33 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool LiveWindow::IsEnabled() {
|
|
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
|
|
|
|
return inst.liveWindowEnabled;
|
2018-05-31 20:47:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LiveWindow::SetEnabled(bool enabled) {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
|
|
|
|
if (inst.liveWindowEnabled == enabled) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.startLiveWindow = enabled;
|
|
|
|
|
inst.liveWindowEnabled = enabled;
|
2018-12-07 22:38:22 -05:00
|
|
|
// Force table generation now to make sure everything is defined
|
|
|
|
|
UpdateValuesUnsafe();
|
2018-05-31 20:47:15 -07:00
|
|
|
if (enabled) {
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.enabled) {
|
|
|
|
|
inst.enabled();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2018-05-31 20:47:15 -07:00
|
|
|
} else {
|
2021-06-15 23:06:03 -07:00
|
|
|
wpi::SendableRegistry::ForeachLiveWindow(
|
|
|
|
|
inst.dataHandle, [&](auto& cbdata) {
|
|
|
|
|
static_cast<SendableBuilderImpl&>(cbdata.builder)
|
|
|
|
|
.StopLiveWindowMode();
|
|
|
|
|
});
|
|
|
|
|
if (inst.disabled) {
|
|
|
|
|
inst.disabled();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2018-05-31 20:47:15 -07:00
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.enabledEntry.SetBoolean(enabled);
|
2018-05-31 20:47:15 -07:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 23:28:33 -08:00
|
|
|
void LiveWindow::UpdateValues() {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock lock(inst.mutex);
|
2018-12-07 22:38:22 -05:00
|
|
|
UpdateValuesUnsafe();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LiveWindow::UpdateValuesUnsafe() {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
2017-12-04 23:28:33 -08:00
|
|
|
// Only do this if either LiveWindow mode or telemetry is enabled.
|
2021-06-15 23:06:03 -07:00
|
|
|
if (!inst.liveWindowEnabled && !inst.telemetryEnabled) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
wpi::SendableRegistry::ForeachLiveWindow(inst.dataHandle, [&](auto& cbdata) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!cbdata.sendable || cbdata.parent) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-10-17 22:01:31 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!cbdata.data) {
|
2021-06-15 23:06:03 -07:00
|
|
|
cbdata.data = std::make_shared<Component>();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2019-10-17 22:01:31 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& comp = *std::static_pointer_cast<Component>(cbdata.data);
|
2019-10-17 22:01:31 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
if (!inst.liveWindowEnabled && !comp.telemetryEnabled) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2019-10-17 22:01:31 -07:00
|
|
|
|
|
|
|
|
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.
|
2020-12-28 12:58:06 -08:00
|
|
|
if (cbdata.name.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
auto ssTable = inst.liveWindowTable->GetSubTable(cbdata.subsystem);
|
2021-04-04 14:34:11 -07:00
|
|
|
std::shared_ptr<nt::NetworkTable> table;
|
2019-10-17 22:01:31 -07:00
|
|
|
// Treat name==subsystem as top level of subsystem
|
2020-12-28 12:58:06 -08:00
|
|
|
if (cbdata.name == cbdata.subsystem) {
|
2019-10-17 22:01:31 -07:00
|
|
|
table = ssTable;
|
2020-12-28 12:58:06 -08:00
|
|
|
} else {
|
2019-10-17 22:01:31 -07:00
|
|
|
table = ssTable->GetSubTable(cbdata.name);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2019-10-17 22:01:31 -07:00
|
|
|
table->GetEntry(".name").SetString(cbdata.name);
|
2021-06-13 16:38:05 -07:00
|
|
|
static_cast<SendableBuilderImpl&>(cbdata.builder).SetTable(table);
|
2019-10-17 22:01:31 -07:00
|
|
|
cbdata.sendable->InitSendable(cbdata.builder);
|
|
|
|
|
ssTable->GetEntry(".type").SetString("LW Subsystem");
|
|
|
|
|
|
|
|
|
|
comp.firstTime = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.startLiveWindow) {
|
2021-06-13 16:38:05 -07:00
|
|
|
static_cast<SendableBuilderImpl&>(cbdata.builder).StartLiveWindowMode();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2021-06-13 16:38:05 -07:00
|
|
|
cbdata.builder.Update();
|
2019-10-17 22:01:31 -07:00
|
|
|
});
|
2017-12-04 23:28:33 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.startLiveWindow = false;
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|